The basic `FindAllAsync()` method returns a collection of `DeviceInformation` objects representing all device interfaces on the system. This MR adds a basic implementation of this method, and the associated `IDeviceInformation` and `DeviceInformationCollection` objects it returns. For `IDeviceInformation`, this MR only implements the `Id()` method, which returns the symbolic link for the registered interface.
-- v4: windows.devices.enumeration: Implement IIterable<IDeviceInformation *> for DeviceInformationCollection. windows.devices.enumeration: Implement IndexOf() and GetMany() for DeviceInformationCollection. windows.devices.enumeration: Create IDeviceInformation objects from all present device interfaces. windows.devices.enumeration: Add a stubbed IDeviceInformation implementation for device interfaces. windows.devices.enumeration: Add a stubbed implementation for FindAllAsync() and DeviceInformationCollection. windows.devices.enumeration/tests: Add conformance tests for IIterable and IIterator interfaces in DeviceInformationCollection. windows.devices.enumeration/tests: Add conformance tests for GetMany() and IndexOf() methods in DeviceInformationCollection. windows.devices.enumeration/tests: Add conformance tests for FindAllAsync().
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/devices.c | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+)
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index ae76e5d754a..f0b3d63a1da 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -1,5 +1,6 @@ /* * Copyright 2022 Julian Klemann for CodeWeavers + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -135,6 +136,199 @@ static void device_watcher_handler_create( struct device_watcher_handler *impl ) impl->ref = 1; }
+struct deviceinformationcollection_async_handler +{ + IAsyncOperationCompletedHandler_DeviceInformationCollection iface; + + IAsyncOperation_DeviceInformationCollection *async; + AsyncStatus status; + BOOL invoked; + HANDLE event; + LONG ref; +}; + +static inline struct deviceinformationcollection_async_handler * +impl_from_IAsyncOperationCompletedHandler_DeviceInformationCollection( + IAsyncOperationCompletedHandler_DeviceInformationCollection *iface ) +{ + return CONTAINING_RECORD( iface, struct deviceinformationcollection_async_handler, iface ); +} + +static HRESULT WINAPI deviceinformationcollection_async_handler_QueryInterface( + IAsyncOperationCompletedHandler_DeviceInformationCollection *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IAsyncOperationCompletedHandler_DeviceInformationCollection )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + if (winetest_debug > 1) trace( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI deviceinformationcollection_async_handler_AddRef( + IAsyncOperationCompletedHandler_DeviceInformationCollection *iface ) +{ + struct deviceinformationcollection_async_handler *impl; + impl = impl_from_IAsyncOperationCompletedHandler_DeviceInformationCollection( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI deviceinformationcollection_async_handler_Release( + IAsyncOperationCompletedHandler_DeviceInformationCollection *iface ) +{ + struct deviceinformationcollection_async_handler *impl; + ULONG ref; + + impl = impl_from_IAsyncOperationCompletedHandler_DeviceInformationCollection( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI deviceinformationcollection_async_handler_Invoke( + IAsyncOperationCompletedHandler_DeviceInformationCollection *iface, + IAsyncOperation_DeviceInformationCollection *async, AsyncStatus status ) +{ + struct deviceinformationcollection_async_handler *impl; + + impl = impl_from_IAsyncOperationCompletedHandler_DeviceInformationCollection( iface ); + ok( !impl->invoked, "invoked twice\n" ); + impl->invoked = TRUE; + impl->async = async; + impl->status = status; + if (impl->event) SetEvent( impl-> event ); + + return S_OK; +} + +static IAsyncOperationCompletedHandler_DeviceInformationCollectionVtbl deviceinformationcollection_async_handler_vtbl = +{ + /* IUnknown */ + deviceinformationcollection_async_handler_QueryInterface, + deviceinformationcollection_async_handler_AddRef, + deviceinformationcollection_async_handler_Release, + /* IAsyncOperationCompletedHandler<DeviceInformationCollection> */ + deviceinformationcollection_async_handler_Invoke, +}; + +static IAsyncOperationCompletedHandler_DeviceInformationCollection * +deviceinformationcollection_async_handler_create( HANDLE event ) +{ + struct deviceinformationcollection_async_handler *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return NULL; + impl->iface.lpVtbl = &deviceinformationcollection_async_handler_vtbl; + impl->event = event; + impl->ref = 1; + + return &impl->iface; +} + +#define await_deviceinformationcollection( a ) await_deviceinformationcollection_( __LINE__, ( a ) ) +static void await_deviceinformationcollection_( int line, IAsyncOperation_DeviceInformationCollection *async ) +{ + IAsyncOperationCompletedHandler_DeviceInformationCollection *handler; + HANDLE event; + HRESULT hr; + DWORD ret; + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok_(__FILE__, line)( !!event, "CreateEventW failed, error %lu\n", GetLastError() ); + + handler = deviceinformationcollection_async_handler_create( event ); + ok_(__FILE__, line)( !!handler, "deviceinformationcollection_async_handler_create failed\n" ); + hr = IAsyncOperation_DeviceInformationCollection_put_Completed( async, handler ); + ok_(__FILE__, line)( hr == S_OK, "put_Completed returned %#lx\n", hr ); + IAsyncOperationCompletedHandler_DeviceInformationCollection_Release( handler ); + + ret = WaitForSingleObject( event, 5000 ); + ok_(__FILE__, line)( !ret, "WaitForSingleObject returned %#lx\n", ret ); + ret = CloseHandle( event ); + ok_(__FILE__, line)( ret, "CloseHandle failed, error %lu\n", GetLastError() ); +} + +#define check_deviceinformationcollection_async( a, b, c, d, e ) check_deviceinformationcollection_async_( __LINE__, a, b, c, d, e ) +static void check_deviceinformationcollection_async_( + int line, IAsyncOperation_DeviceInformationCollection *async, UINT32 expect_id, + AsyncStatus expect_status, HRESULT expect_hr, IVectorView_DeviceInformation **result ) +{ + AsyncStatus async_status; + IAsyncInfo *async_info; + HRESULT hr, async_hr; + UINT32 async_id; + + hr = IAsyncOperation_DeviceInformationCollection_QueryInterface( async, &IID_IAsyncInfo, (void **)&async_info ); + ok_(__FILE__, line)( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + + async_id = 0xdeadbeef; + hr = IAsyncInfo_get_Id( async_info, &async_id ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_Id returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_Id returned %#lx\n", hr ); + ok_(__FILE__, line)( async_id == expect_id, "got id %u\n", async_id ); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status( async_info, &async_status ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_Status returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_Status returned %#lx\n", hr ); + ok_(__FILE__, line)( async_status == expect_status, "got status %u\n", async_status ); + + async_hr = 0xdeadbeef; + hr = IAsyncInfo_get_ErrorCode( async_info, &async_hr ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_ErrorCode returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_ErrorCode returned %#lx\n", hr ); + if (expect_status < 4) todo_wine_if(FAILED(expect_hr)) ok_(__FILE__, line)( async_hr == expect_hr, "got error %#lx\n", async_hr ); + else ok_(__FILE__, line)( async_hr == E_ILLEGAL_METHOD_CALL, "got error %#lx\n", async_hr ); + + IAsyncInfo_Release( async_info ); + + hr = IAsyncOperation_DeviceInformationCollection_GetResults( async, result ); + switch (expect_status) + { + case Completed: + case Error: + todo_wine_if(FAILED(expect_hr)) + ok_(__FILE__, line)( hr == expect_hr, "GetResults returned %#lx\n", hr ); + break; + case Canceled: + case Started: + default: + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "GetResults returned %#lx\n", hr ); + break; + } +} + +static void test_DeviceInformation_obj( int line, IDeviceInformation *info ) +{ + HRESULT hr; + HSTRING str; + boolean bool_val; + + hr = IDeviceInformation_get_Id( info, &str ); + ok_(__FILE__, line)( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + trace_(__FILE__, line)( "id: %s\n", debugstr_hstring( str ) ); + WindowsDeleteString( str ); + str = NULL; + hr = IDeviceInformation_get_Name( info, &str ); + todo_wine ok_(__FILE__, line)( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + trace_(__FILE__, line)( " name: %s\n", debugstr_hstring( str ) ); + WindowsDeleteString( str ); + hr = IDeviceInformation_get_IsEnabled( info, &bool_val ); + todo_wine ok_(__FILE__, line)( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + trace_(__FILE__, line)( " enabled: %d\n", bool_val ); + hr = IDeviceInformation_get_IsDefault( info, &bool_val ); + todo_wine ok_(__FILE__, line)( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + trace_(__FILE__, line)( " default: %d\n", bool_val ); +} + static void test_DeviceInformation( void ) { static const WCHAR *device_info_name = L"Windows.Devices.Enumeration.DeviceInformation"; @@ -147,6 +341,8 @@ static void test_DeviceInformation( void ) IDeviceInformationStatics *device_info_statics; IDeviceWatcher *device_watcher; DeviceWatcherStatus status = 0xdeadbeef; + IAsyncOperation_DeviceInformationCollection *infocollection_async = NULL; + IVectorView_DeviceInformation *info_collection = NULL; ULONG ref; HSTRING str; HRESULT hr; @@ -273,6 +469,46 @@ static void test_DeviceInformation( void ) ok( stopped_handler.args == NULL, "stopped_handler not invoked\n" );
IDeviceWatcher_Release( device_watcher ); + + hr = IDeviceInformationStatics_FindAllAsync( device_info_statics, &infocollection_async ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (infocollection_async) + { + todo_wine await_deviceinformationcollection( infocollection_async ); + todo_wine check_deviceinformationcollection_async( infocollection_async, 1, Completed, S_OK, &info_collection ); + IAsyncOperation_DeviceInformationCollection_Release( infocollection_async ); + } + if (info_collection) + { + UINT32 idx = 0, size = 0; + + hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + for (idx = 0; idx < size ;idx++) + { + IDeviceInformation *info; + winetest_push_context("info_collection %u", idx); + hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr); + if (SUCCEEDED( hr )) + { + UINT32 idx2 = 0; + boolean found = FALSE; + + test_DeviceInformation_obj(__LINE__, info); + IDeviceInformation_Release( info ); + hr = IVectorView_DeviceInformation_IndexOf( info_collection, info, &idx2, &found ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (SUCCEEDED( hr )) + { + ok( found, "Expected IndexOf to return true\n" ); + ok( idx == idx2, "%u != %u\n", idx, idx2); + } + } + winetest_pop_context(); + } + } + IDeviceInformationStatics_Release( device_info_statics ); skip_device_statics: IInspectable_Release( inspectable );
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/devices.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index f0b3d63a1da..a662d43c1f5 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -481,6 +481,7 @@ static void test_DeviceInformation( void ) if (info_collection) { UINT32 idx = 0, size = 0; + IDeviceInformation **devices;
hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); @@ -507,6 +508,49 @@ static void test_DeviceInformation( void ) } winetest_pop_context(); } + + devices = calloc( 1, sizeof( *devices ) * size ); + ok( !!devices, "Unable to allocate array\n" ); + if (devices) + { + UINT32 copied = 0; + + hr = IVectorView_DeviceInformation_GetMany( info_collection, 0, size, devices, &copied ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (SUCCEEDED( hr )) + todo_wine ok( copied == size, "%u != %u\n", copied, size ); + for(idx = 0; idx < copied; idx++) + { + IDeviceInformation *info = NULL; + HSTRING id1 = NULL, id2 = NULL; + + winetest_push_context("devices %u", idx); + hr = IDeviceInformation_get_Id( devices[idx], &id1 ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (SUCCEEDED( hr )) + { + hr = IDeviceInformation_get_Id( info, &id2 ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + } + if (id1 && id2) + { + INT32 order = 1; + WindowsCompareStringOrdinal( id1, id2, &order ); + ok( !order, "%s != %s\n", debugstr_hstring( id1 ), debugstr_hstring( id2 ) ); + } + WindowsDeleteString( id1 ); + WindowsDeleteString( id2 ); + if (info) + IDeviceInformation_Release( info ); + IDeviceInformation_Release( devices[idx] ); + winetest_pop_context(); + } + free( devices ); + } + + IVectorView_DeviceInformation_Release( info_collection ); }
IDeviceInformationStatics_Release( device_info_statics );
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/devices.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index a662d43c1f5..e8c46f90e1c 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -343,6 +343,8 @@ static void test_DeviceInformation( void ) DeviceWatcherStatus status = 0xdeadbeef; IAsyncOperation_DeviceInformationCollection *infocollection_async = NULL; IVectorView_DeviceInformation *info_collection = NULL; + IIterable_DeviceInformation *info_iterable = NULL; + IIterator_DeviceInformation *info_iterator = NULL; ULONG ref; HSTRING str; HRESULT hr; @@ -550,7 +552,37 @@ static void test_DeviceInformation( void ) free( devices ); }
+ hr = IVectorView_DeviceInformation_QueryInterface( + info_collection, &IID_IIterable_DeviceInformation, (void **)&info_iterable ); IVectorView_DeviceInformation_Release( info_collection ); + todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + } + if (info_iterable) + { + hr = IIterable_DeviceInformation_First( info_iterable, &info_iterator ); + todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + IIterable_DeviceInformation_Release( info_iterable ); + } + if (info_iterator) + { + boolean exists; + + hr = IIterator_DeviceInformation_get_HasCurrent( info_iterator, &exists ); + todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + while (SUCCEEDED( hr ) && exists) + { + IDeviceInformation *info; + + hr = IIterator_DeviceInformation_get_Current( info_iterator, &info ); + todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + if (FAILED( hr )) break; + test_DeviceInformation_obj( __LINE__, info ); + IDeviceInformation_Release( info ); + hr = IIterator_DeviceInformation_MoveNext( info_iterator, &exists ); + ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + } + + IIterator_DeviceInformation_Release( info_iterator ); }
IDeviceInformationStatics_Release( device_info_statics );
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 5 +- dlls/windows.devices.enumeration/async.c | 507 ++++++++++++++++++ dlls/windows.devices.enumeration/async.idl | 44 ++ dlls/windows.devices.enumeration/collection.c | 164 ++++++ dlls/windows.devices.enumeration/main.c | 20 +- dlls/windows.devices.enumeration/private.h | 5 + .../tests/devices.c | 6 +- 7 files changed, 745 insertions(+), 6 deletions(-) create mode 100644 dlls/windows.devices.enumeration/async.c create mode 100644 dlls/windows.devices.enumeration/async.idl create mode 100644 dlls/windows.devices.enumeration/collection.c
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 93c15dfcc64..e6c1ef8ddfe 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -3,6 +3,9 @@ IMPORTS = combase uuid
SOURCES = \ access.c \ + async.c \ + async.idl \ classes.idl \ + collection.c \ event_handlers.c \ - main.c + main.c \ diff --git a/dlls/windows.devices.enumeration/async.c b/dlls/windows.devices.enumeration/async.c new file mode 100644 index 00000000000..a172dccaffc --- /dev/null +++ b/dlls/windows.devices.enumeration/async.c @@ -0,0 +1,507 @@ +/* Copyright 2022 Bernhard Kölbl for CodeWeavers + * Copyright 2022 Rémi Bernon 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 "private.h" +#include <initguid.h> +#include "async.h" + +#include <wine/debug.h> + +WINE_DEFAULT_DEBUG_CHANNEL(enumeration); + +#define Closed 4 +#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) + +struct async_info +{ + IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; + IAsyncInfo IAsyncInfo_iface; + IInspectable *IInspectable_outer; + LONG ref; + + async_operation_callback callback; + TP_WORK *async_run_work; + IUnknown *invoker; + IUnknown *param; + + CRITICAL_SECTION cs; + IWineAsyncOperationCompletedHandler *handler; + PROPVARIANT result; + AsyncStatus status; + HRESULT hr; +}; + +static inline struct async_info *impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl *iface ) +{ + return CONTAINING_RECORD( iface, struct async_info, IWineAsyncInfoImpl_iface ); +} + +static HRESULT WINAPI async_impl_QueryInterface( IWineAsyncInfoImpl *iface, REFIID iid, void **out ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IWineAsyncInfoImpl )) + { + IInspectable_AddRef( (*out = &impl->IWineAsyncInfoImpl_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IAsyncInfo )) + { + IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_impl_AddRef( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); + IAsyncInfo_Close( &impl->IAsyncInfo_iface ); + if (impl->param) IUnknown_Release( impl->param ); + if (impl->invoker) IUnknown_Release( impl->invoker ); + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &impl->cs ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI async_impl_put_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler *handler ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, handler %p.\n", iface, handler ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; + else if ((impl->handler = handler)) + { + IWineAsyncOperationCompletedHandler_AddRef( impl->handler ); + + if (impl->status > Started) + { + IInspectable *operation = impl->IInspectable_outer; + AsyncStatus status = impl->status; + impl->handler = NULL; /* Prevent concurrent invoke. */ + LeaveCriticalSection( &impl->cs ); + + IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler ); + + return S_OK; + } + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, handler %p.\n", iface, handler ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; + else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = E_ILLEGAL_METHOD_CALL; + + TRACE( "iface %p, result %p.\n", iface, result ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Completed || impl->status == Error) + { + PropVariantCopy( result, &impl->result ); + hr = impl->hr; + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_Start( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + + TRACE( "iface %p.\n", iface ); + + /* keep the async alive in the callback */ + IInspectable_AddRef( impl->IInspectable_outer ); + SubmitThreadpoolWork( impl->async_run_work ); + + return S_OK; +} + +static const struct IWineAsyncInfoImplVtbl async_impl_vtbl = +{ + /* IUnknown methods */ + async_impl_QueryInterface, + async_impl_AddRef, + async_impl_Release, + /* IWineAsyncInfoImpl */ + async_impl_put_Completed, + async_impl_get_Completed, + async_impl_get_Result, + async_impl_Start, +}; + +DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer ) + +static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, id %p.\n", iface, id ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + *id = 1; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, status %p.\n", iface, status ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + *status = impl->status; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, error_code %p.\n", iface, error_code ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; + else *error_code = impl->hr; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p.\n", iface ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + else if (impl->status == Started) impl->status = Canceled; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p.\n", iface ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Started) + hr = E_ILLEGAL_STATE_CHANGE; + else if (impl->status != Closed) + { + CloseThreadpoolWork( impl->async_run_work ); + impl->async_run_work = NULL; + impl->status = Closed; + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static const struct IAsyncInfoVtbl async_info_vtbl = +{ + /* IUnknown methods */ + async_info_QueryInterface, + async_info_AddRef, + async_info_Release, + /* IInspectable methods */ + async_info_GetIids, + async_info_GetRuntimeClassName, + async_info_GetTrustLevel, + /* IAsyncInfo */ + async_info_get_Id, + async_info_get_Status, + async_info_get_ErrorCode, + async_info_Cancel, + async_info_Close, +}; + +static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + IInspectable *operation = impl->IInspectable_outer; + PROPVARIANT result; + HRESULT hr; + + hr = impl->callback( impl->invoker, impl->param, &result ); + + EnterCriticalSection( &impl->cs ); + if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; + PropVariantCopy( &impl->result, &result ); + impl->hr = hr; + + if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) + { + IWineAsyncOperationCompletedHandler *handler = impl->handler; + AsyncStatus status = impl->status; + impl->handler = NULL; /* Prevent concurrent invoke. */ + LeaveCriticalSection( &impl->cs ); + + IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler ); + } + else LeaveCriticalSection( &impl->cs ); + + /* release refcount acquired in Start */ + IInspectable_Release( operation ); + + PropVariantClear( &result ); +} + +static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, + IInspectable *outer, IWineAsyncInfoImpl **out ) +{ + struct async_info *impl; + HRESULT hr; + + if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY; + impl->IWineAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl; + impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; + impl->IInspectable_outer = outer; + impl->ref = 1; + + impl->callback = callback; + impl->handler = HANDLER_NOT_SET; + impl->status = Started; + if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL ))) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + free( impl ); + return hr; + } + + if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker ); + if ((impl->param = param)) IUnknown_AddRef( impl->param ); + + InitializeCriticalSectionEx( &impl->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); + impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" ); + + *out = &impl->IWineAsyncInfoImpl_iface; + return S_OK; +} + +struct async_result +{ + IAsyncOperation_DeviceInformationCollection IAsyncOperation_DeviceInformationCollection_iface; + IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner; + LONG ref; +}; + +static inline struct async_result *impl_from_IAsyncOperation_DeviceInformationCollection( IAsyncOperation_DeviceInformationCollection *iface ) +{ + return CONTAINING_RECORD( iface, struct async_result, IAsyncOperation_DeviceInformationCollection_iface ); +} + +static HRESULT WINAPI async_result_QueryInterface( IAsyncOperation_DeviceInformationCollection *iface, REFIID iid, void **out ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IAsyncOperation_DeviceInformationCollection )) + { + IInspectable_AddRef( (*out = &impl->IAsyncOperation_DeviceInformationCollection_iface) ); + return S_OK; + } + + return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out ); +} + +static ULONG WINAPI async_result_AddRef( IAsyncOperation_DeviceInformationCollection *iface ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_result_Release( IAsyncOperation_DeviceInformationCollection *iface ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI async_result_GetIids( IAsyncOperation_DeviceInformationCollection *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_result_GetRuntimeClassName( IAsyncOperation_DeviceInformationCollection *iface, HSTRING *class_name ) +{ + return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformationCollection>", + ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformationCollection>"), + class_name ); +} + +static HRESULT WINAPI async_result_GetTrustLevel( IAsyncOperation_DeviceInformationCollection *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_result_put_Completed( IAsyncOperation_DeviceInformationCollection *iface, IAsyncOperationCompletedHandler_DeviceInformationCollection *handler ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + TRACE( "iface %p, handler %p.\n", iface, handler ); + return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler ); +} + +static HRESULT WINAPI async_result_get_Completed( IAsyncOperation_DeviceInformationCollection *iface, IAsyncOperationCompletedHandler_DeviceInformationCollection **handler ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + TRACE( "iface %p, handler %p.\n", iface, handler ); + return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler ); +} + +static HRESULT WINAPI async_result_GetResults( IAsyncOperation_DeviceInformationCollection *iface, IVectorView_DeviceInformation **results ) +{ + struct async_result *impl = impl_from_IAsyncOperation_DeviceInformationCollection( iface ); + PROPVARIANT result = {.vt = VT_UNKNOWN}; + HRESULT hr; + + TRACE( "iface %p, results %p.\n", iface, results ); + + hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result ); + if (SUCCEEDED( hr )) + hr = IUnknown_QueryInterface( result.punkVal, &IID_IVectorView_DeviceInformation, (void **)results ); + PropVariantClear( &result ); + return hr; +} + +static const struct IAsyncOperation_DeviceInformationCollectionVtbl async_result_vtbl = +{ + /* IUnknown methods */ + async_result_QueryInterface, + async_result_AddRef, + async_result_Release, + /* IInspectable methods */ + async_result_GetIids, + async_result_GetRuntimeClassName, + async_result_GetTrustLevel, + /* IAsyncOperation<DeviceInformationCollection> */ + async_result_put_Completed, + async_result_get_Completed, + async_result_GetResults, +}; + +HRESULT async_operation_device_info_collection_result_create( + IUnknown *invoker, IUnknown *param, async_operation_callback callback, + IAsyncOperation_DeviceInformationCollection **out ) +{ + struct async_result *impl; + HRESULT hr; + + *out = NULL; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IAsyncOperation_DeviceInformationCollection_iface.lpVtbl = &async_result_vtbl; + impl->ref = 1; + + if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_DeviceInformationCollection_iface, &impl->IWineAsyncInfoImpl_inner )) || + FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner ))) + { + if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); + free( impl ); + return hr; + } + + *out = &impl->IAsyncOperation_DeviceInformationCollection_iface; + TRACE( "created IAsyncOperation_DeviceInformationCollection %p\n", *out ); + return S_OK; +} diff --git a/dlls/windows.devices.enumeration/async.idl b/dlls/windows.devices.enumeration/async.idl new file mode 100644 index 00000000000..88e1a76f547 --- /dev/null +++ b/dlls/windows.devices.enumeration/async.idl @@ -0,0 +1,44 @@ +/* + * Copyright 2022 Rémi Bernon 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 + */ + +#pragma makedep header + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "propidl.idl"; +import "inspectable.idl"; +import "asyncinfo.idl"; +import "windowscontracts.idl"; + +namespace Windows.Devices.Enumeration { + /* type-pruning version of AsyncOperationCompletedHandler<T> */ + delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); + + [ + uuid(d81ab70d-82e0-481c-983d-401225d98a2c) + ] + interface IWineAsyncInfoImpl : IUnknown + { + [propput] HRESULT Completed([in] WineAsyncOperationCompletedHandler *handler); + [propget] HRESULT Completed([out, retval] WineAsyncOperationCompletedHandler **handler); + [propget] HRESULT Result([out, retval] PROPVARIANT *result); + HRESULT Start(); + } +} diff --git a/dlls/windows.devices.enumeration/collection.c b/dlls/windows.devices.enumeration/collection.c new file mode 100644 index 00000000000..2754c2d5a5d --- /dev/null +++ b/dlls/windows.devices.enumeration/collection.c @@ -0,0 +1,164 @@ +/* DeviceInformationCollection implementation + * + * Copyright 2025 Vibhav Pant + * + * 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 "private.h" +#include "windows.foundation.collections.h" + +#include <wine/debug.h> + +WINE_DEFAULT_DEBUG_CHANNEL(enumeration); + +struct vectorview_DeviceInformation +{ + IVectorView_DeviceInformation IVectorView_DeviceInformation_iface; + LONG ref; +}; + +static inline struct vectorview_DeviceInformation * +impl_from_IVectorView_DeviceInformation( IVectorView_DeviceInformation *iface ) +{ + return CONTAINING_RECORD( iface, struct vectorview_DeviceInformation, IVectorView_DeviceInformation_iface ); +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_QueryInterface( + IVectorView_DeviceInformation *iface, REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IVectorView_DeviceInformation )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE vectorview_DeviceInformation_AddRef( IVectorView_DeviceInformation *iface ) +{ + struct vectorview_DeviceInformation *impl; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_IVectorView_DeviceInformation( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG STDMETHODCALLTYPE vectorview_DeviceInformation_Release( IVectorView_DeviceInformation *iface ) +{ + struct vectorview_DeviceInformation *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_IVectorView_DeviceInformation( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetIids( IVectorView_DeviceInformation *iface, + ULONG *iid_count, IID **iids ) +{ + FIXME( "(%p, %p, %p) stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetRuntimeClassName( IVectorView_DeviceInformation *iface, + HSTRING *class_name ) +{ + const static WCHAR name[] = L"Windows.Foundation.Collections.IVectorView`1<Windows.Devices.Enumeration.DeviceInformation>"; + TRACE( "(%p, %p)\n", iface, class_name ); + return WindowsCreateString( name, ARRAY_SIZE( name ), class_name ); +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetTrustLevel( IVectorView_DeviceInformation *iface, + TrustLevel *trust_level ) +{ + FIXME( "(%p, %p) stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetAt( IVectorView_DeviceInformation *iface, UINT32 index, + IDeviceInformation **value ) +{ + FIXME( "(%p, %u, %p) stub!\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_get_Size( IVectorView_DeviceInformation *iface, + UINT32 *value ) +{ + FIXME( "(%p, %p) stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_IndexOf( IVectorView_DeviceInformation *iface, + IDeviceInformation *elem, UINT32 *index, + boolean *found ) +{ + FIXME( "(%p, %p, %p, %p) stub!\n", iface, elem, index, found ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetMany( IVectorView_DeviceInformation *iface, + UINT32 start, UINT32 size, + IDeviceInformation **items, UINT32 *copied ) +{ + FIXME( "(%p, %u, %u, %p, %p): stub!\n", iface, start, size, items, copied ); + return E_NOTIMPL; +} + +const static IVectorView_DeviceInformationVtbl vectorview_DeviceInformation_vtbl = +{ + /* IUnknown */ + vectorview_DeviceInformation_QueryInterface, + vectorview_DeviceInformation_AddRef, + vectorview_DeviceInformation_Release, + /* IInspectable */ + vectorview_DeviceInformation_GetIids, + vectorview_DeviceInformation_GetRuntimeClassName, + vectorview_DeviceInformation_GetTrustLevel, + /* IVectorView<DeviceInformation> */ + vectorview_DeviceInformation_GetAt, + vectorview_DeviceInformation_get_Size, + vectorview_DeviceInformation_IndexOf, + vectorview_DeviceInformation_GetMany +}; + +HRESULT vectorview_deviceinformation_create( IVectorView_DeviceInformation **view ) +{ + struct vectorview_DeviceInformation *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + + impl->IVectorView_DeviceInformation_iface.lpVtbl = &vectorview_DeviceInformation_vtbl; + impl->ref = 1; + *view = &impl->IVectorView_DeviceInformation_iface; + return S_OK; +} diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 5c930dba121..cb9a64f1452 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -333,11 +333,27 @@ static HRESULT WINAPI device_statics_CreateFromIdAsyncAdditionalProperties( IDev return E_NOTIMPL; }
+static HRESULT WINAPI findall_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +{ + HRESULT hr; + IVectorView_DeviceInformation *view; + + FIXME( "invoker %p, param %p, result %p semi-stub!\n", invoker, param, result ); + + hr = vectorview_deviceinformation_create( &view ); + if (SUCCEEDED( hr )) + { + result->vt = VT_UNKNOWN; + result->punkVal = (IUnknown *)view; + } + return hr; +} + static HRESULT WINAPI device_statics_FindAllAsync( IDeviceInformationStatics *iface, IAsyncOperation_DeviceInformationCollection **op ) { - FIXME( "iface %p, op %p stub!\n", iface, op ); - return E_NOTIMPL; + TRACE( "iface %p, op %p\n", iface, op ); + return async_operation_device_info_collection_result_create( (IUnknown *)iface, NULL, findall_async, op ); }
static HRESULT WINAPI device_statics_FindAllAsyncDeviceClass( IDeviceInformationStatics *iface, DeviceClass class, diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index 06234e984e0..a8df1a8533f 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -46,6 +46,11 @@ HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken * HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args ); HRESULT typed_event_handlers_clear( struct list *list );
+typedef HRESULT (WINAPI *async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ); +extern HRESULT async_operation_device_info_collection_result_create( + IUnknown *invoker, IUnknown *param, async_operation_callback callback, + IAsyncOperation_DeviceInformationCollection **out ); +extern HRESULT vectorview_deviceinformation_create( IVectorView_DeviceInformation **view ); #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index e8c46f90e1c..9bb7bcf5d88 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -473,11 +473,11 @@ static void test_DeviceInformation( void ) IDeviceWatcher_Release( device_watcher );
hr = IDeviceInformationStatics_FindAllAsync( device_info_statics, &infocollection_async ); - todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); if (infocollection_async) { - todo_wine await_deviceinformationcollection( infocollection_async ); - todo_wine check_deviceinformationcollection_async( infocollection_async, 1, Completed, S_OK, &info_collection ); + await_deviceinformationcollection( infocollection_async ); + check_deviceinformationcollection_async( infocollection_async, 1, Completed, S_OK, &info_collection ); IAsyncOperation_DeviceInformationCollection_Release( infocollection_async ); } if (info_collection)
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 1 + dlls/windows.devices.enumeration/collection.c | 38 +++- .../windows.devices.enumeration/information.c | 201 ++++++++++++++++++ dlls/windows.devices.enumeration/main.c | 21 +- dlls/windows.devices.enumeration/private.h | 5 +- .../tests/devices.c | 6 +- 6 files changed, 260 insertions(+), 12 deletions(-) create mode 100644 dlls/windows.devices.enumeration/information.c
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index e6c1ef8ddfe..062a914e322 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -8,4 +8,5 @@ SOURCES = \ classes.idl \ collection.c \ event_handlers.c \ + information.c \ main.c \ diff --git a/dlls/windows.devices.enumeration/collection.c b/dlls/windows.devices.enumeration/collection.c index 2754c2d5a5d..eb501846721 100644 --- a/dlls/windows.devices.enumeration/collection.c +++ b/dlls/windows.devices.enumeration/collection.c @@ -27,6 +27,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(enumeration); struct vectorview_DeviceInformation { IVectorView_DeviceInformation IVectorView_DeviceInformation_iface; + + IDeviceInformation **devices; + SIZE_T len; + LONG ref; };
@@ -76,7 +80,12 @@ static ULONG STDMETHODCALLTYPE vectorview_DeviceInformation_Release( IVectorView impl = impl_from_IVectorView_DeviceInformation( iface ); ref = InterlockedDecrement( &impl->ref ); if (!ref) + { + while (impl->len--) + IDeviceInformation_Release( impl->devices[impl->len] ); + free( impl->devices ); free( impl ); + } return ref; }
@@ -105,15 +114,29 @@ static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetTrustLevel( IVe static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetAt( IVectorView_DeviceInformation *iface, UINT32 index, IDeviceInformation **value ) { - FIXME( "(%p, %u, %p) stub!\n", iface, index, value ); - return E_NOTIMPL; + struct vectorview_DeviceInformation *impl; + + TRACE( "(%p, %u, %p)\n", iface, index, value ); + + impl = impl_from_IVectorView_DeviceInformation( iface ); + *value = NULL; + if (index >= impl->len) + return E_BOUNDS; + *value = impl->devices[index]; + IDeviceInformation_AddRef( *value ); + return S_OK; }
static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_get_Size( IVectorView_DeviceInformation *iface, UINT32 *value ) { - FIXME( "(%p, %p) stub!\n", iface, value ); - return E_NOTIMPL; + struct vectorview_DeviceInformation *impl; + + TRACE( "(%p, %p)\n", iface, value ); + + impl = impl_from_IVectorView_DeviceInformation( iface ); + *value = impl->len; + return S_OK; }
static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_IndexOf( IVectorView_DeviceInformation *iface, @@ -128,7 +151,7 @@ static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetMany( IVectorVi UINT32 start, UINT32 size, IDeviceInformation **items, UINT32 *copied ) { - FIXME( "(%p, %u, %u, %p, %p): stub!\n", iface, start, size, items, copied ); + FIXME( "(%p, %u, %u, %p, %p) stub!\n", iface, start, size, items, copied ); return E_NOTIMPL; }
@@ -149,7 +172,8 @@ const static IVectorView_DeviceInformationVtbl vectorview_DeviceInformation_vtbl vectorview_DeviceInformation_GetMany };
-HRESULT vectorview_deviceinformation_create( IVectorView_DeviceInformation **view ) +HRESULT vectorview_deviceinformation_create( IDeviceInformation **devices, SIZE_T len, + IVectorView_DeviceInformation **view ) { struct vectorview_DeviceInformation *impl;
@@ -158,6 +182,8 @@ HRESULT vectorview_deviceinformation_create( IVectorView_DeviceInformation **vie return E_OUTOFMEMORY;
impl->IVectorView_DeviceInformation_iface.lpVtbl = &vectorview_DeviceInformation_vtbl; + impl->devices = devices; + impl->len = len; impl->ref = 1; *view = &impl->IVectorView_DeviceInformation_iface; return S_OK; diff --git a/dlls/windows.devices.enumeration/information.c b/dlls/windows.devices.enumeration/information.c new file mode 100644 index 00000000000..afff96c9894 --- /dev/null +++ b/dlls/windows.devices.enumeration/information.c @@ -0,0 +1,201 @@ +/* DeviceInformation implementation. + * + * Copyright 2025 Vibhav Pant + * + * 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 "private.h" + +#include <roapi.h> + +#include <wine/debug.h> +#include <wine/rbtree.h> + +WINE_DEFAULT_DEBUG_CHANNEL(enumeration); + +/* DeviceInformation implementation for objects with kind DeviceInformationKind_DeviceInterface. */ +struct devinfo_DeviceInterface +{ + IDeviceInformation IDeviceInformation_iface; + LONG ref; +}; + +static inline struct devinfo_DeviceInterface *impl_DeviceInterface_from_IDeviceInformation( IDeviceInformation *iface ) +{ + return CONTAINING_RECORD( iface, struct devinfo_DeviceInterface, IDeviceInformation_iface ); +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_QueryInterface( IDeviceInformation *iface, REFIID iid, + void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IDeviceInformation )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE devinfo_DeviceInterface_AddRef( IDeviceInformation *iface ) +{ + struct devinfo_DeviceInterface *impl; + + TRACE( "(%p)\n", iface ); + + impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG STDMETHODCALLTYPE devinfo_DeviceInterface_Release( IDeviceInformation *iface ) +{ + struct devinfo_DeviceInterface *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + + return ref; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_GetIids( IDeviceInformation *iface, + ULONG *iid_count, IID **iids ) +{ + FIXME( "(%p, %p, %p) stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI devinfo_DeviceInterface_GetRuntimeClassName( IDeviceInformation *iface, HSTRING *class_name ) +{ + const static WCHAR *name = RuntimeClass_Windows_Devices_Enumeration_DeviceInformation; + + TRACE( "(%p, %p)\n", iface, class_name ); + + return WindowsCreateString( name, wcslen( name ), class_name ); +} + +static HRESULT STDMETHODCALLTYPE device_information_GetTrustLevel( + IDeviceInformation *iface, TrustLevel *trust_level) +{ + FIXME("(%p, %p) stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_Id( IDeviceInformation *iface, HSTRING *id ) +{ + FIXME( "(%p, %p) stub!\n", iface, id ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_Name( IDeviceInformation *iface, HSTRING *name ) +{ + FIXME( "(%p, %p) stub!\n", iface, name ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_IsEnabled( IDeviceInformation *iface, boolean *value ) +{ + FIXME( "(%p, %p) stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_IsDefault( IDeviceInformation *iface, boolean *value ) +{ + FIXME( "(%p, %p) stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_EnclosureLocation( IDeviceInformation *iface, + IEnclosureLocation **location ) +{ + FIXME( "(%p, %p) stub!\n", iface, location ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_Properties( IDeviceInformation *iface, + IMapView_HSTRING_IInspectable **properties ) +{ + FIXME( "(%p, %p) stub!\n", iface, properties ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_Update( IDeviceInformation *iface, + IDeviceInformationUpdate *update ) +{ + FIXME( "(%p, %p) stub!\n", iface, update ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_GetThumbnailAsync( IDeviceInformation *iface, + IAsyncOperation_DeviceThumbnail **async ) +{ + FIXME( "(%p, %p) stub!\n", iface, async ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE +devinfo_DeviceInterface_GetGlyphThumbnailAsync( IDeviceInformation *iface, IAsyncOperation_DeviceThumbnail **async ) +{ + FIXME( "(%p, %p) stub!\n", iface, async ); + return E_NOTIMPL; +} + +static const struct IDeviceInformationVtbl devinfo_DeviceInterface_vtbl = { + /* IUnknown */ + devinfo_DeviceInterface_QueryInterface, + devinfo_DeviceInterface_AddRef, + devinfo_DeviceInterface_Release, + /* IInspectable */ + devinfo_DeviceInterface_GetIids, + devinfo_DeviceInterface_GetRuntimeClassName, + device_information_GetTrustLevel, + /* IDeviceInformation */ + devinfo_DeviceInterface_get_Id, + devinfo_DeviceInterface_get_Name, + devinfo_DeviceInterface_get_IsEnabled, + devinfo_DeviceInterface_IsDefault, + devinfo_DeviceInterface_get_EnclosureLocation, + devinfo_DeviceInterface_get_Properties, + devinfo_DeviceInterface_Update, + devinfo_DeviceInterface_GetThumbnailAsync, + devinfo_DeviceInterface_GetGlyphThumbnailAsync, +}; + +HRESULT deviceinformation_iface_create( IDeviceInformation **info ) +{ + struct devinfo_DeviceInterface *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + + impl->IDeviceInformation_iface.lpVtbl = &devinfo_DeviceInterface_vtbl; + impl->ref = 1; + *info = &impl->IDeviceInformation_iface; + return S_OK; +} diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index cb9a64f1452..9a2bd33d2cb 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -335,17 +335,34 @@ static HRESULT WINAPI device_statics_CreateFromIdAsyncAdditionalProperties( IDev
static HRESULT WINAPI findall_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { - HRESULT hr; + IDeviceInformation **devices; IVectorView_DeviceInformation *view; + HRESULT hr = S_OK;
FIXME( "invoker %p, param %p, result %p semi-stub!\n", invoker, param, result );
- hr = vectorview_deviceinformation_create( &view ); + devices = calloc( 1, sizeof( *devices ) ); + if (!devices) + return E_OUTOFMEMORY; + + hr = deviceinformation_iface_create( &devices[0] ); + if (FAILED( hr )) + { + free( devices ); + return hr; + } + + hr = vectorview_deviceinformation_create( devices, 1, &view ); if (SUCCEEDED( hr )) { result->vt = VT_UNKNOWN; result->punkVal = (IUnknown *)view; } + else + { + IDeviceInformation_Release( devices[0] ); + free( devices ); + } return hr; }
diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index a8df1a8533f..fccae4cea41 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -50,7 +50,10 @@ typedef HRESULT (WINAPI *async_operation_callback)( IUnknown *invoker, IUnknown extern HRESULT async_operation_device_info_collection_result_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, IAsyncOperation_DeviceInformationCollection **out ); -extern HRESULT vectorview_deviceinformation_create( IVectorView_DeviceInformation **view ); +extern HRESULT vectorview_deviceinformation_create( IDeviceInformation **devices, SIZE_T len, + IVectorView_DeviceInformation **view ); +extern HRESULT deviceinformation_iface_create( IDeviceInformation **info ); + #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 9bb7bcf5d88..1eab9711549 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -486,7 +486,7 @@ static void test_DeviceInformation( void ) IDeviceInformation **devices;
hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); - todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); for (idx = 0; idx < size ;idx++) { IDeviceInformation *info; @@ -498,10 +498,10 @@ static void test_DeviceInformation( void ) UINT32 idx2 = 0; boolean found = FALSE;
- test_DeviceInformation_obj(__LINE__, info); + todo_wine test_DeviceInformation_obj(__LINE__, info); IDeviceInformation_Release( info ); hr = IVectorView_DeviceInformation_IndexOf( info_collection, info, &idx2, &found ); - ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); if (SUCCEEDED( hr )) { ok( found, "Expected IndexOf to return true\n" );
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 2 +- .../windows.devices.enumeration/information.c | 26 +++- dlls/windows.devices.enumeration/main.c | 130 ++++++++++++++++-- dlls/windows.devices.enumeration/private.h | 4 +- .../tests/devices.c | 2 +- 5 files changed, 143 insertions(+), 21 deletions(-)
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 062a914e322..ba3bc7a4b6c 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -1,5 +1,5 @@ MODULE = windows.devices.enumeration.dll -IMPORTS = combase uuid +IMPORTS = advapi32 combase setupapi uuid
SOURCES = \ access.c \ diff --git a/dlls/windows.devices.enumeration/information.c b/dlls/windows.devices.enumeration/information.c index afff96c9894..6673f954025 100644 --- a/dlls/windows.devices.enumeration/information.c +++ b/dlls/windows.devices.enumeration/information.c @@ -20,6 +20,8 @@ #include "private.h"
#include <roapi.h> +#include <setupapi.h> +#include <cfgmgr32.h>
#include <wine/debug.h> #include <wine/rbtree.h> @@ -30,6 +32,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(enumeration); struct devinfo_DeviceInterface { IDeviceInformation IDeviceInformation_iface; + + HSTRING path; LONG ref; };
@@ -78,7 +82,10 @@ static ULONG STDMETHODCALLTYPE devinfo_DeviceInterface_Release( IDeviceInformati impl = impl_DeviceInterface_from_IDeviceInformation( iface ); ref = InterlockedDecrement( &impl->ref ); if (!ref) + { + WindowsDeleteString( impl->path ); free( impl ); + }
return ref; } @@ -108,8 +115,12 @@ static HRESULT STDMETHODCALLTYPE device_information_GetTrustLevel(
static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_Id( IDeviceInformation *iface, HSTRING *id ) { - FIXME( "(%p, %p) stub!\n", iface, id ); - return E_NOTIMPL; + struct devinfo_DeviceInterface *impl; + + TRACE( "(%p, %p)\n", iface, id ); + + impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + return WindowsDuplicateString( impl->path, id ); }
static HRESULT STDMETHODCALLTYPE devinfo_DeviceInterface_get_Name( IDeviceInformation *iface, HSTRING *name ) @@ -186,15 +197,24 @@ static const struct IDeviceInformationVtbl devinfo_DeviceInterface_vtbl = { devinfo_DeviceInterface_GetGlyphThumbnailAsync, };
-HRESULT deviceinformation_iface_create( IDeviceInformation **info ) +HRESULT deviceinformation_iface_create( const SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_detail, + IDeviceInformation **info ) { struct devinfo_DeviceInterface *impl; + HRESULT res;
impl = calloc( 1, sizeof( *impl ) ); if (!impl) return E_OUTOFMEMORY;
impl->IDeviceInformation_iface.lpVtbl = &devinfo_DeviceInterface_vtbl; + res = WindowsCreateString( iface_detail->DevicePath, wcslen( iface_detail->DevicePath ), + &impl->path ); + if (FAILED( res )) + { + free( impl ); + return res; + } impl->ref = 1; *info = &impl->IDeviceInformation_iface; return S_OK; diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 9a2bd33d2cb..050c8158dcd 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -335,34 +335,134 @@ static HRESULT WINAPI device_statics_CreateFromIdAsyncAdditionalProperties( IDev
static HRESULT WINAPI findall_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { - IDeviceInformation **devices; - IVectorView_DeviceInformation *view; + IDeviceInformation **devices = NULL; + HKEY iface_key; HRESULT hr = S_OK; + SIZE_T devices_len = 0; + DWORD i;
- FIXME( "invoker %p, param %p, result %p semi-stub!\n", invoker, param, result ); + TRACE( "invoker %p, param %p, result %p\n", invoker, param, result );
- devices = calloc( 1, sizeof( *devices ) ); - if (!devices) - return E_OUTOFMEMORY; - - hr = deviceinformation_iface_create( &devices[0] ); - if (FAILED( hr )) + iface_key = + SetupDiOpenClassRegKeyExW( NULL, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL ); + if (!iface_key) + return HRESULT_FROM_WIN32( GetLastError() ); + for (i = 0;SUCCEEDED( hr );i++) { - free( devices ); - return hr; + WCHAR keyName[40]; + DWORD keylen = 40; + GUID iface_class; + LSTATUS ret; + HDEVINFO devinfo; + DWORD j; + + ret = RegEnumKeyExW( iface_key, i, keyName, &keylen, NULL, NULL, NULL, NULL ); + if (ret == ERROR_NO_MORE_ITEMS) + break; + else if (ret) + { + hr = HRESULT_FROM_WIN32( ret ); + break; + } + hr = CLSIDFromString( keyName, &iface_class ); + if (FAILED( hr )) + { + ERR( "Could not parse interface GUID string %s: %#lx\n", debugstr_w( keyName ), hr ); + continue; + } + + devinfo = SetupDiGetClassDevsW( &iface_class, NULL, NULL, DIGCF_DEVICEINTERFACE ); + if (devinfo == INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + ERR( "Could not get device list for interface %s: %lu\n", debugstr_guid( &iface_class ), err ); + hr = HRESULT_FROM_WIN32( err ); + break; + } + + for (j = 0; ;j++) + { + + SP_DEVICE_INTERFACE_DATA iface_data = {0}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_detail_data; + SIZE_T size = + offsetof( SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath[MAX_PATH + 1] ); + void *addr; + BOOL success; + IDeviceInformation *info; + + iface_data.cbSize = sizeof( iface_data ); + iface_detail_data = malloc( size ); + if (!iface_detail_data) + { + + hr = E_OUTOFMEMORY; + break; + } + iface_detail_data->cbSize = sizeof( *iface_detail_data ); + + success = SetupDiEnumDeviceInterfaces( devinfo, NULL, &iface_class, j, + &iface_data ); + if (!success) + { + + DWORD err = GetLastError(); + free( iface_detail_data ); + + if (err == ERROR_NO_MORE_ITEMS) + break; + ERR( "Could not enumerate device interfaces: %lu\n", err ); + hr = HRESULT_FROM_WIN32( err ); + break; + } + + success = SetupDiGetDeviceInterfaceDetailW( devinfo, &iface_data, iface_detail_data, + size, NULL, NULL ); + if (!success) + { + + DWORD err = GetLastError(); + free( iface_detail_data ); + ERR( "Could not get interface details for %s: %lu\n", + debugstr_guid( &iface_class ), err ); + hr = HRESULT_FROM_WIN32( err ); + break; + } + + hr = deviceinformation_iface_create( iface_detail_data, &info ); + free( iface_detail_data ); + if (FAILED( hr )) + break; + + addr = realloc( devices, sizeof( *devices ) * (devices_len + 1) ); + if (!addr) + { + IDeviceInformation_Release( info ); + hr = E_OUTOFMEMORY; + break; + } + devices = addr; + devices[devices_len++] = info; + } }
- hr = vectorview_deviceinformation_create( devices, 1, &view ); if (SUCCEEDED( hr )) { - result->vt = VT_UNKNOWN; - result->punkVal = (IUnknown *)view; + IVectorView_DeviceInformation *view; + hr = vectorview_deviceinformation_create( devices, devices_len, &view ); + if (SUCCEEDED( hr )) + { + result->vt = VT_UNKNOWN; + result->punkVal = (IUnknown *)view; + } } else { - IDeviceInformation_Release( devices[0] ); + while (devices_len--) + IDeviceInformation_Release( devices[devices_len] ); free( devices ); } + RegCloseKey( iface_key ); return hr; }
diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index fccae4cea41..71fed550a55 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -28,6 +28,7 @@ #include "winbase.h" #include "winstring.h" #include "objbase.h" +#include "setupapi.h"
#include "activation.h"
@@ -52,7 +53,8 @@ extern HRESULT async_operation_device_info_collection_result_create( IAsyncOperation_DeviceInformationCollection **out ); extern HRESULT vectorview_deviceinformation_create( IDeviceInformation **devices, SIZE_T len, IVectorView_DeviceInformation **view ); -extern HRESULT deviceinformation_iface_create( IDeviceInformation **info ); +extern HRESULT deviceinformation_iface_create( const SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_detail, + IDeviceInformation **info );
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 1eab9711549..825db3b38fb 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -498,7 +498,7 @@ static void test_DeviceInformation( void ) UINT32 idx2 = 0; boolean found = FALSE;
- todo_wine test_DeviceInformation_obj(__LINE__, info); + test_DeviceInformation_obj(__LINE__, info); IDeviceInformation_Release( info ); hr = IVectorView_DeviceInformation_IndexOf( info_collection, info, &idx2, &found ); todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr );
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/collection.c | 40 +++++++++++++++++-- .../tests/devices.c | 6 +-- 2 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/windows.devices.enumeration/collection.c b/dlls/windows.devices.enumeration/collection.c index eb501846721..5d14a488341 100644 --- a/dlls/windows.devices.enumeration/collection.c +++ b/dlls/windows.devices.enumeration/collection.c @@ -143,16 +143,48 @@ static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_IndexOf( IVectorVi IDeviceInformation *elem, UINT32 *index, boolean *found ) { - FIXME( "(%p, %p, %p, %p) stub!\n", iface, elem, index, found ); - return E_NOTIMPL; + struct vectorview_DeviceInformation *impl; + UINT32 i; + + TRACE( "(%p, %p, %p, %p)\n", iface, elem, index, found ); + + impl = impl_from_IVectorView_DeviceInformation( iface ); + for (i = 0; i < impl->len; i++) + if (elem == impl->devices[i]) + break; + + if (i < impl->len) + { + *found = TRUE; + *index = i; + } + else + { + *found = FALSE; + *index = 0; + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_GetMany( IVectorView_DeviceInformation *iface, UINT32 start, UINT32 size, IDeviceInformation **items, UINT32 *copied ) { - FIXME( "(%p, %u, %u, %p, %p) stub!\n", iface, start, size, items, copied ); - return E_NOTIMPL; + struct vectorview_DeviceInformation *impl; + UINT32 i; + + TRACE( "(%p, %u, %u, %p, %p)\n", iface, start, size, items, copied ); + impl = impl_from_IVectorView_DeviceInformation( iface ); + memset( items, 0, size * sizeof( *items ) ); + + for (i = start; i < impl->len && i < start + size; i++) + { + items[i] = impl->devices[i - start]; + IUnknown_AddRef( items[i] ); + } + *copied = i - start; + return S_OK; }
const static IVectorView_DeviceInformationVtbl vectorview_DeviceInformation_vtbl = diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 825db3b38fb..cc1de7bebf8 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -501,7 +501,7 @@ static void test_DeviceInformation( void ) test_DeviceInformation_obj(__LINE__, info); IDeviceInformation_Release( info ); hr = IVectorView_DeviceInformation_IndexOf( info_collection, info, &idx2, &found ); - todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); if (SUCCEEDED( hr )) { ok( found, "Expected IndexOf to return true\n" ); @@ -518,9 +518,9 @@ static void test_DeviceInformation( void ) UINT32 copied = 0;
hr = IVectorView_DeviceInformation_GetMany( info_collection, 0, size, devices, &copied ); - todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); if (SUCCEEDED( hr )) - todo_wine ok( copied == size, "%u != %u\n", copied, size ); + ok( copied == size, "%u != %u\n", copied, size ); for(idx = 0; idx < copied; idx++) { IDeviceInformation *info = NULL;
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/collection.c | 197 ++++++++++++++++++ .../tests/devices.c | 8 +- 2 files changed, 201 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.devices.enumeration/collection.c b/dlls/windows.devices.enumeration/collection.c index 5d14a488341..8428944230e 100644 --- a/dlls/windows.devices.enumeration/collection.c +++ b/dlls/windows.devices.enumeration/collection.c @@ -24,9 +24,159 @@
WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
+struct iterator_DeviceInformation +{ + IIterator_DeviceInformation Iterator_DeviceInformation_iface; + + IVectorView_DeviceInformation *IVectorView_DeviceInformation_iface; + UINT32 idx; + UINT32 len; + LONG ref; +}; + +static inline struct iterator_DeviceInformation * +impl_from_Iterator_DeviceInformation( IIterator_DeviceInformation *iface ) +{ + return CONTAINING_RECORD( iface, struct iterator_DeviceInformation, Iterator_DeviceInformation_iface ); +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_QueryInterface( IIterator_DeviceInformation *iface, + REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IIterator_DeviceInformation )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE iterator_DeviceInformation_AddRef( IIterator_DeviceInformation *iface ) +{ + struct iterator_DeviceInformation *impl; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG STDMETHODCALLTYPE iterator_DeviceInformation_Release( IIterator_DeviceInformation *iface ) +{ + struct iterator_DeviceInformation *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + { + IVectorView_DeviceInformation_Release( impl->IVectorView_DeviceInformation_iface ); + free( impl ); + } + return ref; +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_GetIids( IIterator_DeviceInformation *iface, + ULONG *iid_count, IID **iids ) +{ + FIXME( "(%p, %p, %p) stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_DeviceInformation_GetRuntimeClassName( IIterator_DeviceInformation *iface, + HSTRING *class_name ) +{ + const static WCHAR name[] = L"Windows.Foundation.Collections.IIterator`1<Windows.Devices.Enumeration.DeviceInformation>"; + TRACE( "(%p, %p)\n", iface, class_name ); + return WindowsCreateString( name, ARRAY_SIZE( name ), class_name ); +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_GetTrustLevel( IIterator_DeviceInformation *iface, + TrustLevel *trust_level ) +{ + FIXME( "(%p, %p) stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_get_Current( IIterator_DeviceInformation *iface, + IDeviceInformation **info ) +{ + struct iterator_DeviceInformation *impl; + + TRACE( "(%p, %p)\n", iface, info ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + return IVectorView_DeviceInformation_GetAt( impl->IVectorView_DeviceInformation_iface, + impl->idx, info ); +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_get_HasCurrent( IIterator_DeviceInformation *iface, + boolean *exists ) +{ + struct iterator_DeviceInformation *impl; + + TRACE( "(%p, %p)\n", iface, exists ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + *exists = impl->idx < impl->len; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_MoveNext( IIterator_DeviceInformation *iface, + boolean *exists ) +{ + struct iterator_DeviceInformation *impl; + + TRACE( "(%p, %p)\n", iface, exists ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + if (impl->idx < impl->len) impl->idx++; + return IIterator_DeviceInformation_get_HasCurrent( iface, exists ); +} + +static HRESULT STDMETHODCALLTYPE iterator_DeviceInformation_GetMany( IIterator_DeviceInformation *iface, UINT32 size, + IDeviceInformation **info, UINT32 *copied ) +{ + struct iterator_DeviceInformation *impl; + + TRACE( "(%p, %u, %p, %p)\n", iface, size, info, copied ); + + impl = impl_from_Iterator_DeviceInformation( iface ); + return IVectorView_DeviceInformation_GetMany( impl->IVectorView_DeviceInformation_iface, + impl->idx, size, info, copied ); +} + +const static IIterator_DeviceInformationVtbl iterator_DeviceInformation_vtbl = +{ + /* IUnknown */ + iterator_DeviceInformation_QueryInterface, + iterator_DeviceInformation_AddRef, + iterator_DeviceInformation_Release, + /* IInspectable */ + iterator_DeviceInformation_GetIids, + iterator_DeviceInformation_GetRuntimeClassName, + iterator_DeviceInformation_GetTrustLevel, + /* IIterator<DeviceInformation> */ + iterator_DeviceInformation_get_Current, + iterator_DeviceInformation_get_HasCurrent, + iterator_DeviceInformation_MoveNext, + iterator_DeviceInformation_GetMany, +}; + struct vectorview_DeviceInformation { IVectorView_DeviceInformation IVectorView_DeviceInformation_iface; + IIterable_DeviceInformation IIterable_DeviceInformation_iface;
IDeviceInformation **devices; SIZE_T len; @@ -54,6 +204,13 @@ static HRESULT STDMETHODCALLTYPE vectorview_DeviceInformation_QueryInterface( *out = iface; return S_OK; } + if (IsEqualGUID( iid, &IID_IIterable_DeviceInformation )) + { + struct vectorview_DeviceInformation *impl = impl_from_IVectorView_DeviceInformation( iface ); + *out = &impl->IIterable_DeviceInformation_iface; + IUnknown_AddRef( iface ); + return S_OK; + }
FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; @@ -204,6 +361,45 @@ const static IVectorView_DeviceInformationVtbl vectorview_DeviceInformation_vtbl vectorview_DeviceInformation_GetMany };
+DEFINE_IINSPECTABLE( iterable_view_DeviceInformation, IIterable_DeviceInformation, struct vectorview_DeviceInformation, + IVectorView_DeviceInformation_iface ); + +static HRESULT STDMETHODCALLTYPE iterable_view_DeviceInformation_First( IIterable_DeviceInformation *iface, + IIterator_DeviceInformation **iter ) + +{ + struct vectorview_DeviceInformation *impl; + struct iterator_DeviceInformation *impl_iter; + + TRACE( "(%p, %p)\n", iface, iter ); + + impl = impl_from_IIterable_DeviceInformation( iface ); + impl_iter = calloc( 1, sizeof( *impl_iter ) ); + if (!impl_iter) + return E_OUTOFMEMORY; + impl_iter->Iterator_DeviceInformation_iface.lpVtbl = &iterator_DeviceInformation_vtbl; + impl_iter->IVectorView_DeviceInformation_iface = &impl->IVectorView_DeviceInformation_iface; + IUnknown_AddRef( iface ); + impl_iter->len = impl->len; + impl_iter->ref = 1; + *iter = &impl_iter->Iterator_DeviceInformation_iface; + return S_OK; +} + +const static IIterable_DeviceInformationVtbl iterable_view_DeviceInformation_vtbl = +{ + /* IUnknown */ + iterable_view_DeviceInformation_QueryInterface, + iterable_view_DeviceInformation_AddRef, + iterable_view_DeviceInformation_Release, + /* IInspectable */ + iterable_view_DeviceInformation_GetIids, + iterable_view_DeviceInformation_GetRuntimeClassName, + iterable_view_DeviceInformation_GetTrustLevel, + /* IIterable<DeviceInformation> */ + iterable_view_DeviceInformation_First, +}; + HRESULT vectorview_deviceinformation_create( IDeviceInformation **devices, SIZE_T len, IVectorView_DeviceInformation **view ) { @@ -214,6 +410,7 @@ HRESULT vectorview_deviceinformation_create( IDeviceInformation **devices, SIZE_ return E_OUTOFMEMORY;
impl->IVectorView_DeviceInformation_iface.lpVtbl = &vectorview_DeviceInformation_vtbl; + impl->IIterable_DeviceInformation_iface.lpVtbl = &iterable_view_DeviceInformation_vtbl; impl->devices = devices; impl->len = len; impl->ref = 1; diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index cc1de7bebf8..c62405a33e0 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -555,12 +555,12 @@ static void test_DeviceInformation( void ) hr = IVectorView_DeviceInformation_QueryInterface( info_collection, &IID_IIterable_DeviceInformation, (void **)&info_iterable ); IVectorView_DeviceInformation_Release( info_collection ); - todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); } if (info_iterable) { hr = IIterable_DeviceInformation_First( info_iterable, &info_iterator ); - todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); IIterable_DeviceInformation_Release( info_iterable ); } if (info_iterator) @@ -568,13 +568,13 @@ static void test_DeviceInformation( void ) boolean exists;
hr = IIterator_DeviceInformation_get_HasCurrent( info_iterator, &exists ); - todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); while (SUCCEEDED( hr ) && exists) { IDeviceInformation *info;
hr = IIterator_DeviceInformation_get_Current( info_iterator, &info ); - todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); + ok( SUCCEEDED( hr ), "got hr %#lx\n", hr ); if (FAILED( hr )) break; test_DeviceInformation_obj( __LINE__, info ); IDeviceInformation_Release( info );
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
hr = IVectorView_DeviceInformation_get_Size( info_collection, &size );
todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr );
for (idx = 0; idx < size ;idx++)
{
IDeviceInformation *info;
winetest_push_context("info_collection %u", idx);
hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info );
ok( SUCCEEDED( hr ), "got %#lx\n", hr);
if (SUCCEEDED( hr ))
{
UINT32 idx2 = 0;
boolean found = FALSE;
test_DeviceInformation_obj(__LINE__, info);
IDeviceInformation_Release( info );
hr = IVectorView_DeviceInformation_IndexOf( info_collection, info, &idx2, &found );
You're using info after releasing your reference here.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
ok( stopped_handler.args == NULL, "stopped_handler not invoked\n" ); IDeviceWatcher_Release( device_watcher );
- hr = IDeviceInformationStatics_FindAllAsync( device_info_statics, &infocollection_async );
- todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr );
Please use explicit values when testing hr, such as hr == S_OK.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
} winetest_pop_context(); }
devices = calloc( 1, sizeof( *devices ) * size );
ok( !!devices, "Unable to allocate array\n" );
if (devices)
You don't need an if after the test, things are going wrong if it fails anyway.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
} winetest_pop_context(); }
devices = calloc( 1, sizeof( *devices ) * size );
ok( !!devices, "Unable to allocate array\n" );
if (devices)
{
UINT32 copied = 0;
hr = IVectorView_DeviceInformation_GetMany( info_collection, 0, size, devices, &copied );
todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr );
if (SUCCEEDED( hr ))
The if is unnecessary.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
todo_wine check_deviceinformationcollection_async( infocollection_async, 1, Completed, S_OK, &info_collection );
IAsyncOperation_DeviceInformationCollection_Release( infocollection_async );
- }
- if (info_collection)
- {
UINT32 idx = 0, size = 0;
hr = IVectorView_DeviceInformation_get_Size( info_collection, &size );
todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr );
for (idx = 0; idx < size ;idx++)
{
IDeviceInformation *info;
winetest_push_context("info_collection %u", idx);
hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info );
ok( SUCCEEDED( hr ), "got %#lx\n", hr);
if (SUCCEEDED( hr ))
The `if` doesn't look necessary here after the test above, similar comment in multiple other places.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
for(idx = 0; idx < copied; idx++)
{
IDeviceInformation *info = NULL;
HSTRING id1 = NULL, id2 = NULL;
winetest_push_context("devices %u", idx);
hr = IDeviceInformation_get_Id( devices[idx], &id1 );
ok( SUCCEEDED( hr ), "got %#lx\n", hr );
hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info);
ok( SUCCEEDED( hr ), "got %#lx\n", hr );
if (SUCCEEDED( hr ))
{
hr = IDeviceInformation_get_Id( info, &id2 );
ok( SUCCEEDED( hr ), "got %#lx\n", hr );
}
if (id1 && id2)
NULL is a valid HSTRING value, so you shouldn't need to check before calling WindowsCompareStringOrdinal.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
hr = IVectorView_DeviceInformation_GetAt( info_collection, idx, &info);
ok( SUCCEEDED( hr ), "got %#lx\n", hr );
if (SUCCEEDED( hr ))
{
hr = IDeviceInformation_get_Id( info, &id2 );
ok( SUCCEEDED( hr ), "got %#lx\n", hr );
}
if (id1 && id2)
{
INT32 order = 1;
WindowsCompareStringOrdinal( id1, id2, &order );
ok( !order, "%s != %s\n", debugstr_hstring( id1 ), debugstr_hstring( id2 ) );
}
WindowsDeleteString( id1 );
WindowsDeleteString( id2 );
if (info)
This also doesn't look useful, info shouldn't be NULL unless tests have failed already.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/tests/devices.c:
free( devices ); }
hr = IVectorView_DeviceInformation_QueryInterface(
info_collection, &IID_IIterable_DeviceInformation, (void **)&info_iterable ); IVectorView_DeviceInformation_Release( info_collection );
todo_wine ok( SUCCEEDED( hr ), "got hr %#lx\n", hr );
- }
- if (info_iterable)
IMO adding these todo and ifs early just makes things more complicated than it needs, you don't need them if Wine doesn't reach that point anyway and as we have some generic IVector implementation now I expect you would need a single todo_wine/if to skip all the related tests, and then get all of them to pass at once when you put the implementation in place.
Note you can probably save the testing of the inners of the IVector individual methods, if this is what all these tests are about, it's already tested elsewhere and probably not worth testing in every module that duplicates it. Of course if they are checking some windows.device.enumeration specific implementation details, it's alright.
Rémi Bernon (@rbernon) commented about dlls/windows.devices.enumeration/collection.c:
- 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 "private.h" +#include "windows.foundation.collections.h"
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
+struct vectorview_DeviceInformation
Unless there's a reason not to (which I may have missed as I'm not looking into the details), you should use the IVector implementation from w.g.i as well, it's generic and should work for anything that implements IInspectable. You only need to provided it with the right IIDs as it erases the element type otherwise.
(Have only quickly looked up to https://gitlab.winehq.org/wine/wine/-/merge_requests/6874/diffs?commit_id=e5... so far)
On Mon May 5 15:32:47 2025 +0000, Rémi Bernon wrote:
Unless there's a reason not to (which I may have missed as I'm not looking into the details), you should use the IVector implementation from w.g.i as well, it's generic and should work for anything that implements IInspectable. You only need to provided it with the right IIDs as it erases the element type otherwise.
Right, I'm not sure why I reimplemented all of this in the first place. Replaced with the w.g.i code in the latest revision.
On Mon May 5 15:32:47 2025 +0000, Rémi Bernon wrote:
IMO adding these todo and ifs early just makes things more complicated than it needs, you don't need them if Wine doesn't reach that point anyway and as we have some generic IVector implementation now I expect you would need a single todo_wine/if to skip all the related tests, and then get all of them to pass at once when you put the implementation in place. Note you can probably save the testing of the inners of the IVector individual methods, if this is what all these tests are about, it's already tested elsewhere and probably not worth testing in every module that duplicates it. Of course if they are checking some windows.device.enumeration specific implementation details, it's alright.
Yeah, it was a little confusing for me to read after 5 months.
Note you can probably save the testing of the inners of the IVector individual methods, if this is what all these tests are about, it's already tested elsewhere and probably not worth testing in every module that duplicates it. Of course if they are checking some windows.device.enumeration specific implementation details, it's alright.
Now that the latest revision using the w.g.i IVector implementation, all of this has been removed.
On Mon May 5 15:32:46 2025 +0000, Rémi Bernon wrote:
Please use explicit values when testing hr, such as hr == S_OK.
Fixed, thanks.
v2:
* Replace DeviceInformationCollection implementation with `IVector` implementation from `dlls/Windows.Gaming.Input/vector.c`. * Simplify tests, remove IVector/IIterable specific testing code.