来自 C++ 的 C# USB 驱动程序
C# USB driver from C++
我在尝试从 C# 调用 SetupDiEnumDeviceInterfaces 时遇到问题。它总是 returns 1784 错误代码 ("The supplied user buffer is not valid for the requested operation")。
在同一台机器上,如果我执行相应的 C++ 代码,则函数成功。
这是我的 C# 代码:
Guid classGuid = GUID_DEVINTERFACE_DFU; // Guid(0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e)
IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, IntPtr.Zero, Win32.DIGCF_DEVICEINTERFACE | Win32.DIGCF_PRESENT);
if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE)
{
Console.WriteLine("read hardware information error");
}
else
{
uint i = 0;
SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
devInfoData.classGuid = Guid.Empty;
devInfoData.devInst = 0;
devInfoData.reserved = IntPtr.Zero;
bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData);
if (false == result)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
SP_DEVICE_INTERFACE_DATA ifData = new SP_DEVICE_INTERFACE_DATA();
ifData.cbSize = 50;
ifData.Flags = 0;
ifData.InterfaceClassGuid = Guid.Empty;
ifData.Reserved = IntPtr.Zero;
bool result2 = Win32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, i, ref ifData);
if(result2 == false)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
}
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
public Guid classGuid;
public uint devInst;
public IntPtr reserved;
};
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DATA
{
public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
public class Win32
{
[DllImport("setupapi.dll", SetLastError = true)]
public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);
[DllImport("setupapi.dll", SetLastError = true)]
public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, UInt32 dwIndex, SP_DEVINFO_DATA devInfoData);
public const int DIGCF_PRESENT = 0x02;
public const int DIGCF_DEVICEINTERFACE = 0x10;
public const long ERROR_NO_MORE_ITEMS = 259L;
}
这是我的 C++ 代码:
GUID Guid=GUID_DFU; // { 0x3fe809ab, 0xfb91, 0x4cb5, { 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e } }
HDEVINFO info = SetupDiGetClassDevs(&Guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (info!=INVALID_HANDLE_VALUE)
{
SP_INTERFACE_DEVICE_DATA ifData;
ifData.cbSize=sizeof(ifData);
bool result = SetupDiEnumDeviceInterfaces(info, NULL, &Guid, devIndex, &ifData);
}
代码是运行 on Windows 8.1 x64,C#应用平台是x86。
您在 C# 代码中将 SP_DEVICE_INTERFACE_DATA
声明为 class。这意味着它已经是一个参考。然后通过引用 SetupDiEnumDeviceInfo
传递 SP_DEVICE_INTERFACE_DATA
实例。这意味着您传递的是 SP_DEVICE_INTERFACE_DATA**
而不是 SP_DEVICE_INTERFACE_DATA*
,用 C++ 术语来说。
或者:
- 将
SP_DEVICE_INTERFACE_DATA
更改为结构,或者
- 将
SP_DEVICE_INTERFACE_DATA
保留为 class,但按值传递。也就是说,就像您对 SP_DEVINFO_DATA
和 SetupDiEnumDeviceInfo
. 所做的那样
您 cbSize
的设置不正确。应该是:
ifData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
设置 SP_DEVICE_INTERFACE_DATA
的其他成员没有意义,因为它们会被您调用的函数忽略。该函数的工作是填充这些成员。
可能还有其他问题。很难说,因为您还没有发布您的实际代码。 C++代码编译不通过,C#代码不完整
我在尝试从 C# 调用 SetupDiEnumDeviceInterfaces 时遇到问题。它总是 returns 1784 错误代码 ("The supplied user buffer is not valid for the requested operation")。 在同一台机器上,如果我执行相应的 C++ 代码,则函数成功。 这是我的 C# 代码:
Guid classGuid = GUID_DEVINTERFACE_DFU; // Guid(0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e)
IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, IntPtr.Zero, Win32.DIGCF_DEVICEINTERFACE | Win32.DIGCF_PRESENT);
if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE)
{
Console.WriteLine("read hardware information error");
}
else
{
uint i = 0;
SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
devInfoData.classGuid = Guid.Empty;
devInfoData.devInst = 0;
devInfoData.reserved = IntPtr.Zero;
bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData);
if (false == result)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
SP_DEVICE_INTERFACE_DATA ifData = new SP_DEVICE_INTERFACE_DATA();
ifData.cbSize = 50;
ifData.Flags = 0;
ifData.InterfaceClassGuid = Guid.Empty;
ifData.Reserved = IntPtr.Zero;
bool result2 = Win32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, i, ref ifData);
if(result2 == false)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
}
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
public Guid classGuid;
public uint devInst;
public IntPtr reserved;
};
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DATA
{
public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
public class Win32
{
[DllImport("setupapi.dll", SetLastError = true)]
public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);
[DllImport("setupapi.dll", SetLastError = true)]
public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, UInt32 dwIndex, SP_DEVINFO_DATA devInfoData);
public const int DIGCF_PRESENT = 0x02;
public const int DIGCF_DEVICEINTERFACE = 0x10;
public const long ERROR_NO_MORE_ITEMS = 259L;
}
这是我的 C++ 代码:
GUID Guid=GUID_DFU; // { 0x3fe809ab, 0xfb91, 0x4cb5, { 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e } }
HDEVINFO info = SetupDiGetClassDevs(&Guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (info!=INVALID_HANDLE_VALUE)
{
SP_INTERFACE_DEVICE_DATA ifData;
ifData.cbSize=sizeof(ifData);
bool result = SetupDiEnumDeviceInterfaces(info, NULL, &Guid, devIndex, &ifData);
}
代码是运行 on Windows 8.1 x64,C#应用平台是x86。
您在 C# 代码中将 SP_DEVICE_INTERFACE_DATA
声明为 class。这意味着它已经是一个参考。然后通过引用 SetupDiEnumDeviceInfo
传递 SP_DEVICE_INTERFACE_DATA
实例。这意味着您传递的是 SP_DEVICE_INTERFACE_DATA**
而不是 SP_DEVICE_INTERFACE_DATA*
,用 C++ 术语来说。
或者:
- 将
SP_DEVICE_INTERFACE_DATA
更改为结构,或者 - 将
SP_DEVICE_INTERFACE_DATA
保留为 class,但按值传递。也就是说,就像您对SP_DEVINFO_DATA
和SetupDiEnumDeviceInfo
. 所做的那样
您 cbSize
的设置不正确。应该是:
ifData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
设置 SP_DEVICE_INTERFACE_DATA
的其他成员没有意义,因为它们会被您调用的函数忽略。该函数的工作是填充这些成员。
可能还有其他问题。很难说,因为您还没有发布您的实际代码。 C++代码编译不通过,C#代码不完整