window 如何枚举设备并禁用该设备和启用该设备?如何注册设备热拔插消息通知?
目前实现的功能:
1.设备枚举
2.设置设备禁用和启用
3.注册设备热拔插消息通知
4.获取设备 vid pid 数值
需要链接的库 SetupAPI.lib
DeviceManager 类如下:
DeviceManager.h
#include <string>
#include <vector>
#include <setupapi.h>
#include <initguid.h>
#include <devguid.h>
#include <stringapiset.h>
#include <Dbt.h>
#include <Usbiodef.h>
namespace zz {
typedef struct tagDeviceInfo
{
//设备友好名称
std::wstring szFriendlyName;
//设备类
std::wstring szDeviceClass;
//设备描述
std::wstring szDeviceDesc;
//设备硬件ID
std::wstring szDeviceID;
//设备驱动
std::wstring szDriverName;
//设备实例
DWORD dwDevIns;
//设备类标志
GUID Guid;
}DeviceInfo, *pDeviceInfo;
// This GUID is for all USB serial host PnP drivers, but you can replace it
// with any valid device class guid.
static GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
//GUID_DEVINTERFACE_USB_DEVICE
class DeviceManager
{
public:
DeviceManager();
~DeviceManager();
//枚举设备
std::vector<DeviceInfo> enumDeviceInfo(bool isAllInfo = false);
//设置设备状态(禁用/停用),true 禁用,false 启用
bool setDeviceStatus(DeviceInfo &theDevice, bool bStatusFlag);
//pid
std::wstring vid(std::wstring deviceID);
//vid
std::wstring pid(std::wstring deviceID);
//注册设备热拔插通知 win8 以上可使用 CM_Register_Notification 函数 https://docs.microsoft.com/zh-cn/windows-hardware/drivers/install/registering-for-notification-of-device-interface-arrival-and-device-removal
BOOL DoRegisterDeviceInterfaceToHwnd(IN GUID InterfaceClassGuid, IN HWND hWnd, OUT HDEVNOTIFY *hDeviceNotify);
};
//utf8 编码
std::string utf8_encode(const std::wstring &wstr);
}//zz
DeviceManager.cpp
#include "DeviceManager.h"
namespace zz {
DeviceManager::DeviceManager()
{
}
DeviceManager::~DeviceManager()
{
}
std::vector<DeviceInfo> DeviceManager::enumDeviceInfo(bool isAllInfo)
{
//结果集
std::vector<DeviceInfo> result_set;
HDEVINFO device_info_set;
//https://docs.microsoft.com/zh-cn/windows/desktop/api/setupapi/nf-setupapi-setupdigetclassdevsw
if (isAllInfo) {
//获取本地计算机所有设备信息集
device_info_set = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
}else {
//仅串口
device_info_set = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
}
if (device_info_set == INVALID_HANDLE_VALUE) {
fprintf(stderr, "GetLastError = %lu\r\n",GetLastError());
return result_set;
}
SP_DEVINFO_DATA device_info_data;
SecureZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA));
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
unsigned long device_info_set_index = 0;
//枚举设备
while (SetupDiEnumDeviceInfo(device_info_set, device_info_set_index, &device_info_data))
{
++device_info_set_index;
TCHAR szFriendlyName[MAX_PATH] = { 0 };
TCHAR szDeviceClass[MAX_PATH] = { 0 };
TCHAR szDeviceDesc[MAX_PATH] = { 0 };
TCHAR szDeviceID[MAX_PATH] = { 0 };
TCHAR szDriverName[MAX_PATH] = { 0 };
//SPDRP_HARDWAREID
//SPDRP_HARDWAREID
DeviceInfo device_info;
//获取友好名称
if (!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_FRIENDLYNAME, NULL, (PBYTE)szFriendlyName, MAX_PATH - 1, NULL)) {
fprintf(stderr, "%2d %s\r\n", device_info_set_index, utf8_encode(L"Get SPDRP_FRIENDLYNAME Failed").c_str());
}
//获取设备类
if (!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_CLASS, NULL, (PBYTE)szDeviceClass, MAX_PATH - 1, NULL)) {
fprintf(stderr, "%2d %s\r\n", utf8_encode(L"Get SPDRP_CLASS Failed").c_str());
}
//获取设备描述
if (!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_DEVICEDESC, NULL, (PBYTE)szDeviceDesc, MAX_PATH - 1, NULL)) {
fprintf(stderr, "%2d %s\r\n", device_info_set_index, utf8_encode(L"Get SPDRP_DEVICEDESC Failed").c_str());
}
//获取驱动名称
if (!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_HARDWAREID, NULL, (PBYTE)szDeviceID, MAX_PATH - 1, NULL)) {
fprintf(stderr, "%2d %s\r\n", device_info_set_index, utf8_encode(L"Get SPDRP_HARDWAREID Failed").c_str());
}
//获取驱动名称
if (!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_DRIVER, NULL, (PBYTE)szDriverName, MAX_PATH - 1, NULL)) {
fprintf(stderr, "%2d %s\r\n", device_info_set_index, utf8_encode(L"Get SPDRP_DRIVER Failed").c_str());
}
device_info.szFriendlyName = szFriendlyName;
device_info.szDeviceClass = szDeviceClass;
device_info.szDeviceDesc = szDeviceDesc;
device_info.szDeviceID = szDeviceID;
device_info.szDriverName = szDriverName;
device_info.dwDevIns = device_info_data.DevInst;//实例
device_info.Guid = device_info_data.ClassGuid;//GUID
result_set.push_back(device_info);
}
if (device_info_set) {
SetupDiDestroyDeviceInfoList(device_info_set);
}
return result_set;
}
bool DeviceManager::setDeviceStatus(DeviceInfo & theDevice, bool bStatusFlag)
{
//获取设备信息集
HDEVINFO device_info_set = SetupDiGetClassDevs(&theDevice.Guid, 0, 0, DIGCF_PRESENT /*| DIGCF_ALLCLASSES */);
if (device_info_set == INVALID_HANDLE_VALUE) {
fprintf(stderr, "SetupDiGetClassDevs ERR!");
return false;
}
SP_DEVINFO_DATA device_info_data;
SecureZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA));
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
unsigned long device_info_set_index = 0;
bool bFlag = false;
//枚举设备判断指定的设备是否存在
while (SetupDiEnumDeviceInfo(device_info_set, device_info_set_index, &device_info_data)) {
++device_info_set_index;
if (theDevice.dwDevIns == device_info_data.DevInst) {
bFlag = true;
break;
}
}
//
if (bFlag) {
//https://docs.microsoft.com/en-us/windows/desktop/api/setupapi/ns-setupapi-_sp_propchange_params
SP_PROPCHANGE_PARAMS change;
change.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
change.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
change.Scope = DICS_FLAG_GLOBAL;
change.StateChange = bStatusFlag ? DICS_ENABLE : DICS_DISABLE;
change.HwProfile = 0;
if (SetupDiSetClassInstallParams(device_info_set, &device_info_data, (SP_CLASSINSTALL_HEADER*)&change, sizeof(change))) {
if (!SetupDiChangeState(device_info_set, &device_info_data)) {
fprintf(stderr, "SetupDiChangeState ERR!");
bFlag = false;
}
}else {
fprintf(stderr, "SetupDiSetClassInstallParams ERR!");
bFlag = false;
}
}else {
fprintf(stderr, "Device not found!");
}
//释放资源
SetupDiDestroyDeviceInfoList(device_info_set);
return bFlag;
}
std::wstring DeviceManager::vid(std::wstring deviceID)
{
auto pos = deviceID.rfind(L"vid_");
if (pos == std::wstring::npos) {
return std::wstring();
}
return deviceID.substr(pos + 4, 4);
}
std::wstring DeviceManager::pid(std::wstring deviceID)
{
auto pos = deviceID.rfind(L"pid_");
if (pos == std::wstring::npos) {
return std::wstring();
}
return deviceID.substr(pos + 4, 4);
}
// Routine Description:
// Registers an HWND for notification of changes in the device interfaces
// for the specified interface class GUID.
// Parameters:
// InterfaceClassGuid - The interface class GUID for the device
// interfaces.
// hWnd - Window handle to receive notifications.
// hDeviceNotify - Receives the device notification handle. On failure,
// this value is NULL.
// Return Value:
// If the function succeeds, the return value is TRUE.
// If the function fails, the return value is FALSE.
// Note:
// RegisterDeviceNotification also allows a service handle be used,
// so a similar wrapper function to this one supporting that scenario
// could be made from this template.
//窗口需要处理 WM_DEVICECHANGE 消息
//不需要时需要使用 BOOL UnregisterDeviceNotification(HDEVNOTIFY Handle); 函数关闭注册的设备通知
//https://docs.microsoft.com/zh-cn/windows/desktop/DevIO/wm-devicechange
BOOL DeviceManager::DoRegisterDeviceInterfaceToHwnd(IN GUID InterfaceClassGuid, IN HWND hWnd, OUT HDEVNOTIFY * hDeviceNotify)
{
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
SecureZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = InterfaceClassGuid;
*hDeviceNotify = RegisterDeviceNotification(
hWnd, // events recipient
&NotificationFilter, // type of device
DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
);
if (NULL == *hDeviceNotify)
{
fprintf(stderr, "RegisterDeviceNotification");
return FALSE;
}
return TRUE;
}
std::string utf8_encode(const std::wstring & wstr)
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
}//zz
window 如何枚举设备并禁用该设备和启用该设备?如何注册设备热拔插消息通知?的更多相关文章
- 【转】iOS设备的UDID是什么?苹果为什么拒绝获取iOS设备UDID的应用?如何替代UDID?
本文讲诉的主要是为什么苹果2011年8月发布iOS 5后就开始拒绝App获取设备的UDID以及UDID替补方案,特别提醒开发者苹果App Store禁止访问UDID的应用上架(相关推荐:APP被苹果A ...
- linux设备驱动归纳总结(八):2.总线、设备和驱动的关系【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-110295.html linux设备驱动归纳总结(八):2.总线.设备和驱动的关系 xxxxxxxxx ...
- linux设备驱动归纳总结(八):1.总线、设备和驱动【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-109733.html linux设备驱动归纳总结(八):1.总线.设备和驱动 xxxxxxxxxxxx ...
- linux设备驱动归纳总结(三):2.字符型设备的操作open、close、read、write【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-59417.html linux设备驱动归纳总结(三):2.字符型设备的操作open.close.rea ...
- linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-59416.html linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru ...
- linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点
注册完设备和驱动之后,就需要注册设备节点 Linux杂项设备出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费.所以对于这些简单的字符设备它们共 ...
- [Apple开发者帐户帮助]七、注册设备(1)注册一个设备
您需要已注册的设备来创建开发或临时配置文件.要使用开发人员帐户注册设备,您需要拥有设备名称和设备ID. 注意:如果您使用自动签名,Xcode会为您注册连接的设备.Xcode Server也可以配置为注 ...
- 【Linux开发】linux设备驱动归纳总结(八):2.总线、设备和驱动的关系
linux设备驱动归纳总结(八):2.总线.设备和驱动的关系 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(八):1.总线、设备和驱动
linux设备驱动归纳总结(八):1.总线.设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
随机推荐
- [转]对P,NP和NPC问题的解释
总结: 归约(或别的什么叫法):如果解决了问题A,就能用解决A的方法来解决问题B,那么我们说问题B可以归约为/到问题A,本文记为[B]<[A].其含义就是问题A的求解复杂度比问题B要高,比如说A ...
- Netty系列之Netty百万级推送服务设计要点(转)
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
- input checkbox 选中问题
对html控制不熟的人,估计被checkbox的选中问题发愁了,因为input的checkbox只有选中属性 checked='checked' 但是它有另外一个规则就是Request的时候 只有选中 ...
- 由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端,或打开对每个 Microsoft .NET Framework SDK 文档的跟踪并检查服务器跟踪日志。
客户端调用WCF的时候报上面的错误,WCF只能序列化基础的数据类型,不能直接序列化SqlParameter类型,需要使用自定义类,然后在WCF服务端转换的方式解决: 自定义类代码如下: using S ...
- C++ 类的深拷贝和浅拷贝完美解决
//类的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Poin ...
- grafana里prometheus查询语法
名称 描述 label_values(label) 返回label每个指标中的标签值列表. label_values(metric, label) 返回label指定度量标准中的标签值列表. metr ...
- php模拟动态输出效果
读取数据库,显示数据 foreach($s as $ss){ echo '同步中 ...<br />'; for( $i = 1 ; $i < 2 ; $i++ ) { //echo ...
- (转)FFMPEG-数据结构解释(AVCodecContext,AVStream,AVFormatContext)
AVCodecContext 这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息 如果是单纯使用libavcodec,这部分信息需要调用者进行初始化:如果是使用整个FFMPEG库 ...
- 【BZOJ】1639: [Usaco2007 Mar]Monthly Expense 月度开支(二分)
http://www.lydsy.com/JudgeOnline/problem.php?id=1639 同tyvj1359,http://www.cnblogs.com/iwtwiioi/p/394 ...
- Angular入门篇高速开发导航网
简单介绍 AngularJS 是一个为动态WEB应用设计的结构框架,提供给大家一种新的开发应用方式.这样的方式能够让你扩展HTML的语法.以弥补在构建动态WEB应用时静态文本的不足.从而在web应用程 ...