From f1dfb2c23bf358838e22ff4113564fe12955c460 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sun, 18 Aug 2019 17:29:26 -0400 Subject: [PATCH] Added support for AppletApplication. Added AppletApplicationExitReason. Added AppletApplicationLaunchProperty and AppletApplicationLaunchRequestInfo. Added appletCreateApplication, appletPopLaunchRequestedApplication, appletCreateSystemApplication, appletPopFloatingApplicationForDevelopment, and appletOpenMainApplication. Minor internal changes + updated docs. --- nx/include/switch/services/applet.h | 229 +++++++++++- nx/source/services/applet.c | 538 ++++++++++++++++++++++++++-- 2 files changed, 735 insertions(+), 32 deletions(-) diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 8d9ac68c..1a89004c 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -126,6 +126,17 @@ typedef enum { LibAppletExitReason_Unexpected = 10, } LibAppletExitReason; +/// AppletApplicationExitReason +typedef enum { + AppletApplicationExitReason_Normal = 0, + AppletApplicationExitReason_Unknown1 = 1, + AppletApplicationExitReason_Unknown2 = 2, + AppletApplicationExitReason_Unknown3 = 3, + AppletApplicationExitReason_Unknown4 = 4, + AppletApplicationExitReason_Unknown5 = 5, + AppletApplicationExitReason_Unexpected = 100, +} AppletApplicationExitReason; + /// ThemeColorType typedef enum { AppletThemeColorType_Default = 0, @@ -214,6 +225,13 @@ typedef struct { LibAppletExitReason exitreason; ///< Set by \ref appletHolderJoin using the output from cmd GetResult, see \ref LibAppletExitReason. } AppletHolder; +/// IApplicationAccessor container. +typedef struct { + Service s; ///< IApplicationAccessor + Event StateChangedEvent; ///< Output from GetAppletStateChangedEvent, autoclear=false. + AppletApplicationExitReason exitreason; ///< Set by \ref appletApplicationJoin using the output from cmd GetResult, see \ref AppletApplicationExitReason. +} AppletApplication; + /// Used by \ref appletInitialize with __nx_applet_AppletAttribute for cmd OpenLibraryAppletProxy (AppletType_LibraryApplet), on [3.0.0+]. The default for this struct is all-zero. typedef struct { u8 flag; ///< Flag. When non-zero, two state fields are set to 1. @@ -261,6 +279,23 @@ typedef struct { u8 unused[0x14]; ///< Unused. Default is 0. } AppletApplicationAttribute; +/// ApplicationLaunchProperty +typedef struct { + u64 titleID; ///< Application titleID. + u32 version; ///< Application title-version. + u8 app_storageId; ///< FsStorageId for the Application base title. + u8 update_storageId; ///< FsStorageId for the Application update title. + u8 unk_xa; ///< Unknown. + u8 pad; ///< Padding. +} AppletApplicationLaunchProperty; + +/// ApplicationLaunchRequestInfo +typedef struct { + u32 unk_x0; ///< Unknown. + u32 unk_x4; ///< Unknown. + u8 unk_x8[0x8]; ///< Unknown. +} AppletApplicationLaunchRequestInfo; + /// AppletResourceUsageInfo, from \ref appletGetAppletResourceUsageInfo. typedef struct { u32 counter0; ///< Unknown counter. @@ -1397,6 +1432,191 @@ Result appletShouldSleepOnBoot(bool *out); */ Result appletGetHdcpAuthenticationFailedEvent(Event *out_event); +// IApplicationCreator + +/** + * @brief Creates an Application. + * @note Only available with AppletType_SystemApplet. + * @param[out] a \ref AppletApplication + * @param[in] titleID Application titleID. + */ +Result appletCreateApplication(AppletApplication *a, u64 titleID); + +/** + * @brief Pops a \ref AppletApplication for a requested Application launch. + * @note Only available with AppletType_SystemApplet. + * @param[out] a \ref AppletApplication + */ +Result appletPopLaunchRequestedApplication(AppletApplication *a); + +/** + * @brief Creates a SystemApplication. + * @note Only available with AppletType_SystemApplet. + * @param[out] a \ref AppletApplication + * @param[in] titleID SystemApplication titleID. + */ +Result appletCreateSystemApplication(AppletApplication *a, u64 titleID); + +/** + * @brief PopFloatingApplicationForDevelopment. + * @note Only available with AppletType_SystemApplet. Should not be used if no FloatingApplication is available. + * @param[out] a \ref AppletApplication + */ +Result appletPopFloatingApplicationForDevelopment(AppletApplication *a); + +/** + * @brief Close an \ref AppletApplication. + * @param a \ref AppletApplication + */ +void appletApplicationClose(AppletApplication *a); + +/** + * @brief Returns whether the AppletApplication object was initialized. + * @param a \ref AppletApplication + */ +bool appletApplicationActive(AppletApplication *a); + +/** + * @brief Starts the Application. + * @param a \ref AppletApplication + */ +Result appletApplicationStart(AppletApplication *a); + +/** + * @brief Requests the Application to exit. + * @param a \ref AppletApplication + */ +Result appletApplicationRequestExit(AppletApplication *a); + +/** + * @brief Terminate the Application. + * @param a \ref AppletApplication + */ +Result appletApplicationTerminate(AppletApplication *a); + +/** + * @brief Waits for the Application to exit. + * @param a \ref AppletApplication + */ +void appletApplicationJoin(AppletApplication *a); + +/** + * @brief Waits on the Application StateChangedEvent with timeout=0, and returns whether it was successful. + * @param a \ref AppletApplication + */ +bool appletApplicationCheckFinished(AppletApplication *a); + +/** + * @brief Gets the \ref AppletApplicationExitReason set by \ref appletApplicationJoin. + * @param a \ref AppletApplication + */ +AppletApplicationExitReason appletApplicationGetExitReason(AppletApplication *a); + +/** + * @brief RequestForApplicationToGetForeground. + * @param a \ref AppletApplication + */ +Result appletApplicationRequestForApplicationToGetForeground(AppletApplication *a); + +/** + * @brief Gets the titleID for the Application. + * @param a \ref AppletApplication + * @param[out] titleID Output Application titleID. + */ +Result appletApplicationGetApplicationId(AppletApplication *a, u64 *titleID); + +/** + * @brief Pushes a LaunchParameter AppletStorage to the Application. + * @note This uses \ref appletStorageClose automatically. + * @param[in] s Input storage. + * @param kind \ref AppletLaunchParameterKind + */ +Result appletApplicationPushLaunchParameter(AppletApplication *a, AppletLaunchParameterKind kind, AppletStorage* s); + +/** + * @brief Gets the \ref NacpStruct for the Application. + * @param a \ref AppletApplication + * @param[out] nacp \ref NacpStruct + */ +Result appletApplicationGetApplicationControlProperty(AppletApplication *a, NacpStruct *nacp); + +/** + * @brief Gets the \ref AppletApplicationLaunchProperty for the Application. + * @note Only available on [2.0.0+]. Not usable when the AppletId is ::AppletId_starter. + * @param a \ref AppletApplication + * @param[out] out \ref AppletApplicationLaunchProperty + */ +Result appletApplicationGetApplicationLaunchProperty(AppletApplication *a, AppletApplicationLaunchProperty *out); + +/** + * @brief Gets the \ref AppletApplicationLaunchRequestInfo for the Application. + * @note Only available on [6.0.0+]. + * @param a \ref AppletApplication + * @param[out] out \ref AppletApplicationLaunchRequestInfo + */ +Result appletApplicationGetApplicationLaunchRequestInfo(AppletApplication *a, AppletApplicationLaunchRequestInfo *out); + +/** + * @brief SetUsers for the Application. + * @note Only available on [6.0.0+]. + * @param a \ref AppletApplication + * @param[in] userIDs Input array of userIDs. + * @param[in] count Size of the userID array in entries, must be <=ACC_USER_LIST_SIZE. + * @param[in] flag When this flag is true, this just clears the users_available state flag to 0 and returns. + */ +Result appletApplicationSetUsers(AppletApplication *a, const u128 *userIDs, s32 count, bool flag); + +/** + * @brief CheckRightsEnvironmentAvailable. + * @note Only available on [6.0.0+]. + * @param a \ref AppletApplication + * @param[out] out Output flag. + */ +Result appletApplicationCheckRightsEnvironmentAvailable(AppletApplication *a, bool *out); + +/** + * @brief GetNsRightsEnvironmentHandle. + * @note Only available on [6.0.0+]. + * @param a \ref AppletApplication + * @param[out] handle Output NsRightsEnvironmentHandle. + */ +Result appletApplicationGetNsRightsEnvironmentHandle(AppletApplication *a, u64 *handle); + +/** + * @brief Gets an array of userIDs for the Application DesirableUids. + * @note Only available on [6.0.0+]. + * @note qlaunch only uses 1 userID with this. + * @param a \ref AppletApplication + * @param[out] userIDs Output array of userIDs. + * @param[in] count Size of the userID array in entries, must be at least the size stored in state. + * @param[out] total_out Total output entries. + */ +Result appletApplicationGetDesirableUids(AppletApplication *a, u128 *userIDs, s32 count, s32 *total_out); + +/** + * @brief ReportApplicationExitTimeout. + * @note Only available on [6.0.0+]. + * @param a \ref AppletApplication + */ +Result appletApplicationReportApplicationExitTimeout(AppletApplication *a); + +/** + * @brief Sets the \ref AppletApplicationAttribute for the Application. + * @note Only available on [8.0.0+]. + * @param a \ref AppletApplication + * @param[in] attr \ref AppletApplicationAttribute + */ +Result appletApplicationSetApplicationAttribute(AppletApplication *a, const AppletApplicationAttribute *attr); + +/** + * @brief Gets whether the savedata specified by the input titleID is accessible. + * @note Only available on [8.0.0+]. + * @param a \ref AppletApplication + * @param[in] titleID titleID for the savedata. + * @param[out] out Output flag. + */ +Result appletApplicationHasSaveDataAccessPermission(AppletApplication *a, u64 titleID, bool *out); + // ILibraryAppletSelfAccessor /** @@ -1572,7 +1792,7 @@ Result appletRequestExitToSelf(void); * @brief Gets an array of userIDs for the MainApplet AvailableUsers. * @note Only available with AppletType_LibraryApplet on [6.0.0+]. * @param[out] userIDs Output array of userIDs. - * @param[in] count Size of the userID array, must be at least ACC_USER_LIST_SIZE. + * @param[in] count Size of the userID array in entries, must be at least ACC_USER_LIST_SIZE. * @param[out] flag When true, this indicates that no users are available. * @param[out] total_out Total output entries. This is -1 when flag is true. */ @@ -1706,6 +1926,13 @@ Result appletGetHomeButtonDoubleClickEnabled(bool *out); // IDebugFunctions +/** + * @brief Open an \ref AppletApplication for the currently running Application. + * @note Should not be used when no Application is running. + * @param[out] a \ref AppletApplication + */ +Result appletOpenMainApplication(AppletApplication *a); + /** * @brief Perform SystemButtonPressing with the specified \ref AppletSystemButtonType. * @param[in] type \ref AppletSystemButtonType diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 63d8af67..911401b4 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -1083,6 +1083,74 @@ static Result _appletCmdNoInOutStorage(Service* srv, AppletStorage* s, u64 cmd_i return _appletGetSession(srv, &s->s, cmd_id); } +static Result _appletCmdSendBufNoOut(Service* srv, const void* buffer, size_t size, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, buffer, size, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _appletCmdNoInRecvBuf(Service* srv, void* buffer, size_t size, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddRecvBuffer(&c, buffer, size, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + static Result _appletGetLibraryAppletInfo(Service* srv, LibAppletInfo *info, u64 cmd_id) { IpcCommand c; ipcInitialize(&c); @@ -4245,6 +4313,440 @@ Result appletGetHdcpAuthenticationFailedEvent(Event *out_event) { return _appletGetEvent(&g_appletIGlobalStateController, out_event, 15, false); } +// IApplicationCreator + +static Result _appletApplicationCreateState(AppletApplication *a) { + Result rc=0; + + rc = _appletGetEvent(&a->s, &a->StateChangedEvent, 0, false);//GetAppletStateChangedEvent + + return rc; +} + +static Result _appletApplicationCreate(AppletApplication *a, Service* srv, u64 cmd_id) { + Result rc=0; + + memset(a, 0, sizeof(AppletApplication)); + + rc = _appletGetSession(srv, &a->s, cmd_id); + + if (R_SUCCEEDED(rc)) rc = _appletApplicationCreateState(a); + + return rc; +} + +static Result _appletApplicationCreateIn64(AppletApplication *a, Service* srv, u64 cmd_id, u64 val) { + Result rc=0; + + memset(a, 0, sizeof(AppletApplication)); + + rc = _appletGetSessionIn64(srv, &a->s, cmd_id, val); + + if (R_SUCCEEDED(rc)) rc = _appletApplicationCreateState(a); + + return rc; +} + +Result appletCreateApplication(AppletApplication *a, u64 titleID) { + if (__nx_applet_type != AppletType_SystemApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletApplicationCreateIn64(a, &g_appletIApplicationCreator, 0, titleID); +} + +Result appletPopLaunchRequestedApplication(AppletApplication *a) { + if (__nx_applet_type != AppletType_SystemApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletApplicationCreate(a, &g_appletIApplicationCreator, 1); +} + +Result appletCreateSystemApplication(AppletApplication *a, u64 titleID) { + if (__nx_applet_type != AppletType_SystemApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletApplicationCreateIn64(a, &g_appletIApplicationCreator, 10, titleID); +} + +Result appletPopFloatingApplicationForDevelopment(AppletApplication *a) { + if (__nx_applet_type != AppletType_SystemApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletApplicationCreate(a, &g_appletIApplicationCreator, 100); +} + +void appletApplicationClose(AppletApplication *a) { + eventClose(&a->StateChangedEvent); + serviceClose(&a->s); + memset(a, 0, sizeof(AppletApplication)); +} + +bool appletApplicationActive(AppletApplication *a) { + return serviceIsActive(&a->s); +} + +Result appletApplicationStart(AppletApplication *a) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _appletCmdNoIO(&a->s, 10);//Start + + return rc; +} + +Result appletApplicationRequestExit(AppletApplication *a) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _appletCmdNoIO(&a->s, 20);//RequestExit + + return rc; +} + +Result appletApplicationTerminate(AppletApplication *a) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _appletCmdNoIO(&a->s, 25);//Terminate + + return rc; +} + +void appletApplicationJoin(AppletApplication *a) { + Result rc=0; + AppletApplicationExitReason res = AppletApplicationExitReason_Normal; + u32 desc=0; + + eventWait(&a->StateChangedEvent, U64_MAX); + rc = _appletCmdNoIO(&a->s, 30);//GetResult + + if (R_FAILED(rc)) { + res = AppletApplicationExitReason_Unexpected; + + if (R_MODULE(rc) == 128) { + desc = R_DESCRIPTION(rc); + + if (desc >= 35 && desc < 40) res = AppletApplicationExitReason_Unknown5; + else if (desc >= 31 && desc < 40) res = AppletApplicationExitReason_Unknown1; + else if (desc == 23) res = AppletApplicationExitReason_Unknown2; + else if (desc >= 40 && desc < 45) res = AppletApplicationExitReason_Unknown3; + else if (desc == 51) res = AppletApplicationExitReason_Unknown4; + } + } + + a->exitreason = res; +} + +bool appletApplicationCheckFinished(AppletApplication *a) { + return R_SUCCEEDED(eventWait(&a->StateChangedEvent, 0)); +} + +AppletApplicationExitReason appletApplicationGetExitReason(AppletApplication *a) { + return a->exitreason; +} + +Result appletApplicationRequestForApplicationToGetForeground(AppletApplication *a) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _appletCmdNoIO(&a->s, 101);//RequestForApplicationToGetForeground + + return rc; +} + +Result appletApplicationGetApplicationId(AppletApplication *a, u64 *titleID) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + rc = _appletCmdNoInOut64(&a->s, titleID, 120);//GetApplicationId + + return rc; +} + +Result appletApplicationPushLaunchParameter(AppletApplication *a, AppletLaunchParameterKind kind, AppletStorage* s) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (!serviceIsActive(&s->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + IpcCommand c; + ipcInitialize(&c); + + serviceSendObject(&s->s, &c); + + struct { + u64 magic; + u64 cmd_id; + u32 kind; + } *raw; + + raw = serviceIpcPrepareHeader(&a->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 121; + raw->kind = kind; + + Result rc = serviceIpcDispatch(&a->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&a->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + appletStorageClose(s); + + return rc; +} + +Result appletApplicationGetApplicationControlProperty(AppletApplication *a, NacpStruct *nacp) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdNoInRecvBuf(&a->s, nacp, sizeof(*nacp), 122);//GetApplicationControlProperty +} + +Result appletApplicationGetApplicationLaunchProperty(AppletApplication *a, AppletApplicationLaunchProperty *out) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdNoInRecvBuf(&a->s, out, sizeof(*out), 123);//GetApplicationLaunchProperty +} + +Result appletApplicationGetApplicationLaunchRequestInfo(AppletApplication *a, AppletApplicationLaunchRequestInfo *out) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&a->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 124; + + Result rc = serviceIpcDispatch(&a->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + AppletApplicationLaunchRequestInfo out; + } *resp; + + serviceIpcParse(&a->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && out) *out = resp->out; + } + + return rc; +} + +Result appletApplicationSetUsers(AppletApplication *a, const u128 *userIDs, s32 count, bool flag) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, userIDs, count*sizeof(u128), BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + u8 flag; + } *raw; + + raw = serviceIpcPrepareHeader(&a->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 130; + raw->flag = flag!=0; + + Result rc = serviceIpcDispatch(&a->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&a->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result appletApplicationCheckRightsEnvironmentAvailable(AppletApplication *a, bool *out) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + rc = _appletCmdNoInOutBool(&a->s, out, 131);//CheckRightsEnvironmentAvailable + + return rc; +} + +Result appletApplicationGetNsRightsEnvironmentHandle(AppletApplication *a, u64 *handle) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + rc = _appletCmdNoInOut64(&a->s, handle, 132);//GetNsRightsEnvironmentHandle + + return rc; +} + +Result appletApplicationGetDesirableUids(AppletApplication *a, u128 *userIDs, s32 count, s32 *total_out) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + + ipcAddRecvBuffer(&c, userIDs, count*sizeof(u128), BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&a->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 140; + + Result rc = serviceIpcDispatch(&a->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + s32 total_out; + } *resp; + + serviceIpcParse(&a->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && total_out) *total_out = resp->total_out; + } + + return rc; +} + +Result appletApplicationReportApplicationExitTimeout(AppletApplication *a) { + Result rc=0; + + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + rc = _appletCmdNoIO(&a->s, 150);//ReportApplicationExitTimeout + + return rc; +} + +Result appletApplicationSetApplicationAttribute(AppletApplication *a, const AppletApplicationAttribute *attr) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdSendBufNoOut(&a->s, attr, sizeof(*attr), 160);//SetApplicationAttribute +} + +Result appletApplicationHasSaveDataAccessPermission(AppletApplication *a, u64 titleID, bool *out) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 titleID; + } *raw; + + raw = serviceIpcPrepareHeader(&a->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 170; + raw->titleID = titleID; + + Result rc = serviceIpcDispatch(&a->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u8 out; + } *resp; + + serviceIpcParse(&a->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && out) *out = resp->out!=0; + } + + return rc; +} + // ILibraryAppletSelfAccessor Result appletPopInData(AppletStorage *s) { @@ -4330,37 +4832,7 @@ Result appletGetMainAppletApplicationControlProperty(NacpStruct *nacp) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - IpcCommand c; - ipcInitialize(&c); - - ipcAddRecvBuffer(&c, nacp, sizeof(*nacp), BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_appletILibraryAppletSelfAccessor, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 15; - - Result rc = serviceIpcDispatch(&g_appletILibraryAppletSelfAccessor); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_appletILibraryAppletSelfAccessor, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _appletCmdNoInRecvBuf(&g_appletILibraryAppletSelfAccessor, nacp, sizeof(*nacp), 15); } Result appletGetMainAppletStorageId(FsStorageId *storageId) { @@ -4787,6 +5259,10 @@ Result appletGetHomeButtonDoubleClickEnabled(bool *out) { // IDebugFunctions +Result appletOpenMainApplication(AppletApplication *a) { + return _appletApplicationCreate(a, &g_appletIDebugFunctions, 1); +} + Result appletPerformSystemButtonPressing(AppletSystemButtonType type) { return _appletCmdInU32(&g_appletIDebugFunctions, type, 10); }