-- v2: user32: Implement DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/sysparams.c | 56 +++++++++++++++++++++++++++++-- dlls/user32/tests/Makefile.in | 2 +- dlls/user32/tests/monitor.c | 63 +++++++++++++++++++++++++++++++++-- 3 files changed, 115 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index 7ebe8099419..ec78fb21c36 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -39,6 +39,7 @@ #include "d3dkmdt.h" #include "devguid.h" #include "setupapi.h" +#include "ntddvdeo.h" #include "controls.h" #include "user_private.h" #include "wine/asm.h" @@ -1365,13 +1366,64 @@ LONG WINAPI DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER *packet) case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: { DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet; + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + UINT32 output_id;
- FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n"); + TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n");
if (packet->size < sizeof(*target_name)) return ERROR_INVALID_PARAMETER;
- return ERROR_NOT_SUPPORTED; + mutex = get_display_device_init_mutex(); + + devinfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + if (devinfo == INVALID_HANDLE_VALUE) + { + release_display_device_init_mutex(mutex); + return ret; + } + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + + memset(&target_name->flags, 0, sizeof(*target_name) - offsetof(DISPLAYCONFIG_TARGET_DEVICE_NAME, flags)); + while (SetupDiEnumDeviceInterfaces(devinfo, NULL, &GUID_DEVINTERFACE_MONITOR, index++, &iface)) + { + if (!SetupDiGetDeviceInterfaceDetailW(devinfo, &iface, iface_data, + sizeof(iface_detail_buffer), NULL, &device_data)) + continue; + + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID, + &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0)) + continue; + + if ((target_name->header.adapterId.LowPart != gpu_luid.LowPart) || + (target_name->header.adapterId.HighPart != gpu_luid.HighPart)) + continue; + + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID, + &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0)) + continue; + + if (target_name->header.id != output_id) + continue; + + /* FIXME: get real monitor name. */ + swprintf(target_name->monitorFriendlyDeviceName, sizeof(target_name->monitorFriendlyDeviceName), + L"Display%u.\n", output_id); + target_name->flags.friendlyNameForced = 1; + wcscpy(target_name->monitorDevicePath, iface_data->DevicePath); + ret = ERROR_SUCCESS; + break; + } + + SetupDiDestroyDeviceInfoList(devinfo); + release_display_device_init_mutex(mutex); + if (ret) + WARN("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME error %ld.\n", ret); + return ret; } case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: { diff --git a/dlls/user32/tests/Makefile.in b/dlls/user32/tests/Makefile.in index 344a3b66d2b..33c7f13f12d 100644 --- a/dlls/user32/tests/Makefile.in +++ b/dlls/user32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = user32.dll -IMPORTS = user32 gdi32 advapi32 hid imm32 +IMPORTS = user32 gdi32 advapi32 hid imm32 setupapi
C_SRCS = \ broadcast.c \ diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 4b774037508..1dff85b9621 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -23,6 +23,8 @@ #include "ntstatus.h" #define WIN32_NO_STATUS
+#include "initguid.h" + #include "wine/test.h" #include "winbase.h" #include "wingdi.h" @@ -30,9 +32,14 @@ #include "winreg.h" #include "winternl.h" #include "ddk/d3dkmthk.h" +#include "setupapi.h" +#include "ntddvdeo.h" #include "wine/heap.h" #include <stdio.h>
+DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1); +DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2); + static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*); static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*); static LONG (WINAPI *pQueryDisplayConfig)(UINT32,UINT32*,DISPLAYCONFIG_PATH_INFO*,UINT32*, @@ -1624,6 +1631,58 @@ static void test_EnumDisplayMonitors(void) ok(ret, "CloseWindowStation failed, error %#lx.\n", GetLastError()); }
+static void check_device_path(const WCHAR *device_path, const LUID *adapter_id, DWORD id) +{ + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + BOOL ret, found = FALSE; + DEVPROPTYPE type; + DWORD output_id; + unsigned int i; + HDEVINFO set; + LUID luid; + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + + set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "Got error %lu.\n", GetLastError()); + + i = 0; + while (SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_MONITOR, i, &iface)) + { + ret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, + sizeof(iface_detail_buffer), NULL, &device_data); + ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); + + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID, &type, + (BYTE *)&luid, sizeof(luid), NULL, 0); + ok(ret || broken(GetLastError() == ERROR_NOT_FOUND) /* before Win10 1809 */, + "Got error %lu.\n", GetLastError()); + if (!ret) + { + win_skip("DEVPROPKEY_MONITOR_GPU_LUID is not found, skipping device path check.\n"); + SetupDiDestroyDeviceInfoList(set); + return; + } + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID, + &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0); + ok(ret, "Got error %lu.\n", GetLastError()); + + if (output_id == id && RtlEqualLuid(&luid, adapter_id) && !wcsicmp(device_path, iface_data->DevicePath)) + { + found = TRUE; + break; + } + ++i; + } + ok(found, "device_path %s not found, luid %04lx:%04lx.\n", debugstr_w(device_path), adapter_id->HighPart, + adapter_id->LowPart); + SetupDiDestroyDeviceInfoList(set); +} + static void test_QueryDisplayConfig_result(UINT32 flags, UINT32 paths, const DISPLAYCONFIG_PATH_INFO *pi, UINT32 modes, const DISPLAYCONFIG_MODE_INFO *mi) { @@ -1654,7 +1713,6 @@ static void test_QueryDisplayConfig_result(UINT32 flags, ret = pDisplayConfigGetDeviceInfo(&source_name.header); ok(ret == ERROR_GEN_FAILURE, "Expected GEN_FAILURE, got %ld\n", ret);
- todo_wine { target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; target_name.header.size = sizeof(target_name); target_name.header.adapterId = pi[i].targetInfo.adapterId; @@ -1662,8 +1720,7 @@ static void test_QueryDisplayConfig_result(UINT32 flags, target_name.monitorDevicePath[0] = '\0'; ret = pDisplayConfigGetDeviceInfo(&target_name.header); ok(!ret, "Expected 0, got %ld\n", ret); - ok(target_name.monitorDevicePath[0] != '\0', "Expected monitor device path, got empty string\n"); - } + check_device_path(target_name.monitorDevicePath, &target_name.header.adapterId, target_name.header.id);
todo_wine { preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125304
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:746: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected input.c:746: Test failed: 0 (a4/0): 41 from 01 -> 00 unexpected
=== w7u_el (32 bit report) ===
user32: input.c:4551: Test failed: SendInput triggered unexpected message 0xc042 input.c:2404: Test failed: Spurious WM_INPUT messages
=== w7u_adm (32 bit report) ===
user32: listbox.c:1249: Test failed: SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with 28 entries, expected 27
=== w1064v1507 (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
=== w8 (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
=== w10pro64_en_AE_u8 (64 bit report) ===
user32: msg.c:13063: Test failed: coords not changed: (101 101) (101 101) msg.c:13081: Test failed: coords not changed: (101 101) (101 101)
=== w10pro64_ar (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
=== w8adm (32 bit report) ===
user32: win.c:3877: Test failed: GetFocus() = 00000000 win.c:3880: Test failed: GetFocus() = 00000000
=== debian11 (build log) ===
Task: Could not create the win32 wineprefix: Failed to disable the crash dialogs: Task: WineTest did not produce the win32 report
Jacek Caban (@jacek) commented about dlls/user32/sysparams.c:
DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)];
SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data;
UINT32 output_id;
FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n"); if (packet->size < sizeof(*target_name)) return ERROR_INVALID_PARAMETER;
return ERROR_NOT_SUPPORTED;
mutex = get_display_device_init_mutex();
devinfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
We will eventually want this all moved to win32u (NtUserDisplayConfigGetDeviceInfo in this case), where we can't use setupapi and use cached device info instead. I think it would be better to add new code there instead adding new setupapi-based code to user32.
Hello Jacek,
do you have anything for this function already (WIP patches or maybe tested NtUserDisplayConfigGetDeviceInfo arguments)?
Regards, Paul.
On 10/24/22 05:41, Jacek Caban (@jacek) wrote:
Jacek Caban (@jacek) commented about dlls/user32/sysparams.c:
DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)];
SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data;
UINT32 output_id;
FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n"); if (packet->size < sizeof(*target_name)) return ERROR_INVALID_PARAMETER;
return ERROR_NOT_SUPPORTED;
mutex = get_display_device_init_mutex();
devinfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
We will eventually want this all moved to win32u (NtUserDisplayConfigGetDeviceInfo in this case), where we can't use setupapi and use cached device info instead. I think it would be better to add new code there instead adding new setupapi-based code to user32.
On Mon Oct 24 15:12:48 2022 +0000, **** wrote:
Paul Gofman replied on the mailing list:
Hello Jacek, do you have anything for this function already (WIP patches or maybe tested NtUserDisplayConfigGetDeviceInfo arguments)? Regards, Paul. On 10/24/22 05:41, Jacek Caban (@jacek) wrote:
No, I didn't look at that yet, but here is what I usually do as a first guess: https://testbot.winehq.org/JobDetails.pl?Key=125354 It seems to use the same argument as user32 variant, but returns NTSTATUS instead of win32 error.
On 10/24/22 10:28, Jacek Caban (@jacek) wrote:
On Mon Oct 24 15:12:48 2022 +0000, **** wrote:
Paul Gofman replied on the mailing list:
Hello Jacek, do you have anything for this function already (WIP patches or maybe tested NtUserDisplayConfigGetDeviceInfo arguments)? Regards, Paul. On 10/24/22 05:41, Jacek Caban (@jacek) wrote:
No, I didn't look at that yet, but here is what I usually do as a first guess: https://testbot.winehq.org/JobDetails.pl?Key=125354 It seems to use the same argument as user32 variant, but returns NTSTATUS instead of win32 error.
Thanks, I will look into moving DisplayConfigGetDeviceInfo() to win32u first.
This merge request was closed by Paul Gofman.