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 ...
随机推荐
- java:常用的两种设计模式(单例模式和工厂模式)
一.单例模式:即一个类由始至终只有一个实例.有两种实现方式(1)定义一个类,它的构造方法是私有的,有一个私有的静态的该类的变量在初始化的时候就实例化,通过一个公有的静态的方法获取该对象.Java代码 ...
- PHP——连接数据库初
<?php //1.生成连接 造连接对象 //$db=new mysqli($dbhost(服务器),$username,$userpass,$dbdatabase); $db = new my ...
- 亿级Web系统的容错性建设实践(转)
三年多前,我在腾讯负责的活动运营系统,因为业务流量规模的数倍增长,系统出现了各种各样的异常,那个时候,我7*24小时地没日没夜处理告警,周末和凌晨也经常上线,疲于奔命.后来,当时的老领导对我说:你不能 ...
- 如何解决redis高并发客户端频繁time out?
解决方案:https://www.zhihu.com/question/24781521
- json datatable互转(真正能用的-原创)
网上有不少的转换类 可是不全 或者有错误 我现在贴一个 js 和C# 互转代码 希望能帮到需要的童鞋 首先C#转成 json /// <summary> /// DataT ...
- Linux 高频工具快速教程
全书分为三个部分: 第一部分为基础篇,介绍我们工作中常用的工具的高频用法: 第二部分为进阶篇,介绍的工具更多的适合程序员使用,分为程序构建.程序调试及程序优化: 第三部分是工具参考篇,主要介绍实用工具 ...
- 点击edittext并显示其内容
package com.example.sum;//sum import com.example.sum.R;//sum import android.app.Activity; import and ...
- ubuntu 安装dlib 出现dlib.so: undefined symbol: png_set_longjmp_fn
参考网上的教程安装dlib 安装教程1 sudo apt-get install libboost-python-dev cmake sudo pip install dlib 安装教程2ubuntu ...
- 【BZOJ】1641: [Usaco2007 Nov]Cow Hurdles 奶牛跨栏(floyd)
http://www.lydsy.com/JudgeOnline/problem.php?id=1641 这种水题无意义... #include <cstdio> #include < ...
- sed替换
1. sed可以替换给定的文本中的字符串,可以利用正则表达式进行匹配$ sed 's/pattern/replace_string/' file或者$ cat file | sed 's/patter ...