首先使用CreateFile打开USB端口,CreateFile函数会返回一个HANDLE类型的句柄,该句柄可以用于下述的ReadFile和WriteFile之间的操作。
/// 实现以指定的参数方式打开USB设备
CreateFile(devicePathName,
GENERIC_READ | GENERIC_WRITE, // 已读写方式打开
FILE_SHARE_READ| FILE_SHARE_WRITE,
0,
OPEN_EXISTING // 打开已经存在的设备,当设备不存在时会返回错误
FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED, // 通信时的一些属性的设置、FILE_FLAG_OVERLAPPED表示已异步的方式打开设备
);
这是最关键的一步是如何获取devicePathName, 幸好windows提供了解决的方法,
使用SetupDiGetClassDevs方法, 关于该方法在MSDN有非常详细的解答:
详细请参考以下网址:
// 关于HDEVINFO类型在setupapi.h文件中有定义
// typedef LPVOID HDEVINFO
// 表示是一个指向void类型的指针
// 如果调用成功,返回所有符合要求的设备信息的句柄
// 如果调用失败,返回INVALID_HANDLE_VALUE
HDEVINFO SetupDiGetClassDevs(
_In_opt_ constGUID *ClassGuid, // 指向device setup class或device interface class接口的guid,这个参数是可选的, // 可以为NULL
_In_opt_ PCTSTREnumerator, // 指向一个一NULL结尾的字符串,可以是即插即用设备的枚举器ID。该参数也是可选的, // 可以为NULL
_In_opt_ HWND hwndParent,
_In_ DWORD Flags
);
// 调用方法
deviceInfoSet = SetupDiGetClassDevs( * guid, NUL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(deviceInfoSet == INVALID_HANDLE_VALUE) // 失败
{}
else // 成功
{}
如果想要获取详细的错误信息,通过调用GetLastError可以获取。
同时如果想要调用远程计算机上的设备的时候请使用SetupDiGetClassDevsEx。
当调用SetupDiGetClassDevs成功后,调用SetupDiEnumDeviceInterface方法,
枚举包含在设备信息集中的设备接口(enum the device information contained in the device
详细请参考下述网址:
https://msdn.microsoft.com/en-us/library/windows/hardware/ff551015(v=vs.85).aspx
一般的调用流程如下所述
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// 调用一次返回指定设备的硬件信息
while(SetupDiEnumDeviceInterface(deviceInfoSet, // 设备信息集
NULL,
*guid, //设备接口的guid,与SetupDiGetClassDevs保持一致即可
deviceIndex, // 索引号,每调用一次该方法,加1,初始为0
&deviceIntefaceData // SP_DEVICE_INTERFACE_DATA指针,记住在调用该方法之前必须设置cbSize的大小
))
{
DWORD bufferSize;
DWORD requiredSize;
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, //
&deviceInterfaceData, // 表示SP_DEVICE_INTERFACE_DATA,指定DeviceInfoSet的接口,一般来说是SetupDiEnumDeviceInterface返回// 的内容
NULL, // SP_DEVICE_INTERFACE_DETAIL_DATA指针用来接收指定interface的信息
0, // SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小,当上一个参数为NULL时,该参数必须为0
&requiredSize, // 返回DeviceInterfaceDetailData的buffer 大小
NULL );
}
// 第一次调用SetupDiGetDeviceInterfaceDetail方法后返回SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小
SP_DEVICE_INTERFACE_DETAIL_DATA detailBufferData;
detailBufferData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // 如果指定了这个参数,那么在使用之前必须设置cbSize参数的大小
SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
&deviceInterfaceData, //
&detailBufferData, // SP_DEVICE_INTERFACE_DETAIL_DATA指针用来接收指定interface的信息
requiredSize, // 上一次调用后返回的SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小
&requiredSize, // 返回DeviceInterfaceDetailData的buffer 大小
NULL );
// 如果SetupDiDeviceInterfaceDetail调用成功,detailBufferData包含有USB设备的路径信息。
}
关于SetupDiGetInterfaceDetail方法的详细请参考下述网址
还有一个非常重要的结构体需要介绍下。
SP_DEVICE_INTERFACE_DETAIL_DATA
关于详细的资料可以参考以下网址:
// 该结构体返回的DevicePath即设备的路径
typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
DWORD cbSize; // 表示该结构体的大小
TCHAR DevicePath[ANYSIZE_ARRAY]; // 已NULL结尾,包括设备接口路径的字符串(device interface path)
// 这个路径信息可以传递给一些win32函数,例如 CreateFile:
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;
备注: 在SetupDiXXX系列函数中,当SP_DEVICE_INTERFACE_DETAIL_DATA以参数的形式传递时,
函数会判断结构体的大小与成员cbSize是否一致,否则调用的函数会返回error。
/*
调用SetupDiGetClassDevs方法后,请调用SetupDiEnumDeviceInfo方法。该方法返回的SP_DEVINFO_DATA结构体指定了device information set集合中的设备元素信息。
*/
然后是读写USB设备,这有好几种方法,这里介绍两种:
①:ReadFile和WriteFile;
②:使用winusb_readpipe和winusb_writepipe方法;
最后当不再需要的时候一定要记得删除SetupDiGetClassDevs的返回信息,通过调用SetupDiDestroyDeviceInfoList函数即可,关于该函数的详细的介绍请参考下述MSDN网址
因为晚上时间有限,写的有不正确的地方希望大家指出来。
参考:
http://blog.csdn.net/tody_guo/article/details/8675237