C# P/Invoke SetupDiGetDeviceInterfaceDetail返回1784

C# P/Invoke SetupDiGetDeviceInterfaceDetail返回1784,c#,.net,unity3d,pinvoke,C#,.net,Unity3d,Pinvoke,我目前正在尝试p/Invoke到HID(在Unity中(因此使用.NET2.0))。 但是,调用SetupDiGetDeviceInterfaceDetail时,返回错误代码1784 注意:这是第二次调用,因为第一次调用应该(并且确实)返回错误122,并设置所需的缓冲区大小 ..Replaced With Full Source Below.. 使用的结构: ..Replaced With Full Source Below.. 目前没有使用细节数据,因为我看到应该使用IntPtr 如何消除

我目前正在尝试p/Invoke到HID(在Unity中(因此使用.NET2.0))。 但是,调用SetupDiGetDeviceInterfaceDetail时,返回错误代码1784

注意:这是第二次调用,因为第一次调用应该(并且确实)返回错误122,并设置所需的缓冲区大小

..Replaced With Full Source Below..
使用的结构:

..Replaced With Full Source Below..
目前没有使用细节数据,因为我看到应该使用IntPtr

如何消除1784错误并获取/迭代设备路径? 另外,我读到我应该使用“null”,而不是dData,但这也会导致错误(无法将null转换为设备接口数据)

编辑:完整源代码

DebugInput.cs:

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using Assets;

public class DebugInput : MonoBehaviour {
    static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.F3))
        {
            Debug.Log("Checking");
            WindowsHID hid = new WindowsHID();
            Guid gHid = hid.HIDGuid; // "4d1e55b2-f16f-11cf-88cb-001111000030"
            Debug.Log(gHid);
            IntPtr hDevInfo = hid.GetClassDevs(gHid); // 475463200L
            if (hDevInfo != INVALID_HANDLE_VALUE)
            {
                Debug.Log("INTPTR RETREIVED");
                WindowsHID.DEVICE_INTERFACE_DATA diData = new WindowsHID.DEVICE_INTERFACE_DATA();
                diData.cbSize = Marshal.SizeOf(diData); // 32


                Boolean Check = false;
                uint enumerator = 0;
                Check = hid.SetupInterfaces(hDevInfo, IntPtr.Zero, ref gHid, enumerator, ref diData); // Check = True, hDevInfo = 475463200L, diData.reserved = 653193792L (hDevInfo changes on each rebuild)
                uint sizeNeeded;
                WindowsHID.DEVINFO_DATA dData = new WindowsHID.DEVINFO_DATA();
                dData.cbSize = (uint)Marshal.SizeOf(dData); // 32u

                bool result3 = WindowsHID.SetupDiGetDeviceInterfaceDetail(hDevInfo, diData, IntPtr.Zero, 0, out sizeNeeded, dData); // sizeNeeded becomes 180u
                if (!result3)
                {
                    int error = Marshal.GetLastWin32Error(); // Expecting error 122, since we are only setting SizeNeeded Here (getting error 122)
                    Debug.Log(error);
                }
                IntPtr DeviceInterfaceDetailData = Marshal.AllocHGlobal((int)sizeNeeded); // 4640736L

                try
                {
                    uint size = sizeNeeded; // 180u
                    Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size); // DevinceInterfaceDetailData doesnt change (IS THIS LINE NEEDED?)
                    bool result4 = WindowsHID.SetupDiGetDeviceInterfaceDetail(hDevInfo, diData, DeviceInterfaceDetailData, size, out sizeNeeded, dData);
                    if (!result4)
                    {
                        int error = Marshal.GetLastWin32Error(); // GETTING ERROR 1784???
                        Debug.Log(error);
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(DeviceInterfaceDetailData);
                }                
            }
            else
            {
                Debug.Log("INVALID GUID");
            }            
        }
    }
}
WindowsHID.cs:

using UnityEngine;
using System;
using System.Runtime.InteropServices;
using System.Collections;

