Windows 7 64 bit and accessing Win32 API calls via P/Invoke & Marshal problems
I'm relatively new to .net/C# (though very experienced in Win32 / MFC and other platforms) and need to write a utility to talk to a custom USB HID device. The protocol is pretty simple and I already have a working utility written in MFC, but I would prefer to write the utility in .Net / C# as I'm trying to move with the times and leave MFC behind.
I did some investigation and came across this article which seemed to help me understand how to access HID devices from .Net/C#, especially as it's just calling out the to Win32 API calls I am already familiar with:
http://www.developerfusion.com/article/84338/making-usb-c-friendly/
The sample code provided gave me an excellent introduction to how to access the Win32 API calls to talk to the USB device (just as my previous MFC code did) and this all works fine on a 32 bit installation of Windows Vista or 7, but when I try to run the same code on a 64 bit installation it fails. Even if I try creating a dedicated 64 bit application it still fails.
I'm pretty sure the problem is with how the Marshal is passing the parameters (on the stack?) to the Win32 API, but my knowledge and experience of .Net/C# at this stage is not really good enough to understand exactly what the issue is and how to solve开发者_开发问答 it - the problem is likely more advanced than the level I am currently at.
Everything seems to work fine in the code until I reach the instruction...
while (SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref gHid, (uint)nIndex, ref oInterface)) // this gets the device interface information for a device at index 'nIndex' in the memory block
Where the SetupDI... returns true on 32 bit systems and subsequently iterates through all the connected USB devices but returns false on 64 bit systems. I'm pretty sure it's likely to be an issue with how parameters are being passed into the Win32 API function but I don't understand what the exact problem is. The DLLImport definition for the function is:
[DllImport("setupapi.dll", SetLastError = true)] protected static extern bool SetupDiEnumDeviceInterfaces(IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass, uint nIndex, ref DeviceInterfaceData oInterfaceData);
I wonder if anyone is able to suggest what the offending parameter might be and how I might fix it?
Thanks in advance for any help offered, if more information is required please ask for it! Rich
From MSDN:
BOOL SetupDiEnumDeviceInterfaces( __in HDEVINFO DeviceInfoSet, __in_opt PSP_DEVINFO_DATA DeviceInfoData, __in const GUID *InterfaceClassGuid, __in DWORD MemberIndex, __out PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData );DeviceInfoData [in, optional]
A pointer to an SP_DEVINFO_DATA structure...
Note that DeviceInfoData is a pointer - so should be IntPtr, not uInt:
[DllImport("setupapi.dll", SetLastError = true)] protected static extern bool SetupDiEnumDeviceInterfaces(IntPtr lpDeviceInfoSet, IntPtr pDeviceInfoData, ref Guid gClass, uint nIndex, ref DeviceInterfaceData oInterfaceData);
And when calling it, pass IntPtr.Zero instead of 0.
You might be able to track down the offending parameter problem (if that's what it is) by checking the value from GetLastError
, which can be obtained from Marshal.GetLastWin32Error()
in a .NET app.
One possible problem might be how the oInterface
variable is initialized. The cbSize element is supposed to be set. And a 64-bit version of that structure (SP_DEVICE_INTERFACE_DATA) might be larger than the 32-bit version. I looked at it just now briefly and counted in my head (always prone to error), and it looks like the 32-bit version will be 28 bytes, and the 64-bit version would be 32 bytes.
精彩评论