The MSDN documentation for EnumDisplayDevices states that passing NULL as the first parameter to the function returns information about the display adaptor(s) on the machine (passing a string returns information about the device with that name).
Various C# examples that I have seen on-line pass null to the function as follows:
result = EnumDisplayDevices(null, devNum, ref dd, flags);
However, when I pass null as the first parameter, I get a System.AccessViolationException with the message "Attempted to read or write protected memory".
If I change null to any random non-null string (eg, "hello"), then the function call succeeds (I just don't get any device information because there isn't a device called "hello").
So how do I pass null as the first parameter to the EnumDisplayDevices function? (I need to be able to pass names in subsequent calls to the function)
Relevant snippets of my code follow:
[DllImport("user32.dll")]
static extern bool EnumDisplayDevices(
string lpDevice,
uint iDevNum,
ref DISPLAY_DEVICE lpDisplayDevice,
uint dwFlags
);
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAY_DEVICE
{
public int cb;
public string DeviceName;
public string DeviceString;
public int StateFlags;
public string DeviceID;
public string DeviceKey;
}
#region Public Interface
public ObservableCollection<DisplayDevice> LoadDisplayDevices()
{
ObservableCollection<DisplayDevice> displayDevices = new ObservableCollection<DisplayDevice>();
uint devNum = 0;
uint flags = 0;
bool result = false;
DISPLAY_DEVICE dd = new DISPLAY_DEVICE();
dd.cb = (int)Marshal.SizeOf(dd);
try
{
result = EnumDisplayDevices(null, devNum, ref dd, flags);
...
Original definition from MSDN:
typedef struct _DISPLAY_DEVICE {
DWORD cb;
TCHAR DeviceName[32];
TCHAR DeviceString[128];
DWORD StateFlags;
TCHAR DeviceID[128];
TCHAR DeviceKey[128];
} DISPLAY_DEVICE, *PDISPLAY_DEVICE;
All string fields are defined as fixed-size arrays. Your DISPLAY_DEVICE
structure definition contains multiple string
values without instructions how to marshal them, so they will be passed as pointers. You'll need to use MarshalAsAttribute
to fix this:
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAY_DEVICE
{
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
public int StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}