-- v4: Revert "ntoskrnl.exe: Enforce path case in WM_DEVICECHANGE notifications." ntoskrnl: Preserve the device instance ID case in IoRegisterDeviceInterface(). ntoskrnl/tests: Expand tests for device and interface naming.
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 4 +-- dlls/user32/input.c | 46 ++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index ff93cfc98ec..c4521ed652a 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1400,7 +1400,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara if (IsEqualGUID(&iface->dbcc_classguid, &bus_class)) { ++got_bus_arrival; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}"), + ok(!strcmp(iface->dbcc_name, "\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) @@ -1428,7 +1428,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara if (IsEqualGUID(&iface->dbcc_classguid, &bus_class)) { ++got_bus_removal; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}"), + ok(!strcmp(iface->dbcc_name, "\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 3b0a13842c8..2f4dc06f6ce 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -495,12 +495,52 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout ) }
-static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) +static DWORD CALLBACK devnotify_window_callbackW(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); return 0; }
+static DWORD CALLBACK devnotify_window_callbackA(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) +{ + if (flags & 0x8000) + { + switch (header->dbch_devicetype) + { + case DBT_DEVTYP_DEVICEINTERFACE: + { + const DEV_BROADCAST_DEVICEINTERFACE_W *ifaceW = (const DEV_BROADCAST_DEVICEINTERFACE_W *)header; + size_t lenW = wcslen( ifaceW->dbcc_name ); + DEV_BROADCAST_DEVICEINTERFACE_A *ifaceA; + DWORD lenA; + + if (!(ifaceA = malloc( offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[lenW * 3 + 1]) ))) + return 0; + lenA = WideCharToMultiByte( CP_ACP, 0, ifaceW->dbcc_name, lenW + 1, + ifaceA->dbcc_name, lenW * 3 + 1, NULL, NULL ); + + ifaceA->dbcc_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[lenA + 1]); + ifaceA->dbcc_devicetype = ifaceW->dbcc_devicetype; + ifaceA->dbcc_reserved = ifaceW->dbcc_reserved; + ifaceA->dbcc_classguid = ifaceW->dbcc_classguid; + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)ifaceA, SMTO_ABORTIFHUNG, 2000, NULL ); + free( ifaceA ); + return 0; + } + + default: + FIXME( "unimplemented W to A mapping for %#lx\n", header->dbch_devicetype ); + /* fall through */ + case DBT_DEVTYP_HANDLE: + case DBT_DEVTYP_OEM: + break; + } + } + + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL ); + return 0; +} + static DWORD CALLBACK devnotify_service_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { FIXME("Support for service handles is not yet implemented!\n"); @@ -580,8 +620,10 @@ HDEVNOTIFY WINAPI RegisterDeviceNotificationW( HANDLE handle, void *filter, DWOR
if (flags & DEVICE_NOTIFY_SERVICE_HANDLE) details.cb = devnotify_service_callback; + else if (IsWindowUnicode( handle )) + details.cb = devnotify_window_callbackW; else - details.cb = devnotify_window_callback; + details.cb = devnotify_window_callbackA;
return I_ScRegisterDeviceNotification( &details, filter, 0 ); }
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntoskrnl.exe/tests/driver_pnp.c | 22 +++++++++++++++++++++- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 22 +++++++++++++++++----- 2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 9a965f584cd..92ad69762de 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -34,6 +34,19 @@ #include "driver.h" #include "utils.h"
+/* memcmp() isn't exported from ntoskrnl on i386 */ +static int kmemcmp( const void *ptr1, const void *ptr2, size_t n ) +{ + const unsigned char *p1, *p2; + + for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++) + { + if (*p1 < *p2) return -1; + if (*p1 > *p2) return 1; + } + return 0; +} + static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}}; static UNICODE_STRING control_symlink, bus_symlink; @@ -178,7 +191,7 @@ static NTSTATUS fdo_pnp(IRP *irp)
static NTSTATUS query_id(struct device *device, IRP *irp, BUS_QUERY_ID_TYPE type) { - static const WCHAR device_id[] = L"wine\test"; + static const WCHAR device_id[] = L"Wine\Test"; WCHAR *id = NULL;
irp->IoStatus.Information = 0; @@ -256,6 +269,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
case IRP_MN_START_DEVICE: { + static const WCHAR expect_symlink[] = L"\??\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"; static const LARGE_INTEGER wait_time = {.QuadPart = -500 * 10000}; POWER_STATE state = {.DeviceState = PowerDeviceD0}; NTSTATUS status; @@ -267,6 +281,12 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
status = IoRegisterDeviceInterface(device_obj, &child_class, NULL, &device->child_symlink); ok(!status, "Failed to register interface, status %#lx.\n", status); + ok(device->child_symlink.Length == sizeof(expect_symlink) - sizeof(WCHAR), + "Got length %u.\n", device->child_symlink.Length); + ok(device->child_symlink.MaximumLength == sizeof(expect_symlink), + "Got maximum length %u.\n", device->child_symlink.MaximumLength); + todo_wine ok(!kmemcmp(device->child_symlink.Buffer, expect_symlink, device->child_symlink.MaximumLength), + "Got symlink "%ls".\n", device->child_symlink.Buffer);
IoSetDeviceInterfaceState(&device->child_symlink, TRUE);
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c4521ed652a..c5362e3fb2b 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1406,7 +1406,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) { ++got_child_arrival; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\wine#test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + todo_wine ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } break; @@ -1434,7 +1434,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) { ++got_child_removal; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\wine#test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + todo_wine ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } break; @@ -1506,7 +1506,7 @@ static void test_pnp_devices(void)
ret = SetupDiGetDeviceInstanceIdA(set, &device, buffer, sizeof(buffer), NULL); ok(ret, "failed to get device ID, error %#lx\n", GetLastError()); - ok(!strcasecmp(buffer, "root\winetest\0"), "got ID %s\n", debugstr_a(buffer)); + ok(!strcmp(buffer, "ROOT\WINETEST\0"), "got ID %s\n", debugstr_a(buffer));
ret = SetupDiEnumDeviceInterfaces(set, NULL, &control_class, 0, &iface); ok(ret, "failed to get interface, error %#lx\n", GetLastError()); @@ -1517,7 +1517,7 @@ static void test_pnp_devices(void) iface_detail->cbSize = sizeof(*iface_detail); ret = SetupDiGetDeviceInterfaceDetailA(set, &iface, iface_detail, sizeof(buffer), NULL, NULL); ok(ret, "failed to get interface path, error %#lx\n", GetLastError()); - ok(!strcasecmp(iface_detail->DevicePath, "\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}"), + ok(!strcmp(iface_detail->DevicePath, "\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}"), "wrong path %s\n", debugstr_a(iface_detail->DevicePath));
SetupDiDestroyDeviceInfoList(set); @@ -1614,7 +1614,7 @@ static void test_pnp_devices(void)
ret = SetupDiGetDeviceInstanceIdA(set, &device, buffer, sizeof(buffer), NULL); ok(ret, "failed to get device ID, error %#lx\n", GetLastError()); - ok(!strcasecmp(buffer, "wine\test\1"), "got ID %s\n", debugstr_a(buffer)); + ok(!strcmp(buffer, "WINE\TEST\1"), "got ID %s\n", debugstr_a(buffer));
ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_CAPABILITIES, &type, (BYTE *)&dword, sizeof(dword), NULL); @@ -1680,6 +1680,18 @@ static void test_pnp_devices(void) ok(!strcmp(buffer, "\Device\winetest_pnp_1"), "got PDO name %s\n", debugstr_a(buffer)); }
+ ret = SetupDiEnumDeviceInterfaces(set, NULL, &child_class, 0, &iface); + ok(ret, "failed to get interface, error %#lx\n", GetLastError()); + ok(IsEqualGUID(&iface.InterfaceClassGuid, &child_class), + "wrong class %s\n", debugstr_guid(&iface.InterfaceClassGuid)); + ok(iface.Flags == SPINT_ACTIVE, "got flags %#lx\n", iface.Flags); + + iface_detail->cbSize = sizeof(*iface_detail); + ret = SetupDiGetDeviceInterfaceDetailA(set, &iface, iface_detail, sizeof(buffer), NULL, NULL); + ok(ret, "failed to get interface path, error %#lx\n", GetLastError()); + ok(!strcmp(iface_detail->DevicePath, "\\?\wine#test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + "wrong path %s\n", debugstr_a(iface_detail->DevicePath)); + SetupDiDestroyDeviceInfoList(set);
RtlInitUnicodeString(&string, L"\Device\winetest_pnp_1");
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntoskrnl.exe/pnp.c | 40 ++++++++++++++++------------ dlls/ntoskrnl.exe/tests/driver_pnp.c | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 25a52d7d219..e1c34ab57c3 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -883,13 +883,12 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla SP_DEVICE_INTERFACE_DATA sp_iface = {sizeof(sp_iface)}; SP_DEVINFO_DATA sp_device = {sizeof(sp_device)}; WCHAR device_instance_id[MAX_DEVICE_ID_LEN]; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING device_path; struct device_interface *iface; struct wine_rb_entry *entry; - DWORD required; HDEVINFO set; + WCHAR *p;
TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n", device, debugstr_guid(class_guid), debugstr_us(refstr), symbolic_link); @@ -910,22 +909,31 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla if (!SetupDiCreateDeviceInterfaceW( set, &sp_device, class_guid, refstr ? refstr->Buffer : NULL, 0, &sp_iface )) return STATUS_UNSUCCESSFUL;
- required = 0; - SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, NULL, 0, &required, NULL ); - if (required == 0) return STATUS_UNSUCCESSFUL; + /* setupapi mangles the case; construct the interface path manually. */
- data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, required ); - data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + device_path.Length = (4 + wcslen( device_instance_id ) + 1 + 38) * sizeof(WCHAR); + if (refstr) + device_path.Length += sizeof(WCHAR) + refstr->Length; + device_path.MaximumLength = device_path.Length + sizeof(WCHAR);
- if (!SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, data, required, NULL, NULL )) + device_path.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, device_path.MaximumLength ); + swprintf( device_path.Buffer, device_path.MaximumLength / sizeof(WCHAR), + L"\??\%s#{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + device_instance_id, class_guid->Data1, class_guid->Data2, class_guid->Data3, + class_guid->Data4[0], class_guid->Data4[1], class_guid->Data4[2], class_guid->Data4[3], + class_guid->Data4[4], class_guid->Data4[5], class_guid->Data4[6], class_guid->Data4[7] ); + for (p = device_path.Buffer + 4; *p; p++) { - HeapFree( GetProcessHeap(), 0, data ); - return STATUS_UNSUCCESSFUL; + if (*p == '\') + *p = '#'; + } + if (refstr) + { + *p++ = '\'; + wcscpy( p, refstr->Buffer ); }
- data->DevicePath[1] = '?'; - TRACE("Returning path %s.\n", debugstr_w(data->DevicePath)); - RtlCreateUnicodeString( &device_path, data->DevicePath); + TRACE("Returning path %s.\n", debugstr_us(&device_path));
entry = wine_rb_get( &device_interfaces, &device_path ); if (entry) @@ -937,7 +945,7 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla else { iface = heap_alloc_zero( sizeof(struct device_interface) ); - RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath); + RtlDuplicateUnicodeString( 1, &device_path, &iface->symbolic_link ); if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry )) ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link)); } @@ -945,9 +953,7 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla iface->device = device; iface->interface_class = *class_guid; if (symbolic_link) - RtlCreateUnicodeString( symbolic_link, data->DevicePath); - - HeapFree( GetProcessHeap(), 0, data ); + RtlDuplicateUnicodeString( 1, &device_path, symbolic_link );
RtlFreeUnicodeString( &device_path );
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 92ad69762de..77332708fd3 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -285,7 +285,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) "Got length %u.\n", device->child_symlink.Length); ok(device->child_symlink.MaximumLength == sizeof(expect_symlink), "Got maximum length %u.\n", device->child_symlink.MaximumLength); - todo_wine ok(!kmemcmp(device->child_symlink.Buffer, expect_symlink, device->child_symlink.MaximumLength), + ok(!kmemcmp(device->child_symlink.Buffer, expect_symlink, device->child_symlink.MaximumLength), "Got symlink "%ls".\n", device->child_symlink.Buffer);
IoSetDeviceInterfaceState(&device->child_symlink, TRUE);
From: Zebediah Figura zfigura@codeweavers.com
This reverts commit c489356d0b5bf01f2a09f6df8f5a5b9b1894fb17. --- dlls/ntoskrnl.exe/pnp.c | 8 +------- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index e1c34ab57c3..59655a24777 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -725,13 +725,13 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable
size_t namelen = name->Length / sizeof(WCHAR); DEV_BROADCAST_DEVICEINTERFACE_W *broadcast; - WCHAR *path, *refstr, *p, *upper_end; struct device_interface *iface; HANDLE iface_key, control_key; OBJECT_ATTRIBUTES attr = {0}; struct wine_rb_entry *entry; UNICODE_STRING control = RTL_CONSTANT_STRING( L"Control" ); UNICODE_STRING linked = RTL_CONSTANT_STRING( L"Linked" ); + WCHAR *path, *refstr, *p; UNICODE_STRING string; DWORD data = enable; NTSTATUS ret; @@ -817,12 +817,6 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable broadcast->dbcc_classguid = iface->interface_class; lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 ); if (namelen > 1) broadcast->dbcc_name[1] = '\'; - - upper_end = wcschr( broadcast->dbcc_name, '#' ); - if (upper_end) upper_end = wcschr( upper_end + 1, '#' ); - while (upper_end && upper_end-- != broadcast->dbcc_name) - *upper_end = towupper( *upper_end ); - send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, broadcast, len ); heap_free( broadcast ); } diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c5362e3fb2b..859dab4b3a9 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1406,7 +1406,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) { ++got_child_arrival; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } break; @@ -1434,7 +1434,7 @@ static LRESULT WINAPI device_notify_proc(HWND window, UINT message, WPARAM wpara else if (IsEqualGUID(&iface->dbcc_classguid, &child_class)) { ++got_child_removal; - todo_wine ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + ok(!strcmp(iface->dbcc_name, "\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), "got name %s\n", debugstr_a(iface->dbcc_name)); } break;
v3: a hunk got lost in v2 somehow; pushed it again.
Rémi Bernon (@rbernon) commented about dlls/ntoskrnl.exe/tests/driver_pnp.c:
#include "driver.h" #include "utils.h"
+/* memcmp() isn't exported from ntoskrnl on i386 */ +static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
Fwiw you can use `RtlCompareMemory`.
This merge request was approved by Rémi Bernon.