diff --git a/dlls/xgameruntime/GDKComponent/System/XLauncher.c b/dlls/xgameruntime/GDKComponent/System/XLauncher.c new file mode 100644 index 00000000000..daee2808cbc --- /dev/null +++ b/dlls/xgameruntime/GDKComponent/System/XLauncher.c @@ -0,0 +1,106 @@ +/* + * Xbox Game runtime Library + * GDK Component: System API -> XLauncher + * + * Copyright 2026 Olivia Ryan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "../../private.h" +#include + +struct x_launcher +{ + IXLauncherImpl IXLauncherImpl_iface; + LONG ref; +}; + +WINE_DEFAULT_DEBUG_CHANNEL(gdkc); + +static inline struct x_launcher *impl_from_IXLauncherImpl( IXLauncherImpl *iface ) +{ + return CONTAINING_RECORD( iface, struct x_launcher, IXLauncherImpl_iface ); +} + +static HRESULT WINAPI x_launcher_QueryInterface( IXLauncherImpl *iface, REFIID iid, void **out ) +{ + struct x_launcher *impl = impl_from_IXLauncherImpl( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || IsEqualGUID( iid, &IID_IXLauncherImpl )) + { + IXLauncherImpl_AddRef( *out = &impl->IXLauncherImpl_iface ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI x_launcher_AddRef( IXLauncherImpl *iface ) +{ + struct x_launcher *impl = impl_from_IXLauncherImpl( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI x_launcher_Release( IXLauncherImpl *iface ) +{ + struct x_launcher *impl = impl_from_IXLauncherImpl( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI x_launcher_XLaunchUri( IXLauncherImpl *iface, XUserHandle user, const char *uri ) +{ + TRACE( "iface %p, user %p uri %s.\n", iface, user, debugstr_a( uri ) ); + return (SIZE_T)ShellExecuteA( NULL, "open", uri, NULL, NULL, SW_SHOW ) > 32 ? S_OK : E_GAMEPACKAGE_NO_PACKAGE_IDENTIFIER; +} + +static HRESULT WINAPI x_launcher_XDisplayAcquireTimeoutDeferral( IXLauncherImpl *iface, XDisplayTimeoutDeferralHandle *handle ) +{ + FIXME( "iface %p, handle %p stub!\n", iface, handle ); + return E_NOTIMPL; +} + +static void WINAPI x_launcher_XDisplayCloseTimeoutDeferralHandle( IXLauncherImpl *iface, XDisplayTimeoutDeferralHandle handle ) +{ + FIXME( "iface %p stub!\n", iface, handle ); +} + +static const struct IXLauncherImplVtbl x_launcher_vtbl = +{ + /* IUnknown methods */ + x_launcher_QueryInterface, + x_launcher_AddRef, + x_launcher_Release, + /* IXLauncherImpl methods */ + x_launcher_XLaunchUri, + x_launcher_XDisplayAcquireTimeoutDeferral, + x_launcher_XDisplayCloseTimeoutDeferralHandle, +}; + +static struct x_launcher x_launcher = +{ + {&x_launcher_vtbl}, + 0, +}; + +IXLauncherImpl *x_launcher_impl = &x_launcher.IXLauncherImpl_iface; diff --git a/dlls/xgameruntime/Makefile.in b/dlls/xgameruntime/Makefile.in index b00c401eec2..c3a07508df9 100644 --- a/dlls/xgameruntime/Makefile.in +++ b/dlls/xgameruntime/Makefile.in @@ -1,4 +1,4 @@ -IMPORTS = user32 advapi32 crypt32 combase winhttp +IMPORTS = user32 advapi32 crypt32 combase shell32 winhttp MODULE = xgameruntime.dll SOURCES = \ @@ -16,6 +16,7 @@ SOURCES = \ GDKComponent/System/Threading/ThreadPool.c \ GDKComponent/System/XSystemAnalytics.c \ GDKComponent/System/XGameRuntimeFeature.c \ + GDKComponent/System/XLauncher.c \ GDKComponent/System/Networking/HTTPClient.c \ GDKComponent/System/Networking/XNetworking.c diff --git a/dlls/xgameruntime/main.c b/dlls/xgameruntime/main.c index f92911ec8c3..9b004697c9a 100644 --- a/dlls/xgameruntime/main.c +++ b/dlls/xgameruntime/main.c @@ -210,6 +210,10 @@ HRESULT WINAPI QueryApiImpl( const GUID *runtimeClassId, REFIID interfaceId, voi { return IXNetworkingImpl_QueryInterface( x_networking_impl, interfaceId, out ); } + else if ( IsEqualGUID( runtimeClassId, &CLSID_XLauncherImpl ) ) + { + return IXLauncherImpl_QueryInterface( x_launcher_impl, interfaceId, out ); + } FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( runtimeClassId ) ); return E_NOTIMPL; diff --git a/dlls/xgameruntime/private.h b/dlls/xgameruntime/private.h index 2ff793affb3..2f934bffb7b 100644 --- a/dlls/xgameruntime/private.h +++ b/dlls/xgameruntime/private.h @@ -52,6 +52,7 @@ extern IXSystemImpl *x_system_impl; extern IXSystemAnalyticsImpl *x_system_analytics_impl; extern IXThreadingImpl *x_threading_impl; extern IXGameRuntimeFeatureImpl *x_game_runtime_feature_impl; +extern IXLauncherImpl *x_launcher_impl; extern IXNetworkingImpl *x_networking_impl; typedef struct _INITIALIZE_OPTIONS diff --git a/dlls/xgameruntime/provider.idl b/dlls/xgameruntime/provider.idl index 52a837fcb89..98f9b11df7d 100644 --- a/dlls/xgameruntime/provider.idl +++ b/dlls/xgameruntime/provider.idl @@ -24,6 +24,7 @@ import "propidl.idl"; // --- xgameruntime --- // typedef void* XSystemHandle; +typedef struct XUser* XUserHandle; typedef enum XSystemHandleType XSystemHandleType; typedef enum XSystemHandleCallbackReason XSystemHandleCallbackReason; @@ -31,15 +32,18 @@ typedef enum XGameRuntimeFeature XGameRuntimeFeature; typedef struct XVersion XVersion; typedef struct XSystemAnalyticsInfo XSystemAnalyticsInfo; +typedef struct XDisplayTimeoutDeferral *XDisplayTimeoutDeferralHandle; interface IWineAsyncWorkImpl; interface IXSystemImpl; interface IXSystemAnalyticsImpl; interface IXGameRuntimeFeatureImpl; +interface IXLauncherImpl; coclass XSystemImpl; coclass XSystemAnalyticsImpl; coclass XGameRuntimeFeatureImpl; +coclass XLauncherImpl; enum XSystemHandleType { @@ -162,6 +166,18 @@ interface IXGameRuntimeFeatureImpl : IUnknown BOOLEAN XGameRuntimeIsFeatureAvailable( [in] XGameRuntimeFeature feature ); } +[ + local, + object, + uuid(1b339674-328d-4283-a200-3171f18d3639) +] +interface IXLauncherImpl : IUnknown +{ + HRESULT XLaunchUri( [in, optional] XUserHandle user, [in, string] const char *uri ); + HRESULT XDisplayAcquireTimeoutDeferral( [out] XDisplayTimeoutDeferralHandle *handle ); + void XDisplayCloseTimeoutDeferralHandle( [in] XDisplayTimeoutDeferralHandle handle ); +} + [ uuid(e349bd1a-fc20-4e40-b99c-4178cc6b409f) ] @@ -186,3 +202,10 @@ coclass XGameRuntimeFeatureImpl [default] interface IXGameRuntimeFeatureImpl; } +[ + uuid(1b339674-328d-4283-a200-3171f18d3639) +] +coclass XLauncherImpl +{ + [default] interface IXLauncherImpl; +} diff --git a/dlls/xgameruntime/tests/provider.idl b/dlls/xgameruntime/tests/provider.idl index 046c60d372c..7d17ff10adb 100644 --- a/dlls/xgameruntime/tests/provider.idl +++ b/dlls/xgameruntime/tests/provider.idl @@ -26,6 +26,7 @@ cpp_quote("#include ") // --- xgameruntime --- // typedef void* XSystemHandle; +typedef struct XUser* XUserHandle; typedef enum XSystemHandleType XSystemHandleType; typedef enum XSystemHandleCallbackReason XSystemHandleCallbackReason; @@ -33,6 +34,7 @@ typedef enum XGameRuntimeFeature XGameRuntimeFeature; typedef struct XVersion XVersion; typedef struct XSystemAnalyticsInfo XSystemAnalyticsInfo; +typedef struct XDisplayTimeoutDeferral *XDisplayTimeoutDeferralHandle; /* type-pruning version of XAsyncCompletionRoutine */ @@ -40,10 +42,12 @@ interface IWineAsyncWorkImpl; interface IXSystemImpl; interface IXSystemAnalyticsImpl; interface IXGameRuntimeFeatureImpl; +interface IXLauncherImpl; coclass XSystemImpl; coclass XSystemAnalyticsImpl; coclass XGameRuntimeFeatureImpl; +coclass XLauncherImpl; enum XSystemHandleType { @@ -166,6 +170,18 @@ interface IXGameRuntimeFeatureImpl : IUnknown BOOLEAN XGameRuntimeIsFeatureAvailable( [in] XGameRuntimeFeature feature ); } +[ + local, + object, + uuid(1b339674-328d-4283-a200-3171f18d3639) +] +interface IXLauncherImpl : IUnknown +{ + HRESULT XLaunchUri( [in, optional] XUserHandle user, [in, string] const char *uri ); + HRESULT XDisplayAcquireTimeoutDeferral( [out] XDisplayTimeoutDeferralHandle *handle ); + void XDisplayCloseTimeoutDeferralHandle( [in] XDisplayTimeoutDeferralHandle handle ); +} + [ uuid(e349bd1a-fc20-4e40-b99c-4178cc6b409f) ] @@ -190,3 +206,10 @@ coclass XGameRuntimeFeatureImpl [default] interface IXGameRuntimeFeatureImpl; } +[ + uuid(1b339674-328d-4283-a200-3171f18d3639) +] +coclass XLauncherImpl +{ + [default] interface IXLauncherImpl; +} diff --git a/dlls/xgameruntime/tests/xgameruntime.c b/dlls/xgameruntime/tests/xgameruntime.c index 2359364b777..8879ecb41eb 100644 --- a/dlls/xgameruntime/tests/xgameruntime.c +++ b/dlls/xgameruntime/tests/xgameruntime.c @@ -359,6 +359,20 @@ static void test_XThreading(void) } } +void test_XLauncher(void) +{ + IXLauncherImpl *xlauncher; + HRESULT hr; + + hr = QueryApiImpl_fun( &CLSID_XLauncherImpl, &IID_IXLauncherImpl, (void **)&xlauncher ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_interface( xlauncher, &IID_IUnknown, TRUE ); + check_interface( xlauncher, &IID_IXLauncherImpl, TRUE ); + + IXLauncherImpl_Release( xlauncher ); +} + START_TEST(xgameruntime) { HRESULT hr; @@ -371,6 +385,7 @@ START_TEST(xgameruntime) test_XSystemAnalytics(); test_XGameRuntimeFeature(); test_XThreading(); + test_XLauncher(); RoUninitialize(); } \ No newline at end of file