неверный размер буфера при маршалинге в нативный код - PullRequest
0 голосов
/ 18 ноября 2011

Я пытаюсь сделать несколько звонков в SetupApi.У меня конкретно возникают проблемы с SetupDiGetDeviceInterfaceDetail().

Вот мое определение нативного метода:

class NativeMethods {
    [DllImport("SetupApi.dll", SetLastError = true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevs,
                    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
                    ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
                    uint deviceInterfaceDetailDataSize,
                    ref uint requiredSize,
                    ref SP_DEVINFO_DATA deviceInfoData);
}

Вот нативные и управляемые определения для структуручаствует:

[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct GUID
{                    
    public Int32 Data1;
    public Int16 Data2;
    public Int16 Data3;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] Data4;

    public GUID(Int32 d1, Int16 d2, Int16 d3, byte[] d4)
    {
        Data1 = d1;
        Data2 = d2;
        Data3 = d3;
        Data4 = new byte[8];
        Array.Copy(d4, Data4, d4.Length);
    }
}

typedef struct _SP_DEVINFO_DATA {
    DWORD cbSize;
    GUID  ClassGuid;
    DWORD DevInst;    // DEVINST handle
    ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVINFO_DATA
{
    public uint cbSize;
    public GUID  ClassGuid;
    public uint DevInst;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DATA {
    DWORD cbSize;
    GUID  InterfaceClassGuid;
    DWORD Flags;
    ULONG_PTR Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize;
    public GUID  InterfaceClassGuid;
    public uint Flags;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_A {
    DWORD  cbSize;
    CHAR   DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
    public uint cbSize;
    public IntPtr devicePath;
}

Для этой последней структуры я прочитал предыдущий пост, в котором говорится, что структуры, определенные как SP_DEVICE_INTERFACE_DETAIL_DATA, имеют массив переменной длины, структура C # должна использовать IntPtr.Для этого я выделяю память через Marshal.AllocHGlobal (), как показано ниже.Вот как я использую SetupDiGetDeviceInterfaceDetail ():

uint requiredSize = 0; // is ignored in this usage
byte[] foo = new byte[1024];

SP_DEVINFO_DATA spDevInfoData = new SP_DEVINFO_DATA();
spDevInfoData.cbSize = (uint)Marshal.SizeOf(spDevInfoData);

SP_DEVICE_INTERFACE_DATA spDevInfData = new SP_DEVICE_INTERFACE_DATA();
spDevInfData.cbSize = (uint)Marshal.SizeOf(spDevInfData);

SP_DEVICE_INTERFACE_DETAIL_DATA spDevInfDetailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
spDevInfDetailData.cbSize = 5; // the size needs to be 5
spDevInfDetailData.devicePath = Marshal.AllocHGlobal(foo.Length); 

NativeMethods.SetupDiGetDeviceInterfaceDetail(devList,
                                              ref spDevInfData,
                                              ref spDevInfDetailData, 
                                              spDevInfDetailData.cbSize,
                                              ref requiredSize,
                                              ref spDevInfoData);

Я использую SetupDiGetClassDevs () и SetupDiEnumDeviceInterfaces () до моего использования SetupDiGetDeviceInterfaceDetail ().В обоих случаях методы работают.Мне предоставлен список устройств из первой функции, и я перебираю список с помощью вызова enum.

Однако, когда я вызываю SetupDiGetDeviceInterfaceDetail (), функция завершается ошибкой, и Win32 GetLastError () возвращаетошибка 122, которую я нашел: ERROR_INSUFFICIENT_BUFFER.Я не вижу, почему мой буфер имеет недостаточный размер.Я в основном делаю то, что я делаю в C ++ «тестовом приложении», потому что я не мог заставить это работать в C #.В этом приложении я использую массив char [] с 1024 членами, который назначен структуре SP_DEVICE_INTERFACE_DETAIL_DATA.Вот почему я использую байтовый массив из 1024 членов в C #.

Любая помощь или понимание приветствуются.

1 Ответ

1 голос
/ 18 ноября 2011

Да, вы используете функцию неправильно.SP_DEVICE_INTERFACE_DETAIL_DATA - это структура переменного размера, ANYSIZE_ARRAY не имеет смысла.Вы должны вызвать функцию дважды.В первом вызове передайте IntPtr.Zero для DeviceInterfaceDetailData и 0 для DeviceInterfaceDetailDataSize.Возвращенный RequiredSize говорит вам, сколько памяти выделить для структуры.Выделите и позвоните снова, теперь передав указатель и размер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...