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
//
释放设备
[DllImport(
"
hid.dll
"
)]
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,
//
共享读写,或者一起
OPEN_EXISTING,
if
(HidHandle == -
1
)
return
0
;
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
[DllImport(
"
hid.dll
"
, SetLastError =
true
)]
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;
再补充点,释放设备资源的时候需要用到
//
释放设备的访问
[DllImport(
"
kernel32.dll
"
)]
internal
static
extern
int
CloseHandle(
int
hObject);
//
释放设备
[DllImport(
"
setupapi.dll
"
, SetLastError =
true
)]
internal
static
extern
IntPtr SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
public
void
Dispost()
//
释放设备资源(hDevInfo是SetupDiGetClassDevs获取的)
SetupDiDestroyDeviceInfoList(hDevInfo);
//
关闭连接(HidHandle是Create的时候获取的)
CloseHandle(HidHandle);