如何从Windows对象管理器路径获取HMONITOR句柄?
从设备实例ID(DEVINST)获取HMONITOR的实现方法
核心思路
要把DEVINST和HMONITOR关联起来,需要通过**显示器设备的硬件标识(如设备路径、EDID数据)**作为桥梁:先从DEVINST提取显示器的唯一硬件信息,再枚举系统中所有HMONITOR,逐一比对信息找到匹配的句柄。
具体步骤
1. 从DEVINST获取显示器的设备路径
利用显示器类GUID(即你路径中的{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}),结合SetupDi系列函数提取对应DEVINST的设备接口路径:
- 调用
SetupDiGetClassDevs传入显示器GUID,获取系统中所有已连接显示器的设备信息集; - 遍历设备信息集,通过
CM_Get_Device_ID获取每个设备的实例ID,与你已有的DEVINST对应的ID比对; - 找到匹配项后,调用
SetupDiGetDeviceInterfaceDetail获取SP_DEVICE_INTERFACE_DETAIL_DATA结构体,其中的DevicePath就是该显示器的唯一设备路径(格式和你提供的路径一致)。
2. 枚举所有HMONITOR并匹配设备路径
调用EnumDisplayMonitors遍历系统中的每个显示器,在回调函数中完成匹配:
- 对每个HMONITOR,调用
GetMonitorInfo获取MONITORINFOEX结构体,提取显示器名称szDevice; - 调用
EnumDisplayDevices并传入EDD_GET_DEVICE_INTERFACE_NAME标志,获取该显示器的设备接口名称; - 将设备接口名称与之前从DEVINST拿到的设备路径比对,完全一致的即为目标HMONITOR。
关键代码片段示例
获取DEVINST对应的设备路径
#include <SetupAPI.h> #include <Cfgmgr32.h> #include <Windows.h> #pragma comment(lib, "SetupAPI.lib") #pragma comment(lib, "Cfgmgr32.lib") // 替换为你已有的设备实例ID const TCHAR* YOUR_DEVICE_INSTANCE_ID = TEXT("DISPLAY\\IVM1A3E\\5&1778d8b3&1&UID260"); TCHAR g_szTargetDevicePath[MAX_PATH] = {0}; void GetDevicePathFromDevInst() { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) return; SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_MONITOR, i, &deviceInterfaceData); i++) { DWORD requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devInfoData = {0}; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) { TCHAR szDeviceID[MAX_DEVICE_ID_LEN] = {0}; if (CM_Get_Device_ID(devInfoData.DevInst, szDeviceID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS) { if (_tcscmp(szDeviceID, YOUR_DEVICE_INSTANCE_ID) == 0) { _tcscpy_s(g_szTargetDevicePath, MAX_PATH, pDetailData->DevicePath); free(pDetailData); break; } } } free(pDetailData); } SetupDiDestroyDeviceInfoList(hDevInfo); }
枚举HMONITOR并匹配
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { MONITORINFOEX monitorInfo = {0}; monitorInfo.cbSize = sizeof(MONITORINFOEX); if (!GetMonitorInfo(hMonitor, &monitorInfo)) return TRUE; DISPLAY_DEVICE displayDevice = {0}; displayDevice.cb = sizeof(DISPLAY_DEVICE); for (DWORD i = 0; EnumDisplayDevices(monitorInfo.szDevice, i, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME); i++) { if (_tcscmp(displayDevice.DeviceID, g_szTargetDevicePath) == 0) { *(HMONITOR*)dwData = hMonitor; return FALSE; // 找到匹配项,停止枚举 } ZeroMemory(&displayDevice, sizeof(DISPLAY_DEVICE)); displayDevice.cb = sizeof(DISPLAY_DEVICE); } return TRUE; // 继续枚举下一个显示器 } HMONITOR GetTargetHMonitor() { HMONITOR targetHMonitor = NULL; EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&targetHMonitor); return targetHMonitor; }
注意事项
- 优先使用Unicode版本的API(如
SetupDiGetDeviceInterfaceDetailW),避免编码不匹配问题; - 若多个显示器EDID数据相同,设备路径是更可靠的匹配依据;
- 调用
CreateFile打开设备路径时,需设置合理的访问权限(如GENERIC_READ)。
内容的提问来源于stack exchange,提问作者usbpc102
相关产品推荐
相关产品推荐

