Signed-off-by: Andrew Eikum aeikum@codeweavers.com --- configure.ac | 1 + dlls/windows.media.devices/Makefile.in | 2 + dlls/windows.media.devices/classes.idl | 24 +++ dlls/windows.media.devices/main.c | 149 ++++++++++++++++++- dlls/windows.media.devices/tests/Makefile.in | 5 + dlls/windows.media.devices/tests/devices.c | 123 +++++++++++++++ include/Makefile.in | 1 + include/windows.media.devices.idl | 126 ++++++++++++++++ 8 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 dlls/windows.media.devices/classes.idl create mode 100644 dlls/windows.media.devices/tests/Makefile.in create mode 100644 dlls/windows.media.devices/tests/devices.c create mode 100644 include/windows.media.devices.idl
diff --git a/configure.ac b/configure.ac index 408612324b8..6c0c1a33c66 100644 --- a/configure.ac +++ b/configure.ac @@ -3802,6 +3802,7 @@ WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input/tests) WINE_CONFIG_MAKEFILE(dlls/windows.globalization) WINE_CONFIG_MAKEFILE(dlls/windows.globalization/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.devices) +WINE_CONFIG_MAKEFILE(dlls/windows.media.devices/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech/tests) WINE_CONFIG_MAKEFILE(dlls/windowscodecs) diff --git a/dlls/windows.media.devices/Makefile.in b/dlls/windows.media.devices/Makefile.in index b5a3482277c..c0a8649eeb6 100644 --- a/dlls/windows.media.devices/Makefile.in +++ b/dlls/windows.media.devices/Makefile.in @@ -5,3 +5,5 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ main.c + +IDL_SRCS = classes.idl diff --git a/dlls/windows.media.devices/classes.idl b/dlls/windows.media.devices/classes.idl new file mode 100644 index 00000000000..9d6f482d395 --- /dev/null +++ b/dlls/windows.media.devices/classes.idl @@ -0,0 +1,24 @@ +/* + * Runtime Classes for windows.media.devices.dll + * + * Copyright 2021 Andrew Eikum for CodeWeavers + * Copyright 2021 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 register + +#include "windows.media.devices.idl" diff --git a/dlls/windows.media.devices/main.c b/dlls/windows.media.devices/main.c index 8e83c4e4061..9797644d71a 100644 --- a/dlls/windows.media.devices/main.c +++ b/dlls/windows.media.devices/main.c @@ -29,7 +29,11 @@
#include "activation.h"
+#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" +#define WIDL_using_Windows_Media_Devices +#include "windows.media.devices.h"
WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
@@ -45,6 +49,7 @@ static const char *debugstr_hstring(HSTRING hstr) struct windows_media_devices { IActivationFactory IActivationFactory_iface; + IMediaDeviceStatics IMediaDeviceStatics_iface; LONG ref; };
@@ -53,10 +58,17 @@ static inline struct windows_media_devices *impl_from_IActivationFactory(IActiva return CONTAINING_RECORD(iface, struct windows_media_devices, IActivationFactory_iface); }
+static inline struct windows_media_devices *impl_from_IMediaDeviceStatics(IMediaDeviceStatics *iface) +{ + return CONTAINING_RECORD(iface, struct windows_media_devices, IMediaDeviceStatics_iface); +} + static HRESULT STDMETHODCALLTYPE windows_media_devices_QueryInterface( IActivationFactory *iface, REFIID iid, void **out) { - TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + struct windows_media_devices *impl = impl_from_IActivationFactory(iface); + + TRACE("iface %p, iid %s, out %p\n", iface, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IInspectable) || @@ -68,6 +80,13 @@ static HRESULT STDMETHODCALLTYPE windows_media_devices_QueryInterface( return S_OK; }
+ if (IsEqualGUID(iid, &IID_IMediaDeviceStatics)) + { + IUnknown_AddRef(iface); + *out = &impl->IMediaDeviceStatics_iface; + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -132,9 +151,137 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = windows_media_devices_ActivateInstance, };
+static HRESULT WINAPI media_device_statics_QueryInterface(IMediaDeviceStatics *iface, + REFIID riid, void **ppvObject) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_QueryInterface(&This->IActivationFactory_iface, riid, ppvObject); +} + +static ULONG WINAPI media_device_statics_AddRef(IMediaDeviceStatics *iface) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_AddRef(&This->IActivationFactory_iface); +} + +static ULONG WINAPI media_device_statics_Release(IMediaDeviceStatics *iface) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_Release(&This->IActivationFactory_iface); +} + +static HRESULT WINAPI media_device_statics_GetIids(IMediaDeviceStatics *iface, + ULONG *iidCount, IID **iids) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_GetIids(&This->IActivationFactory_iface, iidCount, iids); +} + +static HRESULT WINAPI media_device_statics_GetRuntimeClassName(IMediaDeviceStatics *iface, + HSTRING *className) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_GetRuntimeClassName(&This->IActivationFactory_iface, className); +} + +static HRESULT WINAPI media_device_statics_GetTrustLevel(IMediaDeviceStatics *iface, + TrustLevel *trustLevel) +{ + struct windows_media_devices *This = impl_from_IMediaDeviceStatics(iface); + return windows_media_devices_GetTrustLevel(&This->IActivationFactory_iface, trustLevel); +} + +static HRESULT WINAPI media_device_statics_GetAudioCaptureSelector(IMediaDeviceStatics *iface, + HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_GetAudioRenderSelector(IMediaDeviceStatics *iface, + HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_GetVideoCaptureSelector(IMediaDeviceStatics *iface, + HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_GetDefaultAudioCaptureId(IMediaDeviceStatics *iface, + AudioDeviceRole role, HSTRING *value) +{ + FIXME("iface %p, role 0x%x, value %p stub!\n", iface, role, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_GetDefaultAudioRenderId(IMediaDeviceStatics *iface, + AudioDeviceRole role, HSTRING *value) +{ + FIXME("iface %p, role 0x%x, value %p stub!\n", iface, role, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_add_DefaultAudioCaptureDeviceChanged( + IMediaDeviceStatics *iface, + ITypedEventHandler_IInspectable_DefaultAudioCaptureDeviceChangedEventArgs *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_remove_DefaultAudioCaptureDeviceChanged( + IMediaDeviceStatics *iface, + EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_add_DefaultAudioRenderDeviceChanged( + IMediaDeviceStatics *iface, + ITypedEventHandler_IInspectable_DefaultAudioRenderDeviceChangedEventArgs *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_device_statics_remove_DefaultAudioRenderDeviceChanged( + IMediaDeviceStatics *iface, + EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static IMediaDeviceStaticsVtbl media_device_statics_vtbl = { + media_device_statics_QueryInterface, + media_device_statics_AddRef, + media_device_statics_Release, + media_device_statics_GetIids, + media_device_statics_GetRuntimeClassName, + media_device_statics_GetTrustLevel, + media_device_statics_GetAudioCaptureSelector, + media_device_statics_GetAudioRenderSelector, + media_device_statics_GetVideoCaptureSelector, + media_device_statics_GetDefaultAudioCaptureId, + media_device_statics_GetDefaultAudioRenderId, + media_device_statics_add_DefaultAudioCaptureDeviceChanged, + media_device_statics_remove_DefaultAudioCaptureDeviceChanged, + media_device_statics_add_DefaultAudioRenderDeviceChanged, + media_device_statics_remove_DefaultAudioRenderDeviceChanged, +}; + static struct windows_media_devices windows_media_devices = { {&activation_factory_vtbl}, + {&media_device_statics_vtbl}, 1 };
diff --git a/dlls/windows.media.devices/tests/Makefile.in b/dlls/windows.media.devices/tests/Makefile.in new file mode 100644 index 00000000000..42aa4ac9b10 --- /dev/null +++ b/dlls/windows.media.devices/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.media.devices.dll +IMPORTS = ole32 + +C_SRCS = \ + devices.c diff --git a/dlls/windows.media.devices/tests/devices.c b/dlls/windows.media.devices/tests/devices.c new file mode 100644 index 00000000000..9c3019de773 --- /dev/null +++ b/dlls/windows.media.devices/tests/devices.c @@ -0,0 +1,123 @@ +/* + * Copyright 2021 Andrew Eikum for CodeWeavers + * Copyright 2021 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 + */ +#define COBJMACROS +#include "initguid.h" +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winstring.h" + +#include "mmdeviceapi.h" +#include "audioclient.h" +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Media_Devices +#include "windows.media.devices.h" + +#include "wine/test.h" + +static HRESULT (WINAPI *pRoGetActivationFactory)(HSTRING, REFIID, void **); +static HRESULT (WINAPI *pRoInitialize)(RO_INIT_TYPE); +static void (WINAPI *pRoUninitialize)(void); +static HRESULT (WINAPI *pWindowsCreateString)(LPCWSTR, UINT32, HSTRING *); +static HRESULT (WINAPI *pWindowsDeleteString)(HSTRING); + +static void test_MediaDeviceStatics(void) +{ + static const WCHAR *media_device_statics_name = L"Windows.Media.Devices.MediaDevice"; + + IMediaDeviceStatics *media_device_statics = NULL; + IActivationFactory *factory = NULL; + IInspectable *inspectable = NULL, *tmp_inspectable = NULL; + IAgileObject *agile_object = NULL, *tmp_agile_object = NULL; + HSTRING str; + HRESULT hr; + + hr = pWindowsCreateString(media_device_statics_name, wcslen(media_device_statics_name), &str); + ok(hr == S_OK, "WindowsCreateString failed, hr %#x\n", hr); + + hr = pRoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == S_OK, "RoGetActivationFactory failed, hr %#x\n", hr); + pWindowsDeleteString(str); + + /* interface tests */ + hr = IActivationFactory_QueryInterface(factory, &IID_IInspectable, (void **)&inspectable); + ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IInspectable failed, hr %#x\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_IAgileObject, (void **)&agile_object); + ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IAgileObject failed, hr %#x\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_IMediaDeviceStatics, (void **)&media_device_statics); + ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IMediaDeviceStatics failed, hr %#x\n", hr); + + hr = IMediaDeviceStatics_QueryInterface(media_device_statics, &IID_IInspectable, (void **)&tmp_inspectable); + ok(hr == S_OK, "IMediaDeviceStatics_QueryInterface IID_IInspectable failed, hr %#x\n", hr); + ok(tmp_inspectable == inspectable, "IMediaDeviceStatics_QueryInterface IID_IInspectable returned %p, expected %p\n", tmp_inspectable, inspectable); + IInspectable_Release(tmp_inspectable); + + hr = IMediaDeviceStatics_QueryInterface(media_device_statics, &IID_IAgileObject, (void **)&tmp_agile_object); + ok(hr == S_OK, "IMediaDeviceStatics_QueryInterface IID_IAgileObject failed, hr %#x\n", hr); + ok(tmp_agile_object == agile_object, "IMediaDeviceStatics_QueryInterface IID_IAgileObject returned %p, expected %p\n", tmp_agile_object, agile_object); + IAgileObject_Release(tmp_agile_object); + + IAgileObject_Release(agile_object); + IInspectable_Release(inspectable); + IActivationFactory_Release(factory); + + /* cleanup */ + IMediaDeviceStatics_Release(media_device_statics); +} + +START_TEST(devices) +{ + HMODULE combase; + HRESULT hr; + + if (!(combase = LoadLibraryW(L"combase.dll"))) + { + win_skip("Failed to load combase.dll, skipping tests\n"); + return; + } + +#define LOAD_FUNCPTR(x) \ + if (!(p##x = (void*)GetProcAddress(combase, #x))) \ + { \ + win_skip("Failed to find %s in combase.dll, skipping tests.\n", #x); \ + return; \ + } + + LOAD_FUNCPTR(RoGetActivationFactory); + LOAD_FUNCPTR(RoInitialize); + LOAD_FUNCPTR(RoUninitialize); + LOAD_FUNCPTR(WindowsCreateString); + LOAD_FUNCPTR(WindowsDeleteString); +#undef LOAD_FUNCPTR + + hr = pRoInitialize(RO_INIT_MULTITHREADED); + ok(hr == S_OK, "RoInitialize failed, hr %#x\n", hr); + + test_MediaDeviceStatics(); + + pRoUninitialize(); +} diff --git a/include/Makefile.in b/include/Makefile.in index 3b60e1be303..78297a63524 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -756,6 +756,7 @@ SOURCES = \ windows.gaming.input.idl \ windows.globalization.idl \ windows.h \ + windows.media.devices.idl \ windows.media.speechsynthesis.idl \ windows.system.idl \ windows.system.userprofile.idl \ diff --git a/include/windows.media.devices.idl b/include/windows.media.devices.idl new file mode 100644 index 00000000000..d0b3fcef873 --- /dev/null +++ b/include/windows.media.devices.idl @@ -0,0 +1,126 @@ +/* + * Copyright 2021 Andrew Eikum for CodeWeavers + * Copyright 2020 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "eventtoken.idl"; +import "windows.foundation.idl"; + +namespace Windows { + namespace Media { + namespace Devices { + typedef enum AudioDeviceRole AudioDeviceRole; + interface IDefaultAudioDeviceChangedEventArgs; + interface IMediaDeviceStatics; + runtimeclass DefaultAudioCaptureDeviceChangedEventArgs; + runtimeclass DefaultAudioRenderDeviceChangedEventArgs; + runtimeclass MediaDevice; + } + } +} + +namespace Windows { + namespace Media { + namespace Devices { + declare { + interface Windows.Foundation.TypedEventHandler<IInspectable *, Windows.Media.Devices.DefaultAudioCaptureDeviceChangedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<IInspectable *, Windows.Media.Devices.DefaultAudioRenderDeviceChangedEventArgs *>; + } + } + } +} + +namespace Windows { + namespace Media { + namespace Devices { + enum AudioDeviceRole { + Default = 0, + Communications = 1, + }; + } + } +} + +namespace Windows { + namespace Media { + namespace Devices { + [ + uuid(110f882f-1c05-4657-a18e-47c9b69f07ab) + ] + interface IDefaultAudioDeviceChangedEventArgs : IInspectable + { + [propget] HRESULT Id([out] [retval] HSTRING *value); + [propget] HRESULT Role([out] [retval] Windows.Media.Devices.AudioDeviceRole *value); + } + + [ + exclusiveto(Windows.Media.Devices.MediaDevice), + uuid(aa2d9a40-909f-4bba-bf8b-0c0d296f14f0) + ] + interface IMediaDeviceStatics : IInspectable + { + HRESULT GetAudioCaptureSelector([out] [retval] HSTRING *value); + HRESULT GetAudioRenderSelector([out] [retval] HSTRING *value); + HRESULT GetVideoCaptureSelector([out] [retval] HSTRING *value); + HRESULT GetDefaultAudioCaptureId([in] Windows.Media.Devices.AudioDeviceRole role, [out] [retval] HSTRING *value); + HRESULT GetDefaultAudioRenderId([in] Windows.Media.Devices.AudioDeviceRole role, [out] [retval] HSTRING *value); + + [eventadd] HRESULT DefaultAudioCaptureDeviceChanged( + [in] Windows.Foundation.TypedEventHandler<IInspectable *, Windows.Media.Devices.DefaultAudioCaptureDeviceChangedEventArgs *> *handler, + [out, retval] EventRegistrationToken* token); + [eventremove] HRESULT DefaultAudioCaptureDeviceChanged( + [in] EventRegistrationToken token); + + [eventadd] HRESULT DefaultAudioRenderDeviceChanged( + [in] Windows.Foundation.TypedEventHandler<IInspectable *, Windows.Media.Devices.DefaultAudioRenderDeviceChangedEventArgs *> *handler, + [out, retval] EventRegistrationToken* token); + [eventremove] HRESULT DefaultAudioRenderDeviceChanged( + [in] EventRegistrationToken token); + } + + [ + activatable(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.Media.Devices.IMediaDeviceStatics, Windows.Foundation.UniversalApiContract, 1.0), + ] + runtimeclass MediaDevice + { + } + + [ + marshaling_behavior(agile) + ] + runtimeclass DefaultAudioRenderDeviceChangedEventArgs + { + [default] interface Windows.Media.Devices.IDefaultAudioDeviceChangedEventArgs; + } + + [ + marshaling_behavior(agile) + ] + runtimeclass DefaultAudioCaptureDeviceChangedEventArgs + { + [default] interface Windows.Media.Devices.IDefaultAudioDeviceChangedEventArgs; + } + } + } +}
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=88653
Your paranoid android.
=== debiant2 (build log) ===
Task: Could not create the win32 wineprefix: Failed to disable the crash dialogs: Task: WineTest did not produce the win32 report
=== debiant2 (build log) ===
Task: Could not create the wow32 wineprefix: Failed to disable the crash dialogs: Task: WineTest did not produce the wow32 report