2012-02-12 117 views
2

我正在尝试连接到USB GPS设备。如果我通过CreateFile WinApi手动创建文件(使用设备管理器中指定的路径),我可以成功连接到设备。Win32Api USB SetupDiGetDeviceInterfaceDetail失败

但是,当我尝试通过枚举选择设备时,失败@ SetupDiGetDeviceInterfaceDetail调用。

我有正确工作的C代码,但我的C#翻译似乎无法正常工作。我尝试了许多基本相同的结果。

的作品

// Get enumerator handle for the specified ClassGuid 
HDEVINFO theDevInfo = SetupDiGetClassDevs((GUID*)&GUID_DEVINTERFACE_GRMNUSB, NULL, NULL, 
    DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 

SP_DEVICE_INTERFACE_DATA theInterfaceData; 
theInterfaceData.cbSize = sizeof(theInterfaceData); 

// populate theInterfaceData which contains device class information 
if (!SetupDiEnumDeviceInterfaces(theDevInfo, NULL, (GUID*)&GUID_DEVINTERFACE_GRMNUSB, 0, &theInterfaceData) && 
    GetLastError() == ERROR_NO_MORE_ITEMS) 
{ 
    gHandle = 0; 
    return; 
} 
// This is normally used to obtain the device path information using theInterfaceData obtained above 
bool initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, &theInterfaceData, NULL, 0, &theBytesReturned, NULL); 
// theBytesReturned = 83 
theDevDetailData = 
(PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(theBytesReturned); 
theDevDetailData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); 

bool initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, &theInterfaceData, theDevDetailData, theBytesReturned, NULL, &theDevInfoData); 

C代码C#

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 
public static extern Boolean SetupDiGetDeviceInterfaceDetail(
    IntPtr hDevInfo, 
    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, 
    IntPtr deviceInterfaceDetailData, 
    UInt32 deviceInterfaceDetailDataSize, 
    out UInt32 requiredSize, 
    IntPtr deviceInfoData 
    ); 

[StructLayout(LayoutKind.Sequential)] 
public struct SP_DEVICE_INTERFACE_DATA 
{ 
    public Int32 cbSize; 
    public Guid interfaceClassGuid; 
    public Int32 flags; 
    private UIntPtr reserved; 
} 


// Get enumerator handle for the specified ClassGuid 
IntPtr theDevInfo = SetupDiGetClassDevs(ref ClassGuid, (DiGetClassFlags.DIGCF_PRESENT | DiGetClassFlags.DIGCF_DEVICEINTERFACE)); 

SP_DEVICE_INTERFACE_DATA DevInterfaceData = new SP_DEVICE_INTERFACE_DATA(); 
DevInterfaceData.cbSize = Marshal.SizeOf(DevInterfaceData); 

initialized = SetupDiEnumDeviceInterfaces(theDevInfo, IntPtr.Zero, ref ClassGuid, 0, 
     ref DevInterfaceData); 
// I assume The DevInterfaceData is populated correctly as it matches the C Code 
// And I've compared the values in memory and they match 

uint bytesReturned = 0; 
initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, ref DevInterfaceData, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); 
// I expect bytesReturned = 83 and initialized = true which is the value that is returned in the C Code 
// Instead the value 162 is returned 

回答

2

我相信我发现这个问题。

各地pinvoke.net戳后,我发现下面

// build a Device Interface Detail Data structure 
SP_DEVICE_INTERFACE_DETAIL_DATA didd = new SP_DEVICE_INTERFACE_DETAIL_DATA(); 
if (IntPtr.Size == 8) // for 64 bit operating systems 
    didd.cbSize = 8; 
else didd.cbSize = 4 + Marshal.SystemDefaultCharSize; // for 32 bit systems 

在我的代码更改,这允许我适当地获得则DevicePath。

有兴趣的人参考。

http://pinvoke.net/default.aspx/setupapi.SetupDiGetDeviceInterfaceDetail

+1

不,这会破坏堆栈。使用Marshal.AllocHGlobal()来分配具有所需大小的缓冲区。你从第一个电话获得的大小。 – 2012-02-12 08:25:38

+0

为什么/如何损坏堆栈?当我进行Win32api调用时,是不是应该封送适当的内存? – galford13x 2012-02-12 09:43:46

+0

@HansPassant你有可能解释为什么'IntPtr.Size'测试是必要的,我们不能依靠编组器来获得'SizeOf(SP_DEVICE_INTERFACE_DETAIL_DATA)'对吗?我猜它与填充有关吗? – 2014-06-21 17:25:59

4

恭喜,它正在工作。你会得到一个Unicode字符串,它的长度是它的两倍。并且FALSE返回是正确的。你只需要调用Marshal.GetLastWin32Error()并确认你得到了ERROR_INSUFFICIENT_BUFFER。你的C代码被破坏了,可能是因为你忘记初始化返回为零的字节。

+0

C代码正常工作。这是C#代码无法正常工作。 theBytesReturned被初始化为0,它只是没有显示在上面的代码,因为我没有把整个功能来节省空间。我猜C代码由于是ASCII而返回了83个字节,但是如果C#代码需要一个UNICODE字符串,为什么它是162而不是83x2 = 166? – galford13x 2012-02-12 08:55:39

+0

我不知道,发布字符串,我会告诉你为什么。 C代码确实存在问题,函数必须返回FALSE,并且GetLastError()必须返回ERROR_INSUFFICIENT_BUFFER。然后您知道所需的缓冲区大小,分配它并再次调用该函数。 – 2012-02-12 09:15:10

+0

哦,是的,我同意,第一次调用返回false,还有第二次调用,我显然没有把这是实际deviceDetailData读取。我会编辑我的帖子以保持正确。这里是字符串@“\\?\ usb#vid_091e&pid_0003#5&4a03a84&0&5#{2c9c45c2-8e7d-4c08-a12d-816bbae722c0}” – galford13x 2012-02-12 09:37:27