【问题标题】:Getting the same display names as in "Advanced display settings" panel with WinApi使用 WinApi 获取与“高级显示设置”面板中相同的显示名称
【发布时间】:2019-07-02 00:44:40
【问题描述】:

使用与通过 WinApi 获取显示名称相关的其他问题的答案相同的方法(使用EnumDisplayDevicesW 同时将设备名称作为第一个参数传递,类似于例如this one),我已经能够实现部分成功。我遇到的问题是我得到的信息不完整。在桌面右击,选择“显示设置”,然后选择底部的“高级显示设置”即可进入“高级显示设置”面板,显示如下显示:

DELL P2414H(DisplayPort)
AOC AG271QG
BenQ PJ

但是,通过使用EnumDisplayDevicesW 调用,我提取了以下内容:

AOC AG271QG
DELL P2414H(DisplayPort)
Generic PnP Monitor

虽然订单对我来说并不重要,但问题是我得到的是“通用即插即用监视器”而不是更有用的“BenQ PJ”(这不是我希望的确切型号,但仍然至少提供一些信息)。如何提取“BenQ PJ”而不是“Generic PnP Monitor”(最好保留在 WinApi 中)?

【问题讨论】:

  • 看起来您需要嵌套调用,请参阅:docs.microsoft.com/en-us/windows/desktop/gdi/…
  • 嵌套调用是我已经使用的(它们也在我链接的问题中实现) - 没有它们,我不会在其他监视器上获得信息(而只是在适配器上,所以GPU)。我确信这个 API 调用不会让我更进一步。事实上,当我在我提到的窗口中单击“显示器 3 的显示适配器属性”时,会弹出相同的“通用 PnP 监视器” - 所以肯定有 2 个不同信息的来源(EnumDisplayDevicesW 显然不是我正在寻找)。
  • 您是否在设备管理器的监视器属性对话框中查看过长长的设备属性组合框,看看您想要的字符串是否出现在某处?
  • 屏幕没有安装驱动程序,因此实际设备本身正在使用通用 PnP 监视器驱动程序运行。我想你最好检查一下。查看设备管理器,您会看到。

标签: c++ windows winapi


【解决方案1】:

您可以通过 EDID

获取 Monitor 信息

EDID 可以用 WMI 读取

例如用WmiOpenBlock等进行测试,减少C++中WMI的代码=>

我得到了我的显示器:

Instance Name = DISPLAY\PHLC085\4&20634529&0&UID65793_0
User Friendly Name = 247ELH
Manufacturer Name = PHL
Product Code ID = C085
Serial Number ID = AU01307001613

包含并定义 =>

#define _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <tchar.h>
#include <initguid.h>
#include <wmistr.h>
DEFINE_GUID(WmiMonitorID_GUID, 0x671a8285, 0x4edb, 0x4cae, 0x99,0xfe,0x69,0xa1,0x5c,0x48,0xc0,0xbc );
typedef struct WmiMonitorID {
    USHORT ProductCodeID[16];
    USHORT SerialNumberID[16];
    USHORT ManufacturerName[16];
    UCHAR WeekOfManufacture;
    USHORT YearOfManufacture;
    USHORT UserFriendlyNameLength;
    USHORT UserFriendlyName[1];
} WmiMonitorID, *PWmiMonitorID;
#define OFFSET_TO_PTR(Base, Offset) ((PBYTE)((PBYTE)Base + Offset))

typedef HRESULT(WINAPI*WOB) (IN LPGUID lpGUID, IN DWORD nAccess, OUT LONG*);
WOB WmiOpenBlock;
typedef HRESULT(WINAPI*WQAD) (IN LONG hWMIHandle, ULONG* nBufferSize, OUT UCHAR * pBuffer);
WQAD WmiQueryAllData;
typedef HRESULT(WINAPI*WCB) (IN LONG);
WCB WmiCloseBlock;

测试代码 =>

