I have the following C++ to get information about a specific monitor using the EnumDisplaySettings
WinAPI function.
#include <iostream>
#include <Windows.h>
int main()
{
DEVMODE dm;
dm.dmSize = sizeof dm;
EnumDisplaySettings(L"\\\\.\\DISPLAY1", ENUM_CURRENT_SETTINGS, &dm);
std::wcout << "Name: " << dm.dmDeviceName << std::endl;
std::wcout << "Width: " << dm.dmPelsWidth << std::endl;
std::wcout << "Height: " << dm.dmPelsHeight << std::endl;
}
I am trying to use the EnumDisplaySettings
function in C#.
To do this, I have recreated DEVMODEW as a C# struct and pass it into the method.
static void Main()
{
DeviceModeStruct deviceMode = new DeviceModeStruct();
deviceMode.dmSize = (ushort)Marshal.SizeOf(deviceMode);
bool successfullyGotScale = EnumDisplaySettings("\\\\.\\DISPLAY1",
ENUM_CURRENT_SETTINGS,
ref deviceMode);
if (successfullyGotScale)
{
Console.WriteLine($@"Name: {deviceMode.dmDeviceName}");
Console.WriteLine($@"Width: {deviceMode.dmPelsWidth}");
Console.WriteLine($@"Height: {deviceMode.dmPelsHeight}");
}
}
The issue is, when I run the code, I get the following exception.
Unhandled Exception: System.TypeLoadException: Could not load type 'DeviceModeStruct'
from assembly 'DevModeSo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
because it contains an object field at offset 70 that is incorrectly aligned or
overlapped by a non-object field.
at DevModeSo.Program.Main()
As far as I can tell, the issue is relating to
[FieldOffset(70), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmFormName;
and this answer to another similar Stack Overflow question seems to suggest I can split the string up to fix the issue.
However, when I tried to do that so that the code so that the values were aligned with "DWORDS" I got the same error.
[FieldOffset(70)]
public char dmFormName1;
[FieldOffset(71)]
public char dmFormName2;
[FieldOffset(72), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string dmFormName3;
How can this problem be resolved whilst still meeting the same data structure as defined by DEVMODEW?
Full C# code
using System;
using System.Runtime.InteropServices;
namespace DevModeSo
{
class Program
{
private const int ENUM_CURRENT_SETTINGS = -1;
static void Main()
{
DeviceModeStruct deviceMode = new DeviceModeStruct();
deviceMode.dmSize = (ushort)Marshal.SizeOf(deviceMode);
bool successfullyGotScale = EnumDisplaySettings("\\\\.\\DISPLAY1",
ENUM_CURRENT_SETTINGS,
ref deviceMode);
if (successfullyGotScale)
{
Console.WriteLine($@"Name: {deviceMode.dmDeviceName}");
Console.WriteLine($@"Width: {deviceMode.dmPelsWidth}");
Console.WriteLine($@"Height: {deviceMode.dmPelsHeight}");
}
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool EnumDisplaySettings(string deviceName,
int modeNum,
ref DeviceModeStruct deviceMode);
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
struct DeviceModeStruct
{
private const int STRING_SIZE = 32;
[FieldOffset(0), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmDeviceName;
[FieldOffset(32)] public ushort dmSpecVersion;
[FieldOffset(34)] public ushort dmDriverVersion;
[FieldOffset(36)] public ushort dmSize;
[FieldOffset(38)] public ushort dmDriverExtra;
[FieldOffset(40)] public uint dmFields;
[FieldOffset(44)] public PrinterOnlyFields printerMode;
[FieldOffset(44)] public DisplayOnlyFields displayMode;
[FieldOffset(60)] public short dmColor;
[FieldOffset(62)] public short dmDuplex;
[FieldOffset(64)] public short dmYResolution;
[FieldOffset(66)] public short dmTTOption;
[FieldOffset(68)] public short dmCollate;
[FieldOffset(70), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmFormName;
[FieldOffset(102)] public ushort dmLogPixels;
[FieldOffset(104)] public uint dmBitsPerPel;
[FieldOffset(108)] public uint dmPelsWidth;
[FieldOffset(112)] public uint dmPelsHeight;
[FieldOffset(116)] public uint dmDisplayFlags;
[FieldOffset(116)] public uint dmNup;
[FieldOffset(120)] public uint dmDisplayFrequency;
[FieldOffset(124)] public uint dmICMMethod;
[FieldOffset(128)] public uint dmICMIntent;
[FieldOffset(132)] public uint dmMediaType;
[FieldOffset(136)] public uint dmDitherType;
[FieldOffset(140)] public uint dmReserved1;
[FieldOffset(144)] public uint dmReserved2;
[FieldOffset(148)] public uint dmPanningWidth;
[FieldOffset(152)] public uint dmPanningHeight;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct PrinterOnlyFields
{
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct Point
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct DisplayOnlyFields
{
public Point dmPosition;
public uint dmDisplayOrientation;
public uint dmDisplayFixedOutput;
}
}
}