EnumDisplayDevices vs WMI Win32_DesktopMonitor، كيفية اكتشاف الشاشات النشطة؟

StackOverflow https://stackoverflow.com/questions/181064

  •  05-07-2019
  •  | 
  •  

سؤال

بالنسبة لمشروعي الحالي في C++، أحتاج إلى اكتشاف سلسلة فريدة لكل شاشة متصلة ونشطة على عدد كبير من أجهزة الكمبيوتر.

أشارت الأبحاث إلى خيارين

  1. استخدم WMI واستعلم عن Win32_DesktopMonitor لكافة الشاشات النشطة.استخدم PNPDeviceID للتعرف الفريد على الشاشات.

  2. استخدم واجهة برمجة تطبيقات EnumDisplayDevices، وابحث للحصول على معرف الجهاز.

أنا مهتم باستخدام معرف الجهاز لتحديد الطراز الفريد لأن الشاشات التي تستخدم برنامج تشغيل التوصيل والتشغيل الافتراضي ستبلغ عن سلسلة عامة كاسم الشاشة "شاشة التوصيل والتشغيل الافتراضية"

لقد واجهت مشكلات مع طريقة WMI، ويبدو أنها تعيد شاشة واحدة فقط على جهاز Vista الخاص بي، وبالنظر إلى doco، اتضح أنها لا تعمل كما هو متوقع على الأجهزة غير WDDM.

يبدو أن EnumDisplayDevices يمثل مشكلة صغيرة عند تشغيله من خدمة الخلفية (خاصة في نظام التشغيل Vista)، وإذا كان في الجلسة 0 فلن يُرجع أي معلومات.

  • هل كان على أي شخص آخر أن يفعل شيئًا مشابهًا (ابحث عن سلسلة طراز فريدة لجميع الشاشات النشطة المتصلة؟)

  • ما النهج الذي نجح بشكل أفضل؟

هل كانت مفيدة؟

المحلول

هذا هو رمز العمل الحالي الخاص بي لاكتشاف معرف جهاز المراقبة بشكل موثوق.

CString DeviceID;
DISPLAY_DEVICE dd; 
dd.cb = sizeof(dd); 
DWORD dev = 0; 
// device index 
int id = 1; 
// monitor number, as used by Display Properties > Settings

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))
    {
        if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && 
                     !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
        {
            DeviceID.Format (L"%s", ddMon.DeviceID);
            DeviceID = DeviceID.Mid (8, DeviceID.Find (L"\\", 9) - 8);
        }
        devMon++;

        ZeroMemory(&ddMon, sizeof(ddMon));
        ddMon.cb = sizeof(ddMon);
    }

    ZeroMemory(&dd, sizeof(dd));
    dd.cb = sizeof(dd);
    dev++; 
}

نصائح أخرى

لقد اكتشفت للتو أنه يمكنك الاستعلام عن Win32_PnPEntity لـservice = "monitor"، وسيقوم بإرجاع كافة الشاشات.

النتائج على جهازي:

select * from Win32_PnPEntity where service="monitor"

Availability | Caption               | ClassGuid                              | CompatibleID | ConfigManagerErrorCode | ConfigManagerUserConfig | CreationClassName | Description           | DeviceID                           | ErrorCleared | ErrorDescription | HardwareID  | InstallDate | LastErrorCode | Manufacturer | Name                  | PNPDeviceID                        | PowerManagementCapabilities | PowerManagementSupported | Service | Status | StatusInfo | SystemCreationClassName | SystemName
             | Dell 2007FP (Digital) | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J
             | Dell ST2320L_Digital  | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J

لقد كنا نتعامل مع EnumDisplayDevices لاكتشاف ما إذا كانت الشركة المصنعة لبطاقة الفيديو الحالية هي NVIDIA.انها ليست هي نفسها، ولكن ربما من شأنه أن يساعد.بدا قطعتنا مثل هذا:

int disp_num = 0;
    BOOL res = TRUE;
    do {
        DISPLAY_DEVICE disp_dev_info; 
        ZeroMemory( &disp_dev_info, sizeof(DISPLAY_DEVICE) );
        disp_dev_info.cb = sizeof(DISPLAY_DEVICE);
        res = EnumDisplayDevices( 0, disp_num++, &disp_dev_info, 0x00000001 );
        if(res &&
           disp_dev_info.DeviceString[0]!=0 && disp_dev_info.DeviceString[0]=='N' &&
           disp_dev_info.DeviceString[1]!=0 && disp_dev_info.DeviceString[1]=='V' && 
           disp_dev_info.DeviceString[2]!=0 && disp_dev_info.DeviceString[2]=='I' && 
           disp_dev_info.DeviceString[3]!=0 && disp_dev_info.DeviceString[3]=='D' && 
           disp_dev_info.DeviceString[4]!=0 && disp_dev_info.DeviceString[4]=='I' && 
           disp_dev_info.DeviceString[5]!=0 && disp_dev_info.DeviceString[5]=='A'){
            isNVidia = true;
        }
        int x = 0;
    }while( res != FALSE );

غبية جدا، ولكن العمل.

لم أحاول أبدًا القيام بذلك من خلال الخدمة، ولكن EnumDisplayDevices يعمل بشكل جيد بشكل عام عند تشغيله كمستخدم.أعتقد أن الخدمات تعمل في جلسة منفصلة (بدون رأس)، مما قد يفسر المشكلة التي تراها هناك.

هل يمكنك تشغيل برنامج مساعد من خدمتك، وانتحال شخصية حساب مستخدم لديه حق الوصول إلى شاشات العرض؟

تقوم طريقة Win32_DesktopMonitor بإرجاع شاشة واحدة فقط على جهاز Vista الخاص بي أيضًا.يبدو أنه تم تعيين معرف PnP بشكل صحيح.

لقد قمت بتجربة سريعة مع واجهة برمجة التطبيقات EnumDisplayDevices، وبينما يبدو أنها تكتشف تفاصيل المحول بشكل موثوق (ربما لأن معظم الأشخاص لن يتركوها كـ "Standard VGA" لفترة طويلة)، فإنها تعرض فقط "Plug and Play Monitor" للشاشات المتصلة.

يعكس هذا البحث الذي أجريته منذ عدة سنوات (اضطررت إلى تجميع بعض التعليمات البرمجية معًا للمساعدة في إزالة الغبار عن تلك الذكريات).

هذا من حساب مستخدم عادي.إذا كانت لديك طريقة موثوقة لجعل EnumDisplayDevices يعيد معرف PnP، حتى في جلسات المستخدم العادية، سأكون مهتمًا - نحن نتحقق حاليًا مما إذا كانت أي من هذه المعلومات متاحة لبرنامج تشغيل الجهاز.

هناك شيء واحد يمكنك القيام به، إذا لم يكن تشغيل التعليمات البرمجية من الجلسة رقم 0 موثوقًا بدرجة كافية، وهو معرفة ما إذا كان بإمكانك إنشاء عملية مساعدة (إما باستخدام CreateProcessAsUser أو باستخدام COM مع ألقاب التنشيط) التي سيتم تشغيلها في سياق المستخدم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top