2015-10-12 45 views
0

我目前想的P/Invoke到HID(在Unity(所以使用.NET 2.0))。但是,在調用SetupDiGetDeviceInterfaceDetail時,它返回錯誤代碼1784.的P/Invoke SetupDiGetDeviceInterfaceDetail返回1784

MIND:這是第二次調用,因爲第一次調用應該(並且)會返回錯誤122,並設置所需的緩衝區大小。

..Replaced With Full Source Below.. 

二手結構:

..Replaced With Full Source Below.. 

DETAIL_DATA不是目前使用的,SICE我看到我應該使用一個IntPtr爲代替。

如何才能擺脫我的錯誤1784和獲取/重複我的設備路徑? 另外,我看我應該使用 「空」,在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; 
     } 
    } 
} 
+1

的DevicePath應該是一個IntPtr(或字符串) –

+0

我目前沒有使用結構..相反,我使用的IntPtr DeviceInterfaceDetailData =元帥。AllocHGlobal((int)的sizeNeeded);因爲我讀到我應該「刪除」該結構並使用IntPtr代替 –

+0

您需要提供完整的repro,您的代碼非常偏袒(需要一段時間才能重新定義您正在使用的所有內容) –

回答

3

您需要更換下面一行:

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

通過

Marshal.WriteInt32(DeviceInterfaceDetailData, IntPtr.Size == 8 ? 8 : 6); 

因爲SetupDiGetDeviceInterfaceDetail文件明確地指出這一點:

調用者必須調用此函數之前設置DeviceInterfaceDetailData.cbSize到 的sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)。 cbSize成員總是包含 數據結構,而不是一個尺寸在反射的 端可變長度字符串的固定部分的尺寸。

​​3210取決於過程位數,這是6與X86處理(字節填充+ 1個字符,自動 - >的unicode - > 4 + 2 * 1)和8與X64過程(8字節反正包裝) 。

還要注意你的SetupDiGetDeviceInterfaceDetail的定義應該使用ref參數的結構。一旦你已經改變了這一切,你可以得到這樣的設備路徑:

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

(因爲你選擇了你的頁碼自動字符集的PtrToStringAuto /調用定義)

+0

Dang it,我甚至在使用struct xD時已經有了它。似乎工作,雖然我真的不知道如何從IntPtr DeviceInterfaceDetailData中獲取(字符串)DevicePath ..請不要介意如何使用Struct DEVICE_INTERFACE_DETAIL_DATA執行此操作嗎? –

+0

此外,這是否意味着AllocHGlobal不需要? –

+0

啊,現在我看到其他人都在做它.. 而在其他一些被卡住: 他們有一個IntPtr與DEVICE_INTERFACE_DETAIL_DATA加入SetupDiGetDeviceInterfaceDetail兩次,一次,一次,讓他們先用IntPtr的叫它.Zero(獲取所需的大小),然後使用結構調用它,以獲取設備路徑。 Thx幫助 –