P/Invoke SetupDiGetDeviceInterfaceDetail 返回 1784
P/Invoke SetupDiGetDeviceInterfaceDetail returning 1784
我目前正在尝试 P/Invoke 到 HID(在 Unity 中(因此使用 .Net 2.0))。
但是,在调用 SetupDiGetDeviceInterfaceDetail 时,它是 returning 错误代码 1784。
注意:这是第二次调用,因为第一次调用应该(并且确实)return 错误 122,并设置所需的缓冲区大小。
..Replaced With Full Source Below..
使用的结构:
..Replaced With Full Source Below..
DETAIL_DATA 目前没有使用,因为我看到我应该使用 IntPtr 来代替它。
如何摆脱我的错误 1784 和 get/iterate 我的设备路径?
另外,我读到我应该使用 "null",而不是 dData,但是这个错误也是如此(无法将 null 转换为 DEVICE_INTERFACE_DATA)
编辑:完整来源
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;
}
}
}
您需要替换以下行:
Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);
由
Marshal.WriteInt32(DeviceInterfaceDetailData, IntPtr.Size == 8 ? 8 : 6);
因为 SetupDiGetDeviceInterfaceDetail 文档明确指出:
The caller must set DeviceInterfaceDetailData.cbSize to
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) before calling this function.
The cbSize member always contains the size of the fixed part of the
data structure, not a size reflecting the variable-length string at
the end.
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
取决于进程位数,X86 进程为 6(字节打包 + 1 个字符,自动 -> unicode -> 4 + 2*1),X64 进程为 8(8 字节无论如何打包)。
另请注意,您对 SetupDiGetDeviceInterfaceDetail 的定义应使用结构的 ref 参数。更改所有内容后,您可以获得如下设备路径:
string devicePath = Marshal.PtrToStringAuto(DeviceInterfaceDetailData + 4);
(PtrToStringAuto 因为您在 p/invoke 定义中选择了自动字符集)
我目前正在尝试 P/Invoke 到 HID(在 Unity 中(因此使用 .Net 2.0))。 但是,在调用 SetupDiGetDeviceInterfaceDetail 时,它是 returning 错误代码 1784。
注意:这是第二次调用,因为第一次调用应该(并且确实)return 错误 122,并设置所需的缓冲区大小。
..Replaced With Full Source Below..
使用的结构:
..Replaced With Full Source Below..
DETAIL_DATA 目前没有使用,因为我看到我应该使用 IntPtr 来代替它。
如何摆脱我的错误 1784 和 get/iterate 我的设备路径? 另外,我读到我应该使用 "null",而不是 dData,但是这个错误也是如此(无法将 null 转换为 DEVICE_INTERFACE_DATA)
编辑:完整来源
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;
}
}
}
您需要替换以下行:
Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);
由
Marshal.WriteInt32(DeviceInterfaceDetailData, IntPtr.Size == 8 ? 8 : 6);
因为 SetupDiGetDeviceInterfaceDetail 文档明确指出:
The caller must set DeviceInterfaceDetailData.cbSize to sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) before calling this function. The cbSize member always contains the size of the fixed part of the data structure, not a size reflecting the variable-length string at the end.
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
取决于进程位数,X86 进程为 6(字节打包 + 1 个字符,自动 -> unicode -> 4 + 2*1),X64 进程为 8(8 字节无论如何打包)。
另请注意,您对 SetupDiGetDeviceInterfaceDetail 的定义应使用结构的 ref 参数。更改所有内容后,您可以获得如下设备路径:
string devicePath = Marshal.PtrToStringAuto(DeviceInterfaceDetailData + 4);
(PtrToStringAuto 因为您在 p/invoke 定义中选择了自动字符集)