EnumDisplayDevices - 传递 null 会导致错误
EnumDisplayDevices - passing null causes error
EnumDisplayDevices 的 MSDN 文档指出,将 NULL 作为第一个参数传递给函数 returns 有关机器上显示适配器的信息(传递字符串 returns 有关设备的信息用那个名字)。
我在网上看到的各种C#例子将null传给函数如下:
result = EnumDisplayDevices(null, devNum, ref dd, flags);
但是,当我将 null 作为第一个参数传递时,我得到一个带有消息 "Attempted to read or write protected memory" 的 System.AccessViolationException。
如果我将 null 更改为任何随机的非空字符串(例如,"hello"),那么函数调用就会成功(我只是没有获得任何设备信息,因为没有名为 "hello").
那么如何将 null 作为第一个参数传递给 EnumDisplayDevices 函数? (我需要能够在函数的后续调用中传递名称)
我的代码的相关片段如下:
[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);
...
来自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;
所有字符串字段都定义为固定大小的数组。您的 DISPLAY_DEVICE
结构定义包含多个 string
值,但没有说明如何编组它们,因此它们将作为指针传递。您需要使用 MarshalAsAttribute
来解决这个问题:
[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;
}
EnumDisplayDevices 的 MSDN 文档指出,将 NULL 作为第一个参数传递给函数 returns 有关机器上显示适配器的信息(传递字符串 returns 有关设备的信息用那个名字)。
我在网上看到的各种C#例子将null传给函数如下:
result = EnumDisplayDevices(null, devNum, ref dd, flags);
但是,当我将 null 作为第一个参数传递时,我得到一个带有消息 "Attempted to read or write protected memory" 的 System.AccessViolationException。
如果我将 null 更改为任何随机的非空字符串(例如,"hello"),那么函数调用就会成功(我只是没有获得任何设备信息,因为没有名为 "hello").
那么如何将 null 作为第一个参数传递给 EnumDisplayDevices 函数? (我需要能够在函数的后续调用中传递名称)
我的代码的相关片段如下:
[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);
...
来自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;
所有字符串字段都定义为固定大小的数组。您的 DISPLAY_DEVICE
结构定义包含多个 string
值,但没有说明如何编组它们,因此它们将作为指针传递。您需要使用 MarshalAsAttribute
来解决这个问题:
[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;
}