diff --git a/src/common/Logging.cpp b/src/common/Logging.cpp index f0544762e..35e800217 100644 --- a/src/common/Logging.cpp +++ b/src/common/Logging.cpp @@ -102,6 +102,8 @@ const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = { "XE ", }; std::atomic_int g_CurrentLogLevel = to_underlying(LOG_LEVEL::INFO); +std::atomic_bool g_CurrentLogPopupTestCase = true; +static bool g_disablePopupMessages = false; const char log_debug[] = "DEBUG: "; const char log_info[] = "INFO : "; @@ -111,7 +113,7 @@ const char log_fatal[] = "FATAL: "; const char log_unkwn[] = "???? : "; // Do not use EmuLogOutput function outside of this file. -void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, va_list argp) +void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, const va_list argp) { LOG_THREAD_INIT; @@ -146,6 +148,13 @@ void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarn fflush(stdout); } +inline void EmuLogOutputEx(const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const char *szWarningMessage, ...) +{ + va_list argp; + va_start(argp, szWarningMessage); + EmuLogOutput(cxbxr_module, level, szWarningMessage, argp); + va_end(argp); +} // print out a custom message to the console or kernel debug log file void NTAPI EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...) @@ -186,19 +195,21 @@ void NTAPI EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...) // Set up the logging variables for the GUI process inline void log_get_settings() { - log_set_config(g_Settings->m_core.LogLevel, g_Settings->m_core.LoggedModules); + log_set_config(g_Settings->m_core.LogLevel, g_Settings->m_core.LoggedModules, g_Settings->m_core.bLogPopupTestCase); } inline void log_sync_config() { int LogLevel; unsigned int LoggedModules[NUM_INTEGERS_LOG]; + bool LogPopupTestCase; g_EmuShared->GetLogLv(&LogLevel); g_EmuShared->GetLogModules(LoggedModules); - log_set_config(LogLevel, LoggedModules); + g_EmuShared->GetLogPopupTestCase(&LogPopupTestCase); + log_set_config(LogLevel, LoggedModules, LogPopupTestCase); } -void log_set_config(int LogLevel, unsigned int* LoggedModules) +void log_set_config(int LogLevel, unsigned int* LoggedModules, bool LogPopupTestCase) { g_CurrentLogLevel = LogLevel; for (unsigned int index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::MAX); index++) { @@ -209,6 +220,7 @@ void log_set_config(int LogLevel, unsigned int* LoggedModules) g_EnabledModules[index] = false; } } + g_CurrentLogPopupTestCase = LogPopupTestCase; } // Generate active log filter output. @@ -226,6 +238,106 @@ void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module) } } std::cout << std::flush; +} + +// Use kernel managed environment +void log_init_popup_msg() +{ + Settings::s_video vSettings; + g_EmuShared->GetVideoSettings(&vSettings); + g_disablePopupMessages = vSettings.bFullScreen; +} + +// TODO: Move PopupPlatformHandler into common GUI's window source code or use imgui in the future. +// PopupPlatformHandler is intended to be use as internal wrapper function. +static PopupReturn PopupPlatformHandler(const char* msg, const PopupReturn ret_default, const UINT uType, const HWND hWnd) +{ + int ret = MessageBox(hWnd, msg, /*lpCaption=*/TEXT("Cxbx-Reloaded"), uType); + + switch (ret) { + default: + case IDCANCEL: + return PopupReturn::Cancel; + case IDOK: + return PopupReturn::Ok; + case IDABORT: + return PopupReturn::Abort; + case IDRETRY: + return PopupReturn::Retry; + case IDIGNORE: + return PopupReturn::Ignore; + case IDYES: + return PopupReturn::Yes; + case IDNO: + return PopupReturn::No; + } +} + +PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const PopupIcon icon, const PopupButtons buttons, const PopupReturn ret_default, const char *message, ...) +{ + UINT uType = MB_TOPMOST | MB_SETFOREGROUND; + + // Make assert whenever the format string is null pointer which isn't allow in here. + assert(!message); + + switch (icon) { + case PopupIcon::Warning: { + uType |= MB_ICONWARNING; + break; + } + case PopupIcon::Error: { + uType |= MB_ICONERROR; // Note : MB_ICONERROR == MB_ICONSTOP == MB_ICONHAND + break; + } + case PopupIcon::Info: { + uType |= MB_ICONINFORMATION; + break; + } + case PopupIcon::Question: + case PopupIcon::Unknown: + default: { + uType |= MB_ICONQUESTION; + break; + } + } + + switch (buttons) { + default: + case PopupButtons::Ok: + uType |= MB_OK; + break; + case PopupButtons::OkCancel: + uType |= MB_OKCANCEL; + break; + case PopupButtons::AbortRetryIgnore: + uType |= MB_RETRYCANCEL; + break; + case PopupButtons::YesNoCancel: + uType |= MB_YESNOCANCEL; + break; + case PopupButtons::YesNo: + uType |= MB_YESNO; + break; + case PopupButtons::RetryCancel: + uType |= MB_RETRYCANCEL; + break; + } + + va_list argp; + va_start(argp, message); + // allocate predicted buffer size then write to buffer afterward. + std::vector Buffer(1+std::vsnprintf(nullptr, 0, message, argp)); + vsnprintf(Buffer.data(), Buffer.size(), message, argp); + va_end(argp); + + EmuLogOutputEx(cxbxr_module, level, "Popup : %s", Buffer); + + // If user is using exclusive fullscreen, we need to refrain all popups. + if (g_disablePopupMessages) { + return ret_default; + } + + return PopupPlatformHandler(Buffer.data(), ret_default, uType, (const HWND)hwnd); } const bool needs_escape(const wint_t _char) diff --git a/src/common/Logging.h b/src/common/Logging.h index d733937e8..99c833641 100644 --- a/src/common/Logging.h +++ b/src/common/Logging.h @@ -116,6 +116,7 @@ typedef enum class _CXBXR_MODULE: unsigned int { extern std::atomic_bool g_EnabledModules[to_underlying(CXBXR_MODULE::MAX)]; extern const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)]; extern std::atomic_int g_CurrentLogLevel; +extern std::atomic_bool g_CurrentLogPopupTestCase; // print out a log message to the console or kernel debug log file if level is high enough void NTAPI EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...); @@ -127,9 +128,78 @@ extern inline void log_get_settings(); extern inline void log_sync_config(); -void log_set_config(int LogLevel, unsigned int* LoggedModules); +void log_set_config(int LogLevel, unsigned int* LoggedModules, bool LogPopupTestCase); void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module); + +// Use emulation environment to manage popup messages +// If log_init_popup_msg is not called at earliest point of emulation. +// Then users will have a chance of popup message appear during start of emulation in full screen. +void log_init_popup_msg(); + +typedef enum class _PopupIcon { + Unknown = 0, + Question, + Info, + Warning, + Error +} PopupIcon; + +typedef enum class _PopupButtons { + Unknown = 0, + Ok, + OkCancel, + AbortRetryIgnore, + YesNoCancel, + YesNo, + RetryCancel +} PopupButtons; + +typedef enum class _PopupReturn { + Unknown = 0, + Ok, + Cancel, + Abort, + Retry, + Ignore, + Yes, + No +} PopupReturn; + +PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const PopupIcon icon, const PopupButtons buttons, const PopupReturn ret_default, const char* message, ...); + +#define PopupCustom(hwnd, level, icon, buttons, ret_default, fmt, ...) PopupCustomEx(hwnd, LOG_PREFIX, level, icon, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupQuestionEx(hwnd, level, buttons, ret_default, fmt, ...) PopupCustom(hwnd, level, PopupIcon::Question, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupQuestion(hwnd, fmt, ...) PopupQuestionEx(hwnd, LOG_LEVEL::INFO, PopupButtons::YesNoCancel, PopupReturn::Cancel, fmt, ## __VA_ARGS__) +#define PopupInfoEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::INFO, PopupIcon::Info, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupInfo(hwnd, fmt, ...) (void)PopupInfoEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__) +#define PopupWarningEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::WARNING, PopupIcon::Warning, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupWarning(hwnd, fmt, ...) (void)PopupWarningEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__) +#define PopupErrorEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::ERROR2, PopupIcon::Error, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupError(hwnd, fmt, ...) (void)PopupErrorEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__) +#define PopupFatalEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::FATAL, PopupIcon::Error, buttons, ret_default, fmt, ## __VA_ARGS__) +#define PopupFatal(hwnd, fmt, ...) (void)PopupFatalEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__) + +// For LOG_TEST_CASE +extern inline void EmuLogOutputEx(const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const char *szWarningMessage, ...); + +// The reason of having EmuLogOutputEx in LOG_TEST_CASE is to allow dump to log directly for any test cases triggered. +// Which will make developers easier to note which applications has triggered quicker, easier, and doesn't require any individual log enabled to capture them. +#define LOG_TEST_CASE(message) do { \ + static bool bTestCaseLogged = false; \ + if (bTestCaseLogged) break; \ + bTestCaseLogged = true; \ + if (g_CurrentLogPopupTestCase) { \ + LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \ + PopupInfo(nullptr, "Please report that %s shows the following message:\nLOG_TEST_CASE: %s\nIn %s (%s line %d)", \ + CxbxKrnl_Xbe->m_szAsciiTitle, message, __func__, __FILE__, __LINE__); \ + continue; \ + } \ + } \ + EmuLogOutputEx(LOG_PREFIX, LOG_LEVEL::INFO, "Please report that %s shows the following message:\nLOG_TEST_CASE: %s\nIn %s (%s line %d)", \ + CxbxKrnl_Xbe->m_szAsciiTitle, message, __func__, __FILE__, __LINE__); \ +} while (0) +// was g_pCertificate->wszTitleName // // __FILENAME__ diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index f0c986a2c..819f2d278 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -27,6 +27,8 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::CXBXR + #include "Settings.hpp" #include "core\kernel\support\Emu.h" #include "EmuShared.h" @@ -93,6 +95,7 @@ static struct { const char* LoggedModules = "LoggedModules"; const char* LogLevel = "LogLevel"; const char* LoaderExecutable = "LoaderExecutable"; + const char* LogPopupTestCase = "LogPopupTestCase"; } sect_core_keys; static const char* section_video = "video"; @@ -220,7 +223,7 @@ bool Settings::Init() bRet = LoadConfig(); if (!bRet) { - MessageBox(nullptr, szSettings_setup_error, "Cxbx-Reloaded", MB_OK); + PopupError(nullptr, szSettings_setup_error); return false; } @@ -355,6 +358,7 @@ bool Settings::LoadConfig() m_core.LoggedModules[index] = 0; index++; } + m_core.bLogPopupTestCase = m_si.GetBoolValue(section_core, sect_core_keys.LogPopupTestCase, /*Default=*/true); m_core.bUseLoaderExec = m_si.GetBoolValue(section_core, sect_core_keys.LoaderExecutable, /*Default=*/true); @@ -534,6 +538,7 @@ bool Settings::Save(std::string file_path) stream << "0x" << std::hex << m_core.LoggedModules[i]; m_si.SetValue(section_core, sect_core_keys.LoggedModules, stream.str().c_str(), nullptr, false); } + m_si.SetBoolValue(section_core, sect_core_keys.LogPopupTestCase, m_core.bLogPopupTestCase, nullptr, true); m_si.SetBoolValue(section_core, sect_core_keys.LoaderExecutable, m_core.bUseLoaderExec, nullptr, true); @@ -831,13 +836,13 @@ CXBX_DATA Settings::SetupFile(std::string& file_path_out) setupFile = GenerateExecDirectoryStr(); #else // Only support for Qt compile build. - int iRet = MessageBox(nullptr, szSettings_save_user_option_message, "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONQUESTION); + PopupReturn eRet = PopupQuestion(nullptr, szSettings_save_user_option_message); - if (iRet == IDYES) { + if (eRet == PopupReturn::Yes) { setupFile = GenerateExecDirectoryStr(); data_ret = CXBX_DATA_EXECDIR; } - else if (iRet == IDNO) { + else if (eRet == PopupReturn::No) { setupFile = GenerateUserProfileDirectoryStr(); data_ret = CXBX_DATA_APPDATA; if (setupFile.size() != 0) { @@ -854,7 +859,7 @@ CXBX_DATA Settings::SetupFile(std::string& file_path_out) #endif if (data_ret == CXBX_DATA_INVALID) { - MessageBox(nullptr, szSettings_setup_error, "Cxbx-Reloaded", MB_OK); + PopupError(nullptr, szSettings_setup_error); } else { setupFile.append(szSettings_settings_file); diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index b009d2768..cac692f16 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -102,7 +102,7 @@ public: int LogLevel = 1; bool bUseLoaderExec; bool allowAdminPrivilege; - bool Reserved3 = 0; + bool bLogPopupTestCase; bool Reserved4 = 0; int Reserved99[10] = { 0 }; } m_core; diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 80326f010..c877cd9a2 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -25,10 +25,13 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::GUI + #include "InputWindow.h" #include "gui/resource/ResCxbx.h" #include "common\IPCHybrid.hpp" #include "EmuShared.h" +#include "Logging.h" #include #define INPUT_TIMEOUT 5000 @@ -108,10 +111,10 @@ InputWindow::~InputWindow() bool InputWindow::IsProfileSaved() { if (m_bHasChanges) { - int ret = MessageBox(m_hwnd_window, "Current configuration is not saved. Save before closing?", "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONWARNING | MB_APPLMODAL); + PopupReturn ret = PopupQuestion(m_hwnd_window, "Current configuration is not saved. Save before closing?"); switch (ret) { - case IDYES: { + case PopupReturn::Yes: { char name[50]; SendMessage(m_hwnd_profile_list, WM_GETTEXT, sizeof(name), reinterpret_cast(name)); if (SaveProfile(std::string(name))) { @@ -120,11 +123,11 @@ bool InputWindow::IsProfileSaved() return false; } - case IDNO: { + case PopupReturn::No: { return true; } - case IDCANCEL: + case PopupReturn::Cancel: default: { return false; } @@ -342,11 +345,11 @@ void InputWindow::LoadProfile(const std::string& name) bool InputWindow::SaveProfile(const std::string& name) { if (name == std::string()) { - MessageBox(m_hwnd_window, "Cannot save. Profile name must not be empty", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL); + PopupError(m_hwnd_window, "Cannot save. Profile name must not be empty."); return false; } if (m_host_dev == std::string()) { - MessageBox(m_hwnd_window, "Cannot save. No input devices detected", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL); + PopupError(m_hwnd_window, "Cannot save. No input devices detected", "Cxbx-Reloaded"); return false; } OverwriteProfile(name); diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index a49f4dd2a..1758492f6 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -224,6 +224,12 @@ class EmuShared : public Mutex Unlock(); } + // ****************************************************************** + // * Log Level value Accessors + // ****************************************************************** + void GetLogPopupTestCase(bool *value) { Lock(); *value = m_core.bLogPopupTestCase; Unlock(); } + void SetLogPopupTestCase(const bool value) { Lock(); m_core.bLogPopupTestCase = value; Unlock(); } + // ****************************************************************** // * File storage location // ****************************************************************** diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index b522a5d34..934e4497b 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -600,7 +600,7 @@ VOID CxbxInitWindow(bool bFullInit) if (hRenderWindowThread == NULL) { char szBuffer[1024] = { 0 }; sprintf(szBuffer, "Creating EmuRenderWindowThread Failed: %08X", GetLastError()); - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, szBuffer); + PopupFatal(nullptr, szBuffer); EmuShared::Cleanup(); ExitProcess(0); } diff --git a/src/core/hle/Intercept.cpp b/src/core/hle/Intercept.cpp index 595f13045..05386e524 100644 --- a/src/core/hle/Intercept.cpp +++ b/src/core/hle/Intercept.cpp @@ -147,7 +147,7 @@ bool VerifySymbolAddressAgainstXRef(char *SymbolName, xbaddr Address, int XRef) return true; } - CxbxPopupMessage(LOG_LEVEL::WARNING, CxbxMsgDlgIcon_Warn, + PopupCustom(LOG_LEVEL::WARNING, CxbxMsgDlgIcon_Warn, "Verification of %s failed : XREF was 0x%.8X while lookup gave 0x%.8X", SymbolName, XRefAddr, Address); // test case : Kabuki Warriors (for XREF_D3DTSS_TEXCOORDINDEX) return false; diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 9a923360c..ef865ee7f 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -1188,7 +1188,7 @@ DWORD WINAPI XTL::EMUPATCH(XLaunchNewImageA) if (PathFileExists(szDashboardPath)) { - (void)CxbxMessageBox("The title is rebooting to dashboard", MB_OK, CxbxKrnl_hEmuParent); + PopupInfo(nullptr, "The title is rebooting to dashboard"); lpTitlePath = "C:\\xboxdash.xbe"; xboxkrnl::LaunchDataPage->Header.dwLaunchDataType = LDT_FROM_DASHBOARD; // Other options include LDT_NONE, LDT_FROM_DEBUGGER_CMDLINE and LDT_FROM_UPDATE diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index 9a129c1f8..d1a204123 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -613,7 +613,7 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur retryAttempt++; // Terminate after 5 seconds of failure. if (retryAttempt >= (5 * (1000 / 100))) { - CxbxShowError("Could not reboot, new emulation process did not take over."); + PopupError(nullptr, "Could not reboot, new emulation process did not take over."); break; } } diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index a0bf86782..fb133c8cf 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -243,7 +243,7 @@ XBSYSAPI EXPORTNUM(264) xboxkrnl::VOID NTAPI xboxkrnl::RtlAssert ss << ")"; - CxbxPopupMessage(LOG_LEVEL::WARNING, CxbxMsgDlgIcon_Warn, ss.str().c_str()); + PopupWarning(nullptr, ss.str().c_str()); } // ****************************************************************** diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 27c5fc560..8e9a4f94a 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -276,53 +276,6 @@ std::string CxbxGetLastErrorString(char * lpszFunction) #pragma optimize("", off) -int CxbxMessageBox(const char* msg, UINT uType, HWND hWnd) -{ - return MessageBox(hWnd, msg, /*lpCaption=*/TEXT("Cxbx-Reloaded"), uType); -} - -void CxbxShowError(const char* msg, HWND hWnd) -{ - const UINT uType = MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_ICONERROR; // Note : MB_ICONERROR == MB_ICONSTOP == MB_ICONHAND - - (void)CxbxMessageBox(msg, uType, hWnd); -} - -void CxbxPopupMessageEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, CxbxMsgDlgIcon icon, const char *message, ...) -{ - char Buffer[1024]; - va_list argp; - UINT uType = MB_OK | MB_TOPMOST | MB_SETFOREGROUND; - - switch (icon) { - case CxbxMsgDlgIcon_Warn: { - uType |= MB_ICONWARNING; - break; - } - case CxbxMsgDlgIcon_Error: { - uType |= MB_ICONERROR; - break; - } - case CxbxMsgDlgIcon_Info: { - uType |= MB_ICONINFORMATION; - break; - } - case CxbxMsgDlgIcon_Unknown: - default: { - uType |= MB_ICONQUESTION; - break; - } - } - - va_start(argp, message); - vsprintf(Buffer, message, argp); - va_end(argp); - - EmuLogEx(cxbxr_module, level, "Popup : %s", Buffer); - - (void)CxbxMessageBox(Buffer, uType); -} - void PrintCurrentConfigurationLog() { if (g_bIsWine) { @@ -669,7 +622,7 @@ bool CreateSettings() { g_Settings = new Settings(); if (g_Settings == nullptr) { - CxbxShowError(szSettings_alloc_error); + PopupError(nullptr, szSettings_alloc_error); return false; } @@ -694,10 +647,11 @@ bool HandleFirstLaunch() bool bElevated = CxbxIsElevated(); if (bElevated && !g_Settings->m_core.allowAdminPrivilege) { - int ret = CxbxMessageBox("Cxbx-Reloaded has detected that it has been launched with Administrator rights.\n" + PopupReturn ret = PopupWarningEx(nullptr, PopupButtons::YesNo, PopupReturn::No, + "Cxbx-Reloaded has detected that it has been launched with Administrator rights.\n" "\nThis is dangerous, as a maliciously modified Xbox titles could take control of your system.\n" - "\nAre you sure you want to continue?", MB_YESNO | MB_ICONWARNING); - if (ret != IDYES) { + "\nAre you sure you want to continue?"); + if (ret != PopupReturn::Yes) { return false; } } @@ -733,6 +687,9 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res //g_EmuShared->SetIsReady(true); } + /* Initialize popup message management from kernel side. */ + log_init_popup_msg(); + /* Initialize Cxbx File Paths */ CxbxInitFilePaths(); @@ -793,9 +750,9 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } if (!isReady) { EmuLog(LOG_LEVEL::WARNING, "GUI process is not ready!"); - int mbRet = CxbxMessageBox("GUI process is not ready, do you wish to retry?", - MB_ICONWARNING | MB_RETRYCANCEL | MB_TOPMOST | MB_SETFOREGROUND); - if (mbRet == IDRETRY) { + PopupReturn mbRet = PopupWarningEx(nullptr, PopupButtons::RetryCancel, PopupReturn::Cancel, + "GUI process is not ready, do you wish to retry?"); + if (mbRet == PopupReturn::Retry) { continue; } CxbxKrnlShutDown(); @@ -924,7 +881,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res // verify base of code of our executable is 0x00001000 if (ExeNtHeader->OptionalHeader.BaseOfCode != CXBX_BASE_OF_CODE) { - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, "Cxbx-Reloaded executuable requires it's base of code to be 0x00001000"); + PopupFatal(nullptr, "Cxbx-Reloaded executuable requires it's base of code to be 0x00001000"); return; // TODO : Halt(0); } @@ -932,7 +889,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res // verify virtual_memory_placeholder is located at 0x00011000 if ((UINT_PTR)(&(virtual_memory_placeholder[0])) != (XBE_IMAGE_BASE + CXBX_BASE_OF_CODE)) { - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, "virtual_memory_placeholder is not loaded to base address 0x00011000 (which is a requirement for Xbox emulation)"); + PopupFatal(nullptr, "virtual_memory_placeholder is not loaded to base address 0x00011000 (which is a requirement for Xbox emulation)"); return; // TODO : Halt(0); } #endif @@ -991,7 +948,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res EEPROM = CxbxRestoreEEPROM(szFilePath_EEPROM_bin); if (EEPROM == nullptr) { - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, "Couldn't init EEPROM!"); + PopupFatal(nullptr, "Couldn't init EEPROM!"); return; // TODO : Halt(0); } @@ -1306,7 +1263,7 @@ __declspec(noreturn) void CxbxKrnlInit // Initialize time-related variables for the kernel and the timers CxbxInitPerformanceCounters(); #ifdef _DEBUG -// CxbxPopupMessage(LOG_LEVEL::INFO, "Attach a Debugger"); +// PopupCustom(LOG_LEVEL::INFO, "Attach a Debugger"); // Debug child processes using https://marketplace.visualstudio.com/items?itemName=GreggMiskelly.MicrosoftChildProcessDebuggingPowerTool #endif @@ -1650,7 +1607,7 @@ bool CxbxLockFilePath() } if (GetLastError() == ERROR_ALREADY_EXISTS) { - CxbxShowError("Data path directory is currently in used.\nUse different data path directory or stop emulation from another process."); + PopupError(nullptr, "Data path directory is currently in used.\nUse different data path directory or stop emulation from another process."); CloseHandle(hMapDataHash); return false; } @@ -1694,7 +1651,7 @@ __declspec(noreturn) void CxbxKrnlCleanupEx(CXBXR_MODULE cxbxr_module, const cha vsprintf(szBuffer2, szErrorMessage, argp); va_end(argp); - CxbxPopupMessageEx(cxbxr_module, LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, "Received Fatal Message:\n\n* %s\n", szBuffer2); // Will also EmuLogEx + (void)PopupCustomEx(nullptr, cxbxr_module, LOG_LEVEL::FATAL, PopupIcon::Error, PopupButtons::Ok, PopupReturn::Ok, "Received Fatal Message:\n\n* %s\n", szBuffer2); // Will also EmuLogEx } EmuLogInit(LOG_LEVEL::INFO, "MAIN: Terminating Process"); @@ -1897,12 +1854,12 @@ void CxbxPrintUEMInfo(ULONG ErrorCode) auto it = UEMErrorTable.find(ErrorCode); if (it != UEMErrorTable.end()) { - std::string ErrorMessage = "Fatal error. " + it->second + ". This error screen will persist indefinitely. Stop the emulation to close it"; - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, ErrorMessage.c_str()); + std::string ErrorMessage = "Fatal error. " + it->second + ". This error screen will persist indefinitely. Stop the emulation to close it."; + PopupFatal(nullptr, ErrorMessage.c_str()); } else { - CxbxPopupMessage(LOG_LEVEL::FATAL, CxbxMsgDlgIcon_Error, "Unknown fatal error. This error screen will persist indefinitely. Stop the emulation to close it"); + PopupFatal(nullptr, "Unknown fatal error. This error screen will persist indefinitely. Stop the emulation to close it."); } } diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index 36b6c25ab..0031cead7 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -135,28 +135,6 @@ extern "C" { #define XBOX_MEM_NOZERO 0x800000 // Replaces MEM_ROTATE on WinXP+ #define XBOX_MEM_IMAGE 0x1000000 // ? -typedef enum _CxbxMsgDlgIcon { - CxbxMsgDlgIcon_Info=0, - CxbxMsgDlgIcon_Warn, - CxbxMsgDlgIcon_Error, - CxbxMsgDlgIcon_Unknown -} CxbxMsgDlgIcon; - -int CxbxMessageBox(const char* msg, UINT uType = MB_OK, HWND hWnd = NULL); - -void CxbxShowError(const char* msg, HWND hWnd = NULL); - -void CxbxPopupMessageEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, CxbxMsgDlgIcon icon, const char *message, ...); - -#define CxbxPopupMessage(level, icon, fmt, ...) CxbxPopupMessageEx(LOG_PREFIX, level, icon, fmt, ##__VA_ARGS__) - -#define LOG_TEST_CASE(message) do { static bool bTestCaseLogged = false; \ - if (!bTestCaseLogged) { bTestCaseLogged = true; \ - LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \ - CxbxPopupMessage(LOG_LEVEL::INFO, CxbxMsgDlgIcon_Info, "Please report that %s shows the following message:\nLOG_TEST_CASE: %s\nIn %s (%s line %d)", \ - CxbxKrnl_Xbe->m_szAsciiTitle, message, __func__, __FILE__, __LINE__); } } } while (0) -// was g_pCertificate->wszTitleName - extern Xbe::Certificate *g_pCertificate; /*! validate version string match */ diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index 1a6b9a0df..4ecbbeaa6 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -25,6 +25,8 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::X86 + // prevent name collisions namespace xboxkrnl { @@ -170,12 +172,12 @@ bool EmuExceptionBreakpointAsk(LPEXCEPTION_POINTERS e) " Press Ignore to continue emulation.", EIPToString(e->ContextRecord->Eip).c_str()); - int ret = CxbxMessageBox(buffer, MB_ICONSTOP | MB_ABORTRETRYIGNORE, g_hEmuWindow); - if (ret == IDABORT) + PopupReturn ret = PopupWarningEx(g_hEmuWindow, PopupButtons::AbortRetryIgnore, PopupReturn::Ignore, buffer); + if (ret == PopupReturn::Abort) { EmuExceptionExitProcess(); } - else if (ret == IDIGNORE) + else if (ret == PopupReturn::Ignore) { printf("[0x%.4X] MAIN: Ignored Breakpoint Exception\n", GetCurrentThreadId()); fflush(stdout); @@ -201,7 +203,7 @@ void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e) " Press \"Cancel\" to debug.", e->ExceptionRecord->ExceptionCode, EIPToString(e->ContextRecord->Eip).c_str()); - if (CxbxMessageBox(buffer, MB_ICONSTOP | MB_OKCANCEL, g_hEmuWindow) == IDOK) + if (PopupFatalEx(nullptr, PopupButtons::OkCancel, PopupReturn::Ok, buffer) == PopupReturn::Ok) { EmuExceptionExitProcess(); } @@ -366,13 +368,13 @@ int ExitException(LPEXCEPTION_POINTERS e) fflush(stdout); - (void)CxbxMessageBox("Warning: Could not safely terminate process!", MB_OK, g_hEmuWindow); + PopupFatal(nullptr, "Warning: Could not safely terminate process!"); count++; if(count > 1) { - (void)CxbxMessageBox("Warning: Multiple Problems!", MB_OK, g_hEmuWindow); + PopupFatal(nullptr, "Warning: Multiple Problems!"); return EXCEPTION_CONTINUE_SEARCH; } diff --git a/src/emulator/cxbxr-emu.cpp b/src/emulator/cxbxr-emu.cpp index 5dbeb7c18..70c68a631 100644 --- a/src/emulator/cxbxr-emu.cpp +++ b/src/emulator/cxbxr-emu.cpp @@ -27,6 +27,8 @@ // cxbxr-emu.cpp : Defines the exported functions for the DLL application. +#define LOG_PREFIX CXBXR_MODULE::CXBXR + #include "Cxbx.h" // For FUNC_EXPORTS #include "VerifyAddressRanges.h" // For VerifyBaseAddr() //#include "CxbxKrnl/Emu.h" @@ -128,25 +130,25 @@ DWORD WINAPI Emulate(unsigned int reserved_systems, blocks_reserved_t blocks_res /*! Verify our host executable, cxbxr-ldr.exe, is loaded to base address 0x00010000 */ if (!VerifyBaseAddr()) { - CxbxShowError("cxbx-ldr.exe was not loaded to base address 0x00010000 (which is a requirement for Xbox emulation)"); + PopupError(nullptr, "cxbx-ldr.exe was not loaded to base address 0x00010000 (which is a requirement for Xbox emulation)"); return EXIT_FAILURE; } LPSTR CommandLine = GetCommandLine(); if (!CommandLine) { - CxbxShowError("Couldn't retrieve command line!"); + PopupError(nullptr, "Couldn't retrieve command line!"); return EXIT_FAILURE; } int argc = 0; PCHAR *argv = CommandLineToArgvA(CommandLine, &argc); if (!argv) { - CxbxShowError("Couldn't parse command line!"); + PopupError(nullptr, "Couldn't parse command line!"); return EXIT_FAILURE; } if (!cli_config::GenConfig(argv, argc)) { - CxbxShowError("Couldn't convert parsed command line!"); + PopupError(nullptr, "Couldn't convert parsed command line!"); LocalFree(argv); return EXIT_FAILURE; } @@ -154,24 +156,24 @@ DWORD WINAPI Emulate(unsigned int reserved_systems, blocks_reserved_t blocks_res /*! verify load argument is included */ if (!cli_config::hasKey("load")) { - CxbxShowError("No /load argument in command line!"); + PopupError(nullptr, "No /load argument in command line!"); return EXIT_FAILURE; } /*! initialize shared memory */ if (!EmuShared::Init(cli_config::GetSessionID())) { - CxbxShowError("Could not map shared memory!"); + PopupError(nullptr, "Could not map shared memory!"); return EXIT_FAILURE; } if (!HandleFirstLaunch()) { - CxbxShowError("First launch failed!"); + PopupError(nullptr, "First launch failed!"); EmuShared::Cleanup(); return EXIT_FAILURE; } if (!reserved_systems) { - CxbxShowError("Unable to preserve any system's memory ranges!"); + PopupError(nullptr, "Unable to preserve any system's memory ranges!"); EmuShared::Cleanup(); return EXIT_FAILURE; } diff --git a/src/gui/DlgAudioConfig.cpp b/src/gui/DlgAudioConfig.cpp index d8a7f1171..a6aeb5b60 100644 --- a/src/gui/DlgAudioConfig.cpp +++ b/src/gui/DlgAudioConfig.cpp @@ -25,7 +25,10 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::GUI + #include "common\Settings.hpp" // for g_Settings +#include "common/Logging.h" #include "DlgAudioConfig.h" #include "resource/ResCxbx.h" @@ -123,14 +126,14 @@ INT_PTR CALLBACK DlgAudioConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR /*! if changes have been made, check if the user wants to save them */ if(g_bHasChanges) { - int ret = MessageBox(hWndDlg, "Do you wish to apply your changes?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNOCANCEL); + PopupReturn ret = PopupQuestion(hWndDlg, "Do you wish to apply your changes?"); switch(ret) { - case IDYES: + case PopupReturn::Yes: PostMessage(hWndDlg, WM_COMMAND, IDC_AC_ACCEPT, 0); break; - case IDNO: + case PopupReturn::No: PostMessage(hWndDlg, WM_COMMAND, IDC_AC_CANCEL, 0); break; } @@ -226,8 +229,7 @@ VOID RefreshAudioAdapter() if (pGUID == (LPGUID)CB_ERR) { SendMessage(g_hAudioAdapter, CB_SETCURSEL, 0, 0); g_Settings->m_audio = g_XBAudio; - MessageBox(nullptr, "Your selected audio adapter is invalid,\n" - "reverting to default audio adapter.", "Cxbx-Reloaded", MB_OK | MB_ICONEXCLAMATION); + PopupWarning(nullptr, "Your selected audio adapter is invalid,\nreverting to default audio adapter."); } } } diff --git a/src/gui/DlgDukeControllerConfig.cpp b/src/gui/DlgDukeControllerConfig.cpp index 65eb9ac47..ce40c1ca7 100644 --- a/src/gui/DlgDukeControllerConfig.cpp +++ b/src/gui/DlgDukeControllerConfig.cpp @@ -25,10 +25,13 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::GUI + #include "Windows.h" #include "resource/ResCxbx.h" #include "input\InputWindow.h" #include "gui\DlgInputConfig.h" +#include "common/Logging.h" static INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -108,7 +111,7 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar case IDC_XID_CLEAR: { if (HIWORD(wParam) == BN_CLICKED) { - if (MessageBox(hWndDlg, "Remove all button bindings. Ok?", "Cxbx-Reloaded", MB_OKCANCEL | MB_ICONINFORMATION | MB_APPLMODAL) == IDOK) { + if (PopupQuestionEx(hWndDlg, LOG_LEVEL::WARNING, PopupButtons::YesNo, PopupReturn::No, "Are you sure you want to remove all button bindings?") == PopupReturn::Yes) { g_InputWindow->ClearBindings(); } } diff --git a/src/gui/DlgEepromConfig.cpp b/src/gui/DlgEepromConfig.cpp index 96013edb4..cb7c27fc9 100644 --- a/src/gui/DlgEepromConfig.cpp +++ b/src/gui/DlgEepromConfig.cpp @@ -25,12 +25,15 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::GUI + #include #include // For memcpy #include "EmuEEPROM.h" // For EEPROMInfo, EEPROMInfos #include "core\kernel\init\CxbxKrnl.h" #include "DlgEepromConfig.h" #include "resource/ResCxbx.h" +#include "common/Logging.h" #include @@ -208,7 +211,7 @@ void ShowEepromConfig(HWND hwnd) EepromFile.close(); } else { - MessageBox(hwnd, "Couldn't open eeprom file!", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupWarning(hwnd, "Couldn't open eeprom file!"); return; } } @@ -456,7 +459,7 @@ INT_PTR CALLBACK DlgEepromConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPA EepromFile.close(); } else { - MessageBox(hWndDlg, "Couldn't write eeprom file to disk!", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupWarning(hWndDlg, "Couldn't write eeprom file to disk!"); } } PostMessage(hWndDlg, WM_COMMAND, IDC_EE_CANCEL, 0); diff --git a/src/gui/DlgLoggingConfig.cpp b/src/gui/DlgLoggingConfig.cpp index 233b7577d..0d09a036f 100644 --- a/src/gui/DlgLoggingConfig.cpp +++ b/src/gui/DlgLoggingConfig.cpp @@ -121,6 +121,7 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM int TempLevel; unsigned int LoggedModules[NUM_INTEGERS_LOG]; int LogLevel; + bool LogPopupTestCase; // Set window icon SetClassLong(hWndDlg, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX))); @@ -128,6 +129,7 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM LoggedModules[0] = g_Settings->m_core.LoggedModules[0]; LoggedModules[1] = g_Settings->m_core.LoggedModules[1]; LogLevel = g_Settings->m_core.LogLevel; + LogPopupTestCase = g_Settings->m_core.bLogPopupTestCase; hHandle = GetDlgItem(hWndDlg, IDC_EVENT_LV); TempLevel = to_underlying(LOG_LEVEL::DEBUG); @@ -144,6 +146,10 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM } } + if (LogPopupTestCase) { + (void)SendMessage(GetDlgItem(hWndDlg, IDC_LOG_POPUP_TESTCASE), BM_SETCHECK, BST_CHECKED, 0); + } + counter = 0; for (index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::KRNL); index++) { if (LoggedModules[index / 32] & (1 << (index % 32))) { @@ -233,12 +239,18 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM } } + bool LogPopupTestCase = false; + if (SendMessage(GetDlgItem(hWndDlg, IDC_LOG_POPUP_TESTCASE), BM_GETCHECK, 0, 0) == BST_CHECKED) { + LogPopupTestCase = true; + } + g_Settings->m_core.LoggedModules[0] = LoggedModules[0]; g_Settings->m_core.LoggedModules[1] = LoggedModules[1]; g_Settings->m_core.LogLevel = LogLevel; + g_Settings->m_core.bLogPopupTestCase = LogPopupTestCase; // Update the logging variables for the GUI process - log_set_config(LogLevel, LoggedModules); + log_set_config(LogLevel, LoggedModules, LogPopupTestCase); log_generate_active_filter_output(CXBXR_MODULE::GUI); // Also inform the kernel process if it exists @@ -246,6 +258,7 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM // Sync updated log to kernel process to use run-time settings. g_EmuShared->SetLogLv(&LogLevel); g_EmuShared->SetLogModules(LoggedModules); + g_EmuShared->SetLogPopupTestCase(LogPopupTestCase); ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_LOGGING_SYNC, 0, reinterpret_cast(g_ChildWnd)); } } @@ -259,6 +272,12 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM } break; + case IDC_LOG_POPUP_TESTCASE: + if (HIWORD(wParam) == BN_CLICKED) { + g_bHasChanges = true; + } + break; + case IDC_LOG_ENABLE_GENERAL: { if (HIWORD(wParam) == BN_CLICKED) { for (index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::KRNL); diff --git a/src/gui/DlgVideoConfig.cpp b/src/gui/DlgVideoConfig.cpp index 0ca7b1e2c..8d61f4714 100644 --- a/src/gui/DlgVideoConfig.cpp +++ b/src/gui/DlgVideoConfig.cpp @@ -25,6 +25,8 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::GUI + // Without this, you'll get a ton of errors from the std library for some unknown reason... #include "Logging.h" @@ -159,14 +161,14 @@ INT_PTR CALLBACK DlgVideoConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR /*! if changes have been made, check if the user wants to save them */ if(g_bHasChanges) { - int ret = MessageBox(hWndDlg, "Do you wish to apply your changes?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNOCANCEL); + PopupReturn ret = PopupQuestion(hWndDlg, "Do you wish to apply your changes?"); switch(ret) { - case IDYES: + case PopupReturn::Yes: PostMessage(hWndDlg, WM_COMMAND, IDC_VC_ACCEPT, 0); break; - case IDNO: + case PopupReturn::No: PostMessage(hWndDlg, WM_COMMAND, IDC_VC_CANCEL, 0); break; } diff --git a/src/gui/WinMain.cpp b/src/gui/WinMain.cpp index 9fe266c6b..49c0835e7 100644 --- a/src/gui/WinMain.cpp +++ b/src/gui/WinMain.cpp @@ -25,6 +25,8 @@ // * // ****************************************************************** +#define LOG_PREFIX CXBXR_MODULE::CXBXR + #include "WndMain.h" #include "AddressRanges.h" // For VerifyWow64() @@ -52,26 +54,26 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // First detect if we are running on WoW64, if not, prevent Cxbx-Reloaded from starting // Cxbx-Reloaded needs access to high memory, only exposed to WoW64. if (!VerifyWow64()) { - CxbxShowError("Cxbx-Reloaded can only run under WoW64\nThis means either a 64-bit version of Windows or Wine with a 64-bit prefix"); + PopupError(nullptr, "Cxbx-Reloaded can only run under WoW64\nThis means either a 64-bit version of Windows or Wine with a 64-bit prefix"); return EXIT_FAILURE; } #ifndef CXBXR_EMU /*! verify Cxbx.exe is loaded to base address 0x00010000 */ if (!VerifyBaseAddr()) { - CxbxShowError("Cxbx.exe is not loaded to base address 0x00010000 (which is a requirement for Xbox emulation)"); + PopupError(nullptr, "Cxbx.exe is not loaded to base address 0x00010000 (which is a requirement for Xbox emulation)"); return EXIT_FAILURE; } #endif if (!cli_config::GenConfig(__argv, __argc)) { - CxbxShowError("Couldn't convert parsed command line!"); + PopupError(nullptr, "Couldn't convert parsed command line!"); return EXIT_FAILURE; } /*! initialize shared memory */ if (!EmuShared::Init(cli_config::GetSessionID())) { - CxbxShowError("Could not map shared memory!"); + PopupError(nullptr, "Could not map shared memory!"); return EXIT_FAILURE; } @@ -86,7 +88,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine EmuShared::Cleanup(); return EXIT_SUCCESS; #else - CxbxShowError("Emulation must be launched from cxbxr-ldr.exe!"); + PopupError(nullptr, "Emulation must be launched from cxbxr-ldr.exe!"); EmuShared::Cleanup(); return EXIT_FAILURE; #endif @@ -137,7 +139,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine /*! if an error occurred, notify user */ if(MainWindow->HasError()) { - CxbxShowError(MainWindow->GetError().c_str()); + PopupError(nullptr, MainWindow->GetError().c_str()); } delete MainWindow; diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 2a9d39169..863a5a780 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -647,7 +647,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // ask permission to overwrite if file already exists if (_access(ofn.lpstrFile, 0) != -1) { - if (MessageBox(m_hwnd, "Overwrite existing file?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNO) != IDYES) + if (PopupQuestionEx(m_hwnd, LOG_LEVEL::WARNING, PopupButtons::YesNo, PopupReturn::No, + "Overwrite existing file?") != PopupReturn::Yes) return TRUE; } @@ -718,16 +719,14 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } if (m_Xbe->HasError()) - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); else { char buffer[255]; sprintf(buffer, "%s's logo bitmap was successfully exported.", m_Xbe->m_szAsciiTitle); - MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); - - printf("WndMain: %s\n", buffer); + PopupInfo(m_hwnd, buffer); } } } @@ -804,7 +803,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP if (bmp_err != 0) { - MessageBox(m_hwnd, bmp_err, "Cxbx-Reloaded", MB_OK | MB_ICONEXCLAMATION); + PopupError(m_hwnd, bmp_err); break; } } @@ -813,7 +812,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP if (m_Xbe->HasError()) { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); if (m_Xbe->HasFatalError()) { @@ -835,9 +834,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP sprintf(buffer, "%s's logo bitmap was successfully updated.", m_Xbe->m_szAsciiTitle); - printf("WndMain: %s\n", buffer); - - MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); + PopupInfo(m_hwnd, buffer); } } } @@ -917,7 +914,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // ask permission to overwrite if file exists if (_access(ofn.lpstrFile, 0) != -1) { - if (MessageBox(m_hwnd, "Overwrite existing file?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNO) != IDYES) + if (PopupQuestion(m_hwnd, "Overwrite existing file?") != PopupReturn::Yes) return TRUE; } @@ -925,7 +922,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP { std::string Xbe_info = DumpInformation(m_Xbe); if (m_Xbe->HasError()) { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); } else { std::ofstream Xbe_dump_file(ofn.lpstrFile); @@ -934,11 +931,10 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP Xbe_dump_file.close(); char buffer[255]; sprintf(buffer, "%s's .xbe info was successfully dumped.", m_Xbe->m_szAsciiTitle); - printf("WndMain: %s\n", buffer); - MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); + PopupInfo(m_hwnd, buffer); } else { - MessageBox(m_hwnd, "Could not open Xbe text file.", "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, "Could not open Xbe text file."); } } } @@ -950,7 +946,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP { std::string Xbe_info = DumpInformation(m_Xbe); if (m_Xbe->HasError()) { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); } else { std::cout << Xbe_info; @@ -982,7 +978,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP if (m_bIsStarted) { // We don't allow changing the contents of the eeprom while a game is running, mostly because we lack a "pause emulation" // function necessary to modify the contents safely (the game itself can modify the eeprom) - MessageBox(hwnd, "Cannot modify eeprom file while a title is running", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(hwnd, "Cannot modify eeprom file while a title is running"); break; } ShowEepromConfig(hwnd); @@ -1018,24 +1014,24 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // -14 is for \\Cxbx-Reloaded string to be include later down below. size_t szLen = strnlen(szDir, MAX_PATH - 14); if (szLen == 0) { - MessageBox(hwnd, "You've selected an invalid folder... Go back and try again.", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(hwnd, "You've selected an invalid folder... Go back and try again."); break; } else if (szLen == MAX_PATH - 14) { - MessageBox(hwnd, "You've selected a folder path which is too long... Go back and try again.", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(hwnd, "You've selected a folder path which is too long... Go back and try again."); break; } std::string szDirTemp = std::string(szDir) + std::string("\\Cxbx-Reloaded"); if (szDirTemp.size() > MAX_PATH) { - MessageBox(hwnd, "Directory path is too long. Go back and choose a shorter path.", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(hwnd, "Directory path is too long. Go back and choose a shorter path."); break; } int result = SHCreateDirectoryEx(nullptr, szDirTemp.c_str(), nullptr); if ((result != ERROR_SUCCESS) && (result != ERROR_ALREADY_EXISTS)) { - MessageBox(hwnd, "You don't have write permissions on that directory...", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(hwnd, "You don't have write permissions on that directory..."); break; } @@ -1063,7 +1059,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_CACHE_CLEARHLECACHE_ALL: { ClearSymbolCache(g_Settings->GetDataLocation().c_str()); - MessageBox(m_hwnd, "The entire Symbol Cache has been cleared.", "Cxbx-Reloaded", MB_OK); + PopupInfo(m_hwnd, "The entire Symbol Cache has been cleared."); } break; @@ -1080,19 +1076,19 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP std::string fullpath = sstream.str(); if (std::filesystem::remove(fullpath)) { - MessageBox(m_hwnd, "This title's Symbol Cache entry has been cleared.", "Cxbx-Reloaded", MB_OK); + PopupInfo(m_hwnd, "This title's Symbol Cache entry has been cleared."); } } break; case ID_SETTINGS_INITIALIZE: { - int ret = MessageBox(m_hwnd, "Warning: This will reset all Cxbx-Reloaded settings to their default values." - "\nAre you sure you want to proceed?", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_YESNO); + PopupReturn ret = PopupWarningEx(m_hwnd, PopupButtons::YesNo, PopupReturn::No, + "Warning: This will reset all Cxbx-Reloaded settings to their default values.\nAre you sure you want to proceed?", "Cxbx-Reloaded"); - if (ret == IDYES) { + if (ret == PopupReturn::Yes) { InitializeSettings(); - MessageBox(m_hwnd, "Cxbx-Reloaded has been initialized and will now close.", "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); + PopupInfo(m_hwnd, "Cxbx-Reloaded has been initialized and will now close."); SendMessage(hwnd, WM_CLOSE, 0, 0); } } @@ -1106,7 +1102,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP else { g_Settings->m_core.KrnlDebugMode = DM_NONE; } - MessageBox(m_hwnd, "This will not take effect until the next time emulation is started.\n", "Cxbx-Reloaded", MB_OK); + PopupInfo(m_hwnd, "This will not take effect until the next time emulation is started."); RefreshMenus(); @@ -1143,7 +1139,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP if (GetSaveFileName(&ofn) != FALSE) { - MessageBox(m_hwnd, "This will not take effect until emulation is (re)started.\n", "Cxbx-Reloaded", MB_OK); + PopupInfo(m_hwnd, "This will not take effect until emulation is (re)started."); strncpy(g_Settings->m_core.szKrnlDebug, ofn.lpstrFile, MAX_PATH - 1); @@ -1274,9 +1270,10 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_HACKS_RUNXBOXTHREADSONALLCORES: if (g_Settings->m_hacks.UseAllCores == false) { - int ret = MessageBox(hwnd, "Activating this hack will make the emulator more likely to crash and/or hang. \ -Please do not report issues with games while this hack is active. Are you sure you want to turn it on?", "Cxbx-Reloaded", MB_YESNO | MB_ICONWARNING | MB_APPLMODAL); - if (ret == IDNO) { + PopupReturn ret = PopupWarningEx(hwnd, PopupButtons::YesNo, PopupReturn::No, + "Activating this hack will make the emulator more likely to crash and/or hang." + "\nPlease do not report issues with games while this hack is active. Are you sure you want to turn it on?"); + if (ret != PopupReturn::Yes) { break; } } @@ -1433,7 +1430,7 @@ void WndMain::LoadLogo() if(m_Xbe->HasError()) { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); if (m_Xbe->HasFatalError()) { @@ -1998,7 +1995,7 @@ void WndMain::OpenXbe(const char *x_filename) RedrawWindow(m_hwnd, nullptr, NULL, RDW_INVALIDATE); - MessageBox(m_hwnd, ErrorMessage.c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, ErrorMessage.c_str()); UpdateCaption(); @@ -2007,10 +2004,11 @@ void WndMain::OpenXbe(const char *x_filename) if (!g_Settings->m_gui.bIgnoreInvalidXbeSig && !m_Xbe->CheckXbeSignature()) { - int ret = MessageBox(m_hwnd, "XBE signature check failed!\n" + PopupReturn ret = PopupWarningEx(m_hwnd, PopupButtons::YesNo, PopupReturn::No, + "XBE signature check failed!\n" "\nThis is dangerous, as maliciously modified Xbox titles could take control of your system.\n" - "\nAre you sure you want to continue?", "Cxbx-Reloaded", MB_ICONEXCLAMATION | MB_YESNO); - if (ret != IDYES) + "\nAre you sure you want to continue?"); + if (ret != PopupReturn::Yes) { delete m_Xbe; m_Xbe = nullptr; @@ -2079,11 +2077,11 @@ void WndMain::CloseXbe() if(m_bXbeChanged) { - int ret = MessageBox(m_hwnd, "Changes have been made, do you wish to save?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNOCANCEL); + PopupReturn ret = PopupQuestion(m_hwnd, "Changes have been made, do you wish to save?"); - if(ret == IDYES) + if(ret == PopupReturn::Yes) SaveXbeAs(); - else if(ret == IDCANCEL) + else if(ret == PopupReturn::Cancel) return; } @@ -2147,7 +2145,7 @@ void WndMain::SaveXbe(const char *x_filename) // ask permission to overwrite if the file already exists if(_access(x_filename, 0) != -1) { - if(MessageBox(m_hwnd, "Overwrite existing file?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNO) != IDYES) + if(PopupQuestionEx(m_hwnd, LOG_LEVEL::INFO, PopupButtons::YesNo, PopupReturn::No, "Overwrite existing file?") != PopupReturn::Yes) return; } @@ -2156,16 +2154,14 @@ void WndMain::SaveXbe(const char *x_filename) m_Xbe->Export(x_filename); if(m_Xbe->HasError()) - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, m_Xbe->GetError().c_str()); else { char buffer[255]; sprintf(buffer, "%s was successfully saved.", m_Xbe->m_szAsciiTitle); - printf("WndMain: %s was successfully saved.\n", m_Xbe->m_szAsciiTitle); - - MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); + PopupInfo(m_hwnd, buffer); m_bXbeChanged = false; } @@ -2212,8 +2208,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / g_EmuShared->GetIsEmulating(&isEmulating); if (isEmulating) { - MessageBox(m_hwnd, "A title is currently emulating, please stop emulation before attempting to start again.", - "Cxbx-Reloaded", MB_ICONERROR | MB_OK); + PopupError(m_hwnd, "A title is currently emulating, please stop emulation before attempting to start again."); return; } @@ -2278,7 +2273,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / DebuggerMonitorClose(); if (!CxbxExec(true, &m_hDebuggerProc, true)) { - MessageBox(m_hwnd, "Failed to start emulation with the debugger.\n\nYou will need to build CxbxDebugger manually.", "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, "Failed to start emulation with the debugger.\n\nYou will need to build CxbxDebugger manually."); printf("WndMain: %s debugger shell failed.\n", m_Xbe->m_szAsciiTitle); } @@ -2291,7 +2286,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / else { if (!CxbxExec(false, nullptr, false)) { - MessageBox(m_hwnd, "Emulation failed.\n\n If this message repeats, the Xbe is not supported.", "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + PopupError(m_hwnd, "Emulation failed.\n\n If this message repeats, the Xbe is not supported."); printf("WndMain: %s shell failed.\n", m_Xbe->m_szAsciiTitle); } diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index 0de867c74..795cf18c4 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -401,6 +401,7 @@ FONT 8, "Verdana", 0, 0, 0x1 BEGIN COMBOBOX IDC_EVENT_LV,57,9,50,10,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CTEXT "Event Level",IDC_STATIC,10,11,40,10,0,WS_EX_RIGHT + CONTROL "Enable Test Case Popup",IDC_LOG_POPUP_TESTCASE,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,121,12,113,10 GROUPBOX "Emulator Event",IDC_CXBXR_EVENTS,12,26,234,186,WS_GROUP,WS_EX_CLIENTEDGE CONTROL "Enable all",IDC_LOG_ENABLE_GENERAL,"Button",BS_AUTORADIOBUTTON | BS_LEFTTEXT,19,39,47,10 CONTROL "Disable all",IDC_LOG_DISABLE_GENERAL,"Button",BS_AUTORADIOBUTTON | BS_LEFTTEXT,71,39,50,10 diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 944333217..375a7e584 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -303,6 +303,7 @@ #define IDC_RUMBLE_LIST 1301 #define IDC_RUMBLE_TEST 1302 #define IDC_NETWORK_ADAPTER 1303 +#define IDC_LOG_POPUP_TESTCASE 1304 #define ID_FILE_EXIT 40005 #define ID_HELP_ABOUT 40008 #define ID_EMULATION_START 40009 @@ -372,7 +373,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 136 #define _APS_NEXT_COMMAND_VALUE 40116 -#define _APS_NEXT_CONTROL_VALUE 1304 +#define _APS_NEXT_CONTROL_VALUE 1305 #define _APS_NEXT_SYMED_VALUE 109 #endif #endif