You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:10:12