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

时间:2011-07-26 17:39:23

标签: c++ windows direct3d9

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

    // 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?

我查看了文档,了解从哪里提取实际名称,但直到现在我还没有找到它。有时候我有点愚蠢(如果你愿意,我会失明),所以我会在午休期间再给它一次 - 但也许有人可以指出我正确的方向?非常感谢。

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

2 个答案:

答案 0 :(得分:2)

    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();
}

答案 1 :(得分:1)

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

  • 假设监视器顺序与EnumDisplayDevices()相同的WMI内容。我想比较ID字符串,但无法在WMI数据中找到它。还需要另外看。
  • WMI代码可能没有使用最佳名称字段,但是我现在所拥有的上网本所有人都说“即插即用”blabla所以我将不得不在另一个系统上测试它我很快就有机会。但是,只需在WMI函数中调整此行:

    pClassObj->Get(L"Description", 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";
}