-- v3: windows.media.playback.backgroundmediaplayer: Implement IBackgroundMediaPlayerStatics::get_Current().
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- .../main.c | 62 ++++++++++++++++++- .../private.h | 1 + .../tests/playback.c | 10 +++ 3 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.media.playback.backgroundmediaplayer/main.c b/dlls/windows.media.playback.backgroundmediaplayer/main.c index 66382520957..3bf534ab867 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/main.c +++ b/dlls/windows.media.playback.backgroundmediaplayer/main.c @@ -24,11 +24,22 @@
WINE_DEFAULT_DEBUG_CHANNEL(playback);
+static CRITICAL_SECTION media_player_cs; +static CRITICAL_SECTION_DEBUG media_player_cs_debug = +{ + 0, 0, &media_player_cs, + { &media_player_cs_debug.ProcessLocksList, &media_player_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": media_player_cs") } +}; +static CRITICAL_SECTION media_player_cs = { &media_player_cs_debug, -1, 0, 0, 0, 0 }; + struct background_media_player_statics { IActivationFactory IActivationFactory_iface; IBackgroundMediaPlayerStatics IBackgroundMediaPlayerStatics_iface; LONG ref; + + IMediaPlayer *media_player; };
static inline struct background_media_player_statics *impl_from_IActivationFactory( IActivationFactory *iface ) @@ -76,7 +87,20 @@ 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 ); + + if (!ref) + { + EnterCriticalSection( &media_player_cs ); + if (!impl->ref && impl->media_player) + { + IMediaPlayer_Release( impl->media_player ); + impl->media_player = NULL; + } + LeaveCriticalSection( &media_player_cs ); + } + return ref; }
@@ -120,10 +144,44 @@ static const struct IActivationFactoryVtbl factory_vtbl =
DEFINE_IINSPECTABLE( background_media_player_statics, IBackgroundMediaPlayerStatics, struct background_media_player_statics, IActivationFactory_iface )
+static HRESULT get_media_player( IMediaPlayer **media_player ) +{ + static const WCHAR *media_player_name = L"Windows.Media.Playback.MediaPlayer"; + IInspectable *inspectable = NULL; + HSTRING str = NULL; + HRESULT hr; + + if (FAILED(hr = WindowsCreateString( media_player_name, wcslen( media_player_name ), &str ))) return hr; + if (SUCCEEDED(hr = RoActivateInstance( str, &inspectable ))) + { + hr = IInspectable_QueryInterface( inspectable, &IID_IMediaPlayer, (void **)media_player ); + IInspectable_Release( inspectable ); + } + + WindowsDeleteString( str ); + return hr; +} + 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; + struct background_media_player_statics *impl = impl_from_IBackgroundMediaPlayerStatics( iface ); + HRESULT hr; + + TRACE( "iface %p, player %p\n", iface, player ); + + EnterCriticalSection( &media_player_cs ); + + if (!impl->media_player && FAILED(hr = get_media_player( &impl->media_player ))) + { + *player = NULL; + LeaveCriticalSection( &media_player_cs ); + return hr; + } + + *player = impl->media_player; + IMediaPlayer_AddRef( *player ); + LeaveCriticalSection( &media_player_cs ); + return S_OK; }
static HRESULT WINAPI background_media_player_statics_add_MessageReceivedFromBackground( IBackgroundMediaPlayerStatics *iface, diff --git a/dlls/windows.media.playback.backgroundmediaplayer/private.h b/dlls/windows.media.playback.backgroundmediaplayer/private.h index 63115ff2a6f..345937f80ee 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/private.h +++ b/dlls/windows.media.playback.backgroundmediaplayer/private.h @@ -28,6 +28,7 @@ #include "winstring.h"
#include "activation.h" +#include "roapi.h"
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections diff --git a/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c index a99c4080e1b..593355d67f3 100644 --- a/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c +++ b/dlls/windows.media.playback.backgroundmediaplayer/tests/playback.c @@ -50,6 +50,8 @@ 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; + IMediaPlayer *media_player2 = (void *)0xdeadbeef; + IMediaPlayer *media_player = (void *)0xdeadbeef; HSTRING str; HRESULT hr; LONG ref; @@ -73,6 +75,14 @@ static void test_BackgroundMediaPlayer_Statics(void) hr = IActivationFactory_QueryInterface( factory, &IID_IBackgroundMediaPlayerStatics, (void **)&background_media_player_statics ); ok( hr == S_OK, "got hr %#lx.\n", hr );
+ hr = IBackgroundMediaPlayerStatics_get_Current( background_media_player_statics, &media_player ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IBackgroundMediaPlayerStatics_get_Current( background_media_player_statics, &media_player2 ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( media_player == media_player2, "got media_player %p, media_player2 %p.\n", media_player, media_player2 ); + IMediaPlayer_Release( media_player2 ); + IMediaPlayer_Release( media_player ); + ref = IBackgroundMediaPlayerStatics_Release( background_media_player_statics ); ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory );
On Thu Sep 11 03:53:29 2025 +0000, Rémi Bernon wrote:
HRESULT hr; if (FAILED(hr = WindowsCreateString( media_player_name, wcslen( media_player_name ), &str ))) return hr; if (SUCCEEDED(hr = RoActivateInstance( str, &inspectable ))) { hr = IInspectable_QueryInterface( inspectable, &IID_IMediaPlayer, (void **)media_player ); IInspectable_Release( inspectable ); } WindowsDeleteString( str ); return hr;
Otherwise you'd call WindowsDeleteString even if WindowsCreateString failed (no big deal but still).
Yeah, that's why I initialized the HSTRING to NULL. Though, this looks better style-wise, thanks.
On Thu Sep 11 03:53:33 2025 +0000, Rémi Bernon wrote:
This works because you also guard the factory QueryInterface, but I would say it's not the canonical way to do it. Guarding the factory AddRef shouldn't be necessary, and instead you should probably check the ref count again within the critical section:
EnterCriticalSection( &media_player_cs ); if (!impl->ref && impl->media_player) { IMediaPlayer_Release( impl->media_player ); impl->media_player = NULL; } LeaveCriticalSection( &media_player_cs );
I see, thanks.
This merge request was approved by Rémi Bernon.