2011-11-18 45 views
0

我正在尝试进入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的使用()之前进行。在这两种情况下,这些方法都有效。我提供了第一个函数的设备列表,并使用枚举调用遍历列表。

但是,当我调用SetupDiGetDeviceInterfaceDetail()时,函数失败,并且Win32 GetLastError()返回122的错误,我发现它是:ERROR_INSUFFICIENT_BUFFER。我看不出为什么我的缓冲区不够大小。我基本上正在做我在C++“测试应用程序”中做的事情,因为我无法在C#中使用它。在该应用程序中,我使用分配给SP_DEVICE_INTERFACE_DETAIL_DATA结构的char [] array 1024成员。这就是为什么我在C#中使用1024位字节数组成员。

任何帮助或见解都非常感谢。

+0

之后你看过'requiredSize'吗? – ordag

回答

1

是的,您没有正确使用该功能。 SP_DEVICE_INTERFACE_DETAIL_DATA是一个可变大小的结构,ANYSIZE_ARRAY没有意义。你必须调用两次函数。在第一次调用传递IntPtr.Zero的DeviceInterfaceDetailData和0的DeviceInterfaceDetailDataSize。返回的RequiredSize告诉你为结构分配多少内存。分配并再次调用,现在传递指针和大小。

+0

汉斯,谢谢你的帮助。更仔细地阅读API参考文献表明,我只需要关注自己的“第一次”电话。 SP_DEVICE_INTERFACE_DETAIL_DATA中的信息对我所要做的事情并不重要。我把问题归结为两个不同的东西。 1)我不熟悉这个API,2)我使用的是一个我在网上找到的C++示例(用法是错误的)。无论如何,我认为API中存在一个错误,因为在分配正确的内存之后,我仍然收到错误122(buff太小)。它现在在工作,所以谢谢。 –