EnumDisplayDevices — передача значения null вызывает ошибку

В документации MSDN для EnumDisplayDevices указано, что передача NULL в качестве первого параметра функции возвращает информацию об адаптере(ах) дисплея на компьютере (передача строки возвращает информацию об устройстве с таким именем).

Различные примеры C#, которые я видел в сети, передают null в функцию следующим образом:

result = EnumDisplayDevices(null, devNum, ref dd, flags);

Однако, когда я передаю значение null в качестве первого параметра, я получаю исключение 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);

            ...

person Harry Smith    schedule 16.03.2015    source источник
comment
Возможно, ошибка не вызвана передачей null. Возможно, это связано с одним из других параметров.   -  person John Saunders    schedule 16.03.2015
comment
Я думаю, что ваша проблема заключается в использовании строки вместо char[]. проверьте gadgetweb.de/programming/38-cs- и-the-char-mess.html   -  person Garr Godfrey    schedule 16.03.2015


Ответы (1)


Исходное определение из 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;
}
person max    schedule 16.03.2015
comment
Красиво, фантастика! В вашем ответе так много смысла, что я несколько смущен тем, что не подумал об этом. Очень ценю. - person Harry Smith; 17.03.2015