• 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
    ",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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    
  • 相关阅读:
    SpringBoot集成logback.xml日志配置文件找不到错误
    两个List集合如何去重,取交集,并集,差集
    分转元工具类
    Redis(二十九)PHP 使用 Redis
    Redis学习(二十八)Java 使用 Redis
    Redis学习(二十七)Redis 分区
    Redis学习(二十六)Redis 管道技术
    面试题
    Android 自动化测试
    Inner Functions
  • 原文地址:https://www.cnblogs.com/cheungxiongwei/p/10676051.html
Copyright © 2020-2023  润新知