From: Vibhav Pant vibhavp@gmail.com
--- dlls/ntoskrnl.exe/tests/Makefile.in | 2 +- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 226 ++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 97dee8b25cf..f8fb0fa2ea9 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = ntoskrnl.exe -IMPORTS = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid +IMPORTS = advapi32 cfgmgr32 crypt32 newdev setupapi user32 wintrust ws2_32 hid
driver_IMPORTS = winecrt0 ntoskrnl hal fltmgr driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 819d1497ff9..c00e9aa83d2 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -35,6 +35,8 @@ #include "mssip.h" #include "setupapi.h" #include "cfgmgr32.h" +#include "devfiltertypes.h" +#include "devquery.h" #include "newdev.h" #include "regstr.h" #include "dbt.h" @@ -1443,6 +1445,187 @@ static void pump_messages(void) } }
+struct devquery_callback_data +{ + HANDLE enum_completed_evt; + BOOL initial_enum_completed; + + HANDLE device_added_sem; + DWORD bus_dev_added; + DWORD child_dev_added; + + HANDLE device_removed_sem; + DWORD bus_dev_removed; + DWORD child_dev_removed; +}; + +static const char *debugstr_DEV_OBJECT_TYPE(DEV_OBJECT_TYPE type) +{ + static const char *str[] = { + "DevObjectTypeUnknown", + "DevObjectTypeDeviceInterface", + "DevObjectTypeDeviceContainer", + "DevObjectTypeDevice", + "DevObjectTypeDeviceInterfaceClass", + "DevObjectTypeAEP", + "DevObjectTypeAEPContainer", + "DevObjectTypeDeviceInstallerClass", + "DevObjectTypeDeviceInterfaceDisplay", + "DevObjectTypeDeviceContainerDisplay", + "DevObjectTypeAEPService", + "DevObjectTypeDevicePanel", + "DevObjectTypeAEPProtocol", + }; + if (type >= ARRAY_SIZE(str)) + return wine_dbg_sprintf("(unknown %d)", type); + return wine_dbg_sprintf("%s", str[type]); +} + +static const char *debugstr_DEV_QUERY_RESULT_ACTION_DATA(const DEV_QUERY_RESULT_ACTION_DATA *action_data) +{ + if (!action_data) return wine_dbg_sprintf("(null)"); + switch (action_data->Action) + { + case DevQueryResultStateChange: + { + static const char *str[] = { + "DevQueryStateInitialized", + "DevQueryStateEnumCompleted", + "DevQueryStateAborted", + "DevQueryStateClosed" + }; + + if (action_data->Data.State >= ARRAY_SIZE(str)) + return wine_dbg_sprintf("{ DevQueryResultStateChange { (unknown %d) } }", action_data->Data.State); + return wine_dbg_sprintf("{ DevQueryResultStateChange { %s } }", str[action_data->Data.State]); + } + case DevQueryResultAdd: + case DevQueryResultUpdate: + case DevQueryResultRemove: + { + const DEV_OBJECT *obj = &action_data->Data.DeviceObject; + static const char *str[] = { + "DevQueryResultAdd", + "DevQueryResultUpdate", + "DevQueryResultRemove", + }; + + return wine_dbg_sprintf("{ %s { %s %s %lu %p } }", str[action_data->Action - 1], + debugstr_DEV_OBJECT_TYPE(obj->ObjectType), debugstr_w(obj->pszObjectId), + obj->cPropertyCount, obj->pProperties); + } + default: + return wine_dbg_sprintf("{ (unknown %d) }", action_data->Action); + } +} + +static void CALLBACK devquery_notify_callback(HDEVQUERY devquery, void *user_data, + const DEV_QUERY_RESULT_ACTION_DATA *action_data) +{ + struct devquery_callback_data *data = user_data; + + if (winetest_debug > 1) + trace("(%p, %p, %s)", devquery, user_data, debugstr_DEV_QUERY_RESULT_ACTION_DATA(action_data)); + + switch (action_data->Action) + { + case DevQueryResultStateChange: + if (action_data->Data.State == DevQueryStateEnumCompleted) + { + data->initial_enum_completed = TRUE; + SetEvent(data->enum_completed_evt); + } + break; + case DevQueryResultAdd: + { + const DEV_OBJECT *obj = &action_data->Data.DeviceObject; + DEVPROP_BOOLEAN state = DEVPROP_FALSE; + GUID iface_guid = {0}; + ULONG i; + + if (!data->initial_enum_completed) + break; + if (obj->ObjectType != DevObjectTypeDeviceInterfaceDisplay) + break; + ok(obj->cPropertyCount == 2, "got cPropertyCount %lu\n", obj->cPropertyCount); + ok(!!obj->pProperties, "got pProperties %p\n", obj->pProperties); + if (!obj->pProperties) + return; + for (i = 0; i < obj->cPropertyCount; i++) + { + const DEVPROPERTY *prop = &obj->pProperties[i]; + if (IsEqualDevPropKey(prop->CompKey.Key, DEVPKEY_DeviceInterface_ClassGuid)) + { + ok(prop->Type == DEVPROP_TYPE_GUID, "got Type %#lx != %#x\n", prop->Type, DEVPROP_TYPE_GUID); + ok(prop->BufferSize == sizeof(GUID), "got BufferSize %lu != %Iu\n", prop->BufferSize, sizeof(GUID)); + if (prop->BufferSize == sizeof(GUID) && prop->Type == DEVPROP_TYPE_GUID) + iface_guid = *(GUID *)prop->Buffer; + } + else if (IsEqualDevPropKey(prop->CompKey.Key, DEVPKEY_DeviceInterface_Enabled)) + { + ok(prop->Type == DEVPROP_TYPE_BOOLEAN, "got Type %#lx != %#x\n", prop->Type, DEVPROP_TYPE_BOOLEAN); + ok(prop->BufferSize == sizeof(DEVPROP_BOOLEAN), "got BufferSize %lu != %Iu\n", prop->BufferSize, + sizeof(DEVPROP_BOOLEAN)); + if (prop->BufferSize == sizeof(DEVPROP_BOOLEAN) && prop->Type == DEVPROP_TYPE_BOOLEAN) + state = *(DEVPROP_BOOLEAN *)prop->Buffer; + } + } + + ok(IsEqualGUID(&iface_guid, &bus_class) || IsEqualGUID(&iface_guid, &child_class), "got iface_guid %s\n", + debugstr_guid(&iface_guid)); + if (IsEqualGUID(&iface_guid, &bus_class) && state) + { + data->bus_dev_added++; + ok(!wcsicmp(obj->pszObjectId, L"\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}"), + "got pszObjectId %s\n", debugstr_w(obj->pszObjectId)); + ReleaseSemaphore(data->device_added_sem, 1, NULL); + } + else if (IsEqualGUID(&iface_guid, &child_class) && state) + { + data->child_dev_added++; + ok(!wcsicmp(obj->pszObjectId, L"\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + "got pszObjectId %s\n", debugstr_w(obj->pszObjectId)); + ReleaseSemaphore(data->device_added_sem, 1, NULL); + } + break; + } + case DevQueryResultUpdate: + { + const DEV_OBJECT *obj = &action_data->Data.DeviceObject; + const DEVPROPERTY *prop = &obj->pProperties[0]; + + if (!data->initial_enum_completed) + break; + if (obj->ObjectType != DevObjectTypeDeviceInterfaceDisplay) + break; + ok(!wcsicmp(obj->pszObjectId, L"\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}") || + !wcsicmp(obj->pszObjectId, L"\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}"), + "got pszObjectId %s\n", debugstr_w(obj->pszObjectId)); + ok(obj->cPropertyCount == 1, "got cPropertyCount %lu\n", obj->cPropertyCount); + ok(!!obj->pProperties, "got pProperties %p\n", obj->pProperties); + if (!obj->pProperties) + return; + ok(IsEqualDevPropKey(prop->CompKey.Key, DEVPKEY_DeviceInterface_Enabled), "got CompKey.Key {%s,%#lx}\n", + debugstr_guid(&prop->CompKey.Key.fmtid), prop->CompKey.Key.pid); + ok(prop->Type == DEVPROP_TYPE_BOOLEAN, "got Type %#lx != %#x\n", prop->Type, DEVPROP_TYPE_BOOLEAN); + ok(prop->BufferSize == sizeof(DEVPROP_BOOLEAN), "got BufferSize %lu != %Iu\n", prop->BufferSize, + sizeof(DEVPROP_BOOLEAN)); + if (prop->BufferSize == sizeof(DEVPROP_BOOLEAN) && prop->Type == DEVPROP_TYPE_BOOLEAN && + !*(DEVPROP_BOOLEAN *)prop->Buffer) + { + if (!wcsicmp(obj->pszObjectId, L"\\?\ROOT#WINETEST#0#{deadbeef-29ef-4538-a5fd-b69573a362c1}")) + data->bus_dev_removed++; + else if (!wcsicmp(obj->pszObjectId, L"\\?\Wine#Test#1#{deadbeef-29ef-4538-a5fd-b69573a362c2}")) + data->child_dev_removed++; + ReleaseSemaphore(data->device_removed_sem, 1, NULL); + } + break; + } + default: + break; + } +} + static void test_pnp_devices(void) { static const char expect_hardware_id[] = "winetest_hardware\0winetest_hardware_1\0"; @@ -1469,6 +1652,12 @@ static void test_pnp_devices(void) .lpszClassName = "ntoskrnl_test_wc", .lpfnWndProc = device_notify_proc, }; + struct devquery_callback_data devquery_data = {0}; + DEVPROPCOMPKEY iface_prop_keys[2] = + { + { DEVPKEY_DeviceInterface_ClassGuid, DEVPROP_STORE_SYSTEM, 0 }, + { DEVPKEY_DeviceInterface_Enabled, DEVPROP_STORE_SYSTEM, 0 } + }; HDEVNOTIFY notify_handle; DWORD size = 0, type, dword; HANDLE bus, child, tmp; @@ -1476,9 +1665,11 @@ static void test_pnp_devices(void) UNICODE_STRING string; OVERLAPPED ovl = {0}; IO_STATUS_BLOCK io; + HDEVQUERY query; HDEVINFO set; HWND window; LSTATUS status; + HRESULT hr; HKEY key; BOOL ret; int id; @@ -1490,6 +1681,15 @@ static void test_pnp_devices(void) notify_handle = RegisterDeviceNotificationA(window, &filter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); ok(!!notify_handle, "failed to register window, error %lu\n", GetLastError());
+ devquery_data.enum_completed_evt = CreateEventW(NULL, FALSE, FALSE, NULL); + devquery_data.device_added_sem = CreateSemaphoreW(NULL, 0, 1, NULL); + devquery_data.device_removed_sem = CreateSemaphoreW(NULL, 0, 1, NULL); + hr = DevCreateObjectQuery(DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagUpdateResults, 2, iface_prop_keys, 0, + NULL, devquery_notify_callback, &devquery_data, &query); + ok(hr == S_OK, "Failed to create device query, hr %#lx\n", hr); + status = WaitForSingleObject(devquery_data.enum_completed_evt, 5000); + ok(!status, "WaitforSingleObject failed, error %lu\n", status); + set = SetupDiGetClassDevsA(&control_class, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#lx\n", GetLastError());
@@ -1569,6 +1769,10 @@ static void test_pnp_devices(void) pump_messages(); ok(got_bus_arrival == 1, "got %u bus arrival messages\n", got_bus_arrival); ok(!got_bus_removal, "got %u bus removal messages\n", got_bus_removal); + status = WaitForSingleObject(devquery_data.device_added_sem, 1000); + todo_wine ok(!status, "WaitForSingleObject failed, error %lu\n", status); + todo_wine ok(devquery_data.bus_dev_added == 1, "got %lu new bus device objects\n", devquery_data.bus_dev_added); + todo_wine_if (!status) ok(!devquery_data.bus_dev_removed, "got %lu bus device object removals\n", devquery_data.bus_dev_removed);
set = SetupDiGetClassDevsA(&bus_class, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#lx\n", GetLastError()); @@ -1585,6 +1789,10 @@ static void test_pnp_devices(void) pump_messages(); ok(got_bus_arrival == 1, "got %u bus arrival messages\n", got_bus_arrival); ok(got_bus_removal == 1, "got %u bus removal messages\n", got_bus_removal); + status = WaitForSingleObject(devquery_data.device_removed_sem, 1000); + todo_wine ok(!status, "WaitForSingleObject failed, error %lu\n", status); + todo_wine ok(devquery_data.bus_dev_added == 1, "got %lu new bus device objects\n", devquery_data.bus_dev_added); + todo_wine ok(devquery_data.bus_dev_removed == 1, "got %lu bus device object removals\n", devquery_data.bus_dev_removed);
set = SetupDiGetClassDevsA(&bus_class, NULL, NULL, DIGCF_DEVICEINTERFACE); ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#lx\n", GetLastError()); @@ -1611,6 +1819,10 @@ static void test_pnp_devices(void) pump_messages(); ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival); ok(!got_child_removal, "got %u child removal messages\n", got_child_removal); + status = WaitForSingleObject(devquery_data.device_added_sem, 1000); + todo_wine ok(!status, "WaitForSingleObject failed, error %lu\n", status); + todo_wine ok(devquery_data.child_dev_added == 1, "got %lu new bus device objects\n", devquery_data.child_dev_added); + todo_wine_if(!status) ok(!devquery_data.child_dev_removed, "got %lu bus device object removals\n", devquery_data.child_dev_removed);
set = SetupDiGetClassDevsA(&child_class, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#lx\n", GetLastError()); @@ -1749,6 +1961,10 @@ static void test_pnp_devices(void) pump_messages(); ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival); ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal); + status = WaitForSingleObject(devquery_data.device_removed_sem, 1000); + todo_wine ok(!status, "WaitForSingleObject failed, error %lu\n", status); + todo_wine ok(devquery_data.child_dev_added == 1, "got %lu new bus device objects\n", devquery_data.child_dev_added); + todo_wine ok(devquery_data.child_dev_removed == 1, "got %lu bus device object removals\n", devquery_data.child_dev_removed);
ret = DeviceIoControl(child, IOCTL_WINETEST_CHILD_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL); todo_wine ok(ret, "got error %lu\n", GetLastError()); @@ -1766,6 +1982,12 @@ static void test_pnp_devices(void) pump_messages(); ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival); ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal); + status = WaitForSingleObject(devquery_data.device_added_sem, 1000); + ok(status == WAIT_TIMEOUT, "got status %#lx\n", status); + status = WaitForSingleObject(devquery_data.device_removed_sem, 1000); + ok(status == WAIT_TIMEOUT, "got status %#lx\n", status); + todo_wine ok(devquery_data.child_dev_added == 1, "got %lu new bus device objects\n", devquery_data.child_dev_added); + todo_wine ok(devquery_data.child_dev_removed == 1, "got %lu bus device object removals\n", devquery_data.child_dev_removed);
ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT); ok(ret == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", ret); @@ -1773,6 +1995,10 @@ static void test_pnp_devices(void) CloseHandle(bus);
UnregisterDeviceNotification(notify_handle); + DevCloseObjectQuery(query); + CloseHandle(devquery_data.device_added_sem); + CloseHandle(devquery_data.device_removed_sem); + CloseHandle(devquery_data.enum_completed_evt); DestroyWindow(window); UnregisterClassA("ntoskrnl_test_wc", GetModuleHandleA(NULL)); }