namespace Assets
{
    public class WindowsHID
    {
        /// <summary>Used in SetupDiClassDevs to get devices present in the system</summary>
        protected const int DIGCF_PRESENT = 0x02;
        /// <summary>Used in SetupDiClassDevs to get device interface details</summary>
        protected const int DIGCF_DEVICEINTERFACE = 0x10;
        protected const int DIGCF_ALLCLASSES = 0x04;
        static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        public WindowsHID()
        {

        }

        /// <summary>
        /// Provides Info About a Single USB-Device
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DEVICE_INTERFACE_DATA
        {
            public Int32 cbSize;
            public Guid interfaceClassGuid;
            public Int32 flags;
            public UIntPtr reserved;
        }

        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto, Pack=1)]
        public struct DEVICE_INTERFACE_DETAIL_DATA
        {
            public int cbSize;
            public char DevicePath;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DEVINFO_DATA
        {
            public uint cbSize;
            public Guid classGuid;
            public uint devInst;
            public IntPtr reserved;
        }        

        #region P/Invoke
        /// <summary>
        /// Gets the Windows GUID for the HID class Devices
        /// </summary>
        /// <param name="guid"></param>
        [DllImport("hid.dll", SetLastError = true)]
        protected static extern void HidD_GetHidGuid(out Guid guid);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ClassGuid"></param>
        /// <param name="Enumerator"></param>
        /// <param name="hwndParent"></param>
        /// <param name="Flags"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, IntPtr hwndParent, uint Flags);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hDevInfo"></param>
        /// <param name="devInfo"></param>
        /// <param name="interfaceClassGuid"></param>
        /// <param name="memberIndex"></param>
        /// <param name="deviceInterfaceData"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", SetLastError = true)]
        protected static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, int devInfo, ref Guid interfaceClassGuid, uint memberIndex, ref DEVICE_INTERFACE_DATA deviceInterfaceData);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hDevInfo"></param>
        /// <param name="deviceInterfaceData"></param>
        /// <param name="deviceInterfaceDetailData"></param>
        /// <param name="deviceInterfaceDetailDataSize"></param>
        /// <param name="requiredSize"></param>
        /// <param name="deviceInfoData"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, DEVINFO_DATA deviceInfoData);
        #endregion

        public Guid HIDGuid
        {
            get
            {
                Guid gHid;
                HidD_GetHidGuid(out gHid);
                return gHid;
            }
        }

        public IntPtr GetClassDevs(Guid gHid)
        {
            return SetupDiGetClassDevs(ref gHid, null, IntPtr.Zero, DIGCF_DEVICEINTERFACE);// | DIGCF_ALLCLASSES);
        }

        public Boolean SetupInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, uint memberIndex, ref DEVICE_INTERFACE_DATA deviceInterfaceData)
        {
            Boolean res = SetupDiEnumDeviceInterfaces(hDevInfo, 0, ref interfaceClassGuid, memberIndex, ref deviceInterfaceData);
            int a = Marshal.GetLastWin32Error();
            return res;
        }    

        public Boolean SetupInterfaceDetail(IntPtr hDevInfo, DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, DEVINFO_DATA deviceInfoData)
        {
            Boolean a = SetupDiGetDeviceInterfaceDetail(hDevInfo, deviceInterfaceData, deviceInterfaceDetailData, deviceInterfaceDetailDataSize, out requiredSize, deviceInfoData);
            int b = Marshal.GetLastWin32Error();
            return a;
        }
    }
}
使用UnityEngine;
使用制度;
使用System.Runtime.InteropServices;
使用系统集合;
命名空间资产
{
公共类窗口隐藏
{
///在SetupDiClassDevs中用于获取系统中存在的设备
受保护常数int DIGCF_PRESENT=0x02;
///在SetupDiClassDevs中用于获取设备接口详细信息
受保护常数int DIGCF\u设备接口=0x10;
受保护常量int DIGCF_ALLCLASSES=0x04;
静态只读IntPtr无效\u句柄\u值=新IntPtr(-1);
公共视窗
{
}
/// 
///提供有关单个USB设备的信息
/// 
[StructLayout(LayoutKind.Sequential)]
公共结构设备接口数据
{
公共Int32 cbSize;
公共Guid接口ClassGUID;
32面国旗;
保留公共UIntPtr;
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto,Pack=1)]
公共结构设备\u接口\u详细信息\u数据
{
公共机构的规模;
公共字符设备路径;
}
[StructLayout(LayoutKind.Sequential)]
公共结构DEVINFO_数据
{
公共单位cbSize;
公共Guid类Guid;
公共设备;
保留公共IntPtr;
}        
#区域P/调用
/// 
///获取HID类设备的Windows GUID
/// 
/// 
[DllImport(“hid.dll”,SetLastError=true)]
受保护的静态外部无效HidD_GetHidGuid(out Guid);
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
[DllImport(“setupapi.dll”,CharSet=CharSet.Auto,SetLastError=true)]
静态外部IntPtr SetupDiGetClassDevs(参考Guid ClassGuid[Marshallas(UnmanagedType.LPTStr)]字符串枚举器、IntPtr hwndParent、uint标志);
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
[DllImport(“setupapi.dll”,SetLastError=true)]
受保护的静态外部布尔设置DienumDeviceInterface(IntPtr hDevInfo、int devInfo、ref Guid interfaceClassGuid、uint memberIndex、ref设备接口数据设备接口数据);
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
/// 
[DllImport(“setupapi.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部布尔设置DiGetDeviceInterfaceDetail(IntPtr hDevInfo、设备接口数据设备InterfaceData、IntPtr设备InterfaceDetailData、uint设备InterfaceDetailDataSize、out uint requiredSize、设备信息数据设备信息数据);
#端区
公共Guid HIDGuid
{
得到
{
Guid;
HidD_GetHidGuid(输出gHid);
返回gHid;
}
}
公共IntPtr GetClassDevs(Guid gHid)
{
返回SetupDiGetClassDevs(ref gHid,null,IntPtr.Zero,DIGCF_DEVICEINTERFACE);//DIGCF_ALLCLASSES);
}
公共布尔设置接口(IntPtr hDevInfo、IntPtr devInfo、ref Guid interfaceClassGuid、uint memberIndex、ref设备接口数据设备接口数据)
{
布尔值res=setupDienumDeviceInterface(hDevInfo,0,ref interfaceClassGuid,memberIndex,ref deviceInterfaceData);
int a=Marshal.GetLastWin32Error();
返回res;
}    
公共布尔设置接口详细信息(IntPtr hDevInfo、设备接口数据设备接口数据、IntPtr设备接口详细数据、uint设备接口详细数据大小、out uint requiredSize、设备信息数据设备信息数据)
{
布尔值a=SetupDiGetDeviceInterfaceDetail(hdeInfo、deviceInterfaceData、deviceInterfaceDetailData、deviceInterfaceDetailDataSize、out requiredSize、DeviceInfo数据);
int b=Marshal.GetLastWin32Error();
返回a;
}
}
}

您需要替换以下行:

Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);

因为SetupDiGetDeviceInterfaceDetail文档明确指出:

调用者必须将DeviceInterfaceDetailData.cbSize设置为 调用此函数之前的sizeof(SP\u设备\u接口\u详细信息\u数据)。 cbSize成员始终包含固定部分的大小 数据结构,而不是反映变量长度字符串的大小 结束

sizeof(SP\u设备\u接口\u详细信息\u数据)
取决于进程位,X86进程为6位(字节打包+1字符,自动->unicode->4+2*1),X64进程为8位(无论如何打包8字节)

另请注意,SetupDiGetDeviceInterfaceDetail的定义应使用结构的ref参数。一旦更改了所有选项,您就可以获得如下设备路径:

string devicePath = Marshal.PtrToStringAuto(DeviceInterfaceDetailData + 4);

(PtrToStringAuto,因为您在p/invoke定义中选择了自动字符集)

您需要替换以下行:

Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);

因为SetupDiGetDeviceInterfaceDetail文档明确指出:

调用者必须将DeviceInterfaceDetailData.cbSize设置为 调用前的sizeof(SP\u设备\u接口\u详细信息\u数据)