Files
Xenia-Canary/src/xenia/kernel/xam_ui.cc
2015-05-14 16:21:08 -07:00

118 lines
4.1 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam_private.h"
#include "xenia/xbox.h"
#include <commctrl.h>
namespace xe {
namespace kernel {
// http://www.se7ensins.com/forums/threads/working-xshowmessageboxui.844116/?jdfwkey=sb0vm
SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_state, KernelState* state) {
uint32_t user_index = SHIM_GET_ARG_32(0);
uint32_t title_ptr = SHIM_GET_ARG_32(1);
uint32_t text_ptr = SHIM_GET_ARG_32(2);
uint32_t button_count = SHIM_GET_ARG_32(3);
uint32_t button_ptrs = SHIM_GET_ARG_32(4);
uint32_t active_button = SHIM_GET_ARG_32(5);
uint32_t flags = SHIM_GET_ARG_32(6);
uint32_t result_ptr = SHIM_GET_ARG_32(7);
// arg8 is in stack!
uint32_t sp = (uint32_t)ppc_state->r[1];
uint32_t overlapped_ptr = SHIM_MEM_32(sp + 0x54);
auto title = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(title_ptr));
auto text = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(text_ptr));
std::vector<std::wstring> buttons;
std::wstring all_buttons;
for (uint32_t j = 0; j < button_count; ++j) {
uint32_t button_ptr = SHIM_MEM_32(button_ptrs + j * 4);
auto button = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(button_ptr));
all_buttons.append(button);
if (j + 1 < button_count) {
all_buttons.append(L" | ");
}
buttons.push_back(button);
}
XELOGD(
"XamShowMessageBoxUI(%d, %.8X(%S), %.8X(%S), %d, %.8X(%S), %d, %X, %.8X, "
"%.8X)",
user_index, title_ptr, title.c_str(), text_ptr, text.c_str(),
button_count, button_ptrs, all_buttons.c_str(), active_button, flags,
result_ptr, overlapped_ptr);
uint32_t chosen_button;
if (FLAGS_headless) {
// Auto-pick the focused button.
chosen_button = active_button;
} else {
TASKDIALOGCONFIG config = {0};
config.cbSize = sizeof(config);
config.hInstance = GetModuleHandle(nullptr);
config.hwndParent = state->emulator()->main_window()->hwnd();
config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | // esc to exit
TDF_POSITION_RELATIVE_TO_WINDOW; // center in window
config.dwCommonButtons = 0;
config.pszWindowTitle = title.c_str();
switch (flags & 0xF) {
case 0:
config.pszMainIcon = nullptr;
break;
case 1:
config.pszMainIcon = TD_ERROR_ICON;
break;
case 2:
config.pszMainIcon = TD_WARNING_ICON;
break;
case 3:
config.pszMainIcon = TD_INFORMATION_ICON;
break;
}
config.pszMainInstruction = text.c_str();
config.pszContent = nullptr;
std::vector<TASKDIALOG_BUTTON> taskdialog_buttons;
for (uint32_t i = 0; i < button_count; ++i) {
taskdialog_buttons.push_back({1000 + int(i), buttons[i].c_str()});
}
config.pButtons = taskdialog_buttons.data();
config.cButtons = button_count;
config.nDefaultButton = active_button;
int button_pressed = 0;
TaskDialogIndirect(&config, &button_pressed, nullptr, nullptr);
switch (button_pressed) {
default:
chosen_button = button_pressed - 1000;
break;
case IDCANCEL:
// User cancelled, just pick default.
chosen_button = active_button;
break;
}
}
SHIM_SET_MEM_32(result_ptr, chosen_button);
state->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_SUCCESS);
SHIM_SET_RETURN_32(X_ERROR_IO_PENDING);
}
} // namespace kernel
} // namespace xe
void xe::kernel::xam::RegisterUIExports(
xe::cpu::ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xam.xex", XamShowMessageBoxUI, state);
}