// Startet die App nach einem Update selbst neu. // // CIA: aptSetChainloaderToSelf() - das System startet beim Beenden denselben Titel // (jetzt die neue Version) wieder. // 3DSX: Die App läuft im Homebrew-Titel von Luma (Rosalina). Über dessen Dienst "hb:ldr" // legen wir fest, welche .3dsx beim nächsten Start geladen wird - genau so macht es // auch der Homebrew Launcher. Danach den Homebrew-Titel neu starten lassen. #include <3ds.h> #include #include "relaunch.h" static Result hbldr_call(Handle h, u32 cmd, const void *buf, u32 size, int staticId) { u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(cmd, 0, 2); cmdbuf[1] = IPC_Desc_StaticBuffer(size, staticId); cmdbuf[2] = (u32)buf; Result rc = svcSendSyncRequest(h); return R_SUCCEEDED(rc) ? (Result)cmdbuf[1] : rc; } static bool set_homebrew_target(const char *selfPath) { Handle h; if (R_FAILED(svcConnectToPort(&h, "hb:ldr"))) return false; // hb:ldr erwartet den Pfad ohne "sdmc:" const char *path = strncmp(selfPath, "sdmc:/", 6) == 0 ? selfPath + 5 : selfPath; Result rc = hbldr_call(h, 2, path, strlen(path) + 1, 0); // SetTarget // argv wie beim Homebrew Launcher: u32 Anzahl, dann die Texte static u32 argBuf[0x400 / 4]; memset(argBuf, 0, sizeof(argBuf)); argBuf[0] = 1; strncpy((char *)&argBuf[1], selfPath, sizeof(argBuf) - 5); if (R_SUCCEEDED(rc)) rc = hbldr_call(h, 3, argBuf, sizeof(argBuf), 1); // SetArgv svcCloseHandle(h); return R_SUCCEEDED(rc); } bool relaunch_prepare(const char *selfPath) { if (envIsHomebrew() && !set_homebrew_target(selfPath)) return false; aptSetChainloaderToSelf(); return true; }