天天看點

C# 通路USB(HID)裝置

二話不說,直接給代碼,如果您真想做這方面的東西,還是稍微研究下,沒有現成的好類用,就需要自己了解其原理

//引用空間

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Threading;

using System.Collections;

using System.IO;

 //以下是調用windows的API的函數

        //獲得GUID

        [DllImport("hid.dll")]

        public static extern void HidD_GetHidGuid(ref Guid HidGuid);

        Guid guidHID = Guid.Empty;

        //過濾裝置,擷取需要的裝置

        [DllImport("setupapi.dll", SetLastError = true)]

        public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);

        IntPtr hDevInfo;

        //擷取裝置,true擷取到

        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);

        public struct SP_DEVICE_INTERFACE_DATA

        {

            public int cbSize ;

            public Guid interfaceClassGuid;

            public int flags;

            public int reserved;

        }

        // 擷取接口的詳細資訊 必須調用兩次 第1次傳回長度 第2次擷取資料 

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]

        private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData,

            int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData);

        [StructLayout(LayoutKind.Sequential)]

        public class SP_DEVINFO_DATA

            public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

            public Guid classGuid = Guid.Empty; // temp

            public int devInst = 0; // dumy

            public int reserved = 0;

        [StructLayout(LayoutKind.Sequential, Pack = 2)]

        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA

            internal int cbSize;

            internal short devicePath;

        public enum DIGCF

            DIGCF_DEFAULT = 0x1,

            DIGCF_PRESENT = 0x2,

            DIGCF_ALLCLASSES = 0x4,

            DIGCF_PROFILE = 0x8,

            DIGCF_DEVICEINTERFACE = 0x10

        //擷取裝置檔案

        [DllImport("kernel32.dll", SetLastError = true)]

        private static extern int CreateFile(

            string lpFileName,                            // file name

            uint dwDesiredAccess,                        // access mode

            uint dwShareMode,                            // share mode

            uint lpSecurityAttributes,                    // SD

            uint dwCreationDisposition,                    // how to create

            uint dwFlagsAndAttributes,                    // file attributes

            uint hTemplateFile                            // handle to template file

            );

        //讀取裝置檔案

        [DllImport("Kernel32.dll",SetLastError = true)]

        private static extern bool ReadFile

            (

                IntPtr hFile,

                byte[] lpBuffer,

                uint nNumberOfBytesToRead,

                ref uint lpNumberOfBytesRead,

                IntPtr lpOverlapped

        //釋放裝置

        static public extern bool HidD_FreePreparsedData(ref IntPtr PreparsedData);

        //關閉通路裝置句柄,結束程序的時候把這個加上保險點

        [DllImport("kernel32.dll")]

        static public extern int CloseHandle(int hObject);

接下來是通路裝置的代碼

//代碼暫時沒有整理,傳入參數是裝置序号,

//有些USB裝置其實有很多HID裝置,就是一個接口上有幾個裝置,這個時候需要

//用index++來逐個循環,直到擷取裝置傳回false後,跳出去,把擷取的裝置

//路徑全記錄下來就好了,我這裡知道具體裝置号,是以沒有循環,浪費我時間

         //定于句柄序号和一些參數,具體可以去網上找這些API的參數說明,後文我看能不能把資料也寫上去

         int HidHandle = -1;

        public const uint GENERIC_READ = 0x80000000;

        public const uint GENERIC_WRITE = 0x40000000;

        public const uint FILE_SHARE_READ= 0x00000001;

        public const uint FILE_SHARE_WRITE = 0x00000002;

        public const int OPEN_EXISTING = 3;

private void UsBMethod(int index)

            HidD_GetHidGuid(ref guidHID);

            hDevInfo = SetupDiGetClassDevs(ref guidHID, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);

            int bufferSize = 0;

            ArrayList HIDUSBAddress = new ArrayList();

            //while (true)

            //{

            //擷取裝置,true擷取到

             SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();

            DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData);

            //for (int i = 0; i < 3; i++)

                bool result = SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guidHID, (UInt32)index, ref DeviceInterfaceData);

            //}

            //第一次調用出錯,但可以傳回正确的Size 

            SP_DEVINFO_DATA strtInterfaceData = new SP_DEVINFO_DATA();

            result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, strtInterfaceData);

            //第二次調用傳遞傳回值,調用即可成功

            IntPtr detailDataBuffer = Marshal.AllocHGlobal(bufferSize);

            SP_DEVICE_INTERFACE_DETAIL_DATA detailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();

            detailData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));

            Marshal.StructureToPtr(detailData, detailDataBuffer, false);

            result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, strtInterfaceData);

            if (result == false)

            {

                //break;

            }

            //擷取裝置路徑訪

              IntPtr pdevicePathName = (IntPtr)((int)detailDataBuffer + 4);

            string devicePathName = Marshal.PtrToStringAuto(pdevicePathName);

            HIDUSBAddress.Add(devicePathName);

            //index++;

            //break;

            //連接配接裝置檔案

            int aa = CT_CreateFile(devicePathName);

            bool bb = USBDataRead(HidHandle);

       //建立和裝置的連接配接

       public unsafe int CT_CreateFile(string DeviceName)

            HidHandle = CreateFile(

                DeviceName,

                GENERIC_READ,// | GENERIC_WRITE,//讀寫,或者一起

                FILE_SHARE_READ,// | FILE_SHARE_WRITE,//共享讀寫,或者一起

                0,

                OPEN_EXISTING,

                0);

            if (HidHandle == -1)

                return 0;

            else

                return 1;

        //根據CreateFile拿到的裝置handle通路檔案,并傳回資料

        public unsafe bool USBDataRead(int handle)

            while (true)

                uint read = 0;

                //注意位元組的長度,我這裡寫的是8位,其實可以通過API擷取具體的長度,這樣安全點,

                  //具體方法我知道,但是沒有寫,過幾天整理完代碼,一起給出來

                Byte[] m_rd_data = new Byte[8];

                bool isread = ReadFile((IntPtr)handle, m_rd_data, (uint)8, ref read, IntPtr.Zero);

                //這裡已經是拿到的資料了

                Byte[] m_rd_dataout = new Byte[read];

                Array.Copy(m_rd_data, m_rd_dataout, read);

