[PATCH v6 7/7] user32: Implement EnumDisplayDevicesW().

Zhiyi Zhang zzhang at codeweavers.com
Wed May 22 04:17:38 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/user32/misc.c          | 223 ++++++++++++++++++++++++++++++++----
 dlls/user32/tests/monitor.c |  26 ++---
 2 files changed, 213 insertions(+), 36 deletions(-)

diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 1a03d70dde..92d8a0ea1b 100644
--- a/dlls/user32/misc.c
+++ b/dlls/user32/misc.c
@@ -29,9 +29,13 @@
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
+#include "winreg.h"
 #include "winnls.h"
 #include "winternl.h"
 #include "controls.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "setupapi.h"
 #include "user_private.h"
 
 #include "wine/unicode.h"
@@ -39,6 +43,42 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(win);
 
+/* Wine specific monitor properties */
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
+
+static const WCHAR monitor_fmtW[] =
+    {'\\','M','o','n','i','t','o','r','%','d',0};
+static const WCHAR adapter_fmtW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0};
+static const WCHAR displayW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'};
+static const WCHAR video_keyW[] =
+    {'H','A','R','D','W','A','R','E','\\',
+     'D','E','V','I','C','E','M','A','P','\\',
+     'V','I','D','E','O','\\',0};
+static const WCHAR video_value_fmtW[] =
+    {'\\','D','e','v','i','c','e','\\',
+     'V','i','d','e','o','%','d',0};
+static const WCHAR nt_machine_prefixW[] =
+    {'\\','R','e','g','i','s','t','r','y','\\',
+     'M','a','c','h','i','n','e','\\'};
+static const WCHAR monitor_interface_prefixW[] = {'\\','\\','\?','\\',0};
+static const WCHAR guid_devinterface_monitorW[] =
+    {'#','{','e','6','f','0','7','b','5','f','-','e','e','9','7','-',
+     '4','a','9','0','-','b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
+static const WCHAR backslashW[] = {'\\',0};
+static const WCHAR nt_classW[] =
+    {'\\','R','e','g','i','s','t','r','y','\\',
+     'M','a','c','h','i','n','e','\\',
+     'S','y','s','t','e','m','\\',
+     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+     'C','o','n','t','r','o','l','\\',
+     'C','l','a','s','s','\\',0};
+static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
+static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR mointor_id_value_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
+
 #define IMM_INIT_MAGIC 0x19650412
 static HWND (WINAPI *imm_get_ui_window)(HKL);
 BOOL (WINAPI *imm_register_window)(HWND) = NULL;
@@ -243,11 +283,6 @@ DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd)
     return 1;
 }
 
-static const WCHAR primary_device_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
-static const WCHAR primary_device_string[] = {'X','1','1',' ','W','i','n','d','o','w','i','n','g',' ',
-                                              'S','y','s','t','e','m',0};
-static const WCHAR primary_device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&',
-                                                'D','E','V','_','0','0','0','0',0};
 
 /***********************************************************************
  *		EnumDisplayDevicesA (USER32.@)
@@ -285,28 +320,170 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR lpDevice, DWORD i, LPDISPLAY_DEVICEA lpD
 /***********************************************************************
  *		EnumDisplayDevicesW (USER32.@)
  */
-BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice,
-                                 DWORD dwFlags )
+BOOL WINAPI EnumDisplayDevicesW(LPCWSTR name, DWORD index, LPDISPLAY_DEVICEW display_device, DWORD flags)
 {
-    FIXME("(%s,%d,%p,0x%08x), stub!\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags);
-
-    if (i)
-        return FALSE;
+    SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+    HDEVINFO set;
+    WCHAR key_nameW[MAX_PATH];
+    WCHAR instanceW[MAX_PATH];
+    WCHAR bufferW[1024];
+    WCHAR *next_charW;
+    DWORD size;
+    DWORD type;
+    long adapter_index;
+    BOOL ret = FALSE;
 
-    memcpy(lpDisplayDevice->DeviceName, primary_device_name, sizeof(primary_device_name));
-    memcpy(lpDisplayDevice->DeviceString, primary_device_string, sizeof(primary_device_string));
-  
-    lpDisplayDevice->StateFlags =
-        DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
-        DISPLAY_DEVICE_PRIMARY_DEVICE |
-        DISPLAY_DEVICE_VGA_COMPATIBLE;
+    TRACE("%s %d %p 0x%08x\n", debugstr_w(name), index, display_device, flags);
 
-    if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
-        memcpy(lpDisplayDevice->DeviceID, primary_device_deviceid, sizeof(primary_device_deviceid));
-    if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
-        lpDisplayDevice->DeviceKey[0] = 0;
+    /* Find adapter */
+    if (!name)
+    {
+        sprintfW(key_nameW, video_value_fmtW, index);
+        size = sizeof(bufferW);
+        if (RegGetValueW(HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+                         bufferW, &size))
+            return FALSE;
+
+        /* DeviceKey */
+        if(display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(display_device->DeviceKey))
+            strcpyW(display_device->DeviceKey, bufferW);
+
+        /* DeviceName */
+        sprintfW(display_device->DeviceName, adapter_fmtW, index + 1);
+
+        /* Strip \Registry\Machine\ */
+        strcpyW(key_nameW, bufferW + ARRAY_SIZE(nt_machine_prefixW));
+
+        /* DeviceString */
+        size = sizeof(display_device->DeviceString);
+        if (RegGetValueW(HKEY_LOCAL_MACHINE, key_nameW, driver_descW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+                         display_device->DeviceString, &size))
+            return FALSE;
+
+        /* StateFlags */
+        size = sizeof(display_device->StateFlags);
+        if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD | RRF_ZEROONFAILURE, NULL,
+                         &display_device->StateFlags, &size))
+            return FALSE;
+
+        /* DeviceID */
+        if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(display_device->DeviceID))
+        {
+            if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
+                display_device->DeviceID[0] = 0;
+            else
+            {
+                size = sizeof(bufferW);
+                if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, gpu_idW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+                                 bufferW, &size))
+                    return FALSE;
+                set = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+                if (!SetupDiOpenDeviceInfoW(set, bufferW, NULL, 0, &device_data)
+                    || !SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
+                                                          sizeof(bufferW), NULL))
+                {
+                    SetupDiDestroyDeviceInfoList(set);
+                    return FALSE;
+                }
+                strcpyW(display_device->DeviceID, bufferW);
+            }
+        }
 
-    return TRUE;
+        return TRUE;
+    }
+    /* Find monitor */
+    else
+    {
+        /* Check adapter name */
+        if (strncmpiW(name, displayW, ARRAY_SIZE(displayW)))
+            return FALSE;
+
+        adapter_index = strtolW(name + ARRAY_SIZE(displayW), NULL, 10);
+        sprintfW(key_nameW, video_value_fmtW, adapter_index - 1);
+
+        size = sizeof(bufferW);
+        if (RegGetValueW(HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL, bufferW,
+                         &size))
+            return FALSE;
+
+        /* DeviceName */
+        sprintfW(display_device->DeviceName, adapter_fmtW, adapter_index);
+        sprintfW(display_device->DeviceName + strlenW(display_device->DeviceName), monitor_fmtW, index);
+
+        /* Get monitor instance */
+        /* Strip \Registry\Machine\ first */
+        strcpyW(key_nameW, bufferW + ARRAY_SIZE(nt_machine_prefixW));
+        sprintfW(bufferW, mointor_id_value_fmtW, index);
+
+        size = sizeof(instanceW);
+        if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE,
+                         NULL, instanceW, &size))
+            return FALSE;
+
+        set = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
+        if (!SetupDiOpenDeviceInfoW(set, instanceW, NULL, 0, &device_data))
+            goto fail;
+
+        /* StateFlags */
+        if (!SetupDiGetDevicePropertyW(set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
+                                       (BYTE *)&display_device->StateFlags, sizeof(display_device->StateFlags), NULL, 0))
+            goto fail;
+
+        /* DeviceString */
+        if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DEVICEDESC, NULL,
+                                               (BYTE *)display_device->DeviceString,
+                                               sizeof(display_device->DeviceString), NULL))
+            goto fail;
+
+        /* DeviceKey */
+        if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(display_device->DeviceKey))
+        {
+            if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+                                                   sizeof(bufferW), NULL))
+                goto fail;
+
+            strcpyW(display_device->DeviceKey, nt_classW);
+            strcatW(display_device->DeviceKey, bufferW);
+        }
+
+        /* DeviceID */
+        if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(display_device->DeviceID))
+        {
+            if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
+            {
+                strcpyW(display_device->DeviceID, monitor_interface_prefixW);
+                strcatW(display_device->DeviceID, instanceW);
+                strcatW(display_device->DeviceID, guid_devinterface_monitorW);
+                /* Replace '\\' with '#' after prefix */
+                for (next_charW = display_device->DeviceID + strlenW(monitor_interface_prefixW); *next_charW;
+                     next_charW++)
+                {
+                    if (*next_charW == '\\')
+                        *next_charW = '#';
+                }
+            }
+            else
+            {
+                if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
+                                                       sizeof(bufferW), NULL))
+                    goto fail;
+
+                strcpyW(display_device->DeviceID, bufferW);
+                strcatW(display_device->DeviceID, backslashW);
+
+                if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+                                                       sizeof(bufferW), NULL))
+                    goto fail;
+
+                strcatW(display_device->DeviceID, bufferW);
+            }
+        }
+
+        ret = TRUE;
+    fail:
+        SetupDiDestroyDeviceInfoList(set);
+        return ret;
+    }
 }
 
 /***********************************************************************
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index bee1085a14..26ee28a122 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -115,7 +115,7 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
             ls = RegQueryValueExA(hkey, video_name, NULL, NULL, (unsigned char *)video_value, &size);
             ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
             RegCloseKey(hkey);
-            todo_wine ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
+            ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
         }
     }
     else
@@ -146,13 +146,13 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
      * by changing the data and rerun EnumDisplayDevices. But it's difficult to find corresponding PCI device on
      * userland. So here we check the expected format instead. */
     if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
