-- v3: wineusb.sys: Print a warning for unhandled IRP_MN_QUERY_DEVICE_TEXT text types. winebth.sys: Print a warning for unhandled IRP_MN_QUERY_DEVICE_TEXT text types. hidclass: Print a warning for unhandled IRP_MN_QUERY_DEVICE_TEXT text types. winebus: Handle IRP_MN_QUERY_DEVICE_TEXT.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/ntoskrnl.exe/tests/driver_pnp.c | 37 +++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 41 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 1a0717656c5..c33a8d6a082 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -265,6 +265,38 @@ static NTSTATUS query_id(struct device *device, IRP *irp, BUS_QUERY_ID_TYPE type return STATUS_SUCCESS; }
+static NTSTATUS query_text(struct device *device, IRP *irp, DEVICE_TEXT_TYPE type, LCID locale) +{ + static const WCHAR device_text2[] = L"WineTestDeviceLocation"; + static const WCHAR device_text[] = L"WineTestDevice"; + WCHAR *text = NULL; + + irp->IoStatus.Information = 0; + switch (type) + { + case DeviceTextDescription: + todo_wine ok(locale, "Expected locale to be set.\n"); + if (!(text = ExAllocatePool(PagedPool, sizeof(device_text)))) + return STATUS_NO_MEMORY; + wcscpy(text, device_text); + break; + + case DeviceTextLocationInformation: + todo_wine ok(locale, "Expected locale to be set.\n"); + if (!(text = ExAllocatePool(PagedPool, sizeof(device_text2)))) + return STATUS_NO_MEMORY; + wcscpy(text, device_text2); + break; + + default: + ok(0, "Unexpected device text type %#x.\n", type); + return irp->IoStatus.Status; + } + + irp->IoStatus.Information = (ULONG_PTR)text; + return STATUS_SUCCESS; +} + static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -422,6 +454,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) cancel_remove_device_count++; ret = STATUS_SUCCESS; break; + + case IRP_MN_QUERY_DEVICE_TEXT: + ret = query_text(device, irp, stack->Parameters.QueryDeviceText.DeviceTextType, + stack->Parameters.QueryDeviceText.LocaleId); + break; }
irp->IoStatus.Status = ret; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 6d3914c8c0b..63b7f13d6b4 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1640,6 +1640,9 @@ static void test_pnp_devices(void) static const char expect_hardware_id[] = "winetest_hardware\0winetest_hardware_1\0"; static const WCHAR expect_hardware_id_w[] = L"winetest_hardware\0winetest_hardware_1\0"; static const char expect_compat_id[] = "winetest_compat\0winetest_compat_1\0"; + static const char expect_device_location[] = "WineTestDeviceLocation"; + static const WCHAR expect_device_location_w[] = L"WineTestDeviceLocation"; + static const WCHAR expect_device_bus_desc_w[] = L"WineTestDevice"; static const WCHAR expect_compat_id_w[] = L"winetest_compat\0winetest_compat_1\0"; static const WCHAR expect_container_id_w[] = L"{12345678-1234-1234-1234-123456789123}"; static const char foobar[] = "foobar"; @@ -1926,6 +1929,16 @@ static void test_pnp_devices(void) ok(!strcmp(buffer, "\Device\winetest_pnp_1"), "got PDO name %s\n", debugstr_a(buffer)); }
+ ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_LOCATION_INFORMATION, &type, (BYTE *)buffer, + sizeof(buffer), &size); + todo_wine ok(ret, "Got error %#lx.\n", GetLastError()); + if (ret) + { + ok(type == REG_SZ, "Got type %lu.\n", type); + ok(size == sizeof(expect_device_location), "Got size %lu.\n", size); + ok(!strcmp(buffer, expect_device_location), "Got location information %s.\n", debugstr_a(buffer)); + } + prop_type = DEVPROP_TYPE_EMPTY; size = 0; memset(buffer_w, 0, sizeof(buffer_w)); @@ -1956,6 +1969,34 @@ static void test_pnp_devices(void) ok(IsEqualGUID(&buffer_guid, &expect_container_id_guid), "got container ID %s != %s\n", debugstr_guid(&buffer_guid), debugstr_guid(&expect_container_id_guid));
+ /* DEVPKEY_Device_BusReportedDeviceDesc. */ + prop_type = DEVPROP_TYPE_EMPTY; + size = 0; + memset(buffer_w, 0, sizeof(buffer_w)); + ret = SetupDiGetDevicePropertyW(set, &device, &DEVPKEY_Device_BusReportedDeviceDesc, &prop_type, (BYTE *)buffer_w, + sizeof(buffer_w), &size, 0); + todo_wine ok(ret, "Got error %#lx.\n", GetLastError()); + if (ret) + { + ok(prop_type == DEVPROP_TYPE_STRING, "got type %#lx\n", prop_type); + ok(size == sizeof(expect_device_bus_desc_w), "Got size %lu.\n", size); + ok(!wcscmp(buffer_w, expect_device_bus_desc_w), "Got device bus desc %s.\n", debugstr_w(buffer_w)); + } + + /* DEVPKEY_Device_LocationInfo. */ + prop_type = DEVPROP_TYPE_EMPTY; + size = 0; + memset(buffer_w, 0, sizeof(buffer_w)); + ret = SetupDiGetDevicePropertyW(set, &device, &DEVPKEY_Device_LocationInfo, &prop_type, (BYTE *)buffer_w, + sizeof(buffer_w), &size, 0); + todo_wine ok(ret, "Got error %#lx.\n", GetLastError()); + if (ret) + { + ok(prop_type == DEVPROP_TYPE_STRING, "got type %#lx\n", prop_type); + ok(size == sizeof(expect_device_location_w), "Got size %lu.\n", size); + ok(!wcscmp(buffer_w, expect_device_location_w), "Got device location info %s.\n", debugstr_w(buffer_w)); + } + ret = SetupDiEnumDeviceInterfaces(set, NULL, &child_class, 0, &iface); ok(ret, "failed to get interface, error %#lx\n", GetLastError()); ok(IsEqualGUID(&iface.InterfaceClassGuid, &child_class),
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/ntoskrnl.exe/pnp.c | 35 ++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 11 ++++------ 2 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 86067a35692..1824fb28cab 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -33,6 +33,7 @@
#include "initguid.h" DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +#include "devpkey.h"
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
@@ -95,6 +96,32 @@ static NTSTATUS get_device_id( DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WC return irp_status.Status; }
+static NTSTATUS get_device_text( DEVICE_OBJECT *device, DEVICE_TEXT_TYPE type, WCHAR **text ) +{ + IO_STACK_LOCATION *irpsp; + IO_STATUS_BLOCK irp_status; + KEVENT event; + IRP *irp; + + device = IoGetAttachedDevice( device ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, &event, &irp_status ))) + return STATUS_NO_MEMORY; + + irpsp = IoGetNextIrpStackLocation( irp ); + irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_TEXT; + irpsp->Parameters.QueryDeviceText.DeviceTextType = type; + irpsp->Parameters.QueryDeviceText.LocaleId = 0; + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + if (IoCallDriver( device, irp ) == STATUS_PENDING) + KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); + + *text = (WCHAR *)irp_status.Information; + return irp_status.Status; +} + static NTSTATUS send_pnp_irp( DEVICE_OBJECT *device, UCHAR minor ) { IO_STACK_LOCATION *irpsp; @@ -362,6 +389,14 @@ static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set ) ExFreePool( id ); }
+ if (!get_device_text(device, DeviceTextDescription, &id) && id) + { + if (!SetupDiSetDevicePropertyW( set, &sp_device, &DEVPKEY_Device_BusReportedDeviceDesc, DEVPROP_TYPE_STRING, + (BYTE *)id, (lstrlenW( id ) + 1) * sizeof(WCHAR), 0 )) + WARN("Failed to set bus reported device desc property.\n"); + ExFreePool( id ); + } + if (need_driver && !install_device_driver( device, set, &sp_device ) && !caps.RawDeviceOK) { ERR("Unable to install a function driver for device %s.\n", debugstr_w(device_instance_id)); diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 63b7f13d6b4..87f41895511 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1975,13 +1975,10 @@ static void test_pnp_devices(void) memset(buffer_w, 0, sizeof(buffer_w)); ret = SetupDiGetDevicePropertyW(set, &device, &DEVPKEY_Device_BusReportedDeviceDesc, &prop_type, (BYTE *)buffer_w, sizeof(buffer_w), &size, 0); - todo_wine ok(ret, "Got error %#lx.\n", GetLastError()); - if (ret) - { - ok(prop_type == DEVPROP_TYPE_STRING, "got type %#lx\n", prop_type); - ok(size == sizeof(expect_device_bus_desc_w), "Got size %lu.\n", size); - ok(!wcscmp(buffer_w, expect_device_bus_desc_w), "Got device bus desc %s.\n", debugstr_w(buffer_w)); - } + ok(ret, "Got error %#lx.\n", GetLastError()); + ok(prop_type == DEVPROP_TYPE_STRING, "got type %#lx\n", prop_type); + ok(size == sizeof(expect_device_bus_desc_w), "Got size %lu.\n", size); + ok(!wcscmp(buffer_w, expect_device_bus_desc_w), "Got device bus desc %s.\n", debugstr_w(buffer_w));
/* DEVPKEY_Device_LocationInfo. */ prop_type = DEVPROP_TYPE_EMPTY;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/winebus.sys/main.c | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index ba8603204d4..1b1aafb0891 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -264,6 +264,21 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device) return dst; }
+static WCHAR *get_device_text(DEVICE_OBJECT *device) +{ + struct device_extension *ext = device->DeviceExtension; + const WCHAR *src = ext->desc.product; + DWORD size; + WCHAR *dst; + + size = (wcslen(src) + 1) * sizeof(WCHAR); + if ((dst = ExAllocatePool( PagedPool, size ))) + memcpy( dst, src, size ); + + TRACE("Returning %s.\n", debugstr_w(dst)); + return dst; +} + static IRP *pop_pending_read(struct device_extension *ext) { IRP *pending; @@ -700,6 +715,30 @@ static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp) return status; }
+static NTSTATUS handle_IRP_MN_QUERY_DEVICE_TEXT(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + DEVICE_TEXT_TYPE type = irpsp->Parameters.QueryDeviceText.DeviceTextType; + NTSTATUS status = irp->IoStatus.Status; + + TRACE("(%p, %p)\n", device, irp); + + switch (type) + { + case DeviceTextDescription: + TRACE("DeviceTextDescription.\n"); + irp->IoStatus.Information = (ULONG_PTR)get_device_text(device); + break; + + default: + WARN("Unhandled type %08x.\n", type); + return status; + } + + status = irp->IoStatus.Information ? STATUS_SUCCESS : STATUS_NO_MEMORY; + return status; +} + static void mouse_device_create(void) { struct device_create_params params = {{0}}; @@ -1224,6 +1263,10 @@ static NTSTATUS pdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) status = handle_IRP_MN_QUERY_ID(device, irp); break;
+ case IRP_MN_QUERY_DEVICE_TEXT: + status = handle_IRP_MN_QUERY_DEVICE_TEXT(device, irp); + break; + case IRP_MN_QUERY_CAPABILITIES: status = STATUS_SUCCESS; break;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/hidclass.sys/pnp.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 8356c646f50..4774ba2b9fc 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -620,6 +620,14 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) status = STATUS_SUCCESS; break;
+ case IRP_MN_QUERY_DEVICE_TEXT: + { + DEVICE_TEXT_TYPE type = irpsp->Parameters.QueryDeviceText.DeviceTextType; + WARN("Ignoring IRP_MN_QUERY_TEXT type %u.\n", type); + status = STATUS_NOT_SUPPORTED; + break; + } + default: FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/winebth.sys/winebth.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index ba83ac92ca9..416d74e9db4 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -1420,6 +1420,10 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct ret = STATUS_SUCCESS; break; } + case IRP_MN_QUERY_DEVICE_TEXT: + WARN("Unhandled IRP_MN_QUERY_DEVICE_TEXT text type %u.\n", stack->Parameters.QueryDeviceText.DeviceTextType); + break; + default: FIXME( "Unhandled minor function %#x.\n", stack->MinorFunction ); } @@ -1530,6 +1534,9 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot LeaveCriticalSection( &device_list_cs ); ret = STATUS_SUCCESS; break; + case IRP_MN_QUERY_DEVICE_TEXT: + WARN("Unhandled IRP_MN_QUERY_DEVICE_TEXT text type %u.\n", stack->Parameters.QueryDeviceText.DeviceTextType); + break; default: FIXME( "Unhandled minor function %s.\n", debugstr_minor_function_code( stack->MinorFunction ) ); break;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 05603de1377..a56d4c1a0c7 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -503,6 +503,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) ret = STATUS_SUCCESS; break;
+ case IRP_MN_QUERY_DEVICE_TEXT: + WARN("Unhandled IRP_MN_QUERY_DEVICE_TEXT text type %u.\n", stack->Parameters.QueryDeviceText.DeviceTextType); + break; + default: FIXME("Unhandled minor function %#x.\n", stack->MinorFunction); }
On Thu Aug 21 14:33:34 2025 +0000, Connor McAdams wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/8770/diffs?diff_id=202010&start_sha=427565003e10a2348adb50cb56abd527324075bb#453bdfd7a345f2ff44b190df51beaa364ade5ca0_274_274)
Should be fixed now.
On Thu Aug 21 14:35:31 2025 +0000, Rémi Bernon wrote:
case IRP_MN_QUERY_DEVICE_TEXT: { DEVICE_TEXT_TYPE type = irpsp->Parameters.QueryDeviceText.DeviceTextType; WARN("Ignoring IRP_MN_QUERY_TEXT type %u\n", type); status = STATUS_NOT_SUPPORTED; break; }
Done, but I added a period at the end of the `WARN`, hopefully that's still acceptable :)
This merge request was approved by Rémi Bernon.
On Thu Aug 21 15:54:36 2025 +0000, Connor McAdams wrote:
I've added some code to wineusb/winebth to print a `WARN` instead of a `FIXME` for `IRP_MN_QUERY_DEVICE_TEXT`. Those seem pretty simple, but adding Vibhav as a reviewer to make sure I haven't messed anything up. :) I've added an actual implementation for `IRP_MN_QUERY_DEVICE_TEXT` to winebus.sys, so that part will need a bit of extra review/scrutiny.
Thanks for the heads up, it'll be nice to implement this in the next winebth MR :)
This merge request was approved by Vibhav Pant.