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
原文地址:https://www.cnblogs.com/cheungxiongwei/p/10676051.html