开发者

Descriptive monitor name from D3D display adapter ID

开发者 https://www.devze.com 2023-03-22 21:03 出处:网络
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 wh

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 w开发者_开发百科here 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)


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


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";
}
0

精彩评论

暂无评论...
验证码 换一张
取 消