D3D 显示适配器 ID 中的描述性显示器名称

发布于 2024-11-26 19:51:15 字数 796 浏览 0 评论 0原文

正如问题所示,我正在尝试提取描述性显示器名称以与显示适配器名称相匹配。下面的代码给了我一个像 \.\DISPLAY1 这样的设备 ID,这是可以理解的,但不是我正在寻找的。

    // Get name.
    D3DADAPTER_IDENTIFIER9 d3dID;
    d3d9.Get().GetAdapterIdentifier(iAdapter, 0, &d3dID);   
    dispAd.name = d3dID.Description;

    // Add monitor ID to display adapter name.
    FIX_ME // Not happy with this yet!
    HMONITOR hMonitor = d3d9.Get().GetAdapterMonitor(iAdapter);
    MONITORINFOEXA monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEXA);
    if (GetMonitorInfoA(hMonitor, &monInfoEx))
    {
        dispAd.name = dispAd.name + " on: " + monInfoEx.szDevice;
    }
    else TPB_ASSERT(0); // Mute?

我已经查看了文档以了解从哪里提取实际名称,但直到现在我还没有找到它。有时我有点愚蠢(或者盲目,如果你愿意的话),所以我会在午休时间再试一次——但也许有人可以给我指出正确的方向?多谢。

(我所说的实际名称是指图形配置面板中显示的名称)

As the question suggests, I'm trying to pull a descriptive monitor name to match with a display adapter name. The code below gives me a device ID like \.\DISPLAY1 which is understandable but not what I'm looking for.

    // Get name.
    D3DADAPTER_IDENTIFIER9 d3dID;
    d3d9.Get().GetAdapterIdentifier(iAdapter, 0, &d3dID);   
    dispAd.name = d3dID.Description;

    // Add monitor ID to display adapter name.
    FIX_ME // Not happy with this yet!
    HMONITOR hMonitor = d3d9.Get().GetAdapterMonitor(iAdapter);
    MONITORINFOEXA monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEXA);
    if (GetMonitorInfoA(hMonitor, &monInfoEx))
    {
        dispAd.name = dispAd.name + " on: " + monInfoEx.szDevice;
    }
    else TPB_ASSERT(0); // Mute?

I've looked around the documentation for where to pull that actual name from but until now I haven't been able to find it. Sometimes I am a little stupid (or blind if you will), so I'll give it another go during my lunch break -- but perhaps someone can point me in the right direction? Thanks a lot.

(and by actual name I mean the one presented in the graphics configuration panel)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故事未完 2024-12-03 19:51:15
    UINT iOutput = 0;
IDXGIOutput *pOutput = nullptr;
while (DXGI_ERROR_NOT_FOUND != pAdapter->EnumOutputs(iOutput++, &pOutput))
{
    DXGI_OUTPUT_DESC desc;
    VERIFY(S_OK == pOutput->GetDesc(&desc));

    MONITORINFOEXW monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEXW);
    GetMonitorInfoW(desc.Monitor, &monInfoEx);

    DISPLAY_DEVICEW dispDev;
    dispDev.cb = sizeof(DISPLAY_DEVICEW);
    EnumDisplayDevicesW(monInfoEx.szDevice, 0, &dispDev, 0);

    // FIXME: far from perfect, but should do the job if a vendor driver is installed.
    //        Otherwise it just displays something along the lines of "Plug & Play monitor".
    SendDlgItemMessageW(hDialog, IDC_COMBO_OUTPUT, CB_ADDSTRING, 0, (LPARAM) dispDev.DeviceString);

    pOutput->Release();
}
    UINT iOutput = 0;
