Files
AnyPS5/core/libs/tests/GuestErrorDialog.cpp
T
Phi1ow 7854fb6bff feat(errordialog): implement the libSceErrorDialog state machine
The six libSceErrorDialog exports were throwing stubs. They now implement the dialog's
NONE -> INITIALIZED -> RUNNING -> FINISHED state machine without a visible window, so a title
that opens an error dialog and waits for it never blocks:

- sceErrorDialogInitialize -> INITIALIZED, or 0x80ED0002 if already initialized
- sceErrorDialogOpen -> checks the state and the 16-byte parameter, then RUNNING
- sceErrorDialogUpdateStatus -> turns RUNNING into FINISHED and returns the status
- sceErrorDialogGetStatus -> returns the status
- sceErrorDialogClose -> FINISHED, or 0x80ED0005 when no dialog is running
- sceErrorDialogTerminate -> NONE, or 0x80ED0001 when not initialized

Re-opening is allowed once a previous dialog has finished. The status values and error codes
are the documented SCE error-dialog ones. Adds a CMakeLists.txt so the library can carry its
guest test.

New test core/libs/tests/GuestErrorDialog.cpp drives the whole state machine (the
not-initialized and already-initialized errors, the state and parameter checks of open,
open/update/close and re-open after finish). It fails on main (the stubs throw) and passes
with the change.
2026-10-04 22:33:43 +02:00

64 lines
2.0 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
extern "C" {
int APS5_VABI sceErrorDialogInitialize(void);
int APS5_VABI sceErrorDialogOpen(const void* param);
int APS5_VABI sceErrorDialogUpdateStatus(void);
int APS5_VABI sceErrorDialogGetStatus(void);
int APS5_VABI sceErrorDialogClose(void);
int APS5_VABI sceErrorDialogTerminate(void);
}
namespace {
void Require(bool value) { if (!value) std::abort(); }
constexpr int kStatusRunning = 2;
constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80ED0001);
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80ED0002);
constexpr int kErrParam = static_cast<int>(0x80ED0003);
constexpr int kErrInvalidState = static_cast<int>(0x80ED0005);
struct ErrorDialogParam {
std::int32_t size;
std::int32_t error_code;
std::int32_t user_id;
std::int32_t reserved;
};
}
int main() {
ErrorDialogParam param{16, static_cast<std::int32_t>(0x80020001), 0, 0};
Require(sceErrorDialogTerminate() == kErrNotInitialized);
Require(sceErrorDialogOpen(&param) == kErrInvalidState);
Require(sceErrorDialogInitialize() == 0);
Require(sceErrorDialogInitialize() == kErrAlreadyInitialized);
Require(sceErrorDialogClose() == kErrInvalidState);
Require(sceErrorDialogOpen(nullptr) == kErrParam);
ErrorDialogParam bad{8, 0, 0, 0};
Require(sceErrorDialogOpen(&bad) == kErrParam);
Require(sceErrorDialogOpen(&param) == 0);
Require(sceErrorDialogGetStatus() == kStatusRunning);
Require(sceErrorDialogOpen(&param) == kErrInvalidState);
Require(sceErrorDialogUpdateStatus() == kStatusFinished);
Require(sceErrorDialogGetStatus() == kStatusFinished);
Require(sceErrorDialogOpen(&param) == 0);
Require(sceErrorDialogGetStatus() == kStatusRunning);
Require(sceErrorDialogClose() == 0);
Require(sceErrorDialogGetStatus() == kStatusFinished);
Require(sceErrorDialogTerminate() == 0);
Require(sceErrorDialogTerminate() == kErrNotInitialized);
}