use std map pairs instead of string for cli usage
Plus enable individual memory shared settings and lock data file path hash whenever in used.
This commit is contained in:
parent
11c046e0aa
commit
0f38209e4b
|
@ -85,6 +85,8 @@ file (GLOB CXBXR_HEADER_COMMON
|
|||
"${CXBXR_ROOT_DIR}/src/common/ReservedMemory.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Settings.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConfig.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConverter.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CPUID.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/crc32c.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.h"
|
||||
|
@ -218,6 +220,8 @@ file (GLOB CXBXR_SOURCE_COMMON
|
|||
"${CXBXR_ROOT_DIR}/src/common/Logging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Settings.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConverter.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/crc32c.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/hasher.cpp"
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <filesystem>
|
||||
#include "common\input\InputManager.h"
|
||||
#include "common\input\layout_xbox_controller.h"
|
||||
#include <fstream>
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
// TODO: Implement Qt support when real CPU emulation is available.
|
||||
#ifndef QT_VERSION // NOTE: Non-Qt will be using current directory for data
|
||||
|
@ -45,8 +47,6 @@ static_assert(false, "Please implement support for cross-platform's user profile
|
|||
#include <QStandardPaths> // for cross-platform's user profile support
|
||||
#endif
|
||||
|
||||
std::string g_exec_filepath;
|
||||
|
||||
// Individual library version
|
||||
uint16_t g_LibVersion_D3D8 = 0;
|
||||
uint16_t g_LibVersion_DSOUND = 0;
|
||||
|
@ -144,7 +144,9 @@ static struct {
|
|||
|
||||
std::string GenerateExecDirectoryStr()
|
||||
{
|
||||
return g_exec_filepath.substr(0, g_exec_filepath.find_last_of("\\/"));
|
||||
std::string exec_path;
|
||||
(void)cli_config::GetValue(cli_config::exec, &exec_path);
|
||||
return exec_path.substr(0, exec_path.find_last_of("\\/"));
|
||||
}
|
||||
|
||||
// NOTE: This function will be only have Qt support, std::filesystem doesn't have generic support.
|
||||
|
@ -203,41 +205,12 @@ bool Settings::Init()
|
|||
// Enter setup installer process
|
||||
if (!bRet) {
|
||||
|
||||
std::string saveFile;
|
||||
#ifdef RETRO_API_VERSION // TODO: Change me to #ifndef QT_VERSION
|
||||
// Can only have one option without Qt.
|
||||
saveFile = GenerateExecDirectoryStr();
|
||||
std::string setupFile;
|
||||
m_gui.DataStorageToggle = SetupFile(setupFile);
|
||||
|
||||
#else // Only support for Qt compile build.
|
||||
int iRet = MessageBox(nullptr, szSettings_save_user_option_message, "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONQUESTION);
|
||||
|
||||
if (iRet == IDYES) {
|
||||
saveFile = GenerateExecDirectoryStr();
|
||||
m_gui.DataStorageToggle = CXBX_DATA_EXECDIR;
|
||||
}
|
||||
else if (iRet == IDNO){
|
||||
saveFile = GenerateUserProfileDirectoryStr();
|
||||
m_gui.DataStorageToggle = CXBX_DATA_APPDATA;
|
||||
if (saveFile.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if data directory exists.
|
||||
bRet = std::filesystem::exists(saveFile);
|
||||
if (!bRet) {
|
||||
// Then try create data directory.
|
||||
bRet = std::filesystem::create_directory(saveFile);
|
||||
if (!bRet) {
|
||||
// Unable to create a data directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_gui.DataStorageToggle == CXBX_DATA_INVALID) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
saveFile.append(szSettings_settings_file);
|
||||
|
||||
// Call LoadConfig, this will load the config, applying defaults for any missing fields
|
||||
bRet = LoadConfig();
|
||||
|
@ -247,30 +220,18 @@ bool Settings::Init()
|
|||
return false;
|
||||
}
|
||||
|
||||
bRet = Save(saveFile);
|
||||
bRet = Save(setupFile);
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool Settings::LoadUserConfig()
|
||||
{
|
||||
std::string fileSearch = GenerateExecDirectoryStr();
|
||||
std::string fileSearch;
|
||||
m_gui.DataStorageToggle = FindSettingsLocation(fileSearch);
|
||||
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check and see if file exists from portable, current, directory.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
|
||||
fileSearch = GenerateUserProfileDirectoryStr();
|
||||
if (fileSearch.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check if the user profile directory settings file exists.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
return false;
|
||||
}
|
||||
if (m_gui.DataStorageToggle == CXBX_DATA_INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadFile(fileSearch);
|
||||
|
@ -820,6 +781,82 @@ std::string Settings::GetDataLocation()
|
|||
return m_current_data_location;
|
||||
}
|
||||
|
||||
// Detect where settings file is located and return default data mode.
|
||||
CXBX_DATA Settings::FindSettingsLocation(std::string& file_path_out)
|
||||
{
|
||||
std::string fileSearch = GenerateExecDirectoryStr();
|
||||
CXBX_DATA ret = CXBX_DATA_EXECDIR;
|
||||
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check and see if file exists from portable, current, directory.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
|
||||
fileSearch = GenerateUserProfileDirectoryStr();
|
||||
if (fileSearch.size() == 0) {
|
||||
return CXBX_DATA_INVALID;
|
||||
}
|
||||
CXBX_DATA ret = CXBX_DATA_APPDATA;
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check if the user profile directory settings file exists.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
return CXBX_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
file_path_out = fileSearch;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enter setup installer process
|
||||
CXBX_DATA Settings::SetupFile(std::string& file_path_out)
|
||||
{
|
||||
std::string setupFile;
|
||||
CXBX_DATA data_ret = CXBX_DATA_INVALID;
|
||||
#ifdef RETRO_API_VERSION // TODO: Change me to #ifndef QT_VERSION
|
||||
// Can only have one option without Qt.
|
||||
setupFile = GenerateExecDirectoryStr();
|
||||
|
||||
#else // Only support for Qt compile build.
|
||||
int iRet = MessageBox(nullptr, szSettings_save_user_option_message, "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONQUESTION);
|
||||
|
||||
if (iRet == IDYES) {
|
||||
setupFile = GenerateExecDirectoryStr();
|
||||
data_ret = CXBX_DATA_EXECDIR;
|
||||
}
|
||||
else if (iRet == IDNO) {
|
||||
setupFile = GenerateUserProfileDirectoryStr();
|
||||
data_ret = CXBX_DATA_APPDATA;
|
||||
if (setupFile.size() != 0) {
|
||||
// Check if data directory exists.
|
||||
if (!std::filesystem::exists(setupFile)) {
|
||||
// Then try create data directory.
|
||||
if (!std::filesystem::create_directory(setupFile)) {
|
||||
// Unable to create a data directory
|
||||
data_ret = CXBX_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data_ret == CXBX_DATA_INVALID) {
|
||||
MessageBox(nullptr, szSettings_setup_error, "Cxbx-Reloaded", MB_OK);
|
||||
}
|
||||
else {
|
||||
setupFile.append(szSettings_settings_file);
|
||||
// Create the file, that's it. Load the default configuration later on;
|
||||
std::ofstream createFile(setupFile);
|
||||
if (createFile.is_open()) {
|
||||
createFile.close();
|
||||
}
|
||||
file_path_out = setupFile;
|
||||
}
|
||||
|
||||
return data_ret;
|
||||
}
|
||||
|
||||
void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision)
|
||||
{
|
||||
switch (CurrentRevision) {
|
||||
|
|
|
@ -44,6 +44,7 @@ extern uint16_t g_LibVersion_DSOUND;
|
|||
|
||||
// Cxbx-Reloaded's data storage location.
|
||||
typedef enum _CXBX_DATA {
|
||||
CXBX_DATA_INVALID = -1,
|
||||
CXBX_DATA_APPDATA = 0,
|
||||
CXBX_DATA_EXECDIR = 1,
|
||||
CXBX_DATA_CUSTOM = 2,
|
||||
|
@ -74,6 +75,8 @@ public:
|
|||
void SyncToEmulator();
|
||||
void Verify();
|
||||
std::string GetDataLocation();
|
||||
static CXBX_DATA FindSettingsLocation(std::string& file_path_out);
|
||||
static CXBX_DATA SetupFile(std::string& file_path_out);
|
||||
|
||||
// GUI settings
|
||||
struct s_gui {
|
||||
|
|
|
@ -258,15 +258,25 @@ void unix2dos(std::string& string)
|
|||
// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt.
|
||||
|
||||
// Source: StringUtil.cpp of Dolphin emulator
|
||||
/* Turns " hello " into "hello". Also handles tabs */
|
||||
std::string StripSpaces(const std::string& str)
|
||||
std::string StripChars(const std::string& str, const char* strip_chars)
|
||||
{
|
||||
const size_t s = str.find_first_not_of(" \t\r\n");
|
||||
const size_t s = str.find_first_not_of(strip_chars);
|
||||
|
||||
if (str.npos != s) {
|
||||
return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1);
|
||||
return str.substr(s, str.find_last_not_of(strip_chars) - s + 1);
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Turns " hello " into "hello". Also handles tabs */
|
||||
std::string StripSpaces(const std::string& str)
|
||||
{
|
||||
return StripChars(str, " \t\r\n");
|
||||
}
|
||||
|
||||
std::string StripQuotes(const std::string& str)
|
||||
{
|
||||
return StripChars(str, "\"");
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ bool Memory_RW(void* Addr, void* Buf, size_t Num, bool bIsWrite);
|
|||
|
||||
void unix2dos(std::string& string);
|
||||
std::string StripSpaces(const std::string& str);
|
||||
std::string StripQuotes(const std::string& str);
|
||||
|
||||
// Retrieves the underlying integer value of a scoped enumerator. It allows to avoid using static_cast every time
|
||||
template <typename E>
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2019 RadWolfie
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cliConverter.hpp"
|
||||
#include "cliConfig.hpp"
|
||||
|
||||
std::unordered_map<std::string, std::string> g_cli_configs;
|
||||
|
||||
namespace cli_config {
|
||||
|
||||
bool GenConfig(char** argv, int argc)
|
||||
{
|
||||
g_cli_configs = cliToMapPairs(argv, argc);
|
||||
return (g_cli_configs.size() != 0);
|
||||
}
|
||||
|
||||
size_t ConfigSize()
|
||||
{
|
||||
return g_cli_configs.size();
|
||||
}
|
||||
|
||||
bool GenCMD(std::string& cmd_line_out)
|
||||
{
|
||||
cmd_line_out = cliMapPairsToString(g_cli_configs);
|
||||
return (cmd_line_out.length() != 0);
|
||||
}
|
||||
|
||||
// Generic check if key exist
|
||||
bool hasKey(std::string key)
|
||||
{
|
||||
auto found = g_cli_configs.find(key);
|
||||
if (found != g_cli_configs.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generic getter
|
||||
bool GetValue(const std::string key, std::string* value)
|
||||
{
|
||||
auto found = g_cli_configs.find(key);
|
||||
if (found != g_cli_configs.end() && found->second.length() != 0) {
|
||||
if (value != nullptr) {
|
||||
*value = found->second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value != nullptr) {
|
||||
*value = "";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GetValue(const std::string key, int* value)
|
||||
{
|
||||
auto found = g_cli_configs.find(key);
|
||||
if (found != g_cli_configs.end() && found->second.length() != 0) {
|
||||
if (value != nullptr) {
|
||||
*value = std::stoi(found->second, nullptr, 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value != nullptr) {
|
||||
*value = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GetValue(const std::string key, long long* value)
|
||||
{
|
||||
auto found = g_cli_configs.find(key);
|
||||
if (found != g_cli_configs.end() && found->second.length() != 0) {
|
||||
if (value != nullptr) {
|
||||
*value = std::stoll(found->second, nullptr, 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value != nullptr) {
|
||||
*value = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generic setter (allow modification from gui/cli, emulation does not need it.)
|
||||
void SetValue(const std::string key, const std::string value)
|
||||
{
|
||||
auto found = g_cli_configs.find(key);
|
||||
if (found != g_cli_configs.end()) {
|
||||
found->second = value;
|
||||
}
|
||||
else {
|
||||
g_cli_configs[key] = value;
|
||||
}
|
||||
}
|
||||
void SetValue(const std::string key, const char* value)
|
||||
{
|
||||
SetValue(key, std::string(value));
|
||||
}
|
||||
void SetValue(const std::string key, const void* value)
|
||||
{
|
||||
SetValue(key, std::to_string((size_t)value));
|
||||
}
|
||||
void SetValue(const std::string key, int value)
|
||||
{
|
||||
SetValue(key, std::to_string(value));
|
||||
}
|
||||
void SetValue(const std::string key, long long value)
|
||||
{
|
||||
SetValue(key, std::to_string(value));
|
||||
}
|
||||
|
||||
// Custom setter for emulation accessible.
|
||||
void SetLoad(const std::string value)
|
||||
{
|
||||
SetValue(cli_config::load, value);
|
||||
}
|
||||
|
||||
void SetSID(long long value)
|
||||
{
|
||||
// If sid key exist, then do not replace old or new one.
|
||||
if (!hasKey(cli_config::sid)) {
|
||||
SetValue(cli_config::sid, value);
|
||||
}
|
||||
}
|
||||
|
||||
long long GetSessionID()
|
||||
{
|
||||
long long sessionID = 0;
|
||||
|
||||
// Check if previous session ID had been set then use it.
|
||||
if (!GetValue(cli_config::sid, &sessionID)) {
|
||||
sessionID = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
// From now and the future will continue to use the same sessionID until all processes end.
|
||||
SetSID(sessionID);
|
||||
}
|
||||
|
||||
return sessionID;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2019 RadWolfie
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// Command Line Interface functions
|
||||
// NOTE - Reason only provide functions is to prevent misuse "exec"
|
||||
|
||||
namespace cli_config {
|
||||
|
||||
static constexpr char exec[] = "exec";
|
||||
static constexpr char arg1[] = "arg1";
|
||||
static constexpr char load[] = "load";
|
||||
static constexpr char hwnd[] = "hwnd";
|
||||
static constexpr char debug_mode[] = "dm";
|
||||
static constexpr char debug_file[] = "df";
|
||||
static constexpr char sid[] = "sid";
|
||||
|
||||
bool GenConfig(char** argv, int argc);
|
||||
size_t ConfigSize();
|
||||
bool GenCMD(std::string& cmd_line_out);
|
||||
|
||||
// Generic check if key exist
|
||||
bool hasKey(const std::string key);
|
||||
// Generic getter
|
||||
bool GetValue(const std::string key, std::string* value);
|
||||
|
||||
long long GetSessionID();
|
||||
|
||||
// Change xbe path to launch.
|
||||
void SetLoad(const std::string value);
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2019 RadWolfie
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "CxbxUtil.h" // for StripQuotes
|
||||
#include "cliConverter.hpp"
|
||||
#include "cliConfig.hpp"
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> unordered_map_strings;
|
||||
|
||||
constexpr char str_quote[] = "\"";
|
||||
constexpr char str_quote_space[] = "\" ";
|
||||
constexpr char str_space_quote[] = " \"";
|
||||
constexpr char str_space[] = " ";
|
||||
constexpr char str_slash_forward[] = "/";
|
||||
|
||||
std::string cliMapPairsToString(std::unordered_map<std::string, std::string>& map_pairs_out)
|
||||
{
|
||||
std::string to_string;
|
||||
|
||||
unordered_map_strings::iterator i = map_pairs_out.begin();
|
||||
|
||||
// If map pairs are empty, return empty string.
|
||||
// Or "exec" is not in first iterator by requirement, then return empty string.
|
||||
if (i == map_pairs_out.end() || i->first.compare(cli_config::exec)) {
|
||||
return to_string;
|
||||
}
|
||||
|
||||
to_string += str_quote + i->second + str_quote_space;
|
||||
|
||||
i++;
|
||||
|
||||
for (i; i != map_pairs_out.end();) {
|
||||
// If argument 1 was input, ignore it since key is reserved from user first input.
|
||||
if (!i->first.compare(cli_config::arg1)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// If argument has space inside, return as empty.
|
||||
size_t found = i->first.find(str_space);
|
||||
if (found != std::string::npos) {
|
||||
return std::string();
|
||||
}
|
||||
// If argument has quote inside, return as empty.
|
||||
found = i->first.find(str_quote);
|
||||
if (found != std::string::npos) {
|
||||
return std::string();
|
||||
}
|
||||
to_string += str_slash_forward + i->first;
|
||||
|
||||
if (i->second.length() != 0) {
|
||||
found = i->second.find(str_space);
|
||||
// If found space inside, then escape with quote.
|
||||
if (found != std::string::npos) {
|
||||
// If argument has quote inside, return as empty.
|
||||
found = i->second.find(str_quote);
|
||||
if (found != std::string::npos) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
to_string += str_space_quote + i->second + str_quote;
|
||||
}
|
||||
else {
|
||||
to_string += str_space + i->second;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are more, then add space
|
||||
i++;
|
||||
if (i != map_pairs_out.end()) {
|
||||
to_string += str_space;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return to_string;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> cliToMapPairs(char** argv, int argc)
|
||||
{
|
||||
unordered_map_strings map_pairs;
|
||||
|
||||
// Always set first since first argument is the path to executable file.
|
||||
map_pairs[cli_config::exec] = argv[0];
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// Check for forward slash to trigger pair bind.
|
||||
std::string first = StripQuotes(argv[i]);
|
||||
if (first.at(0) == str_slash_forward[0]) {
|
||||
first = first.substr(1);
|
||||
// Do not allow overwrite argv[0].
|
||||
if (!first.compare(cli_config::exec)) {
|
||||
continue;
|
||||
}
|
||||
// And do not allow overwrite argv[1].
|
||||
if (!first.compare(cli_config::arg1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the count is at maximum, then simply do empty pair.
|
||||
if (i + 1 == argc) {
|
||||
map_pairs[first] = "";
|
||||
continue;
|
||||
}
|
||||
// Check for forward slash to bind pair.
|
||||
else if (i + 1 < argc) {
|
||||
std::string second = StripQuotes(argv[i + 1]);
|
||||
// If next arg has a slash, then do a empty pair.
|
||||
if (second.at(0) == str_slash_forward[0]) {
|
||||
map_pairs[first] = "";
|
||||
}
|
||||
// Otherwise, do the input pair.
|
||||
else {
|
||||
map_pairs[first] = second;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Check if 1st argument exist then allow forward it.
|
||||
else if (i == 1) {
|
||||
map_pairs[cli_config::arg1] = first;
|
||||
continue;
|
||||
}
|
||||
// Otherwise, let's mark as invalid input
|
||||
return unordered_map_strings();
|
||||
}
|
||||
return map_pairs;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2019 RadWolfie
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
std::string cliMapPairsToString(std::unordered_map<std::string, std::string>& array_map_out);
|
||||
|
||||
std::unordered_map<std::string, std::string> cliToMapPairs(char** argv, int argc);
|
|
@ -48,7 +48,7 @@ HMODULE hActiveModule = NULL;
|
|||
// ******************************************************************
|
||||
// * func: EmuShared::EmuSharedInit
|
||||
// ******************************************************************
|
||||
bool EmuShared::Init(DWORD guiProcessID)
|
||||
bool EmuShared::Init(long long sessionID)
|
||||
{
|
||||
// ******************************************************************
|
||||
// * Ensure initialization only occurs once
|
||||
|
@ -58,15 +58,22 @@ bool EmuShared::Init(DWORD guiProcessID)
|
|||
// ******************************************************************
|
||||
// * Prevent multiple initializations
|
||||
// ******************************************************************
|
||||
if(hMapObject != NULL)
|
||||
if (hMapObject != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * Prevent invalid session process id
|
||||
// ******************************************************************
|
||||
if (sessionID == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * Create the shared memory "file"
|
||||
// ******************************************************************
|
||||
{
|
||||
// NOTE: guiProcessID support is not available due to 2+ emulation is causing problem with graphic screen.
|
||||
std::string emuSharedStr = "Local\\EmuShared-s" + std::to_string(settings_version);// +"-p" + std::to_string(guiProcessID);
|
||||
std::string emuSharedStr = "Local\\EmuShared-s" + std::to_string(sessionID);
|
||||
hMapObject = CreateFileMapping
|
||||
(
|
||||
INVALID_HANDLE_VALUE, // Paging file
|
||||
|
@ -97,8 +104,10 @@ bool EmuShared::Init(DWORD guiProcessID)
|
|||
0 // default: map entire file
|
||||
);
|
||||
|
||||
if(g_EmuShared == nullptr)
|
||||
if (g_EmuShared == nullptr) {
|
||||
CloseHandle(hMapObject);
|
||||
return false; // CxbxKrnlCleanupEx(CXBXR_MODULE::INIT, "Could not map view of shared memory!");
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
@ -109,6 +118,12 @@ bool EmuShared::Init(DWORD guiProcessID)
|
|||
}
|
||||
|
||||
g_EmuShared->m_RefCount++;
|
||||
|
||||
if (g_EmuShared->m_size != sizeof(EmuShared)) {
|
||||
EmuShared::Cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -131,6 +146,7 @@ void EmuShared::Cleanup()
|
|||
// ******************************************************************
|
||||
EmuShared::EmuShared()
|
||||
{
|
||||
m_size = sizeof(EmuShared);
|
||||
// m_bMultiXbe = false;
|
||||
// m_LaunchDataPAddress = NULL;
|
||||
m_bDebugging = false;
|
||||
|
|
|
@ -60,10 +60,15 @@ class EmuShared : public Mutex
|
|||
public:
|
||||
int m_RefCount;
|
||||
|
||||
// ******************************************************************
|
||||
// * Fixed memory allocation size
|
||||
// ******************************************************************
|
||||
unsigned int m_size;
|
||||
|
||||
// ******************************************************************
|
||||
// * Each process needs to call this to initialize shared memory
|
||||
// ******************************************************************
|
||||
static bool Init(DWORD guiProcessID);
|
||||
static bool Init(long long sessionID);
|
||||
|
||||
// ******************************************************************
|
||||
// * Each process needs to call this to cleanup shared memory
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#if defined(_WIN32) || defined(WIN32)
|
||||
|
||||
#include "core\kernel\init\CxbxKrnl.h"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
// Source: https://stackoverflow.com/questions/8046097/how-to-check-if-a-process-has-the-administrative-rights
|
||||
bool CxbxIsElevated() {
|
||||
|
@ -46,15 +47,19 @@ bool CxbxIsElevated() {
|
|||
return fRet;
|
||||
}
|
||||
|
||||
bool CxbxExec(std::string &execCommand, HANDLE* hProcess, bool requestHandleProcess) {
|
||||
bool CxbxExec(bool useDebugger, HANDLE* hProcess, bool requestHandleProcess) {
|
||||
|
||||
STARTUPINFO startupInfo = { 0 };
|
||||
PROCESS_INFORMATION processInfo = { 0 };
|
||||
size_t szSize = execCommand.size();
|
||||
char* szArgsBufferOutput = new char[szSize + 1];
|
||||
|
||||
strncpy(szArgsBufferOutput, execCommand.c_str(), szSize);
|
||||
szArgsBufferOutput[szSize] = '\0';
|
||||
std::string szProcArgsBuffer;
|
||||
if (!cli_config::GenCMD(szProcArgsBuffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Set a configuration variable for this. For now it will be within the same folder as Cxbx.exe
|
||||
if (useDebugger) {
|
||||
szProcArgsBuffer = "cxbxr-debugger.exe " + szProcArgsBuffer;
|
||||
}
|
||||
|
||||
/* NOTE: CreateProcess's 2nd parameter (lpCommandLine) is char*, not const char*. Plus it has ability to change the input buffer data.
|
||||
Source: https://msdn.microsoft.com/en-us/library/ms682425.aspx
|
||||
|
@ -63,11 +68,9 @@ bool CxbxExec(std::string &execCommand, HANDLE* hProcess, bool requestHandleProc
|
|||
Plus ShellExecute is high level whilst CreateProcess is low level. We want to use official low level functions as possible to reduce
|
||||
cpu load cycles to get the task done.
|
||||
*/
|
||||
if (CreateProcess(nullptr, szArgsBufferOutput, nullptr, nullptr, false, 0, nullptr, nullptr, &startupInfo, &processInfo) == 0) {
|
||||
delete[] szArgsBufferOutput;
|
||||
if (CreateProcess(nullptr, const_cast<LPSTR>(szProcArgsBuffer.c_str()), nullptr, nullptr, false, 0, nullptr, nullptr, &startupInfo, &processInfo) == 0) {
|
||||
return 0;
|
||||
}
|
||||
delete[] szArgsBufferOutput;
|
||||
CloseHandle(processInfo.hThread);
|
||||
|
||||
if (requestHandleProcess) {
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace xboxkrnl
|
|||
#include "Logging.h" // For LOG_FUNC()
|
||||
#include "EmuKrnl.h" // For InitializeListHead(), etc.
|
||||
#include "EmuKrnlLogging.h"
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup, CxbxConvertArgToString, and CxbxExec
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For CxbxKrnlCleanup, and CxbxExec
|
||||
#include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, )
|
||||
#include "EmuKrnl.h"
|
||||
#include "devices\x86\EmuX86.h" // HalReadWritePciSpace needs this
|
||||
|
@ -47,8 +47,9 @@ namespace xboxkrnl
|
|||
#include "common\EmuEEPROM.h" // For EEPROM
|
||||
#include "devices\Xbox.h" // For g_SMBus, SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER
|
||||
#include "devices\SMCDevice.h" // For SMC_COMMAND_SCRATCH
|
||||
#include "common/util/strConverter.hpp" // for utf16_to_ascii
|
||||
#include "common/util/strConverter.hpp" // for utf16_to_ascii
|
||||
#include "core\kernel\memory-manager\VMManager.h"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
#include <algorithm> // for std::replace
|
||||
#include <locale>
|
||||
|
@ -572,10 +573,8 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
|
|||
// Some titles (Xbox Dashboard and retail/demo discs) use ";" as a current directory path seperator
|
||||
// This process is handled during initialization. No speical handling here required.
|
||||
|
||||
std::string szProcArgsBuffer;
|
||||
CxbxConvertArgToString(szProcArgsBuffer, szFilePath_CxbxReloaded_Exe, XbePath.c_str(), CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str());
|
||||
|
||||
if (!CxbxExec(szProcArgsBuffer, nullptr, false)) {
|
||||
cli_config::SetLoad(XbePath);
|
||||
if (!CxbxExec(false, nullptr, false)) {
|
||||
CxbxKrnlCleanup("Could not launch %s", XbePath.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -593,10 +592,8 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur
|
|||
|
||||
g_VMManager.SavePersistentMemory();
|
||||
|
||||
std::string szProcArgsBuffer;
|
||||
CxbxConvertArgToString(szProcArgsBuffer, szFilePath_CxbxReloaded_Exe, szFilePath_Xbe, CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str());
|
||||
|
||||
if (!CxbxExec(szProcArgsBuffer, nullptr, false)) {
|
||||
cli_config::SetLoad(szFilePath_Xbe);
|
||||
if (!CxbxExec(false, nullptr, false)) {
|
||||
CxbxKrnlCleanup("Could not launch %s", szFilePath_Xbe);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -52,6 +52,8 @@ namespace xboxkrnl
|
|||
#include "ReservedMemory.h" // For virtual_memory_placeholder
|
||||
#include "core\kernel\memory-manager\VMManager.h"
|
||||
#include "CxbxDebugger.h"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
#include "common/util/xxhash.h"
|
||||
|
||||
#include <clocale>
|
||||
#include <process.h>
|
||||
|
@ -679,33 +681,6 @@ void ImportLibraries(XbeImportEntry *pImportDirectory)
|
|||
}
|
||||
}
|
||||
|
||||
bool CheckLoadArgument(int argc, char* argv[], DWORD *pguiProcessID)
|
||||
{
|
||||
bool bHasLoadArgument;
|
||||
|
||||
if (argc >= 2 && std::strcmp(argv[1], "/load") == 0 && std::strlen(argv[2]) > 0) {
|
||||
HWND hWnd = nullptr;
|
||||
bHasLoadArgument = true;
|
||||
// Perform check if command line contain gui's hWnd value.
|
||||
if (argc > 3) {
|
||||
hWnd = (HWND)std::stoi(argv[3], nullptr, 10);
|
||||
hWnd = IsWindow(hWnd) ? hWnd : nullptr;
|
||||
if (hWnd != nullptr) {
|
||||
// We don't need thread ID from window handle.
|
||||
GetWindowThreadProcessId(hWnd, pguiProcessID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
bHasLoadArgument = false;
|
||||
*pguiProcessID = GetCurrentProcessId();
|
||||
}
|
||||
|
||||
g_exec_filepath = argv[0]; // NOTE: Workaround solution until simulated "main" function is made.
|
||||
|
||||
return bHasLoadArgument;
|
||||
}
|
||||
|
||||
bool CreateSettings()
|
||||
{
|
||||
g_Settings = new Settings();
|
||||
|
@ -749,8 +724,10 @@ bool HandleFirstLaunch()
|
|||
return true;
|
||||
}
|
||||
|
||||
void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
||||
void CxbxKrnlEmulate(uint32_t blocks_reserved[384])
|
||||
{
|
||||
std::string tempStr;
|
||||
|
||||
// NOTE: This is designated for standalone kernel mode launch without GUI
|
||||
if (g_Settings != nullptr) {
|
||||
|
||||
|
@ -775,29 +752,39 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
/* Initialize Cxbx File Paths */
|
||||
CxbxInitFilePaths();
|
||||
|
||||
/* Must be called after CxbxInitFilePaths */
|
||||
if (!CxbxLockFilePath()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip '/load' switch
|
||||
// Get XBE Name :
|
||||
std::string xbePath = std::filesystem::absolute(std::filesystem::path(argv[2])).string();
|
||||
std::string xbePath;
|
||||
cli_config::GetValue(cli_config::load, &xbePath);
|
||||
xbePath = std::filesystem::absolute(std::filesystem::path(xbePath)).string();
|
||||
|
||||
// Get DCHandle :
|
||||
HWND hWnd = 0;
|
||||
if (argc > 3) {
|
||||
hWnd = (HWND)std::atoi(argv[3]);
|
||||
// We must save this handle now to keep the child window working in the case we need to display the UEM
|
||||
HWND hWnd = nullptr;
|
||||
if (cli_config::GetValue(cli_config::hwnd, &tempStr)) {
|
||||
hWnd = (HWND)std::atoi(tempStr.c_str());
|
||||
}
|
||||
CxbxKrnl_hEmuParent = IsWindow(hWnd) ? hWnd : nullptr;
|
||||
|
||||
// Get KernelDebugMode :
|
||||
DebugMode DbgMode = DebugMode::DM_NONE;
|
||||
if (argc > 4) {
|
||||
DbgMode = (DebugMode)std::atoi(argv[4]);
|
||||
if (cli_config::GetValue(cli_config::debug_mode, &tempStr)) {
|
||||
DbgMode = (DebugMode)std::atoi(tempStr.c_str());
|
||||
}
|
||||
|
||||
// Get KernelDebugFileName :
|
||||
std::string DebugFileName = "";
|
||||
if (argc > 5) {
|
||||
DebugFileName = argv[5];
|
||||
if (cli_config::GetValue(cli_config::debug_file, &tempStr)) {
|
||||
DebugFileName = tempStr;
|
||||
}
|
||||
|
||||
int BootFlags;
|
||||
FILE* krnlLog = nullptr;
|
||||
g_EmuShared->GetBootFlags(&BootFlags);
|
||||
|
||||
// debug console allocation (if configured)
|
||||
|
@ -811,8 +798,8 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
GetConsoleScreenBufferInfo(StdHandle, &coninfo);
|
||||
coninfo.dwSize.Y = SHRT_MAX - 1; // = 32767-1 = 32766 = maximum value that works
|
||||
SetConsoleScreenBufferSize(StdHandle, coninfo.dwSize);
|
||||
freopen("CONOUT$", "wt", stdout);
|
||||
freopen("CONIN$", "rt", stdin);
|
||||
(void)freopen("CONOUT$", "wt", stdout);
|
||||
(void)freopen("CONIN$", "rt", stdin);
|
||||
SetConsoleTitle("Cxbx-Reloaded : Kernel Debug Console");
|
||||
SetConsoleTextAttribute(StdHandle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
|
||||
}
|
||||
|
@ -822,7 +809,7 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
FreeConsole();
|
||||
if (DbgMode == DM_FILE) {
|
||||
// Peform clean write to kernel log for first boot. Unless multi-xbe boot occur then perform append to existing log.
|
||||
freopen(DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout);
|
||||
krnlLog = freopen(DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout);
|
||||
// Append separator for better readability after reboot.
|
||||
if (BootFlags != DebugMode::DM_NONE) {
|
||||
std::cout << "\n------REBOOT------REBOOT------REBOOT------REBOOT------REBOOT------\n" << std::endl;
|
||||
|
@ -831,13 +818,10 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
else {
|
||||
char buffer[16];
|
||||
if (GetConsoleTitle(buffer, 16) != NULL)
|
||||
freopen("nul", "w", stdout);
|
||||
(void)freopen("nul", "w", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
// We must save this handle now to keep the child window working in the case we need to display the UEM
|
||||
CxbxKrnl_hEmuParent = IsWindow(hWnd) ? hWnd : NULL;
|
||||
|
||||
g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
||||
|
||||
// Set up the logging variables for the kernel process during initialization.
|
||||
|
@ -891,7 +875,7 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
}
|
||||
}
|
||||
|
||||
if (dwExitCode != EXIT_SUCCESS) {// StopEmulation
|
||||
if (dwExitCode != EXIT_SUCCESS) {// Stop emulation
|
||||
CxbxKrnlShutDown();
|
||||
}
|
||||
|
||||
|
@ -1202,6 +1186,10 @@ void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384])
|
|||
BootFlags
|
||||
);
|
||||
}
|
||||
|
||||
if (!krnlLog) {
|
||||
(void)fclose(krnlLog);
|
||||
}
|
||||
}
|
||||
#pragma optimize("", on)
|
||||
|
||||
|
@ -1559,13 +1547,21 @@ __declspec(noreturn) void CxbxKrnlInit
|
|||
EmuLogInit(LOG_LEVEL::DEBUG, "XBE entry point returned");
|
||||
fflush(stdout);
|
||||
|
||||
CxbxUnlockFilePath();
|
||||
|
||||
// EmuShared::Cleanup(); FIXME: commenting this line is a bad workaround for issue #617 (https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/617)
|
||||
CxbxKrnlTerminateThread();
|
||||
}
|
||||
|
||||
void CxbxInitFilePaths()
|
||||
{
|
||||
g_EmuShared->GetStorageLocation(szFolder_CxbxReloadedData);
|
||||
if (g_Settings) {
|
||||
std::string dataLoc = g_Settings->GetDataLocation();
|
||||
std::strncpy(szFolder_CxbxReloadedData, dataLoc.c_str(), dataLoc.length() + 1);
|
||||
}
|
||||
else {
|
||||
g_EmuShared->GetStorageLocation(szFolder_CxbxReloadedData);
|
||||
}
|
||||
|
||||
// Make sure our data folder exists :
|
||||
bool result = std::filesystem::exists(szFolder_CxbxReloadedData);
|
||||
|
@ -1585,6 +1581,50 @@ void CxbxInitFilePaths()
|
|||
GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH);
|
||||
}
|
||||
|
||||
HANDLE hMapDataHash = nullptr;
|
||||
|
||||
bool CxbxLockFilePath()
|
||||
{
|
||||
std::stringstream filePathHash("Local\\");
|
||||
uint64_t hashValue = XXH3_64bits(szFolder_CxbxReloadedData, strlen(szFolder_CxbxReloadedData) + 1);
|
||||
if (!hashValue) {
|
||||
CxbxKrnlCleanup("%s : Couldn't generate Cxbx-Reloaded's data folder hash!", __func__);
|
||||
}
|
||||
|
||||
filePathHash << std::hex << hashValue;
|
||||
|
||||
hMapDataHash = CreateFileMapping
|
||||
(
|
||||
INVALID_HANDLE_VALUE, // Paging file
|
||||
nullptr, // default security attributes
|
||||
PAGE_READONLY, // readonly access
|
||||
0, // size: high 32 bits
|
||||
/*Dummy size*/4, // size: low 32 bits
|
||||
filePathHash.str().c_str() // name of map object
|
||||
);
|
||||
|
||||
if (hMapDataHash == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
CxbxShowError("Data path directory is currently in used.\nUse different data path directory or stop emulation from another process.");
|
||||
CloseHandle(hMapDataHash);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CxbxUnlockFilePath()
|
||||
{
|
||||
// Close opened file path lockdown shared memory.
|
||||
if (hMapDataHash) {
|
||||
CloseHandle(hMapDataHash);
|
||||
hMapDataHash = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// REMARK: the following is useless, but PatrickvL has asked to keep it for documentation purposes
|
||||
/*xboxkrnl::LAUNCH_DATA_PAGE DefaultLaunchDataPage =
|
||||
{
|
||||
|
@ -1730,8 +1770,11 @@ void CxbxKrnlShutDown()
|
|||
// Shutdown the input device manager
|
||||
g_InputDeviceManager.Shutdown();
|
||||
|
||||
if (CxbxKrnl_hEmuParent != NULL)
|
||||
CxbxUnlockFilePath();
|
||||
|
||||
if (CxbxKrnl_hEmuParent != NULL) {
|
||||
SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0);
|
||||
}
|
||||
|
||||
EmuShared::Cleanup();
|
||||
TerminateProcess(g_CurrentProcessHandle, 0);
|
||||
|
@ -1828,21 +1871,6 @@ void CxbxKrnlPanic()
|
|||
CxbxKrnlCleanup("Kernel Panic!");
|
||||
}
|
||||
|
||||
void CxbxConvertArgToString(std::string &dest, const char* krnlExe, const char* xbeFile, HWND hwndParent, DebugMode krnlDebug, const char* krnlDebugFile) {
|
||||
|
||||
std::stringstream szArgsStream;
|
||||
|
||||
// The format is: "krnlExe" /load "xbeFile" hwndParent krnlDebug "krnlDebugFile"
|
||||
szArgsStream <<
|
||||
"\"" << krnlExe << "\""
|
||||
" /load \"" << xbeFile << "\""
|
||||
" " << std::dec << (int)hwndParent <<
|
||||
" " << std::dec << (int)krnlDebug <<
|
||||
" \"" << krnlDebugFile << "\"";
|
||||
|
||||
dest = szArgsStream.str();
|
||||
}
|
||||
|
||||
static clock_t g_DeltaTime = 0; // Used for benchmarking/fps count
|
||||
static unsigned int g_Frames = 0;
|
||||
|
||||
|
|
|
@ -231,15 +231,13 @@ extern Xbe::Certificate *g_pCertificate;
|
|||
bool CxbxKrnlVerifyVersion(const char *szVersion);
|
||||
|
||||
extern bool g_bIsDebugKernel;
|
||||
|
||||
bool CheckLoadArgument(int argc, char* argv[], DWORD *pguiProcessID);
|
||||
|
||||
bool CreateSettings();
|
||||
|
||||
bool HandleFirstLaunch();
|
||||
|
||||
/*! Cxbx Kernel Entry Point */
|
||||
void CxbxKrnlMain(int argc, char* argv[], uint32_t blocks_reserved[384]);
|
||||
void CxbxKrnlEmulate(uint32_t blocks_reserved[384]);
|
||||
|
||||
/*! initialize emulation */
|
||||
__declspec(noreturn) void CxbxKrnlInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32_t XbeHeaderSize, void (*Entry)(), int BootFlags);
|
||||
|
@ -279,11 +277,12 @@ void CxbxKrnlNoFunc();
|
|||
void CxbxInitPerformanceCounters(); // Implemented in EmuKrnlKe.cpp
|
||||
|
||||
void CxbxInitFilePaths();
|
||||
|
||||
// For emulation usage only
|
||||
bool CxbxLockFilePath();
|
||||
void CxbxUnlockFilePath();
|
||||
|
||||
/*! Generate a standard arg format string */
|
||||
void CxbxConvertArgToString(std::string &dest, const char* krnlExe, const char* xbeFile, HWND hwndParent, DebugMode krnlDebug, const char* krnlDebugFile);
|
||||
|
||||
bool CxbxExec(std::string &execCommand, HANDLE* hProcess, bool requestHandleProcess);
|
||||
bool CxbxExec(bool useDebugger, HANDLE* hProcess, bool requestHandleProcess);
|
||||
|
||||
bool CxbxIsElevated();
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "EmuShared.h"
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For HandleFirstLaunch() and LaunchEmulation()
|
||||
//#include <commctrl.h>
|
||||
#include "common/util/cliConverter.hpp"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
PCHAR*
|
||||
CommandLineToArgvA(
|
||||
|
@ -143,17 +145,22 @@ DWORD WINAPI Emulate(int system, uint32_t blocks_reserved[384])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
DWORD guiProcessID = 0;
|
||||
bool bHasLoadArgument = CheckLoadArgument(argc, argv, &guiProcessID);
|
||||
if (!bHasLoadArgument) {
|
||||
CxbxShowError("No /load argument on command line!");
|
||||
if (!cli_config::GenConfig(argv, argc)) {
|
||||
CxbxShowError("Couldn't convert parsed command line!");
|
||||
LocalFree(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
LocalFree(argv);
|
||||
|
||||
/*! verify load argument is included */
|
||||
if (!cli_config::hasKey("load")) {
|
||||
CxbxShowError("No /load argument in command line!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*! initialize shared memory */
|
||||
if (!EmuShared::Init(guiProcessID)) {
|
||||
if (!EmuShared::Init(cli_config::GetSessionID())) {
|
||||
CxbxShowError("Could not map shared memory!");
|
||||
LocalFree(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -163,9 +170,7 @@ DWORD WINAPI Emulate(int system, uint32_t blocks_reserved[384])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CxbxKrnlMain(argc, argv, blocks_reserved);
|
||||
|
||||
LocalFree(argv);
|
||||
CxbxKrnlEmulate(blocks_reserved);
|
||||
|
||||
/*! cleanup shared memory */
|
||||
EmuShared::Cleanup();
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "EmuShared.h"
|
||||
#include "common\Settings.hpp"
|
||||
#include <commctrl.h>
|
||||
#include "common/util/cliConverter.hpp"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
|
||||
// Enable Visual Styles
|
||||
|
@ -45,6 +47,7 @@ processorArchitecture = '*' publicKeyToken = '6595b64144ccf1df' language = '*'\"
|
|||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
hActiveModule = hInstance; // == GetModuleHandle(NULL); // Points to GUI (Cxbx.exe) ImageBase
|
||||
std::string tempStr;
|
||||
|
||||
// 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.
|
||||
|
@ -61,12 +64,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
}
|
||||
#endif
|
||||
|
||||
DWORD guiProcessID = 0;
|
||||
// TODO: Convert ALL __argc & __argv to use main(int argc, char** argv) method.
|
||||
bool bHasLoadArgument = CheckLoadArgument(__argc, __argv, &guiProcessID);
|
||||
if (!cli_config::GenConfig(__argv, __argc)) {
|
||||
CxbxShowError("Couldn't convert parsed command line!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*! initialize shared memory */
|
||||
if (!EmuShared::Init(guiProcessID)) {
|
||||
if (!EmuShared::Init(cli_config::GetSessionID())) {
|
||||
CxbxShowError("Could not map shared memory!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -76,18 +80,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (bHasLoadArgument) {
|
||||
if (cli_config::hasKey("load")) {
|
||||
#ifndef CXBX_LOADER
|
||||
CxbxKrnlMain(__argc, __argv, nullptr);
|
||||
CxbxKrnlEmulate(nullptr);
|
||||
EmuShared::Cleanup();
|
||||
return EXIT_SUCCESS;
|
||||
#else
|
||||
std::string szProcArgsBuffer;
|
||||
for (int i = 0; i < __argc; i++) {
|
||||
szProcArgsBuffer.append(__argv[i]);
|
||||
}
|
||||
|
||||
if (!CxbxExec(szProcArgsBuffer, nullptr, false)) {
|
||||
if (!CxbxExec(false, nullptr, false)) {
|
||||
CxbxShowError("Could not launch Cxbx-R loader!");
|
||||
EmuShared::Cleanup();
|
||||
return EXIT_FAILURE;
|
||||
|
@ -124,9 +123,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
}
|
||||
|
||||
/*! optionally open xbe and start emulation, if command line parameter was specified */
|
||||
if(__argc > 1 && false == MainWindow->HasError())
|
||||
if(cli_config::ConfigSize() > 1 && false == MainWindow->HasError() && cli_config::GetValue(cli_config::arg1, &tempStr))
|
||||
{
|
||||
MainWindow->OpenXbe(std::filesystem::absolute(std::filesystem::path(__argv[1])).string().c_str());
|
||||
tempStr = std::filesystem::absolute(std::filesystem::path(tempStr)).string();
|
||||
MainWindow->OpenXbe(tempStr.c_str());
|
||||
|
||||
MainWindow->StartEmulation(MainWindow->GetHwnd());
|
||||
}
|
||||
|
|
|
@ -43,8 +43,9 @@
|
|||
#include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For CxbxSetPixelContainerHeader
|
||||
#include "core\hle\D3D8\XbConvert.h" // For EmuPC2XB_D3DFormat
|
||||
#include "common\Settings.hpp"
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For CxbxConvertArgToString and CxbxExec
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For CxbxExec
|
||||
#include "resource/ResCxbx.h"
|
||||
#include "CxbxVersion.h"
|
||||
#include "Shlwapi.h"
|
||||
|
@ -2214,6 +2215,13 @@ void WndMain::SaveXbeAs()
|
|||
SaveXbe(ofn.lpstrFile);
|
||||
}
|
||||
|
||||
// Only grant access to GUI end.
|
||||
namespace cli_config {
|
||||
extern void SetValue(const std::string key, const std::string value);
|
||||
extern void SetValue(const std::string key, const char* value);
|
||||
extern void SetValue(const std::string key, const void* value);
|
||||
extern void SetValue(const std::string key, int value);
|
||||
}
|
||||
// start emulation
|
||||
void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /*= debuggerOff*/)
|
||||
{
|
||||
|
@ -2268,8 +2276,19 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
|
|||
bool AttachLocalDebugger = (LocalDebuggerState == debuggerOn);
|
||||
g_EmuShared->SetDebuggingFlag(&AttachLocalDebugger);
|
||||
|
||||
std::string szProcArgsBuffer;
|
||||
CxbxConvertArgToString(szProcArgsBuffer, szExeFileName, m_XbeFilename, hwndParent, g_Settings->m_core.KrnlDebugMode, g_Settings->m_core.szKrnlDebug);
|
||||
/* Main process to generate emulation command line begin. */
|
||||
// If we are adding more arguments, this is the place to do so.
|
||||
cli_config::SetValue(cli_config::exec, szExeFileName);
|
||||
cli_config::SetLoad(m_XbeFilename);
|
||||
cli_config::SetValue(cli_config::hwnd, hwndParent);
|
||||
cli_config::SetValue(cli_config::debug_mode, g_Settings->m_core.KrnlDebugMode);
|
||||
if (g_Settings->m_core.KrnlDebugMode == DM_FILE) {
|
||||
cli_config::SetValue(cli_config::debug_file, g_Settings->m_core.szKrnlDebug);
|
||||
}
|
||||
else {
|
||||
cli_config::SetValue(cli_config::debug_file, "");
|
||||
}
|
||||
/* Main process to generate emulation command line end. */
|
||||
|
||||
UnmapPersistedMemory();
|
||||
|
||||
|
@ -2278,10 +2297,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
|
|||
// Check then close existing debugger monitor.
|
||||
DebuggerMonitorClose();
|
||||
|
||||
// TODO: Set a configuration variable for this. For now it will be within the same folder as Cxbx.exe
|
||||
std::string szProcDbgArgsBuffer = "cxbxr-debugger.exe " + szProcArgsBuffer;
|
||||
|
||||
if (!CxbxExec(szProcDbgArgsBuffer, &m_hDebuggerProc, true)) {
|
||||
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);
|
||||
|
||||
printf("WndMain: %s debugger shell failed.\n", m_Xbe->m_szAsciiTitle);
|
||||
|
@ -2294,7 +2310,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
|
|||
}
|
||||
else {
|
||||
|
||||
if (!CxbxExec(szProcArgsBuffer, nullptr, false)) {
|
||||
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);
|
||||
|
||||
printf("WndMain: %s shell failed.\n", m_Xbe->m_szAsciiTitle);
|
||||
|
|
Loading…
Reference in New Issue