From: Julian Klemann jklemann@codeweavers.com
--- configure | 1 + configure.ac | 1 + .../tests/Makefile.in | 5 + .../tests/devices.c | 221 ++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 dlls/windows.devices.enumeration/tests/Makefile.in create mode 100644 dlls/windows.devices.enumeration/tests/devices.c
diff --git a/configure b/configure index 89500dc8f7a..19c151f0b19 100755 --- a/configure +++ b/configure @@ -22005,6 +22005,7 @@ wine_fn_config_makefile dlls/win87em.dll16 enable_win16 wine_fn_config_makefile dlls/winaspi.dll16 enable_win16 wine_fn_config_makefile dlls/windebug.dll16 enable_win16 wine_fn_config_makefile dlls/windows.devices.enumeration enable_windows_devices_enumeration +wine_fn_config_makefile dlls/windows.devices.enumeration/tests enable_tests wine_fn_config_makefile dlls/windows.gaming.input enable_windows_gaming_input wine_fn_config_makefile dlls/windows.gaming.input/tests enable_tests wine_fn_config_makefile dlls/windows.globalization enable_windows_globalization diff --git a/configure.ac b/configure.ac index 49d414e1d17..d75f5231f82 100644 --- a/configure.ac +++ b/configure.ac @@ -3144,6 +3144,7 @@ WINE_CONFIG_MAKEFILE(dlls/win87em.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winaspi.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/windebug.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/windows.devices.enumeration) +WINE_CONFIG_MAKEFILE(dlls/windows.devices.enumeration/tests) WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input) WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input/tests) WINE_CONFIG_MAKEFILE(dlls/windows.globalization) diff --git a/dlls/windows.devices.enumeration/tests/Makefile.in b/dlls/windows.devices.enumeration/tests/Makefile.in new file mode 100644 index 00000000000..fe8780974c8 --- /dev/null +++ b/dlls/windows.devices.enumeration/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.devices.enumeration.dll +IMPORTS = combase uuid + +C_SRCS = \ + devices.c diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c new file mode 100644 index 00000000000..d679145e11b --- /dev/null +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -0,0 +1,221 @@ +/* + * Copyright 2022 Julian Klemann for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winstring.h" + +#include "initguid.h" +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Enumeration +#include "windows.devices.enumeration.h" + +#include "wine/test.h" + +struct device_watcher_handler +{ + ITypedEventHandler_DeviceWatcher_IInspectable ITypedEventHandler_DeviceWatcher_IInspectable_iface; + LONG ref; + + HANDLE event; + BOOL invoked; + IInspectable *args; +}; + +static inline struct device_watcher_handler *impl_from_ITypedEventHandler_DeviceWatcher_IInspectable( + ITypedEventHandler_DeviceWatcher_IInspectable *iface) +{ + return CONTAINING_RECORD(iface, struct device_watcher_handler, ITypedEventHandler_DeviceWatcher_IInspectable_iface); +} + +static HRESULT WINAPI device_watcher_handler_QueryInterface( + ITypedEventHandler_DeviceWatcher_IInspectable *iface, REFIID iid, void **out) +{ + struct device_watcher_handler *impl = impl_from_ITypedEventHandler_DeviceWatcher_IInspectable(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_ITypedEventHandler_DeviceWatcher_IInspectable)) + { + IUnknown_AddRef(&impl->ITypedEventHandler_DeviceWatcher_IInspectable_iface); + *out = &impl->ITypedEventHandler_DeviceWatcher_IInspectable_iface; + return S_OK; + } + + trace("%s not implemented, returning E_NO_INTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI device_watcher_handler_AddRef(ITypedEventHandler_DeviceWatcher_IInspectable *iface) +{ + struct device_watcher_handler *impl = impl_from_ITypedEventHandler_DeviceWatcher_IInspectable(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + return ref; +} + +static ULONG WINAPI device_watcher_handler_Release(ITypedEventHandler_DeviceWatcher_IInspectable *iface) +{ + struct device_watcher_handler *impl = impl_from_ITypedEventHandler_DeviceWatcher_IInspectable(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + return ref; +} + +static HRESULT WINAPI device_watcher_handler_Invoke( + ITypedEventHandler_DeviceWatcher_IInspectable *iface, IDeviceWatcher *sender, IInspectable *args) +{ + struct device_watcher_handler *impl = impl_from_ITypedEventHandler_DeviceWatcher_IInspectable(iface); + trace("iface %p, sender %p, args %p\n", iface, sender, args); + + impl->invoked = TRUE; + impl->args = args; + SetEvent(impl->event); + + return S_OK; +} + +static const ITypedEventHandler_DeviceWatcher_IInspectableVtbl device_watcher_handler_vtbl = +{ + device_watcher_handler_QueryInterface, + device_watcher_handler_AddRef, + device_watcher_handler_Release, + /* ITypedEventHandler<DeviceWatcher*,IInspectable*> methods */ + device_watcher_handler_Invoke, +}; + +static void device_watcher_handler_create(struct device_watcher_handler *impl) +{ + impl->ITypedEventHandler_DeviceWatcher_IInspectable_iface.lpVtbl = &device_watcher_handler_vtbl; + impl->invoked = FALSE; + impl->ref = 1; +} + +static void test_device_watcher_stop(void) +{ + static const WCHAR *device_info_name = L"Windows.Devices.Enumeration.DeviceInformation"; + + struct device_watcher_handler stopped_handler, dummy_handler; + EventRegistrationToken stopped_token, added_token; + IInspectable *inspectable, *inspectable2; + IAgileObject *agile, *agile2; + IActivationFactory *factory; + IDeviceInformationStatics2 *device_info_statics2; + IDeviceWatcher *device_watcher; + DeviceWatcherStatus status = 0xdeadbeef; + HSTRING str; + HRESULT hr; + + device_watcher_handler_create(&dummy_handler); + device_watcher_handler_create(&stopped_handler); + stopped_handler.event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!stopped_handler.event, "failed to create event, got error %lu\n", GetLastError()); + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(hr == S_OK, "got hr %#lx\n", hr); + + hr = WindowsCreateString(device_info_name, wcslen(device_info_name), &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "got hr %#lx\n", hr); + WindowsDeleteString(str); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("%s runtimeclass, not registered.\n", wine_dbgstr_w(device_info_name)); + return; + } + + hr = IActivationFactory_QueryInterface(factory, &IID_IInspectable, (void **)&inspectable); + ok(hr == S_OK, "got hr %#lx\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_IAgileObject, (void **)&agile); + ok(hr == S_OK, "got hr %#lx\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_IDeviceInformationStatics2, (void **)&device_info_statics2); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got hr %#lx\n", hr); + IActivationFactory_Release(factory); + if (hr != S_OK) + { + IAgileObject_Release(agile); + IInspectable_Release(inspectable); + win_skip("IDeviceInformationStatics2 not supported.\n"); + return; + } + + hr = IDeviceInformationStatics2_QueryInterface(device_info_statics2, &IID_IInspectable, (void **)&inspectable2); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(inspectable == inspectable2, "got inspectable %p, inspectable2 %p\n", inspectable, inspectable2); + IInspectable_Release(inspectable); + IInspectable_Release(inspectable2); + + hr = IDeviceInformationStatics2_QueryInterface(device_info_statics2, &IID_IAgileObject, (void **)&agile2); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(agile == agile2, "got agile %p, agile2 %p\n", agile, agile2); + IAgileObject_Release(agile); + IAgileObject_Release(agile2); + + hr = IDeviceInformationStatics2_CreateWatcherWithKindAqsFilterAndAdditionalProperties( + device_info_statics2, NULL, NULL, DeviceInformationKind_AssociationEndpoint, &device_watcher); + IDeviceInformationStatics2_Release(device_info_statics2); + + hr = IDeviceWatcher_add_Added( + device_watcher, + (ITypedEventHandler_DeviceWatcher_DeviceInformation *)&dummy_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, + &added_token); + ok(hr == S_OK, "got hr %#lx\n", hr); + hr = IDeviceWatcher_add_Stopped( + device_watcher, &stopped_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, + &stopped_token); + ok(hr == S_OK, "got hr %#lx\n", hr); + + hr = IDeviceWatcher_get_Status(device_watcher, &status); + todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine ok(status == DeviceWatcherStatus_Created, "got status %u\n", status); + + hr = IDeviceWatcher_Start(device_watcher); + ok(hr == S_OK, "got hr %#lx\n", hr); + hr = IDeviceWatcher_get_Status(device_watcher, &status); + todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine ok(status == DeviceWatcherStatus_Started, "got status %u\n", status); + + hr = IDeviceWatcher_Stop(device_watcher); + ok(hr == S_OK, "got hr %#lx\n", hr); + WaitForSingleObject(stopped_handler.event, INFINITE); + + hr = IDeviceWatcher_get_Status(device_watcher, &status); + todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine ok(status == DeviceWatcherStatus_Stopped, "got status %u\n", status); + ok(stopped_handler.invoked, "stopped_handler not invoked\n"); + ok(stopped_handler.args == NULL, "stopped_handler not invoked\n"); + + CloseHandle(stopped_handler.event); + IDeviceWatcher_Release(device_watcher); + + RoUninitialize(); +} + +START_TEST(devices) +{ + test_device_watcher_stop(); +}