如何将 PHYSICAL_MONITOR 与监视器 DeviceID 关联

PuF*_*F1k 6 c++ winapi multiple-monitors low-level low-level-api

我需要帮助将从GetPhysicalMonitorsFromHMONITOR获得的 PHYSICAL_MONITOR与监视器 DISPLAY_DEVICE.DeviceID 关联起来(例如“\?\DISPLAY#GSM59AB#5&932a802&1&UID261#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}”),它来自使用的EnumDisplayDevices带有标志 EDD_GET_DEVICE_INTERFACE_NAME ,或者以某种方式从 DISPLAY_DEVICE.DeviceID 获取 PHYSICAL_MONITOR ,反之亦然。

我需要将它们关联起来,因为:

  1. HANDLE PHYSICAL_MONITOR.hPhysicalMonitor 将用于lowlevelmonitorconfigurationapi,因为我需要向监视器发送命令。

  2. DISPLAY_DEVICE.DeviceID 用于使用 SetupAPI 从注册表获取 EDID 结构(前 128 个字节对我来说足够了,只需要制造商代码和型号)

1和2已经完成,问题在于将id与物理监视器关联起来。 此外,还可以仅使用 SetupAPI 从注册表获取所有显示器 EDID,但在这种情况下,不可能获取物理显示器句柄。

MSDN上同样的问题,没有解决((

我还注意到一件事:此代码枚举了所有监视器:

DWORD DispNum = 0;
DISPLAY_DEVICE DisplayDevice;
// Initialize DisplayDevice.
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);

while ((EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0)))
{
    std::wstring deviceName = DisplayDevice.DeviceName;
    DISPLAY_DEVICE DisplayDeviceM;
    ZeroMemory(&DisplayDeviceM, sizeof(DisplayDeviceM));
    DisplayDeviceM.cb = sizeof(DisplayDeviceM);
    int monitorIndex = 0;
    while (EnumDisplayDevices(deviceName.c_str(), monitorIndex, &DisplayDeviceM, EDD_GET_DEVICE_INTERFACE_NAME))
    {
        std::wstring monitorID = DisplayDeviceM.DeviceID;
        ++monitorIndex;
    }
    DispNum++;
}
Run Code Online (Sandbox Code Playgroud)

与此相同的顺序:

BOOL CALLBACK EnumProc2(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
LPPHYSICAL_MONITOR pMons = NULL;
DWORD i, mcnt;

MONITORINFOEX mi;
ZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi);

GetMonitorInfo(hMonitor, &mi);

DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
EnumDisplayDevices(mi.szDevice, 0, &dd, EDD_GET_DEVICE_INTERFACE_NAME);

monitorModelMnufac MdlManuf = findMonitorModelManufactFromEDID(dd.DeviceID);

if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &mcnt)) return TRUE;
pMons = (LPPHYSICAL_MONITOR)malloc(mcnt * sizeof(PHYSICAL_MONITOR));
if (GetPhysicalMonitorsFromHMONITOR(hMonitor, mcnt, pMons))
    for (i = 0; i < mcnt; i++)
    {
        AddToMonHandles(pMons[i].hPhysicalMonitor, MdlManuf);
    }
free(pMons);
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)

物理监视器句柄是 0,1,2 等等,所以我可以从“monitorIndex”创建句柄,但我不确定这样做是否安全。

我还在注册表中查找物理显示器句柄,但什么也没有。

还找到了有用的VideoPortDDCMonitorHelper功能,但正如我在谷歌上搜索的那样,它需要在驱动程序/过滤器中使用,并且不能从简单的可执行文件中使用。

还尝试逆向 Windows dll,所有调用似乎都是从 WIN32U.dll 进行的,而 Ghidra 不想反编译它,或者我对此只是菜鸟。

请大家帮助我:)

Str*_*Sun 0

我找到了一些有用的信息,希望对你有帮助。

...
while ((EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0)))
    {
        std::wstring deviceName = DisplayDevice.DeviceName;
        DISPLAY_DEVICE DisplayDeviceM;
        ZeroMemory(&DisplayDeviceM, sizeof(DisplayDeviceM));
        DisplayDeviceM.cb = sizeof(DisplayDeviceM);
        int monitorIndex = 0;
        while (EnumDisplayDevices(deviceName.c_str(), monitorIndex, &DisplayDeviceM, EDD_GET_DEVICE_INTERFACE_NAME))
        {
            wcout << "deviceName:" << deviceName << endl;
            std::wstring monitorID = DisplayDeviceM.DeviceID;
            wcout <<"monitorID :"<< monitorID<< endl;
            ++monitorIndex;            
        }
        DispNum++;
    }
...
Run Code Online (Sandbox Code Playgroud)

输出:

deviceName: \\.\DISPLAY1
Run Code Online (Sandbox Code Playgroud)

然后使用EnumDisplayMonitors来获取HMONITOR并将其用作 的参数GetMonitorInfo

static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
    cout << "hmonitor:" << hMon << endl;

    MONITORINFOEX mi;
    mi.cbSize = sizeof(mi);

    GetMonitorInfo(hMon, (LPMONITORINFO)&mi);

    wcout << "deviceName: "<<mi.szDevice << endl;

    DWORD cPhysicalMonitors;
    BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(hMon, &cPhysicalMonitors);
    cout << "GetNumber: " << bSuccess << ", number of physical monitors: " << cPhysicalMonitors << endl;

    LPPHYSICAL_MONITOR pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors * sizeof(PHYSICAL_MONITOR));
    bSuccess = GetPhysicalMonitorsFromHMONITOR(hMon, cPhysicalMonitors, pPhysicalMonitors);
    cout << "GetPhysicalMonitor: " << bSuccess << endl
        << "Handle: " << pPhysicalMonitors->hPhysicalMonitor << endl
        << "Description: ";
    wcout << (WCHAR*)(pPhysicalMonitors->szPhysicalMonitorDescription) << endl;;

    D(pPhysicalMonitors->hPhysicalMonitor);

    DestroyPhysicalMonitors(cPhysicalMonitors, pPhysicalMonitors);
    free(pPhysicalMonitors);

    cout << "---------------------------------------" << endl;

    return TRUE;
}

...

EnumDisplayMonitors(0, 0, MonitorEnum, NULL);
Run Code Online (Sandbox Code Playgroud)

输出:

deviceName: \\.\DISPLAY1
Run Code Online (Sandbox Code Playgroud)

如果两个输出相同,则对应同一台显示器。最后我们可以将得到的作为HMONITOR的参数GetPhysicalMonitorsFromHMONITOR,这样就可以得到hPhysicalMonitor我们需要的了。