2011-11-18 71 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太小)。它現在在工作,所以謝謝。 –