IDXGIOutput *pOutput = nullptr;
while (DXGI_ERROR_NOT_FOUND != pAdapter->EnumOutputs(iOutput++, &pOutput))
{
    DXGI_OUTPUT_DESC desc;
    VERIFY(S_OK == pOutput->GetDesc(&desc));

    MONITORINFOEXW monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEXW);
    GetMonitorInfoW(desc.Monitor, &monInfoEx);

    DISPLAY_DEVICEW dispDev;
    dispDev.cb = sizeof(DISPLAY_DEVICEW);
    EnumDisplayDevicesW(monInfoEx.szDevice, 0, &dispDev, 0);

    // FIXME: far from perfect, but should do the job if a vendor driver is installed.
    //        Otherwise it just displays something along the lines of "Plug & Play monitor".
    SendDlgItemMessageW(hDialog, IDC_COMBO_OUTPUT, CB_ADDSTRING, 0, (LPARAM) dispDev.DeviceString);

    pOutput->Release();
}
深府石板幽径 2024-12-03 19:51:15

这有效。它应该只需要 Windows+stl 来编译并吃 HMONITOR。有些事情我不满意:

  • WMI 的东西假设监视器顺序与 EnumDisplayDevices() 相同。我想与 ID 字符串进行比较,但在 WMI 数据中找不到它。还需要再看一下。
  • WMI 代码可能不使用最佳名称字段,但在我现在拥有的上网本上,它们都说“即插即用”blabla,所以我必须尽快在另一个系统上测试它得到机会。不过,只需在 WMI 函数中调整这一行即可:

    pClassObj->Get(L"描述", 0, &varProp, NULL, NULL);
    

代码:

// tpbds -- Windows monitor description

// Disable warnings about non-unwindable objects in case C++ exceptions are disabled.
#pragma warning(disable:4530)

// Force Unicode.
#ifndef _UNICODE
    #define _UNICODE
#endif

#define _WIN32_DCOM
#pragma comment(lib, "wbemuuid.lib")

#include <windows.h>
#include <comdef.h>
#include <wbemidl.h>

#include <string>
#include <sstream>

#include "monitordescription.h"

#define FIX_ME
#define SAFE_RELEASE(pX) if (pX) pX->Release(); pX = NULL;

// serialize constant value T to std::wstring
template<typename T> inline std::wstring ToWideString(const T &X)
{
    std::wstringstream stream;
    stream << X;
    return stream.str();
}

static const std::wstring GetMonitorDescriptonFromWMI(DWORD iMonitor)
{
    // If anything fails down the line I just return an empty string and apply a fallback mechanism.
    // This type of function should never fail unless you're probing a non-existent piece of harwdare.

    // Initialize COM.
    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
    {
        return L"";
    }

    // Set COM security levels.
    // Note: if you are using Windows 200, you need to specify the default authentication
    // credentials for a user by using a SOLE_AUTHENTICATION_LIST structure in the pAuthList parameter.
    if (FAILED(CoInitializeSecurity(
        NULL,                        
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL, // pAuthList
        EOAC_NONE,
        NULL)))
    {
        CoUninitialize();
        return L"";
    }

    // Obtain initial locator to WMI.
    IWbemLocator *pLocator = NULL;
    if (FAILED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<LPVOID *>(&pLocator))))
    {
        CoUninitialize();
        return L"";
    }

    // Connect to WMI.
    IWbemServices *pServices = NULL;
    if (FAILED(pLocator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, NULL, NULL, NULL, &pServices)))
    {
        pLocator->Release();
        CoUninitialize();
        return NULL;
    }

    // Set security levels on the proxy.
    if (FAILED(CoSetProxyBlanket(
        pServices,
        RPC_C_AUTHN_WINNT,
        RPC_C_AUTHZ_NONE,
        NULL,
        RPC_C_AUTHN_LEVEL_CALL,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        EOAC_NONE)))
    {
        pServices->Release();
        pLocator->Release();
        CoUninitialize();
        return L"";
    }

    // Request WMI data.
    IEnumWbemClassObject* pEnumerator = NULL;
    if (FAILED(pServices->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_DesktopMonitor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator)))
    {
        pServices->Release();
        pLocator->Release();
        CoUninitialize();
        return L"";
    }

    // Try to compile a correct description.
    std::wstring description;
    DWORD iLoop = 1; // Monitor index is 1-based.
    IWbemClassObject *pClassObj = NULL;
    while (pEnumerator != NULL)
    {
        ULONG uReturn = 0;
        const HRESULT hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn);
        if (uReturn == 0)
        {
            // Done (pClassObj remains NULL).
            break;
        }

        // Is this the one we're looking for?
        FIX_ME // Untested shortcut (assumes order is identical to that of EnumDisplayDevices).
        if (iMonitor == iLoop) 
        {
            FIX_ME // This needs to be tested, I only had a Netbook without proper driver!
            VARIANT varProp;
            pClassObj->Get(L"Description", 0, &varProp, NULL, NULL); // Check the MSDN for Win32_DesktopMonitor to see what your options are!
            description = varProp.bstrVal;
            description += L" #" + ToWideString(iMonitor);
            VariantClear(&varProp);
            SAFE_RELEASE(pClassObj);

            // Done.
            break;
        }
        else
            SAFE_RELEASE(pClassObj);
    }

    pServices->Release();
    pLocator->Release();
    CoUninitialize();

    // With a bit of luck this string was just built.
    return description;
}

