Added command-line parameters.

However, there's an issue with initialisation and the whole
multi-process thing making that difficult.
This commit is contained in:
WrinklyNinja
2014-07-12 16:36:39 +01:00
parent afaa1e4209
commit 17aadb565e
6 changed files with 212 additions and 44 deletions
+2 -1
View File
@@ -64,7 +64,7 @@ set (LOOT_GUI_SRC ${LOOT_SRC}
set (LOOT_API_SRC ${LOOT_SRC}
"${CMAKE_SOURCE_DIR}/src/api/api.cpp")
find_package(Boost REQUIRED COMPONENTS log log_setup locale thread chrono date_time filesystem system regex iostreams)
find_package(Boost REQUIRED COMPONENTS log log_setup locale thread chrono date_time filesystem program_options system regex iostreams)
# Include source and library directories.
include_directories ("${CMAKE_SOURCE_DIR}/src"
@@ -113,6 +113,7 @@ IF (MINGW)
boost_chrono
boost_date_time
boost_filesystem
boost_program_options
boost_system
boost_regex
version
+1 -1
View File
@@ -6,7 +6,7 @@ These instructions were used to build LOOT using Microsoft Visual Studio 2012 an
```
bootstrap.bat
b2 toolset=msvc threadapi=win32 link=static runtime-link=static variant=release address-model=32 --with-log --with-date_time --with-thread --with-filesystem --with-locale --with-regex --with-system --with-iostreams
b2 toolset=msvc threadapi=win32 link=static runtime-link=static variant=release address-model=32 --with-log --with-date_time --with-thread --with-filesystem --with-program_options --with-locale --with-regex --with-system --with-iostreams
```
`link`, `runtime-link` and `address-model` can all be modified if shared linking or 64 bit builds are desired. LOOT uses statically-linked Boost libraries by default: to change this, edit [CMakeLists.txt](../CMakeLists.txt).
+1 -1
View File
@@ -7,7 +7,7 @@ These instructions were used to build LOOT using mingw-w64 on Ubuntu and Debian
```
./bootstrap.sh
echo "using gcc : 4.6.3 : i686-w64-mingw32-g++ : <rc>i686-w64-mingw32-windres <archiver>i686-w64-mingw32-ar <ranlib>i686-w64-mingw32-ranlib ;" > tools/build/v2/user-config.jam
./b2 toolset=gcc-4.6.3 target-os=windows threadapi=win32 link=static runtime-link=static variant=release address-model=32 cxxflags=-fPIC --with-log --with-date_time --with-thread --with-filesystem --with-locale --with-regex --with-system --with-iostreams --stagedir=stage-32
./b2 toolset=gcc-4.6.3 target-os=windows threadapi=win32 link=static runtime-link=static variant=release address-model=32 cxxflags=-fPIC --with-log --with-date_time --with-thread --with-filesystem --with-program_options --with-locale --with-regex --with-system --with-iostreams
```
#### Chromium Embedded Framework
+112 -2
View File
@@ -27,13 +27,104 @@
#include <include/cef_browser.h>
#include <include/cef_task.h>
#include <include/cef_runnable.h>
#include <boost/log/trivial.hpp>
#include <boost/format.hpp>
#include <boost/locale.hpp>
using namespace std;
using boost::locale::translate;
using boost::format;
namespace loot {
LootApp::LootApp(YAML::Node& settings) : _settings(settings) {}
LootApp::LootApp() {}
void LootApp::Init(YAML::Node& settings, std::string& cmdLineGame) {
_settings = settings;
string initError;
// Detect Games
//-------------
int gameIndex = -1;
//Detect installed games.
BOOST_LOG_TRIVIAL(debug) << "Detecting installed games.";
try {
_games = GetGames(settings);
}
catch (YAML::Exception& e) {
BOOST_LOG_TRIVIAL(error) << "Games' settings parsing failed. " << e.what();
initError = (format(translate("Error: Games' settings parsing failed. %1%")) % e.what()).str();
return;
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
initError = (format(translate("Error: Game-specific settings could not be initialised. %1%")) % e.what()).str();
return;
}
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
if (cmdLineGame.empty()) {
if (_settings["Game"] && _settings["Game"].as<string>() != "auto")
cmdLineGame = _settings["Game"].as<string>();
else if (_settings["Last Game"] && _settings["Last Game"].as<string>() != "auto")
cmdLineGame = _settings["Last Game"].as<string>();
}
if (!cmdLineGame.empty()) {
for (size_t i = 0, max = _games.size(); i < max; ++i) {
if (cmdLineGame == _games[i].FolderName() && _games[i].IsInstalled())
gameIndex = i;
}
}
if (gameIndex < 0) {
//Set gameIndex to the first installed game.
for (size_t i = 0, max = _games.size(); i < max; ++i) {
if (_games[i].IsInstalled()) {
gameIndex = i;
break;
}
}
if (gameIndex < 0) {
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
initError = translate("Error: None of the supported games were detected.").str();
return;
}
}
loot::Game& game(_games[gameIndex]);
BOOST_LOG_TRIVIAL(debug) << "Game selected is " << game.Name();
//Now that game is selected, initialise it.
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
try {
game.Init();
*find(_games.begin(), _games.end(), game) = game; //Sync changes.
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
initError = (format(translate("Error: Game-specific settings could not be initialised. %1%")) % e.what()).str();
return;
}
// Create the message object.
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("initJSVars");
// Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg>GetArgumentList();
// Populate the argument values.
args->SetString(0, my string);
args->SetInt(0, 10);
// Send the process message to the render process.
// Use PID_BROWSER instead when sending a message to the browser process.
browser->SendProcessMessage(PID_RENDERER, msg);
}
CefRefPtr<CefBrowserProcessHandler> LootApp::GetBrowserProcessHandler() {
return this;
@@ -90,8 +181,24 @@ namespace loot {
// Register javascript functions.
message_router_->OnContextCreated(browser, frame, context);
_context = context;
}
void LootApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) {
_context = NULL;
}
void LootApp::InitJSVars() {
BOOST_LOG_TRIVIAL(debug) << "Populating JS object variable initial values.";
if (_context == NULL)
return;
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal();
CefRefPtr<CefV8Value> object = _context->GetGlobal();
// Here the initialisation values should be set.
@@ -167,6 +274,9 @@ namespace loot {
lootObj->SetValue("languages", langsArr, V8_PROPERTY_ATTRIBUTE_NONE);
// Load Order
//-----------
object->SetValue("loot", lootObj, V8_PROPERTY_ATTRIBUTE_NONE);
}
}
+11 -1
View File
@@ -38,7 +38,9 @@ namespace loot {
public CefBrowserProcessHandler,
public CefRenderProcessHandler {
public:
LootApp(YAML::Node& settings);
LootApp();
void Init(YAML::Node& settings, std::string& cmdLineGame);
// Override CefApp methods.
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE;
@@ -59,6 +61,14 @@ namespace loot {
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
void InitJSVars();
CefRefPtr<CefV8Context> _context;
YAML::Node _settings;
std::vector<loot::Game> _games;
+85 -38
View File
@@ -40,8 +40,10 @@
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/program_options.hpp>
namespace fs = boost::filesystem;
namespace po = boost::program_options;
using namespace std;
using namespace loot;
@@ -50,11 +52,91 @@ using boost::format;
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
// Do application init
//--------------------
// Do all the standard CEF setup stuff.
//-------------------------------------
// Set up CEF sandbox.
CefScopedSandboxInfo scoped_sandbox;
void * sandbox_info = scoped_sandbox.sandbox_info();
// Read command line arguments.
CefMainArgs main_args(hInstance);
// Create the process reference.
CefRefPtr<loot::LootApp> app(new loot::LootApp);
// Run the process.
int exit_code = CefExecuteProcess(main_args, app.get(), sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
string initError;
string gameStr;
YAML::Node settings;
unsigned int verbosity = 0;
// Check if LOOT is already running
//---------------------------------
HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, L"LOOT.Shell.Instance");
if (hMutex != NULL) {
// An instance of LOOT is already running, so quit.
return 0;
}
else {
//Create the mutex so that future instances will not run.
hMutex = ::CreateMutex(NULL, FALSE, L"LOOT.Shell.Instance");
}
// Handle command line args (not CEF args)
//----------------------------------------
// declare the supported options
po::options_description opts("Options");
opts.add_options()
("help,h", translate("produces this help message").str().c_str())
("version,V", translate("prints the version banner").str().c_str())
("game,g", po::value(&gameStr),
translate("Override game autodetection. Valid values are the folder "
"names defined in the settings file.").str().c_str());
// parse command line arguments
po::variables_map vm;
try{
vector<wstring> args = po::split_winmain(lpCmdLine);
po::store(po::wcommand_line_parser(args).options(opts).run(), vm);
po::notify(vm);
}
catch (po::multiple_occurrences &){
BOOST_LOG_TRIVIAL(error) << "Cannot specify options multiple times; please use the '--help' option to see usage instructions";
std::cout << "Cannot specify options multiple times; please use the '--help' option to see usage instructions";
return 1;
}
catch (exception & e){
BOOST_LOG_TRIVIAL(error) << e.what() << "; please use the '--help' option to see usage instructions";
std::cout << e.what() << "; please use the '--help' option to see usage instructions";
return 1;
}
if (vm.count("help")) {
BOOST_LOG_TRIVIAL(info) << "Displaying command line help...";
std::cout << opts << std::endl;
if (hMutex != NULL)
ReleaseMutex(hMutex);
return 0;
}
if (vm.count("version")) {
BOOST_LOG_TRIVIAL(info) << "Displaying command line version...";
std::cout << "LOOT v" << g_version_major << "." << g_version_minor << "." << g_version_patch << std::endl;
if (hMutex != NULL)
ReleaseMutex(hMutex);
return 0;
}
// Do application init
//--------------------
//Load settings.
if (!fs::exists(g_path_settings)) {
@@ -64,7 +146,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
}
catch (fs::filesystem_error& /*e*/) {
initError = "Error: Could not create local app data LOOT folder.";
return 1;
}
GenerateDefaultSettingsFile(g_path_settings.string());
}
@@ -75,7 +156,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
}
catch (YAML::ParserException& e) {
initError = (format(translate("Error: Settings parsing failed. %1%")) % e.what()).str();
return 1;
}
//Set up logging.
@@ -90,7 +170,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
)
);
boost::log::add_common_attributes();
unsigned int verbosity = 0;
if (settings["Debug Verbosity"]) {
verbosity = settings["Debug Verbosity"].as<unsigned int>();
}
@@ -128,39 +207,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
cout.imbue(locale());
boost::filesystem::path::imbue(locale());
// Now do all the standard CEF setup stuff.
//----------------------------
// Set up CEF sandbox.
CefScopedSandboxInfo scoped_sandbox;
void * sandbox_info = scoped_sandbox.sandbox_info();
// Read command line arguments.
CefMainArgs main_args(hInstance);
// Create the process reference.
CefRefPtr<loot::LootApp> app(new loot::LootApp(settings));
// Run the process.
int exit_code = CefExecuteProcess(main_args, app.get(), sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
// Check if LOOT is already running
//---------------------------------
HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, L"LOOT.Shell.Instance");
if (hMutex != NULL) {
// An instance of LOOT is already running, so quit.
return 0;
}
else {
//Create the mutex so that future instances will not run.
hMutex = ::CreateMutex(NULL, FALSE, L"LOOT.Shell.Instance");
}
app.get()->Init(settings, gameStr);
// Back to CEF
//------------