Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58631
-- v13: https://gitlab.winehq.org/wine/wine/-/merge_requests/8829
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- include/Makefile.in | 1 + include/windows.media.playback.idl | 128 +++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 include/windows.media.playback.idl
diff --git a/include/Makefile.in b/include/Makefile.in index 2913b018a9b..cd748b8f00d 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -906,6 +906,7 @@ SOURCES = \ windows.media.faceanalysis.idl \ windows.media.idl \ windows.media.mediaproperties.idl \ + windows.media.playback.idl \ windows.media.render.idl \ windows.media.speechrecognition.idl \ windows.media.speechsynthesis.idl \ diff --git a/include/windows.media.playback.idl b/include/windows.media.playback.idl new file mode 100644 index 00000000000..86db9726d74 --- /dev/null +++ b/include/windows.media.playback.idl @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +import "windows.devices.enumeration.idl"; +import "windows.foundation.numerics.idl"; +import "windows.graphics.directx.direct3d11.idl"; +import "windows.media.idl"; +/* import "windows.media.audio.idl"; */ +/* import "windows.media.casting.idl"; */ +import "windows.media.core.idl"; +import "windows.media.mediaproperties.idl"; +/* import "windows.media.protection.idl"; */ +import "windows.storage.idl"; +import "windows.storage.streams.idl"; +import "windows.ui.composition.idl"; + +namespace Windows.Media.Playback { + interface IBackgroundMediaPlayerStatics; + interface IMediaPlayer; + interface IMediaPlayerDataReceivedEventArgs; + + runtimeclass BackgroundMediaPlayer; + runtimeclass MediaPlayer; + runtimeclass MediaPlayerDataReceivedEventArgs; + + declare { + interface Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *>; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.BackgroundMediaPlayer), + uuid(856ddbc1-55f7-471f-a0f2-68ac4c904592) + ] + interface IBackgroundMediaPlayerStatics : IInspectable + { + [propget] HRESULT Current([out, retval] Windows.Media.Playback.MediaPlayer **player); + [eventadd] HRESULT MessageReceivedFromBackground( + [in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MessageReceivedFromBackground([in] EventRegistrationToken token); + [eventadd] HRESULT MessageReceivedFromForeground( + [in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MessageReceivedFromForeground([in] EventRegistrationToken token); + HRESULT SendMessageToBackground([in] Windows.Foundation.Collections.ValueSet *value); + HRESULT SendMessageToForeground([in] Windows.Foundation.Collections.ValueSet *value); + HRESULT IsMediaPlaying([out, retval] boolean *value); + HRESULT Shutdown(); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.MediaPlayerDataReceivedEventArgs), + uuid(c75a9405-c801-412a-835b-83fc0e622a8e) + ] + interface IMediaPlayerDataReceivedEventArgs : IInspectable + { + [propget] HRESULT Data([out, retval] Windows.Foundation.Collections.ValueSet **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.Media.Playback.IBackgroundMediaPlayerStatics, Windows.Foundation.UniversalApiContract, 1.0), + threading(both) + ] + runtimeclass BackgroundMediaPlayer + { + } + + [ + activatable(Windows.Foundation.UniversalApiContract, 3.0), + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + threading(both) + ] + runtimeclass MediaPlayer + { + [default] interface Windows.Media.Playback.IMediaPlayer; + interface Windows.Media.Playback.IMediaPlayerSource; + [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Media.Playback.IMediaPlayerSource2; + [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Media.Playback.IMediaPlayer2; + [contract(Windows.Foundation.UniversalApiContract, 2.0)] interface Windows.Media.Playback.IMediaPlayerEffects; + [contract(Windows.Foundation.UniversalApiContract, 3.0)] interface Windows.Foundation.IClosable; + [contract(Windows.Foundation.UniversalApiContract, 3.0)] interface Windows.Media.Playback.IMediaPlayer3; + [contract(Windows.Foundation.UniversalApiContract, 3.0)] interface Windows.Media.Playback.IMediaPlayer4; + [contract(Windows.Foundation.UniversalApiContract, 3.0)] interface Windows.Media.Playback.IMediaPlayerEffects2; + [contract(Windows.Foundation.UniversalApiContract, 4.0)] interface Windows.Media.Playback.IMediaPlayer5; + [contract(Windows.Foundation.UniversalApiContract, 5.0)] interface Windows.Media.Playback.IMediaPlayer6; + [contract(Windows.Foundation.UniversalApiContract, 6.0)] interface Windows.Media.Playback.IMediaPlayer7; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass MediaPlayerDataReceivedEventArgs + { + [default] interface Windows.Media.Playback.IMediaPlayerDataReceivedEventArgs; + } +}
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- configure.ac | 2 + .../Makefile.in | 6 + .../classes.idl | 28 ++++ .../main.c | 140 ++++++++++++++++++ .../private.h | 38 +++++ .../tests/Makefile.in | 5 + .../tests/playback.c | 86 +++++++++++ ....media.playback.backgroundmediaplayer.spec | 3 + 8 files changed, 308 insertions(+) create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/Makefile.in create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/classes.idl create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/main.c create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/private.h create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/tests/Makefile.in create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c create mode 100644 dlls/windows.media.playback.backgroundmediaplayer/windows.media.playback.backgroundmediaplayer.spec
diff --git a/configure.ac b/configure.ac index 2cc5398d178..a243ffe31a2 100644 --- a/configure.ac +++ b/configure.ac @@ -3292,6 +3292,8 @@ WINE_CONFIG_MAKEFILE(dlls/windows.media.devices) WINE_CONFIG_MAKEFILE(dlls/windows.media.devices/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.mediacontrol) WINE_CONFIG_MAKEFILE(dlls/windows.media.mediacontrol/tests) +WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.backgroundmediaplayer) +WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.backgroundmediaplayer/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media) diff --git a/dlls/windows.media.playback.backgroundmediaplayer/Makefile.in b/dlls/windows.media.playback.backgroundmediaplayer/Makefile.in new file mode 100644 index 00000000000..88c79aa6636 --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/Makefile.in @@ -0,0 +1,6 @@ +MODULE = windows.media.playback.backgroundmediaplayer.dll +IMPORTS = combase + +SOURCES = \ + classes.idl \ + main.c diff --git a/dlls/windows.media.playback.backgroundmediaplayer/classes.idl b/dlls/windows.media.playback.backgroundmediaplayer/classes.idl new file mode 100644 index 00000000000..ce531d7fac0 --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/classes.idl @@ -0,0 +1,28 @@ +/* + * Runtime Classes for windows.media.playback.backgroundmediaplayer.dll + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 +#pragma winrt ns_prefix + +import "windows.media.playback.idl"; + +namespace Windows.Media.Playback { + runtimeclass BackgroundMediaPlayer; +} diff --git a/dlls/windows.media.playback.backgroundmediaplayer/main.c b/dlls/windows.media.playback.backgroundmediaplayer/main.c new file mode 100644 index 00000000000..1eb3e09990f --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/main.c @@ -0,0 +1,140 @@ +/* WinRT Windows.Media.Playback.BackgroundMediaPlayer Implementation + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "initguid.h" +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(playback); + +struct background_media_player_statics +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct background_media_player_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct background_media_player_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct background_media_player_statics *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 ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + *out = &impl->IActivationFactory_iface; + IInspectable_AddRef( *out ); + 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 background_media_player_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct background_media_player_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %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 = +{ + /* IUnknown methods */ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +static struct background_media_player_statics background_media_player_statics = +{ + {&factory_vtbl}, + 1, +}; + +static IActivationFactory *background_media_player_factory = &background_media_player_statics.IActivationFactory_iface; + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out ) +{ + FIXME( "clsid %s, riid %s, out %p stub!\n", debugstr_guid( clsid ), debugstr_guid( riid ), out ); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **factory ) +{ + const WCHAR *buffer = WindowsGetStringRawBuffer( classid, NULL ); + + TRACE( "class %s, factory %p.\n", debugstr_hstring( classid ), factory ); + + *factory = NULL; + + if (!wcscmp( buffer, RuntimeClass_Windows_Media_Playback_BackgroundMediaPlayer )) + IActivationFactory_QueryInterface( background_media_player_factory, &IID_IActivationFactory, (void **)factory ); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/windows.media.playback.backgroundmediaplayer/private.h b/dlls/windows.media.playback.backgroundmediaplayer/private.h new file mode 100644 index 00000000000..8202db332cd --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/private.h @@ -0,0 +1,38 @@ +/* WinRT Windows.Media.Playback.BackgroundMediaPlayer Implementation + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 + */ + +#ifndef __WINE_WINDOWS_MEDIA_PLAYBACK_BACKGROUNDMEDIAPLAYER_PRIVATE_H +#define __WINE_WINDOWS_MEDIA_PLAYBACK_BACKGROUNDMEDIAPLAYER_PRIVATE_H + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Media_Playback +#include "windows.media.playback.h" + +#endif diff --git a/dlls/windows.media.playback.backgroundmediaplayer/tests/Makefile.in b/dlls/windows.media.playback.backgroundmediaplayer/tests/Makefile.in new file mode 100644 index 00000000000..de29ce8f980 --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.media.playback.backgroundmediaplayer.dll +IMPORTS = combase + +SOURCES = \ + playback.c diff --git a/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c new file mode 100644 index 00000000000..a596e899294 --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "winstring.h" + +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Media_Playback +#include "windows.media.playback.h" + +#include "wine/test.h" + +#define check_interface( obj, iid ) check_interface_( __LINE__, obj, iid ) +static void check_interface_( unsigned int line, void *obj, const IID *iid ) +{ + IUnknown *iface = obj; + IUnknown *unk; + HRESULT hr; + + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + IUnknown_Release( unk ); +} + +static void test_BackgroundMediaPlayer_Statics(void) +{ + static const WCHAR *background_media_player_statics_name = L"Windows.Media.Playback.BackgroundMediaPlayer"; + IActivationFactory *factory = (void *)0xdeadbeef; + HSTRING str; + HRESULT hr; + LONG ref; + + hr = WindowsCreateString( background_media_player_statics_name, wcslen( background_media_player_statics_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); + WindowsDeleteString( str ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "got hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( background_media_player_statics_name ) ); + return; + } + + check_interface( factory, &IID_IUnknown ); + check_interface( factory, &IID_IInspectable ); + check_interface( factory, &IID_IAgileObject ); + + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %ld.\n", ref ); +} + +START_TEST(playback) +{ + HRESULT hr; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + + test_BackgroundMediaPlayer_Statics(); + + RoUninitialize(); +} diff --git a/dlls/windows.media.playback.backgroundmediaplayer/windows.media.playback.backgroundmediaplayer.spec b/dlls/windows.media.playback.backgroundmediaplayer/windows.media.playback.backgroundmediaplayer.spec new file mode 100644 index 00000000000..20a8bfa98ea --- /dev/null +++ b/dlls/windows.media.playback.backgroundmediaplayer/windows.media.playback.backgroundmediaplayer.spec @@ -0,0 +1,3 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetActivationFactory(ptr ptr) +@ stdcall -private DllGetClassObject(ptr ptr ptr)
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- include/windows.media.playback.idl | 266 +++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+)
diff --git a/include/windows.media.playback.idl b/include/windows.media.playback.idl index 86db9726d74..ed3ebd3e9ad 100644 --- a/include/windows.media.playback.idl +++ b/include/windows.media.playback.idl @@ -39,18 +39,64 @@ import "windows.storage.streams.idl"; import "windows.ui.composition.idl";
namespace Windows.Media.Playback { + typedef enum MediaPlayerError MediaPlayerError; + typedef enum MediaPlayerState MediaPlayerState; + interface IBackgroundMediaPlayerStatics; interface IMediaPlayer; interface IMediaPlayerDataReceivedEventArgs; + interface IMediaPlayerFailedEventArgs; + interface IMediaPlayerRateChangedEventArgs; + interface IPlaybackMediaMarker; + interface IPlaybackMediaMarkerFactory; + interface IPlaybackMediaMarkerReachedEventArgs; + interface IPlaybackMediaMarkerSequence;
runtimeclass BackgroundMediaPlayer; runtimeclass MediaPlayer; runtimeclass MediaPlayerDataReceivedEventArgs; + runtimeclass MediaPlayerFailedEventArgs; + runtimeclass MediaPlayerRateChangedEventArgs; + runtimeclass PlaybackMediaMarker; + runtimeclass PlaybackMediaMarkerSequence; + runtimeclass PlaybackMediaMarkerReachedEventArgs;
declare { + interface Windows.Foundation.Collections.IIterable<Windows.Media.Playback.PlaybackMediaMarker *>; + interface Windows.Foundation.Collections.IIterator<Windows.Media.Playback.PlaybackMediaMarker *>; interface Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *>; + interface Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.MediaPlayerFailedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.MediaPlayerRateChangedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.PlaybackMediaMarkerReachedEventArgs *>; }
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0) + ] + enum MediaPlayerError + { + Unknown = 0, + Aborted = 1, + NetworkError = 2, + DecodingError = 3, + SourceNotSupported = 4, + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + /* deprecated("Use MediaPlaybackState instead of MediaPlayerState. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0) */ + ] + enum MediaPlayerState + { + Closed = 0, + Opening = 1, + Buffering = 2, + Playing = 3, + Paused = 4, + Stopped = 5, + }; + [ contract(Windows.Foundation.UniversalApiContract, 1.0), exclusiveto(Windows.Media.Playback.BackgroundMediaPlayer), @@ -75,6 +121,111 @@ namespace Windows.Media.Playback { HRESULT Shutdown(); }
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.MediaPlayer), + uuid(381a83cb-6fff-499b-8d64-2885dfc1249e) + ] + interface IMediaPlayer : IInspectable + { + [propget] HRESULT AutoPlay([out, retval] boolean *value); + [propput] HRESULT AutoPlay([in] boolean value); + [deprecated("Use PlaybackSession.NaturalDuration instead of NaturalDuration. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT NaturalDuration([out, retval] Windows.Foundation.TimeSpan *value); + [deprecated("Use PlaybackSession.Position instead of Position. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT Position([out, retval] Windows.Foundation.TimeSpan *value); + [deprecated("Use PlaybackSession.Position instead of Position. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propput] HRESULT Position([in] Windows.Foundation.TimeSpan value); + [deprecated("Use PlaybackSession.BufferingProgress instead of BufferingProgress. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT BufferingProgress([out, retval] DOUBLE *value); + [deprecated("Use PlaybackSession.State instead of CurrentState. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT CurrentState([out, retval] Windows.Media.Playback.MediaPlayerState *value); + [deprecated("Use PlaybackSession.CanSeek instead of CanSeek. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT CanSeek([out, retval] boolean *value); + [deprecated("Use PlaybackSession.CanPause instead of CanPause. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT CanPause([out, retval] boolean *value); + [propget] HRESULT IsLoopingEnabled([out, retval] boolean *value); + [propput] HRESULT IsLoopingEnabled([in] boolean value); + [deprecated("Use PlaybackSession.IsProtected instead of IsProtected. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT IsProtected([out, retval] boolean *value); + [propget] HRESULT IsMuted([out, retval] boolean *value); + [propput] HRESULT IsMuted([in] boolean value); + [deprecated("Use PlaybackSession.PlaybackRate instead of PlaybackRate. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propget] HRESULT PlaybackRate([out, retval] DOUBLE *value); + [deprecated("Use PlaybackSession.PlaybackRate instead of PlaybackRate. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [propput] HRESULT PlaybackRate([in] DOUBLE value); + [propget] HRESULT Volume([out, retval] DOUBLE *value); + [propput] HRESULT Volume([in] DOUBLE value); + [deprecated("Use media tracks on MediaPlaybackItem instead of PlaybackMediaMarkers. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 2.0)] + [propget] HRESULT PlaybackMediaMarkers([out, retval] Windows.Media.Playback.PlaybackMediaMarkerSequence **value); + [eventadd] HRESULT MediaOpened( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MediaOpened([in] EventRegistrationToken token); + [eventadd] HRESULT MediaEnded( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MediaEnded([in] EventRegistrationToken token); + [eventadd] HRESULT MediaFailed( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.MediaPlayerFailedEventArgs *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MediaFailed([in] EventRegistrationToken token); + [deprecated("Use PlaybackSession.PlaybackStateChanged instead of CurrentStateChanged. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventadd] HRESULT CurrentStateChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use PlaybackSession.PlaybackStateChanged instead of CurrentStateChanged. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventremove] HRESULT CurrentStateChanged([in] EventRegistrationToken token); + [deprecated("Use media tracks on MediaPlaybackItem instead of PlaybackMediaMarkers. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 2.0)] + [eventadd] HRESULT PlaybackMediaMarkerReached( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.PlaybackMediaMarkerReachedEventArgs *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use media tracks on MediaPlaybackItem instead of PlaybackMediaMarkers. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 2.0)] + [eventremove] HRESULT PlaybackMediaMarkerReached([in] EventRegistrationToken token); + [deprecated("Use PlaybackSession.PlaybackRateChanged instead of MediaPlayerRateChanged. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventadd] HRESULT MediaPlayerRateChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, Windows.Media.Playback.MediaPlayerRateChangedEventArgs *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use PlaybackSession.PlaybackRateChanged instead of MediaPlayerRateChanged. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventremove] HRESULT MediaPlayerRateChanged([in] EventRegistrationToken token); + [eventadd] HRESULT VolumeChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT VolumeChanged([in] EventRegistrationToken token); + [deprecated("Use PlaybackSession.SeekCompleted instead of SeekCompleted. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventadd] HRESULT SeekCompleted( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use PlaybackSession.SeekCompleted instead of SeekCompleted. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventremove] HRESULT SeekCompleted([in] EventRegistrationToken token); + [deprecated("Use PlaybackSession.BufferingStarted instead of BufferingStarted. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventadd] HRESULT BufferingStarted( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use PlaybackSession.BufferingStarted instead of BufferingStarted. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventremove] HRESULT BufferingStarted([in] EventRegistrationToken token); + [deprecated("Use PlaybackSession.BufferingEnded instead of BufferingEnded. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventadd] HRESULT BufferingEnded( + [in] Windows.Foundation.TypedEventHandler<Windows.Media.Playback.MediaPlayer *, IInspectable *> *value, + [out, retval] EventRegistrationToken *token + ); + [deprecated("Use PlaybackSession.BufferingEnded instead of BufferingEnded. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)] + [eventremove] HRESULT BufferingEnded([in] EventRegistrationToken token); + HRESULT Play(); + HRESULT Pause(); + [deprecated("Use Source instead of SetUriSource. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 2.0)] + HRESULT SetUriSource([in] Windows.Foundation.Uri *value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), exclusiveto(Windows.Media.Playback.MediaPlayerDataReceivedEventArgs), @@ -85,6 +236,74 @@ namespace Windows.Media.Playback { [propget] HRESULT Data([out, retval] Windows.Foundation.Collections.ValueSet **value); }
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.MediaPlayerFailedEventArgs), + uuid(2744e9b9-a7e3-4f16-bac4-7914ebc08301) + ] + interface IMediaPlayerFailedEventArgs : IInspectable + { + [propget] HRESULT Error([out, retval] Windows.Media.Playback.MediaPlayerError *value); + [propget] HRESULT ExtendedErrorCode([out, retval] HRESULT *value); + [propget] HRESULT ErrorMessage([out, retval] HSTRING *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.MediaPlayerRateChangedEventArgs), + uuid(40600d58-3b61-4bb2-989f-fc65608b6cab) + ] + interface IMediaPlayerRateChangedEventArgs : IInspectable + { + [propget] HRESULT NewRate([out, retval] DOUBLE *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.PlaybackMediaMarker), + uuid(c4d22f5c-3c1c-4444-b6b9-778b0422d41a) + ] + interface IPlaybackMediaMarker : IInspectable + { + [propget] HRESULT Time([out, retval] Windows.Foundation.TimeSpan *value); + [propget] HRESULT MediaMarkerType([out, retval] HSTRING *value); + [propget] HRESULT Text([out, retval] HSTRING *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.PlaybackMediaMarker), + uuid(8c530a78-e0ae-4e1a-a8c8-e23f982a937b) + ] + interface IPlaybackMediaMarkerFactory : IInspectable + { + HRESULT CreateFromTime([in] Windows.Foundation.TimeSpan value, [out, retval] Windows.Media.Playback.PlaybackMediaMarker **marker); + HRESULT Create([in] Windows.Foundation.TimeSpan value, [in] HSTRING media_market_type, [in] HSTRING text, [out, retval] Windows.Media.Playback.PlaybackMediaMarker **marker); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.PlaybackMediaMarkerReachedEventArgs), + uuid(578cd1b9-90e2-4e60-abc4-8740b01f6196) + ] + interface IPlaybackMediaMarkerReachedEventArgs : IInspectable + { + [propget] HRESULT PlaybackMediaMarker([out, retval] Windows.Media.Playback.PlaybackMediaMarker **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.Playback.PlaybackMediaMarkerSequence), + uuid(f2810cee-638b-46cf-8817-1d111fe9d8c4) + ] + interface IPlaybackMediaMarkerSequence : IInspectable + requires Windows.Foundation.Collections.IIterable<Windows.Media.Playback.PlaybackMediaMarker *> + { + [propget] HRESULT Size([out, retval] UINT32 *value); + HRESULT Insert([in] Windows.Media.Playback.PlaybackMediaMarker *value); + HRESULT Clear(); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile), @@ -125,4 +344,51 @@ namespace Windows.Media.Playback { { [default] interface Windows.Media.Playback.IMediaPlayerDataReceivedEventArgs; } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass MediaPlayerFailedEventArgs + { + [default] interface Windows.Media.Playback.IMediaPlayerFailedEventArgs; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass MediaPlayerRateChangedEventArgs + { + [default] interface Windows.Media.Playback.IMediaPlayerRateChangedEventArgs; + } + + [ + activatable(Windows.Media.Playback.IPlaybackMediaMarkerFactory, Windows.Foundation.UniversalApiContract, 1.0), + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass PlaybackMediaMarker + { + [default] interface Windows.Media.Playback.IPlaybackMediaMarker; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass PlaybackMediaMarkerSequence + { + [default] interface Windows.Media.Playback.IPlaybackMediaMarkerSequence; + interface Windows.Foundation.Collections.IIterable<Windows.Media.Playback.PlaybackMediaMarker*>; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass PlaybackMediaMarkerReachedEventArgs + { + [default] interface Windows.Media.Playback.IPlaybackMediaMarkerReachedEventArgs; + } }
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- .../main.c | 91 +++++++++++++++++++ .../private.h | 38 ++++++++ .../tests/playback.c | 6 ++ 3 files changed, 135 insertions(+)
diff --git a/dlls/windows.media.playback.backgroundmediaplayer/main.c b/dlls/windows.media.playback.backgroundmediaplayer/main.c index 1eb3e09990f..66382520957 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/main.c +++ b/dlls/windows.media.playback.backgroundmediaplayer/main.c @@ -27,6 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(playback); struct background_media_player_statics { IActivationFactory IActivationFactory_iface; + IBackgroundMediaPlayerStatics IBackgroundMediaPlayerStatics_iface; LONG ref; };
@@ -51,6 +52,13 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID return S_OK; }
+ if (IsEqualGUID( iid, &IID_IBackgroundMediaPlayerStatics )) + { + *out = &impl->IBackgroundMediaPlayerStatics_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -110,9 +118,92 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
+DEFINE_IINSPECTABLE( background_media_player_statics, IBackgroundMediaPlayerStatics, struct background_media_player_statics, IActivationFactory_iface ) + +static HRESULT WINAPI background_media_player_statics_get_Current( IBackgroundMediaPlayerStatics *iface, IMediaPlayer **player ) +{ + FIXME( "iface %p, player %p stub!\n", iface, player ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_add_MessageReceivedFromBackground( IBackgroundMediaPlayerStatics *iface, + IEventHandler_MediaPlayerDataReceivedEventArgs *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_remove_MessageReceivedFromBackground( IBackgroundMediaPlayerStatics *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_add_MessageReceivedFromForeground( IBackgroundMediaPlayerStatics *iface, + IEventHandler_MediaPlayerDataReceivedEventArgs *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_remove_MessageReceivedFromForeground( IBackgroundMediaPlayerStatics *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_SendMessageToBackground( IBackgroundMediaPlayerStatics *iface, IPropertySet *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_SendMessageToForeground( IBackgroundMediaPlayerStatics *iface, IPropertySet *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_IsMediaPlaying( IBackgroundMediaPlayerStatics *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI background_media_player_statics_Shutdown( IBackgroundMediaPlayerStatics *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static const struct IBackgroundMediaPlayerStaticsVtbl background_media_player_statics_vtbl = +{ + /* IUnknown methods */ + background_media_player_statics_QueryInterface, + background_media_player_statics_AddRef, + background_media_player_statics_Release, + /* IInspectable methods */ + background_media_player_statics_GetIids, + background_media_player_statics_GetRuntimeClassName, + background_media_player_statics_GetTrustLevel, + /* IBackgroundMediaPlayerStatics methods */ + background_media_player_statics_get_Current, + background_media_player_statics_add_MessageReceivedFromBackground, + background_media_player_statics_remove_MessageReceivedFromBackground, + background_media_player_statics_add_MessageReceivedFromForeground, + background_media_player_statics_remove_MessageReceivedFromForeground, + background_media_player_statics_SendMessageToBackground, + background_media_player_statics_SendMessageToForeground, + background_media_player_statics_IsMediaPlaying, + background_media_player_statics_Shutdown, +}; + static struct background_media_player_statics background_media_player_statics = { {&factory_vtbl}, + {&background_media_player_statics_vtbl}, 1, };
diff --git a/dlls/windows.media.playback.backgroundmediaplayer/private.h b/dlls/windows.media.playback.backgroundmediaplayer/private.h index 8202db332cd..63115ff2a6f 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/private.h +++ b/dlls/windows.media.playback.backgroundmediaplayer/private.h @@ -35,4 +35,42 @@ #define WIDL_using_Windows_Media_Playback #include "windows.media.playback.h"
+#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) + #endif diff --git a/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c index a596e899294..a99c4080e1b 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c +++ b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c @@ -48,6 +48,7 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid ) static void test_BackgroundMediaPlayer_Statics(void) { static const WCHAR *background_media_player_statics_name = L"Windows.Media.Playback.BackgroundMediaPlayer"; + IBackgroundMediaPlayerStatics *background_media_player_statics = (void *)0xdeadbeef; IActivationFactory *factory = (void *)0xdeadbeef; HSTRING str; HRESULT hr; @@ -69,6 +70,11 @@ static void test_BackgroundMediaPlayer_Statics(void) check_interface( factory, &IID_IInspectable ); check_interface( factory, &IID_IAgileObject );
+ hr = IActivationFactory_QueryInterface( factory, &IID_IBackgroundMediaPlayerStatics, (void **)&background_media_player_statics ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + ref = IBackgroundMediaPlayerStatics_Release( background_media_player_statics ); + ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory ); ok( ref == 1, "got ref %ld.\n", ref ); }
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- configure.ac | 2 + .../Makefile.in | 6 + .../classes.idl | 29 + .../windows.media.playback.mediaplayer/main.c | 532 ++++++++++++++++++ .../private.h | 39 ++ .../tests/Makefile.in | 5 + .../tests/mediaplayer.c | 102 ++++ .../windows.media.playback.mediaplayer.spec | 3 + 8 files changed, 718 insertions(+) create mode 100644 dlls/windows.media.playback.mediaplayer/Makefile.in create mode 100644 dlls/windows.media.playback.mediaplayer/classes.idl create mode 100644 dlls/windows.media.playback.mediaplayer/main.c create mode 100644 dlls/windows.media.playback.mediaplayer/private.h create mode 100644 dlls/windows.media.playback.mediaplayer/tests/Makefile.in create mode 100644 dlls/windows.media.playback.mediaplayer/tests/mediaplayer.c create mode 100644 dlls/windows.media.playback.mediaplayer/windows.media.playback.mediaplayer.spec
diff --git a/configure.ac b/configure.ac index a243ffe31a2..0f639b6670d 100644 --- a/configure.ac +++ b/configure.ac @@ -3294,6 +3294,8 @@ WINE_CONFIG_MAKEFILE(dlls/windows.media.mediacontrol) WINE_CONFIG_MAKEFILE(dlls/windows.media.mediacontrol/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.backgroundmediaplayer) WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.backgroundmediaplayer/tests) +WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.mediaplayer) +WINE_CONFIG_MAKEFILE(dlls/windows.media.playback.mediaplayer/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech) WINE_CONFIG_MAKEFILE(dlls/windows.media.speech/tests) WINE_CONFIG_MAKEFILE(dlls/windows.media) diff --git a/dlls/windows.media.playback.mediaplayer/Makefile.in b/dlls/windows.media.playback.mediaplayer/Makefile.in new file mode 100644 index 00000000000..9fa6895c9ea --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/Makefile.in @@ -0,0 +1,6 @@ +MODULE = windows.media.playback.mediaplayer.dll +IMPORTS = combase + +SOURCES = \ + classes.idl \ + main.c diff --git a/dlls/windows.media.playback.mediaplayer/classes.idl b/dlls/windows.media.playback.mediaplayer/classes.idl new file mode 100644 index 00000000000..1d4dc5e7985 --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/classes.idl @@ -0,0 +1,29 @@ +/* + * Runtime Classes for windows.media.playback.mediaplayer.dll + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 +#pragma winrt ns_prefix + +import "windows.media.playback.idl"; + +namespace Windows.Media.Playback { + runtimeclass MediaPlayer; + runtimeclass PlaybackMediaMarker; +} diff --git a/dlls/windows.media.playback.mediaplayer/main.c b/dlls/windows.media.playback.mediaplayer/main.c new file mode 100644 index 00000000000..08d170c88df --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/main.c @@ -0,0 +1,532 @@ +/* WinRT Windows.Media.Playback.MediaPlayer Implementation + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "initguid.h" +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mediaplayer); + +struct media_player +{ + IMediaPlayer IMediaPlayer_iface; + LONG ref; +}; + +static inline struct media_player *impl_from_IMediaPlayer( IMediaPlayer *iface ) +{ + return CONTAINING_RECORD( iface, struct media_player, IMediaPlayer_iface ); +} + +static HRESULT WINAPI media_player_QueryInterface( IMediaPlayer *iface, REFIID iid, void **out ) +{ + struct media_player *impl = impl_from_IMediaPlayer( 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_IMediaPlayer )) + { + *out = &impl->IMediaPlayer_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_player_AddRef( IMediaPlayer *iface ) +{ + struct media_player *impl = impl_from_IMediaPlayer( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI media_player_Release( IMediaPlayer *iface ) +{ + struct media_player *impl = impl_from_IMediaPlayer( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI media_player_GetIids( IMediaPlayer *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 media_player_GetRuntimeClassName( IMediaPlayer *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_GetTrustLevel( IMediaPlayer *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_AutoPlay( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_AutoPlay( IMediaPlayer *iface, boolean value ) +{ + FIXME( "iface %p, value %d stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_NaturalDuration( IMediaPlayer *iface, TimeSpan *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_Position( IMediaPlayer *iface, TimeSpan *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_Position( IMediaPlayer *iface, TimeSpan value ) +{ + FIXME( "iface %p, value %I64d stub!\n", iface, value.Duration ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_BufferingProgress( IMediaPlayer *iface, DOUBLE *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_CurrentState( IMediaPlayer *iface, MediaPlayerState *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_CanSeek( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_CanPause( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_IsLoopingEnabled( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_IsLoopingEnabled( IMediaPlayer *iface, boolean value ) +{ + FIXME( "iface %p, value %d stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_IsProtected( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_IsMuted( IMediaPlayer *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_IsMuted( IMediaPlayer *iface, boolean value ) +{ + FIXME( "iface %p, value %d stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_PlaybackRate( IMediaPlayer *iface, DOUBLE *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_PlaybackRate( IMediaPlayer *iface, DOUBLE value ) +{ + FIXME( "iface %p, value %lf stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_Volume( IMediaPlayer *iface, DOUBLE *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_put_Volume( IMediaPlayer *iface, DOUBLE value ) +{ + FIXME( "iface %p, value %lf stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_get_PlaybackMediaMarkers( IMediaPlayer *iface, IPlaybackMediaMarkerSequence **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_MediaOpened( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_MediaOpened( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_MediaEnded( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_MediaEnded( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_MediaFailed( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_MediaPlayerFailedEventArgs *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_MediaFailed( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_CurrentStateChanged( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_CurrentStateChanged( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_PlaybackMediaMarkerReached( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_PlaybackMediaMarkerReachedEventArgs *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_PlaybackMediaMarkerReached( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_MediaPlayerRateChanged( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_MediaPlayerRateChangedEventArgs *value, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_MediaPlayerRateChanged( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_VolumeChanged( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_VolumeChanged( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_SeekCompleted( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_SeekCompleted( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_BufferingStarted( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_BufferingStarted( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_add_BufferingEnded( IMediaPlayer *iface, ITypedEventHandler_MediaPlayer_IInspectable *value, EventRegistrationToken *token ) +{ + FIXME( "iface %p, value %p, token %p stub!\n", iface, value, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_remove_BufferingEnded( IMediaPlayer *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %#I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_Play( IMediaPlayer *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_Pause( IMediaPlayer *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_player_SetUriSource( IMediaPlayer *iface, IUriRuntimeClass *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct IMediaPlayerVtbl media_player_vtbl = +{ + /* IUnknown methods */ + media_player_QueryInterface, + media_player_AddRef, + media_player_Release, + /* IInspectable methods */ + media_player_GetIids, + media_player_GetRuntimeClassName, + media_player_GetTrustLevel, + /* IMediaPlayer methods */ + media_player_get_AutoPlay, + media_player_put_AutoPlay, + media_player_get_NaturalDuration, + media_player_get_Position, + media_player_put_Position, + media_player_get_BufferingProgress, + media_player_get_CurrentState, + media_player_get_CanSeek, + media_player_get_CanPause, + media_player_get_IsLoopingEnabled, + media_player_put_IsLoopingEnabled, + media_player_get_IsProtected, + media_player_get_IsMuted, + media_player_put_IsMuted, + media_player_get_PlaybackRate, + media_player_put_PlaybackRate, + media_player_get_Volume, + media_player_put_Volume, + media_player_get_PlaybackMediaMarkers, + media_player_add_MediaOpened, + media_player_remove_MediaOpened, + media_player_add_MediaEnded, + media_player_remove_MediaEnded, + media_player_add_MediaFailed, + media_player_remove_MediaFailed, + media_player_add_CurrentStateChanged, + media_player_remove_CurrentStateChanged, + media_player_add_PlaybackMediaMarkerReached, + media_player_remove_PlaybackMediaMarkerReached, + media_player_add_MediaPlayerRateChanged, + media_player_remove_MediaPlayerRateChanged, + media_player_add_VolumeChanged, + media_player_remove_VolumeChanged, + media_player_add_SeekCompleted, + media_player_remove_SeekCompleted, + media_player_add_BufferingStarted, + media_player_remove_BufferingStarted, + media_player_add_BufferingEnded, + media_player_remove_BufferingEnded, + media_player_Play, + media_player_Pause, + media_player_SetUriSource, +}; + +struct media_player_statics +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct media_player_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct media_player_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct media_player_statics *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 ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + *out = &impl->IActivationFactory_iface; + IInspectable_AddRef( *out ); + 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 media_player_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct media_player_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %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 ) +{ + struct media_player *impl; + + TRACE( "iface %p, instance %p.\n", iface, instance ); + + if (!(impl = calloc( 1, sizeof( *impl ) ))) + { + *instance = NULL; + return E_OUTOFMEMORY; + } + + impl->IMediaPlayer_iface.lpVtbl = &media_player_vtbl; + impl->ref = 1; + + *instance = (IInspectable *)&impl->IMediaPlayer_iface; + return S_OK; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + /* IUnknown methods */ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +static struct media_player_statics media_player_statics = +{ + {&factory_vtbl}, + 1, +}; + +static IActivationFactory *media_player_factory = &media_player_statics.IActivationFactory_iface; + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out ) +{ + FIXME( "clsid %s, riid %s, out %p stub!\n", debugstr_guid( clsid ), debugstr_guid( riid ), out ); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **factory ) +{ + const WCHAR *buffer = WindowsGetStringRawBuffer( classid, NULL ); + + TRACE( "class %s, factory %p.\n", debugstr_hstring( classid ), factory ); + + *factory = NULL; + + if (!wcscmp( buffer, RuntimeClass_Windows_Media_Playback_MediaPlayer )) + IActivationFactory_QueryInterface( media_player_factory, &IID_IActivationFactory, (void **)factory ); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/windows.media.playback.mediaplayer/private.h b/dlls/windows.media.playback.mediaplayer/private.h new file mode 100644 index 00000000000..e356abcff28 --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/private.h @@ -0,0 +1,39 @@ +/* WinRT Windows.Media.Playback.MediaPlayer Implementation + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 + */ + +#ifndef __WINE_WINDOWS_MEDIA_PLAYBACK_MEDIAPLAYER_PRIVATE_H +#define __WINE_WINDOWS_MEDIA_PLAYBACK_MEDIAPLAYER_PRIVATE_H + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Media +#define WIDL_using_Windows_Media_Playback +#include "windows.media.playback.h" + +#endif diff --git a/dlls/windows.media.playback.mediaplayer/tests/Makefile.in b/dlls/windows.media.playback.mediaplayer/tests/Makefile.in new file mode 100644 index 00000000000..20894397845 --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.media.playback.mediaplayer.dll +IMPORTS = combase + +SOURCES = \ + mediaplayer.c diff --git a/dlls/windows.media.playback.mediaplayer/tests/mediaplayer.c b/dlls/windows.media.playback.mediaplayer/tests/mediaplayer.c new file mode 100644 index 00000000000..6262190e81d --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/tests/mediaplayer.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "winstring.h" + +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Media_Playback +#include "windows.media.playback.h" + +#include "wine/test.h" + +#define check_interface( obj, iid, supported ) check_interface_( __LINE__, obj, iid, supported ) +static void check_interface_( unsigned int line, void *obj, const IID *iid, BOOL supported ) +{ + IUnknown *iface = obj; + IUnknown *unk; + HRESULT hr; + + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_(__FILE__, line)( hr == S_OK || (!supported && hr == E_NOINTERFACE), "got hr %#lx.\n", hr ); + if (SUCCEEDED(hr)) IUnknown_Release( unk ); +} + +static void test_MediaPlayer_Statics(void) +{ + static const WCHAR *media_player_name = L"Windows.Media.Playback.MediaPlayer"; + IActivationFactory *factory = (void *)0xdeadbeef; + IMediaPlayer *media_player = (void *)0xdeadbeef; + IInspectable *inspectable = (void *)0xdeadbeef; + HSTRING str; + HRESULT hr; + LONG ref; + + hr = WindowsCreateString( media_player_name, wcslen( media_player_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 ); + if (hr == REGDB_E_CLASSNOTREG) + { + WindowsDeleteString( str ); + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( media_player_name ) ); + return; + } + + check_interface( factory, &IID_IUnknown, TRUE ); + check_interface( factory, &IID_IInspectable, TRUE ); + check_interface( factory, &IID_IAgileObject, FALSE ); + check_interface( factory, &IID_IMediaPlayer, FALSE ); + + hr = RoActivateInstance( str, &inspectable ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + + hr = IInspectable_QueryInterface( inspectable, &IID_IMediaPlayer, (void **)&media_player ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_interface( media_player, &IID_IAgileObject, TRUE ); + + ref = IMediaPlayer_Release( media_player ); + ok( ref == 1, "got ref %ld.\n", ref ); + ref = IInspectable_Release( inspectable ); + ok( ref == 0, "got ref %ld.\n", ref ); + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %ld.\n", ref ); +} + +START_TEST(mediaplayer) +{ + HRESULT hr; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + + test_MediaPlayer_Statics(); + + RoUninitialize(); +} diff --git a/dlls/windows.media.playback.mediaplayer/windows.media.playback.mediaplayer.spec b/dlls/windows.media.playback.mediaplayer/windows.media.playback.mediaplayer.spec new file mode 100644 index 00000000000..20a8bfa98ea --- /dev/null +++ b/dlls/windows.media.playback.mediaplayer/windows.media.playback.mediaplayer.spec @@ -0,0 +1,3 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetActivationFactory(ptr ptr) +@ stdcall -private DllGetClassObject(ptr ptr ptr)
Nikolay Sivov (@nsivov) commented about dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c:
+#include "windows.foundation.h" +#define WIDL_using_Windows_Media_Playback +#include "windows.media.playback.h"
+#include "wine/test.h"
+#define check_interface( obj, iid ) check_interface_( __LINE__, obj, iid ) +static void check_interface_( unsigned int line, void *obj, const IID *iid ) +{
- IUnknown *iface = obj;
- IUnknown *unk;
- HRESULT hr;
- hr = IUnknown_QueryInterface( iface, iid, (void **)&unk );
- ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
- IUnknown_Release( unk );
This shouldn't release unconditionally, we don't want to crash if something is missing.
On Mon Sep 1 19:17:14 2025 +0000, Nikolay Sivov wrote:
This shouldn't release unconditionally, we don't want to crash if something is missing.
Why does it matter? The test above is not supposed to fail in the first place. In pretty much all of our tests we assume that the checks succeed to avoid having to handle errors like here.
On Mon Sep 1 19:22:10 2025 +0000, Rémi Bernon wrote:
Why does it matter? The test above is not supposed to fail in the first place. In pretty much all of our tests we assume that the checks succeed to avoid having to handle errors like here.
Certainly not all of our check_interface() checks do that. But it's true that for modules like that we probably shouldn't care too much.
On Mon Sep 1 19:26:30 2025 +0000, Nikolay Sivov wrote:
Certainly not all of our check_interface() checks do that. But it's true that for modules like that we probably shouldn't care too much.
Well most of the other variants of the helpers have an extra parameter to check that an interface is *not* supposed to be there, therefore they have to handle the failure case. It's useful in such case, and it'd be useful too if the helper were called within todo_wine but it's not the case here.
But I was also talking more generally, we usually don't handle error cases in tests unless they actually happen under some configuration.
Rémi Bernon (@rbernon) commented about include/windows.media.playback.idl:
[propget] HRESULT Current([out, retval] Windows.Media.Playback.MediaPlayer **player);
[eventadd] HRESULT MessageReceivedFromBackground(
[in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value,
[out, retval] EventRegistrationToken *token
);
[eventremove] HRESULT MessageReceivedFromBackground([in] EventRegistrationToken token);
[eventadd] HRESULT MessageReceivedFromForeground(
[in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value,
[out, retval] EventRegistrationToken *token
);
[eventremove] HRESULT MessageReceivedFromForeground([in] EventRegistrationToken token);
HRESULT SendMessageToBackground([in] Windows.Foundation.Collections.ValueSet *value);
HRESULT SendMessageToForeground([in] Windows.Foundation.Collections.ValueSet *value);
HRESULT IsMediaPlaying([out, retval] boolean *value);
HRESULT Shutdown();
- }
As far as I can tell this should be made deprecated. Something like that:
```suggestion:-22+0 [ contract(Windows.Foundation.UniversalApiContract, 1.0), exclusiveto(Windows.Media.Playback.BackgroundMediaPlayer), deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), uuid(856ddbc1-55f7-471f-a0f2-68ac4c904592) ] interface IBackgroundMediaPlayerStatics : IInspectable { [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), propget] HRESULT Current([out, retval] Windows.Media.Playback.MediaPlayer **player); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), eventadd] HRESULT MessageReceivedFromBackground( [in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value, [out, retval] EventRegistrationToken *token ); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), eventremove] HRESULT MessageReceivedFromBackground([in] EventRegistrationToken token); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), eventadd] HRESULT MessageReceivedFromForeground( [in] Windows.Foundation.EventHandler<Windows.Media.Playback.MediaPlayerDataReceivedEventArgs *> *value, [out, retval] EventRegistrationToken *token ); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), eventremove] HRESULT MessageReceivedFromForeground([in] EventRegistrationToken token); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0)] HRESULT SendMessageToBackground([in] Windows.Foundation.Collections.ValueSet *value); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0)] HRESULT SendMessageToForeground([in] Windows.Foundation.Collections.ValueSet *value); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0)] HRESULT IsMediaPlaying([out, retval] boolean *value); [deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0)] HRESULT Shutdown(); } ```
Rémi Bernon (@rbernon) commented about include/windows.media.playback.idl:
uuid(c75a9405-c801-412a-835b-83fc0e622a8e)
- ]
- interface IMediaPlayerDataReceivedEventArgs : IInspectable
- {
[propget] HRESULT Data([out, retval] Windows.Foundation.Collections.ValueSet **value);
- }
- [
contract(Windows.Foundation.UniversalApiContract, 1.0),
marshaling_behavior(agile),
static(Windows.Media.Playback.IBackgroundMediaPlayerStatics, Windows.Foundation.UniversalApiContract, 1.0),
threading(both)
- ]
- runtimeclass BackgroundMediaPlayer
- {
- }
```suggestion:-8+0 [ contract(Windows.Foundation.UniversalApiContract, 1.0), deprecated("Use MediaPlayer", deprecate, Windows.Foundation.UniversalApiContract, 4.0), marshaling_behavior(agile), static(Windows.Media.Playback.IBackgroundMediaPlayerStatics, Windows.Foundation.UniversalApiContract, 1.0), threading(both) ] runtimeclass BackgroundMediaPlayer { } ```
Rémi Bernon (@rbernon) commented about include/windows.media.playback.idl:
- [
contract(Windows.Foundation.UniversalApiContract, 1.0)
- ]
- enum MediaPlayerError
- {
Unknown = 0,
Aborted = 1,
NetworkError = 2,
DecodingError = 3,
SourceNotSupported = 4,
- };
- [
contract(Windows.Foundation.UniversalApiContract, 1.0),
/* deprecated("Use MediaPlaybackState instead of MediaPlayerState. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0) */
Why commenting this? Also I don't think we need to match the message, just something like:
```suggestion:-0+0 deprecated("Use MediaPlaybackState", deprecate, Windows.Foundation.UniversalApiContract, 3.0), ```
Rémi Bernon (@rbernon) commented about include/windows.media.playback.idl:
HRESULT Shutdown(); }
- [
contract(Windows.Foundation.UniversalApiContract, 1.0),
exclusiveto(Windows.Media.Playback.MediaPlayer),
uuid(381a83cb-6fff-499b-8d64-2885dfc1249e)
- ]
- interface IMediaPlayer : IInspectable
- {
[propget] HRESULT AutoPlay([out, retval] boolean *value);
[propput] HRESULT AutoPlay([in] boolean value);
[deprecated("Use PlaybackSession.NaturalDuration instead of NaturalDuration. For more info, see MSDN.", deprecate, Windows.Foundation.UniversalApiContract, 3.0)]
Same here, the messages could probably be shorter but it also doesn't matter much.
Rémi Bernon (@rbernon) commented about dlls/windows.media.playback.mediaplayer/classes.idl:
- 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 +#pragma winrt ns_prefix
+import "windows.media.playback.idl";
+namespace Windows.Media.Playback {
- runtimeclass MediaPlayer;
- runtimeclass PlaybackMediaMarker;
```suggestion:-0+0 ```
This one isn't stubbed and shouldn't be registered.
On Mon Sep 1 19:29:58 2025 +0000, Rémi Bernon wrote:
Well most of the other variants of the helpers have an extra parameter to check that an interface is *not* supposed to be there, therefore they have to handle the failure case. It's useful in such case, and it'd be useful too if the helper were called within todo_wine but it's not the case here. But I was also talking more generally, we usually don't handle error cases in tests unless they actually happen under some configuration.
I agree with Rémi. In general checking seems a waste of time. If a test fails it needs to be addressed, whether that failure is just an incremented failure count or a crash.
On Tue Sep 2 17:32:34 2025 +0000, Elizabeth Figura wrote:
I agree with Rémi. In general checking seems a waste of time. If a test fails it needs to be addressed, whether that failure is just an incremented failure count or a crash.
It's not what this is about. Similar helpers in other modules check for that to make it possible to use todo's and not to crash. I'm mentioning that only because it's better to have this stuff matching across modules.
It's not what this is about. Similar helpers in other modules check for that to make it possible to use todo's and not to crash. I'm mentioning that only because it's better to have this stuff matching across modules.
Sure, I'm inclined to agree, though that's not quite what you said in the first place.