const std::wstring GetMonitorDescription(HMONITOR hMonitor)
{
    MONITORINFOEX monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEX);
    if (GetMonitorInfo(hMonitor, &monInfoEx))
    {
        // Get monitor index by matching ID.
        DWORD iDevNum = 0;
        DISPLAY_DEVICE dispDev;
        do
        {
            dispDev.cb = sizeof(DISPLAY_DEVICE);
            EnumDisplayDevices(NULL, iDevNum, &dispDev, 0);
            ++iDevNum; // Incrementing here is right since we want a 1-based display.
        }
        while (0 != wcscmp(dispDev.DeviceName, monInfoEx.szDevice));

        // Attempt to get the description from WMI.
        // If it's empty, carry on.
        const std::wstring descriptionFromWMI = GetMonitorDescriptonFromWMI(iDevNum);
        if (!descriptionFromWMI.empty())
            return descriptionFromWMI;

        // Enumerate again, since doing it by string instead of index yields a different (more usable) DeviceString.
        dispDev.cb = sizeof(DISPLAY_DEVICE);
        EnumDisplayDevices(monInfoEx.szDevice, 0, &dispDev, 0);

        // WMI approach failed so we rely on EnumDisplayDevices() for an acceptable result.
        std::wstring description(dispDev.DeviceString);
        return description + L" #" + ToWideString(iDevNum);
    }
    else return L"Unknown monitor";
}

This works. It is supposed to need only Windows+stl to compile and eats HMONITOR. Some things I'm not happy with:

  • The WMI stuff assuming the monitor order is the same as EnumDisplayDevices(). I wanted to compare to the ID string but could not find it in the WMI data. Still needs another look.
  • The WMI code probably doesn't use the optimal name field but on the Netbook I have around right now all of them say "Plug & play" blabla so I'll have to test it on another system a soon as I get the chance. Just a matter of tuning this line in the WMI function, though:

    pClassObj->Get(L"Description", 0, &varProp, NULL, NULL);
    

Code:

// tpbds -- Windows monitor description

// Disable warnings about non-unwindable objects in case C++ exceptions are disabled.
#pragma warning(disable:4530)

// Force Unicode.
#ifndef _UNICODE
    #define _UNICODE
#endif

#define _WIN32_DCOM
#pragma comment(lib, "wbemuuid.lib")

#include <windows.h>
#include <comdef.h>
#include <wbemidl.h>

#include <string>
#include <sstream>

#include "monitordescription.h"

#define FIX_ME
#define SAFE_RELEASE(pX) if (pX) pX->Release(); pX = NULL;

// serialize constant value T to std::wstring
template<typename T> inline std::wstring ToWideString(const T &X)
{
    std::wstringstream stream;
    stream << X;
    return stream.str();
}

