C# 封送到本机代码时缓冲区大小不正确

C# 封送到本机代码时缓冲区大小不正确,c#,pinvoke,C#,Pinvoke,我正在尝试对SetupApi进行一些调用。我在这方面特别有问题 以下是我对本机方法的定义: class NativeMethods { [DllImport("SetupApi.dll", SetLastError = true)] [return : MarshalAs(UnmanagedType.Bool)] public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevs,

我正在尝试对SetupApi进行一些调用。我在这方面特别有问题

以下是我对本机方法的定义:

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()的:

在使用SetupDiGetDeviceInterfaceDetail()之前,我正在使用SetupDiGetClassDevs()和SetupDiEnumDeviceInterfaces()。在这两种情况下,方法都有效。我从第一个函数中获得了设备列表,并且正在使用enum调用对该列表进行迭代

但是,当我调用SetupDiGetDeviceInterfaceDetail()时,函数失败,Win32 GetLastError()返回一个122的错误,我发现这个错误是:错误\u缓冲区不足\u。我不明白为什么我的缓冲区大小不够。我基本上在C++中做我的测试应用程序,因为我不能在C语言中工作。在那个应用程序中,我使用了一个char[]数组1024个成员,分配给SP\u DEVICE\u INTERFACE\u DETAIL\u数据结构。这就是为什么我在C#中使用1024个成员的字节数组


非常感谢您的帮助或见解。

是的,您没有正确使用该功能。SP_设备_接口_细节_数据是一个可变大小的结构,任何大小的_数组都没有意义。您必须调用该函数两次。在第一个调用过程中,DeviceInterfaceDetailData的IntPtr.0和DeviceInterfaceDetailDataSize的IntPtr.0。返回的RequiredSize告诉您要为结构分配多少内存。分配并再次调用,现在传递指针和大小。

之后您是否查看了
requiredSize
?Hans,谢谢您的帮助。对API引用的更仔细的阅读表明,我只需要关心“第一个”调用。SP_DEVICE_INTERFACE_DETAIL_数据中的信息对于我尝试执行的操作并不重要。我把这个问题归咎于两件不同的事情。1)我不熟悉API,2)我使用了一个C++例子,我在网上发现它正在工作(用法错误)。无论如何,我认为API中有一个bug,因为在分配了适当的内存后,我仍然得到错误122(buff太小)。现在可以用了,谢谢。
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);