HRESULT hr = E_FAIL;
LONG hWmiHandle;
PWmiMonitorID MonitorID;
HINSTANCE hDLL = LoadLibrary(L"Advapi32.dll");
WmiOpenBlock = (WOB)GetProcAddress(hDLL, "WmiOpenBlock");
WmiQueryAllData = (WQAD)GetProcAddress(hDLL, "WmiQueryAllDataW");
WmiCloseBlock = (WCB)GetProcAddress(hDLL, "WmiCloseBlock");
if (WmiOpenBlock != NULL && WmiQueryAllData && WmiCloseBlock)
{
    WCHAR pszDeviceId[256] = L"";
    hr = WmiOpenBlock((LPGUID)&WmiMonitorID_GUID, GENERIC_READ, &hWmiHandle);
    if (hr == ERROR_SUCCESS)
    {
        ULONG nBufferSize = 0;
        UCHAR *pAllDataBuffer = 0;
        PWNODE_ALL_DATA pWmiAllData;
        hr = WmiQueryAllData(hWmiHandle, &nBufferSize, 0);
        if (hr == ERROR_INSUFFICIENT_BUFFER)
        {
            pAllDataBuffer = (UCHAR*)malloc(nBufferSize);
            hr = WmiQueryAllData(hWmiHandle, &nBufferSize, pAllDataBuffer);
            if (hr == ERROR_SUCCESS)
            {
                while (1)
                {
                    pWmiAllData = (PWNODE_ALL_DATA)pAllDataBuffer;
                    if (pWmiAllData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE)
                        MonitorID = (PWmiMonitorID)&pAllDataBuffer[pWmiAllData->DataBlockOffset];
                    else
                        MonitorID = (PWmiMonitorID)&pAllDataBuffer[pWmiAllData->OffsetInstanceDataAndLength[0].OffsetInstanceData];

                    ULONG nOffset = 0;
                    WCHAR *pwsInstanceName = 0;
                    nOffset = (ULONG)pAllDataBuffer[pWmiAllData->OffsetInstanceNameOffsets];
                    pwsInstanceName = (WCHAR*)OFFSET_TO_PTR(pWmiAllData, nOffset + sizeof(USHORT));
                    WCHAR wsText[255] = L"";
                    swprintf(wsText, L"Instance Name = %s\r\n", pwsInstanceName);
                    OutputDebugString(wsText);

                    WCHAR *pwsUserFriendlyName;
                    pwsUserFriendlyName = (WCHAR*)MonitorID->UserFriendlyName;
                    swprintf(wsText, L"User Friendly Name = %s\r\n", pwsUserFriendlyName);
                    OutputDebugString(wsText);

                    WCHAR *pwsManufacturerName;
                    pwsManufacturerName = (WCHAR*)MonitorID->ManufacturerName;
                    swprintf(wsText, L"Manufacturer Name = %s\r\n", pwsManufacturerName);
                    OutputDebugString(wsText);

                    WCHAR *pwsProductCodeID;
                    pwsProductCodeID = (WCHAR*)MonitorID->ProductCodeID;
                    swprintf(wsText, L"Product Code ID = %s\r\n", pwsProductCodeID);
                    OutputDebugString(wsText);

                    WCHAR *pwsSerialNumberID;
                    pwsSerialNumberID = (WCHAR*)MonitorID->SerialNumberID;
                    swprintf(wsText, L"Serial Number ID = %s\r\n", pwsSerialNumberID);
                    OutputDebugString(wsText);

                    if (!pWmiAllData->WnodeHeader.Linkage)
                        break;
                    pAllDataBuffer += pWmiAllData->WnodeHeader.Linkage;
                }
                free(pAllDataBuffer);
            }
        }
        WmiCloseBlock(hWmiHandle);
    }
}

【讨论】:

  • 这是正确的 - “BenQ PJ”显然是用户友好的名称。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 1970-01-01
  • 2014-04-06
  • 2016-10-04
  • 1970-01-01
相关资源
最近更新 更多