From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.devices.enumeration/Makefile.in | 1 + dlls/windows.devices.enumeration/access.c | 164 ++++++++++++++++++ dlls/windows.devices.enumeration/main.c | 18 +- dlls/windows.devices.enumeration/private.h | 4 + .../tests/devices.c | 68 +++++++- include/windows.devices.enumeration.idl | 80 +++++++++ 6 files changed, 327 insertions(+), 8 deletions(-) create mode 100644 dlls/windows.devices.enumeration/access.c
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 77aa007c0dc..e5b492e2bb9 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -2,6 +2,7 @@ MODULE = windows.devices.enumeration.dll IMPORTS = combase uuid
C_SRCS = \ + access.c \ event_handlers.c \ main.c
diff --git a/dlls/windows.devices.enumeration/access.c b/dlls/windows.devices.enumeration/access.c new file mode 100644 index 00000000000..3d773969a61 --- /dev/null +++ b/dlls/windows.devices.enumeration/access.c @@ -0,0 +1,164 @@ +/* WinRT Windows.Devices.Enumeration implementation + * + * Copyright 2022 Paul Gofman 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 "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); + +struct device_access_information_statics +{ + IActivationFactory IActivationFactory_iface; + IDeviceAccessInformationStatics IDeviceAccessInformationStatics_iface; + LONG ref; +}; + +static inline struct device_access_information_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct device_access_information_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct device_access_information_statics *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p stub!\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IDeviceAccessInformationStatics )) + { + IInspectable_AddRef( (*out = &impl->IDeviceAccessInformationStatics_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IActivationFactory *iface ) +{ + struct device_access_information_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct device_access_information_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI factory_GetIids( IActivationFactory *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 factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( statics, IDeviceAccessInformationStatics, struct device_access_information_statics, IActivationFactory_iface ); + +static HRESULT WINAPI statics_CreateFromId( IDeviceAccessInformationStatics *iface, + HSTRING device_id, IDeviceAccessInformation **value) +{ + FIXME( "device_id %s, value %p stub.\n", debugstr_hstring( device_id ), value ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI statics_CreateFromDeviceClassId( IDeviceAccessInformationStatics *iface, + GUID device_class_id, IDeviceAccessInformation **value) +{ + FIXME( "device_class_id %s, value %p stub.\n", debugstr_guid( &device_class_id ), value ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI statics_CreateFromDeviceClass( IDeviceAccessInformationStatics *iface, + enum DeviceClass device_class, IDeviceAccessInformation **value) +{ + FIXME( "device_class %d, value %p stub.\n", device_class, value ); + + return E_NOTIMPL; +} + +static const struct IDeviceAccessInformationStaticsVtbl statics_vtbl = +{ + statics_QueryInterface, + statics_AddRef, + statics_Release, + /* IInspectable methods */ + statics_GetIids, + statics_GetRuntimeClassName, + statics_GetTrustLevel, + /* IDeviceAccessInformationStatics methods */ + statics_CreateFromId, + statics_CreateFromDeviceClassId, + statics_CreateFromDeviceClass, +}; + +static struct device_access_information_statics device_access_information_statics = +{ + {&factory_vtbl}, + {&statics_vtbl}, + 1 +}; + +IActivationFactory *device_access_factory = &device_access_information_statics.IActivationFactory_iface; diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 603b27fe356..03bca4f0118 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -25,7 +25,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
-static const char *debugstr_hstring( HSTRING hstr ) +const char *debugstr_hstring( HSTRING hstr ) { const WCHAR *str; UINT32 len; @@ -395,8 +395,18 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out )
HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **factory ) { + const WCHAR *buffer = WindowsGetStringRawBuffer( classid, NULL ); + TRACE( "classid %s, factory %p.\n", debugstr_hstring( classid ), factory ); - *factory = &device_information_statics.IActivationFactory_iface; - IUnknown_AddRef( *factory ); - return S_OK; + + *factory = NULL; + + if (!wcscmp( buffer, RuntimeClass_Windows_Devices_Enumeration_DeviceInformation )) + IActivationFactory_QueryInterface( &device_information_statics.IActivationFactory_iface, + &IID_IActivationFactory, (void **)factory ); + else if (!wcscmp( buffer, RuntimeClass_Windows_Devices_Enumeration_DeviceAccessInformation )) + IActivationFactory_QueryInterface( device_access_factory, &IID_IActivationFactory, (void **)factory ); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; } diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index 7ce7d11bc46..dd06b25926e 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -39,6 +39,10 @@
#include "wine/list.h"
+extern IActivationFactory *device_access_factory; + +extern const char *debugstr_hstring( HSTRING hstr ); + HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token ); HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token ); HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args ); diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index a678a242622..1ffa464d83f 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -154,9 +154,6 @@ static void test_DeviceInformation( void ) 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 ); @@ -233,11 +230,74 @@ skip_device_statics2: done: WindowsDeleteString( str ); CloseHandle( stopped_handler.event ); +}
- RoUninitialize(); +static void test_DeviceAccessInformation( void ) +{ + static const WCHAR *device_access_info_name = L"Windows.Devices.Enumeration.DeviceAccessInformation"; + static const WCHAR *device_info_name = L"Windows.Devices.Enumeration.DeviceInformation"; + IDeviceAccessInformationStatics *statics; + IActivationFactory *factory, *factory2; + IDeviceAccessInformation *access_info; + enum DeviceAccessStatus access_status; + HSTRING str; + HRESULT hr; + ULONG ref; + + hr = WindowsCreateString( device_access_info_name, wcslen( device_access_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_access_info_name) ); + return; + } + + 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 **)&factory2 ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + WindowsDeleteString( str ); + + ok( factory != factory2, "Got the same factory.\n" ); + IActivationFactory_Release( factory2 ); + + check_interface( factory, &IID_IAgileObject, FALSE ); + check_interface( factory, &IID_IDeviceAccessInformation, FALSE ); + + hr = IActivationFactory_QueryInterface( factory, &IID_IDeviceAccessInformationStatics, (void **)&statics ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + hr = IDeviceAccessInformationStatics_CreateFromDeviceClass( statics, DeviceClass_AudioCapture, &access_info ); + todo_wine ok( hr == S_OK || broken( hr == RPC_E_CALL_COMPLETE ) /* broken on some Testbot machines */, "got hr %#lx\n", hr ); + + if (hr == S_OK) + { + hr = IDeviceAccessInformation_get_CurrentStatus( access_info, &access_status ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( access_status == DeviceAccessStatus_Allowed, "got %d.\n", access_status ); + ref = IDeviceAccessInformation_Release( access_info ); + ok( !ref, "got ref %lu\n", ref ); + } + + ref = IDeviceAccessInformationStatics_Release( statics ); + ok( ref == 2, "got ref %lu\n", ref ); + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %lu\n", ref ); }
START_TEST( devices ) { + HRESULT hr; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + test_DeviceInformation(); + test_DeviceAccessInformation(); + + RoUninitialize(); } diff --git a/include/windows.devices.enumeration.idl b/include/windows.devices.enumeration.idl index 3b3ed383531..d33cc940efe 100644 --- a/include/windows.devices.enumeration.idl +++ b/include/windows.devices.enumeration.idl @@ -32,6 +32,7 @@ namespace Windows.Devices.Enumeration { typedef enum DeviceInformationKind DeviceInformationKind; typedef enum DeviceWatcherStatus DeviceWatcherStatus; typedef enum Panel Panel; + typedef enum DeviceAccessStatus DeviceAccessStatus;
interface IDeviceInformation; interface IDeviceInformationStatics; @@ -45,6 +46,8 @@ namespace Windows.Devices.Enumeration { runtimeclass DeviceThumbnail; runtimeclass DeviceWatcher; runtimeclass EnclosureLocation; + runtimeclass DeviceAccessChangedEventArgs; + runtimeclass DeviceAccessInformation;
declare { @@ -61,6 +64,7 @@ namespace Windows.Devices.Enumeration { interface Windows.Foundation.TypedEventHandler<Windows.Devices.Enumeration.DeviceWatcher *, IInspectable *>; interface Windows.Foundation.TypedEventHandler<Windows.Devices.Enumeration.DeviceWatcher *, Windows.Devices.Enumeration.DeviceInformation *>; interface Windows.Foundation.TypedEventHandler<Windows.Devices.Enumeration.DeviceWatcher *, Windows.Devices.Enumeration.DeviceInformationUpdate *>; + interface Windows.Foundation.TypedEventHandler<Windows.Devices.Enumeration.DeviceAccessInformation *, Windows.Devices.Enumeration.DeviceAccessChangedEventArgs *>; } }
@@ -115,6 +119,15 @@ namespace Windows.Devices.Enumeration { Right = 6, };
+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] + enum DeviceAccessStatus + { + Unspecified = 0, + Allowed = 1, + DeniedByUser = 2, + DeniedBySystem = 3 + }; + [ exclusiveto(Windows.Devices.Enumeration.DeviceInformation), uuid(aba0fb95-4398-489d-8e44-e6130927011f) @@ -204,6 +217,51 @@ namespace Windows.Devices.Enumeration { [out, retval] Windows.Devices.Enumeration.DeviceWatcher **watcher); }
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Enumeration.DeviceAccessChangedEventArgs), + uuid(deda0bcc-4f9d-4f58-9dba-a9bc800408d5) + ] + interface IDeviceAccessChangedEventArgs : IInspectable + { + [propget] HRESULT Status([out, retval] Windows.Devices.Enumeration.DeviceAccessStatus *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 3.0), + exclusiveto(Windows.Devices.Enumeration.DeviceAccessChangedEventArgs), + uuid(82523262-934b-4b30-a178-adc39f2f2be3) + ] + interface IDeviceAccessChangedEventArgs2 : IInspectable + requires Windows.Devices.Enumeration.IDeviceAccessChangedEventArgs + { + [propget] HRESULT Id([out, retval] HSTRING *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Enumeration.DeviceAccessInformation), + uuid(0baa9a73-6de5-4915-8ddd-9a0554a6f545) + ] + interface IDeviceAccessInformation : IInspectable + { + [eventadd] HRESULT AccessChanged([in] Windows.Foundation.TypedEventHandler<Windows.Devices.Enumeration.DeviceAccessInformation *, Windows.Devices.Enumeration.DeviceAccessChangedEventArgs *> *handler, [out, retval] EventRegistrationToken *cookie); + [eventremove] HRESULT AccessChanged([in] EventRegistrationToken cookie); + [propget] HRESULT CurrentStatus([out, retval] Windows.Devices.Enumeration.DeviceAccessStatus *status); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Enumeration.DeviceAccessInformation), + uuid(574bd3d3-5f30-45cd-8a94-724fe5973084), + ] + interface IDeviceAccessInformationStatics : IInspectable + { + HRESULT CreateFromId([in] HSTRING device_id, [out, retval] Windows.Devices.Enumeration.DeviceAccessInformation **value); + HRESULT CreateFromDeviceClassId([in] GUID device_class_id, [out, retval] Windows.Devices.Enumeration.DeviceAccessInformation **value); + HRESULT CreateFromDeviceClass([in] Windows.Devices.Enumeration.DeviceClass device_class, [out, retval] Windows.Devices.Enumeration.DeviceAccessInformation **value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile), @@ -265,4 +323,26 @@ namespace Windows.Devices.Enumeration { { [default] interface Windows.Devices.Enumeration.IEnclosureLocation; } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass DeviceAccessChangedEventArgs + { + [default] interface Windows.Devices.Enumeration.IDeviceAccessChangedEventArgs; + [contract(Windows.Foundation.UniversalApiContract, 3.0)] interface Windows.Devices.Enumeration.IDeviceAccessChangedEventArgs2; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.Devices.Enumeration.IDeviceAccessInformationStatics, Windows.Foundation.UniversalApiContract, 1.0), + threading(both) + ] + runtimeclass DeviceAccessInformation + { + [default] interface Windows.Devices.Enumeration.IDeviceAccessInformation; + } + }