-        todo_wine ok(strlen(device->DeviceID) == 0 || /* vista+ */
+        ok(strlen(device->DeviceID) == 0 || /* vista+ */
            sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
                   &vendor_id, &device_id, &subsys_id, &revision_id) == 4, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
            "#%d: got %s\n", index, device->DeviceID);
     else
     {
-        todo_wine ok(broken(strlen(device->DeviceID) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */
+        ok(broken(strlen(device->DeviceID) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */
            sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X", &vendor_id, &device_id, &subsys_id,
                   &revision_id) == 4, "#%d: wrong DeviceID %s\n", index, device->DeviceID);
     }
@@ -173,14 +173,14 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
     /* DeviceName */
     lstrcpyA(monitor_name, adapter_name);
     sprintf(monitor_name + strlen(monitor_name), "\\Monitor%d", monitor_index);
-    todo_wine ok(!strcmp(monitor_name, device->DeviceName), "#%d: expect %s, got %s\n", monitor_index, monitor_name, device->DeviceName);
+    ok(!strcmp(monitor_name, device->DeviceName), "#%d: expect %s, got %s\n", monitor_index, monitor_name, device->DeviceName);
 
     /* DeviceString */
     ok(strlen(device->DeviceString) > 0, "#%d: expect DeviceString not empty\n", monitor_index);
 
     /* StateFlags */
     if (adapter_index == 0 && monitor_index == 0)
-        todo_wine ok(device->StateFlags & DISPLAY_DEVICE_ATTACHED, "#%d expect to have a primary monitor attached\n", monitor_index);
+        ok(device->StateFlags & DISPLAY_DEVICE_ATTACHED, "#%d expect to have a primary monitor attached\n", monitor_index);
     else
         ok(device->StateFlags <= (DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE), "#%d wrong state %#x\n", monitor_index,
            device->StateFlags);
@@ -191,7 +191,7 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
     {   /* HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\4&2abfaa30&0&UID0 GUID_DEVINTERFACE_MONITOR
          *                                                   ^                ^                     ^
          * Expect format                  \\?\DISPLAY#Default_Monitor#4&2abfaa30&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} */
-        todo_wine ok(strlen(device->DeviceID) == 0 || /* vista ~ win7 */
+        ok(strlen(device->DeviceID) == 0 || /* vista ~ win7 */
             sscanf(device->DeviceID, "\\\\?\\DISPLAY#Default_Monitor#%[^#]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}", buffer) == 1 || /* win8+ */
             (!lstrcmpiA(buffer, device_id_prefix) &&
              sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1), /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
@@ -201,16 +201,16 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
     {
         /* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\{Instance} */
         /* But we don't know which monitor instance this belongs to, so check format instead */
-        todo_wine ok(!lstrcmpiA(buffer, device_id_prefix), "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
-        todo_wine ok(sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1,
-                     "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
+        ok(!lstrcmpiA(buffer, device_id_prefix), "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
+        ok(sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1,
+           "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
     }
 
     /* DeviceKey */
     lstrcpynA(buffer, device->DeviceKey, sizeof(device_key_prefix));
-    todo_wine ok(!lstrcmpiA(buffer, device_key_prefix), "#%d: wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
-    todo_wine ok(sscanf(device->DeviceKey + sizeof(device_key_prefix) - 1, "%04d", &number) == 1,
-                 "#%d wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
+    ok(!lstrcmpiA(buffer, device_key_prefix), "#%d: wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
+    ok(sscanf(device->DeviceKey + sizeof(device_key_prefix) - 1, "%04d", &number) == 1,
+       "#%d wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
 }
 
 static void test_enumdisplaydevices(void)
@@ -235,7 +235,7 @@ static void test_enumdisplaydevices(void)
     /* Doesn't accept \\.\DISPLAY */
     dd.cb = sizeof(dd);
     ret = pEnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd, 0);
-    todo_wine ok(!ret, "Expect failure\n");
+    ok(!ret, "Expect failure\n");
 
     /* Enumeration */
     for (flag_index = 0; flag_index < ARRAY_SIZE(flags); flag_index++)
-- 
2.20.1




More information about the wine-devel mailing list