OK,如果隻是擷取USB傳過來的資料,這裡已經足夠了,但是有點要注意,2000和XP如果要擷取HID鍵盤和滑鼠的資料,readfile是不行的,;

在Win2000和WinXP下不能用CreateFile+ReadFile/WriteFile的方式來讀寫标準滑鼠和标準鍵盤的資料,因為它們是系統獨占的(Exlusive)。

如果你是其他HID類裝置,比如遊戲搖桿或者自定義HID裝置,都可以用上面的方式來收發資料,

怎麼通路我暫時也不知道,估計要用它方法,看到有些軟體是用截取的手段,估計是用鈎子了吧。。

還有擷取封包長度的代碼,如果不确定封包長度,或者為了驅動适應變化,就用一下代碼來确定封包的長度

//擷取裝置具體資訊   

        [DllImport("hid.dll", SetLastError = true)]   

        private unsafe static extern int HidP_GetCaps(   

            int pPHIDP_PREPARSED_DATA,                    // IN PHIDP_PREPARSED_DATA  PreparsedData,   

            ref HIDP_CAPS myPHIDP_CAPS);                // OUT PHIDP_CAPS  Capabilities   

        private unsafe static extern int HidD_GetPreparsedData(   

            int hObject,                                // IN HANDLE  HidDeviceObject,   

            ref int pPHIDP_PREPARSED_DATA);           

        // HIDP_CAPS   

        [StructLayout(LayoutKind.Sequential)]   

        public unsafe struct HIDP_CAPS   

        {   

            public System.UInt16 Usage;                    // USHORT   

            public System.UInt16 UsagePage;                // USHORT   

            public System.UInt16 InputReportByteLength;   

            public System.UInt16 OutputReportByteLength;   

            public System.UInt16 FeatureReportByteLength;   

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]   

            public System.UInt16[] Reserved;                // USHORT  Reserved[17];               

            public System.UInt16 NumberLinkCollectionNodes;   

            public System.UInt16 NumberInputButtonCaps;   

            public System.UInt16 NumberInputValueCaps;   

            public System.UInt16 NumberInputDataIndices;   

            public System.UInt16 NumberOutputButtonCaps;   

            public System.UInt16 NumberOutputValueCaps;   

            public System.UInt16 NumberOutputDataIndices;   

            public System.UInt16 NumberFeatureButtonCaps;   

            public System.UInt16 NumberFeatureValueCaps;   

            public System.UInt16 NumberFeatureDataIndices;   

        }   

 int reportLength = 8;   

            //擷取裝置發送的位元組的長度(也有其他資訊)   

            int myPtrToPreparsedData = -1;   

            int result1 = HidD_GetPreparsedData(handle, ref myPtrToPreparsedData);   

            HIDP_CAPS myHIDP_CAPS = new HIDP_CAPS();   

            int result2 = HidP_GetCaps(myPtrToPreparsedData, ref myHIDP_CAPS);   

            reportLength = myHIDP_CAPS.InputReportByteLength;  

再補充點,釋放裝置資源的時候需要用到

//釋放裝置的通路

        internal static extern int CloseHandle(int hObject);

//釋放裝置

        internal static extern IntPtr SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

public void Dispost()

            //釋放裝置資源(hDevInfo是SetupDiGetClassDevs擷取的)

            SetupDiDestroyDeviceInfoList(hDevInfo);

            //關閉連接配接(HidHandle是Create的時候擷取的)

            CloseHandle(HidHandle);

ok

了. 

繼續閱讀