Win32 code to get EDID in Windows XP/7

后端 未结 3 517
野的像风
野的像风 2020-12-06 08:39

I found this page and was unable to get any useful information out of it (it searches the registry for something but never finds it and goes into an infinite loop).

相关标签:
3条回答
  • 2020-12-06 09:10

    Based on Ofek Shilon's blog post, and tweaked to get all the device IDs (manufacturer ID + product ID strings):

    DISPLAY_DEVICE dd;
    dd.cb = sizeof(dd);
    DWORD dev = 0;  // device index
    int id = 1;        // monitor number, as used by Display Properties > Settings
    
    Str DeviceID;
    
    while (EnumDisplayDevices(0, dev, &dd, 0))
    {
        DISPLAY_DEVICE ddMon;
        ZeroMemory(&ddMon, sizeof(ddMon));
        ddMon.cb = sizeof(ddMon);
        DWORD devMon = 0;
    
        while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0))
        {
            DeviceID.Sprintf("%s", ddMon.DeviceID);
            DeviceID = DeviceID.Slice(8);
            if (DeviceID.Index("\\") > 0)
                DeviceID = DeviceID.Slice(0, DeviceID.Index("\\"));
    
            printf ("DEVICEID = %s --------\n", DeviceID.utf8());
        }
    
        devMon++;
    
        ZeroMemory(&ddMon, sizeof(ddMon));
        ddMon.cb = sizeof(ddMon);
      }
    
      ZeroMemory(&dd, sizeof(dd));
      dd.cb = sizeof(dd);
      dev++;
    }
    

    N.B. Str here is a custom string class but should be easy to refactor to use anything.

    0 讨论(0)
  • 2020-12-06 09:26

    WMI didn't support monitor classes in Windows XP. The documented way of getting the EDID was - and still is - with the Setup API.

    Longer survey and a VC++ code sample are available here.

    0 讨论(0)
  • 2020-12-06 09:28

    First I got a C# version working using WMI Code Creator:

            try
            {
                ManagementObjectSearcher searcher =
                    new ManagementObjectSearcher("root\\WMI",
                    "SELECT * FROM WmiMonitorID");
    
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("WmiMonitorID instance");
                    Console.WriteLine("-----------------------------------");
                    //Console.WriteLine("Active: {0}", queryObj["Active"]);
                    Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);
                    dynamic snid = queryObj["SerialNumberID"];
    
                    Console.WriteLine("SerialNumberID: (length) {0}", snid.Length);
                    Console.WriteLine("YearOfManufacture: {0}", queryObj["YearOfManufacture"]);
                    dynamic code = queryObj["ProductCodeID"];
                    string pcid = "";
                    for (int i = 0; i < code.Length; i++)
                    {
                        pcid = pcid + Char.ConvertFromUtf32(code[i]);
                        //pcid = pcid +code[i].ToString("X4");
                    }
                    Console.WriteLine("ProductCodeID: " +  pcid);
                }
            }
            catch (ManagementException e)
            {
                Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
            }
    

    Below is the C++ code I found and tweaked to work with the InstanceName field in WmiMonitorID class (EDID structure) that I wanted to read. Don't forget to add setupapi.lib to your Linker > Additional Libraries build setting.

    #define _WIN32_DCOM
    #include <iostream>
    using namespace std;
    #include <wbemidl.h>
    # pragma comment(lib, "wbemuuid.lib")
    
    int EnumMonitorIDs()
    {
        ret.clear();
    
        HRESULT hres =  CoInitializeEx(0, COINIT_MULTITHREADED); 
        if (FAILED(hres))
        {
            cout << "Failed to initialize COM library. Error code = 0x" 
                << hex << hres << endl;
            return 1;                  // Program has failed.
        }
    
        hres =  CoInitializeSecurity(
            NULL, 
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities 
            NULL                         // Reserved
            );
    
        if (FAILED(hres))
        {
            cout << "Failed to initialize security. Error code = 0x" 
                << hex << hres << endl;
            CoUninitialize();
            return 1;
        }
    
        IWbemLocator *pLoc = NULL;
        hres = CoCreateInstance(
            CLSID_WbemLocator,             
            0, 
            CLSCTX_INPROC_SERVER, 
            IID_IWbemLocator, (LPVOID *) &pLoc);
    
        if (FAILED(hres))
        {
            cout << "Failed to create IWbemLocator object."
                << " Err code = 0x"
                << hex << hres << endl;
            CoUninitialize();
            return 1;                 // Program has failed.
        }
    
        IWbemServices *pSvc = NULL; 
        BSTR AbackB = SysAllocString(L"root\\WMI");
        // Connect to the root\cimv2 namespace with
        // the current user and obtain pointer pSvc
        // to make IWbemServices calls.
        hres = pLoc->ConnectServer(
             AbackB, // Object path of WMI namespace
             NULL,                    // User name. NULL = current user
             NULL,                    // User password. NULL = current
             0,                       // Locale. NULL indicates current
             NULL,                    // Security flags.
             0,                       // Authority (e.g. Kerberos)
             0,                       // Context object 
             &pSvc                    // pointer to IWbemServices proxy
             );
        SysFreeString(AbackB);
    
        if (FAILED(hres))
        {
            cout << "Could not connect. Error code = 0x" 
                 << hex << hres << endl;
            pLoc->Release();     
            CoUninitialize();
            return 1;                // Program has failed.
        }
    
        hres = CoSetProxyBlanket(
           pSvc,                        // Indicates the proxy to set
           RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
           RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
           NULL,                        // Server principal name 
           RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
           RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
           NULL,                        // client identity
           EOAC_NONE                    // proxy capabilities 
        );
    
        if (FAILED(hres))
        {
            cout << "Could not set proxy blanket. Error code = 0x" 
                << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();     
            CoUninitialize();
            return 1;               // Program has failed.
        }
    
        BSTR wql = SysAllocString(L"WQL");
        BSTR select = SysAllocString(L"SELECT * FROM WmiMonitorID");
        IEnumWbemClassObject* pEnumerator = NULL;
        hres = pSvc->ExecQuery(
            wql,
            select,
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
            NULL,
            &pEnumerator);
        SysFreeString(wql);
        SysFreeString(select);
    
        if (FAILED(hres))
        {
            cout << "Query for operating system name failed."
                << " Error code = 0x" 
                << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();
            CoUninitialize();
            return 1;               // Program has failed.
        }
    
        IWbemClassObject *pclsObj = 0;
        ULONG uReturn = 0;   
        while (pEnumerator)
        {
            HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, 
                &pclsObj, &uReturn);
    
            if (0 == uReturn)
            {
                break;
            }
    
            // ok, we have the EDID record, pull some fields out of it
    
            VARIANT vtProp;
            hr = pclsObj->Get(L"InstanceName", 0, &vtProp, 0, 0);
            wcout << "----------------" << endl << "InstanceName : " << vtProp.bstrVal << endl;
            VariantClear(&vtProp);
    
    
    
            pclsObj->Release();
        }
    
        pSvc->Release();
        pLoc->Release();
        pEnumerator->Release();
        CoUninitialize();
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题