从Windows对象管理器路径获取HMONITOR句柄是否可行?

4

我有一个路径看起来像这样:

\\?\DISPLAY#IVM1A3E#5&1778d8b3&1&UID260#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}

我想从中获取HMONITOR handle

使用WinObj,我可以在GLOBAL??下看到它是一个符号链接到一些\Device\<number>

我该怎么做呢?

编辑:

路径可以分为三个部分。首先是\\?\前缀,其次是DISPLAY\IVM1A3E\5&1778d8b3&1&UID260,如果将#替换为\,则与设备实例ID相同。第三个是{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7},它是监视器设备GUID

有了设备实例 ID,我可以使用 CM_Get_ChildCM_Get_Sibling 遍历设备树,并使用 CM_Get_Device_ID 检查设备名称。但这只会给我一个 DEVINST 而不是一个 HMONITOR


你最开始是从哪里得到了 \?... 设备路径的? - Simon Mourier
注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wisp\Pen\Digimon - usbpc102
1个回答

6
你可以使用连接和配置显示器 (CCD) API,特别是The QueryDisplayConfig function函数,该函数检索当前设置中所有显示设备或视图的所有可能显示路径的信息。
使用以下代码,您将获得设备路径和监视器(及其句柄)之间的对应关系。
#include <Windows.h>
#include <stdio.h>
#include <vector>
#include <tuple>
#include <string>

int main()
{
    // get all paths
    UINT pathCount;
    UINT modeCount;
    if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount))
        return 0;

    std::vector<DISPLAYCONFIG_PATH_INFO> paths(pathCount);
    std::vector<DISPLAYCONFIG_MODE_INFO> modes(modeCount);
    if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr))
        return 0;

    // enum all monitors => (handle, device name)>
    std::vector<std::tuple<HMONITOR, std::wstring>> monitors;
    EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM lp)
    {
        MONITORINFOEX mi = {};
        mi.cbSize = sizeof(MONITORINFOEX);
        GetMonitorInfo(hmon, &mi);
        auto monitors = (std::vector<std::tuple<HMONITOR, std::wstring>>*)lp;
        monitors->push_back({ hmon, mi.szDevice });
        return TRUE;
    }, (LPARAM)&monitors);

    // for each path, get GDI device name and compare with monitor device name
    for (UINT i = 0; i < pathCount; i++)
    {
        DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
        deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
        deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
        deviceName.header.adapterId = paths[i].targetInfo.adapterId;
        deviceName.header.id = paths[i].targetInfo.id;
        if (DisplayConfigGetDeviceInfo((DISPLAYCONFIG_DEVICE_INFO_HEADER*)&deviceName))
            continue;

        wprintf(L"Monitor Friendly Name : %s\n", deviceName.monitorFriendlyDeviceName);
        wprintf(L"Monitor Device Path   : %s\n", deviceName.monitorDevicePath);

        DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {};
        sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
        sourceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
        sourceName.header.adapterId = paths[i].targetInfo.adapterId;
        sourceName.header.id = paths[i].sourceInfo.id;
        if (DisplayConfigGetDeviceInfo((DISPLAYCONFIG_DEVICE_INFO_HEADER*)&sourceName))
            continue;

        wprintf(L"GDI Device Name       : %s\n", sourceName.viewGdiDeviceName);

        // find the monitor with this device name
        auto mon = std::find_if(monitors.begin(), monitors.end(), [&sourceName](std::tuple<HMONITOR, std::wstring> t)
        {
            return !std::get<1>(t).compare(sourceName.viewGdiDeviceName);
        });
        wprintf(L"Monitor Handle        : %p\n", std::get<0>(*mon));
        wprintf(L"\n");
    }
    return 0;
}

在我的电脑上(有两个显示器),它将输出类似于这样的内容:
Monitor Friendly Name : C27HG7x
Monitor Device Path   : \\?\DISPLAY#SAM0E16#7&307b5912&0&UID1024#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
GDI Device Name       : \\.\DISPLAY2
Monitor Handle        : 0000000000160045

Monitor Friendly Name : DELL U2715H
Monitor Device Path   : \\?\DISPLAY#DELD069#7&307b5912&0&UID1028#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
GDI Device Name       : \\.\DISPLAY1
Monitor Handle        : 0000000000020083

请注意,您也可以使用WinRT的DisplayManager类 => DisplayView类 => Paths属性DisplayPath类 => Target属性 => TryGetMonitor函数获取相同的信息。保留HTML标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接