Signed-off-by: Zhiyi Zhang zzhang@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++)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52537
Your paranoid android.
=== debian9 (32 bit report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000