static const std::wstring GetMonitorDescriptonFromWMI(DWORD iMonitor)
{
    // If anything fails down the line I just return an empty string and apply a fallback mechanism.
    // This type of function should never fail unless you're probing a non-existent piece of harwdare.

    // Initialize COM.
    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
    {
        return L"";
    }

    // Set COM security levels.
    // Note: if you are using Windows 200, you need to specify the default authentication
    // credentials for a user by using a SOLE_AUTHENTICATION_LIST structure in the pAuthList parameter.
    if (FAILED(CoInitializeSecurity(
        NULL,                        
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL, // pAuthList
        EOAC_NONE,
        NULL)))
    {
        CoUninitialize();
        return L"";
    }

    // Obtain initial locator to WMI.
    IWbemLocator *pLocator = NULL;
    if (FAILED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<LPVOID *>(&pLocator))))
    {
        CoUninitialize();
        return L"";
    }

    // Connect to WMI.
    IWbemServices *pServices = NULL;
    if (FAILED(pLocator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, NULL, NULL, NULL, &pServices)))
    {
        pLocator->Release();
        CoUninitialize();
        return NULL;
    }

    // Set security levels on the proxy.
    if (FAILED(CoSetProxyBlanket(
        pServices,
        RPC_C_AUTHN_WINNT,
        RPC_C_AUTHZ_NONE,
        NULL,
        RPC_C_AUTHN_LEVEL_CALL,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        EOAC_NONE)))
    {
        pServices->Release();
        pLocator->Release();
        CoUninitialize();
        return L"";
    }

    // Request WMI data.
    IEnumWbemClassObject* pEnumerator = NULL;
    if (FAILED(pServices->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_DesktopMonitor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator)))
    {
        pServices->Release();
        pLocator->Release();
        CoUninitialize();
        return L"";
    }

    // Try to compile a correct description.
    std::wstring description;
    DWORD iLoop = 1; // Monitor index is 1-based.
    IWbemClassObject *pClassObj = NULL;
    while (pEnumerator != NULL)
    {
        ULONG uReturn = 0;
        const HRESULT hRes = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn);
        if (uReturn == 0)
        {
            // Done (pClassObj remains NULL).
            break;
        }

        // Is this the one we're looking for?
        FIX_ME // Untested shortcut (assumes order is identical to that of EnumDisplayDevices).
        if (iMonitor == iLoop) 
        {
            FIX_ME // This needs to be tested, I only had a Netbook without proper driver!
            VARIANT varProp;
            pClassObj->Get(L"Description", 0, &varProp, NULL, NULL); // Check the MSDN for Win32_DesktopMonitor to see what your options are!
            description = varProp.bstrVal;
            description += L" #" + ToWideString(iMonitor);
            VariantClear(&varProp);
            SAFE_RELEASE(pClassObj);

            // Done.
            break;
        }
        else
            SAFE_RELEASE(pClassObj);
    }

    pServices->Release();
    pLocator->Release();
    CoUninitialize();

    // With a bit of luck this string was just built.
    return description;
}

const std::wstring GetMonitorDescription(HMONITOR hMonitor)
{
    MONITORINFOEX monInfoEx;
    monInfoEx.cbSize = sizeof(MONITORINFOEX);
    if (GetMonitorInfo(hMonitor, &monInfoEx))
    {
        // Get monitor index by matching ID.
        DWORD iDevNum = 0;
        DISPLAY_DEVICE dispDev;
        do
        {
            dispDev.cb = sizeof(DISPLAY_DEVICE);
            EnumDisplayDevices(NULL, iDevNum, &dispDev, 0);
            ++iDevNum; // Incrementing here is right since we want a 1-based display.
        }
        while (0 != wcscmp(dispDev.DeviceName, monInfoEx.szDevice));

        // Attempt to get the description from WMI.
        // If it's empty, carry on.
        const std::wstring descriptionFromWMI = GetMonitorDescriptonFromWMI(iDevNum);
        if (!descriptionFromWMI.empty())
            return descriptionFromWMI;

        // Enumerate again, since doing it by string instead of index yields a different (more usable) DeviceString.
        dispDev.cb = sizeof(DISPLAY_DEVICE);
        EnumDisplayDevices(monInfoEx.szDevice, 0, &dispDev, 0);

        // WMI approach failed so we rely on EnumDisplayDevices() for an acceptable result.
        std::wstring description(dispDev.DeviceString);
        return description + L" #" + ToWideString(iDevNum);
    }
    else return L"Unknown monitor";
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文