【问题标题】:C# USB driver from C++来自 C++ 的 C# USB 驱动程序
【发布时间】:2015-06-22 11:11:51
【问题描述】:

我在尝试从 C# 调用 SetupDiEnumDeviceInterfaces 时遇到问题。它总是返回 1784 错误代码(“提供的用户缓冲区对于请求的操作无效”)。 如果我在同一台机器上执行相应的 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);
    }

代码在 Windows 8.1 x64 上运行,C# 应用平台为 x86。

【问题讨论】:

  • 你的 C++ 代码说,SP_INTERFACE_DEVICE_DATA 但我猜你的意思是 SP_DEVICE_INTERFACE_DATA。

标签: c# c++ winapi pinvoke


【解决方案1】:

您在 C# 代码中将 SP_DEVICE_INTERFACE_DATA 声明为一个类。这意味着它已经是一个参考。然后通过引用SetupDiEnumDeviceInfo 传递SP_DEVICE_INTERFACE_DATA 实例。这意味着您传递的是 SP_DEVICE_INTERFACE_DATA** 而不是 SP_DEVICE_INTERFACE_DATA*,在 C++ 术语中。

要么:

  1. 将SP_DEVICE_INTERFACE_DATA 更改为结构,或者
  2. 将SP_DEVICE_INTERFACE_DATA 保留为一个类,但按值传递它。也就是说,就像您对 SP_DEVINFO_DATA 和 SetupDiEnumDeviceInfo 所做的那样。

您错误地设置了cbSize。应该是:

ifData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

设置SP_DEVICE_INTERFACE_DATA 的其他成员没有意义,因为您调用的函数会忽略它们。该函数的工作是填充这些成员。

可能还有其他问题。很难说,因为你还没有发布你的实际代码。 C++代码不编译,C#代码不完整。

【讨论】:

  • 嗨,大卫,非常感谢您的回答。问题是 SP_DEVICE_INTERFACE_DATA 定义为类而不是结构。
  • 使用类也是完全可行的。你用SP_DEVINFO_DATA 做到了。您只需要按值传递。因为一个类已经是一个引用。并作为指针编组。结构也很好,但是你会通过ref。为了您的理智,您可能应该尝试对所有这些 C++ 结构使用相同的技术。这有助于避免混淆。
  • 现在我添加了一段新代码“SetupDiGetDeviceInterfaceDetail”,并且出现了同样的 1784 错误。你现在为什么?
  • 没有。我看不到你的代码。文档说 获取所需的缓冲区大小。使用 NULLDeviceInterfaceDetailData 指针、零的 DeviceInterfaceDetailDataSize 和有效的 RequiredSize 变量调用 SetupDiGetDeviceInterfaceDetail。作为对此类调用的响应,此函数在 RequiredSize 处返回所需的缓冲区大小,并因 GetLastError 返回 ERROR_INSUFFICIENT_BUFFER 而失败。 此外,我认为必须在此问题中调试其余代码是不公平的。我想我回答了这个问题。我不确定您对这个问题还有什么期望。
  • 这个网站不能这样工作。你不能一直这样改变问题。你问了一个问题。让我们坚持下去。完成后接受最佳答案。如果您有新问题,请提出新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多