diff --git a/src/openrct2/cmdline/CommandLine.hpp b/src/openrct2/cmdline/CommandLine.hpp index 21463f9467..2014326da6 100644 --- a/src/openrct2/cmdline/CommandLine.hpp +++ b/src/openrct2/cmdline/CommandLine.hpp @@ -110,4 +110,5 @@ namespace CommandLine exitcode_t HandleCommandDefault(); exitcode_t HandleCommandConvert(CommandLineArgEnumerator * enumerator); + exitcode_t HandleCommandUri(CommandLineArgEnumerator * enumerator); } diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index b68ca8e7f1..1d64d017b8 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -126,6 +126,7 @@ const CommandLineCommand CommandLine::RootCommands[] DefineCommand("set-rct2", "", StandardOptions, HandleCommandSetRCT2), DefineCommand("convert", " ", StandardOptions, CommandLine::HandleCommandConvert), DefineCommand("scan-objects", "", StandardOptions, HandleCommandScanObjects), + DefineCommand("handle-uri", "openrct2://.../", StandardOptions, CommandLine::HandleCommandUri), #if defined(__WINDOWS__) && !defined(__MINGW32__) DefineCommand("register-shell", "", RegisterShellOptions, HandleCommandRegisterShell), diff --git a/src/openrct2/cmdline/UriHandler.cpp b/src/openrct2/cmdline/UriHandler.cpp new file mode 100644 index 0000000000..041f6c0bb9 --- /dev/null +++ b/src/openrct2/cmdline/UriHandler.cpp @@ -0,0 +1,93 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/Console.hpp" +#include "../core/Memory.hpp" +#include "../core/String.hpp" +#include "../network/network.h" +#include "CommandLine.hpp" + +extern "C" +{ + #include "../openrct2.h" +} + +static exitcode_t HandleUri(const utf8 * uri); + +exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) +{ + const utf8 * uri; + if (enumerator->TryPopString(&uri)) + { + if (String::StartsWith(uri, "openrct2://")) + { + const utf8 * uriCommand = uri + 11; + return HandleUri(uriCommand); + } + } + + Console::Error::WriteLine("Invalid URI"); + return EXITCODE_FAIL; +} + +static exitcode_t HandleUri(const utf8 * uri) +{ + utf8 * * args; + size_t numArgs = String::Split(&args, uri, '/'); + if (numArgs > 0) + { + utf8 * arg = args[0]; + if (String::Equals(arg, "join")) + { + if (numArgs > 1) + { + utf8 * hostnamePort = args[1]; + + // Argument is in hostname:port format, so we need to split + utf8 * hostname = String::Duplicate(hostnamePort); + sint32 port = NETWORK_DEFAULT_PORT; + size_t colonIndex = String::IndexOf(hostnamePort, ':'); + if (colonIndex != SIZE_MAX) + { + Memory::Free(hostname); + hostname = String::Substring(hostnamePort, 0, colonIndex); + port = atoi(hostnamePort + colonIndex + 1); + } + + // Set the network start configuration + gNetworkStart = NETWORK_MODE_CLIENT; + String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname); + gNetworkStartPort = port; + + Memory::Free(hostname); + } + else + { + Console::Error::WriteLine("Expected hostname:port after join"); + return EXITCODE_FAIL; + } + } + } + + // Clean up + for (size_t i = 0; i < numArgs; i++) + { + Memory::Free(args[i]); + } + Memory::FreeArray(args, numArgs); + + return EXITCODE_CONTINUE; +} diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 8096eb5290..fe636745d1 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -72,6 +72,7 @@ + diff --git a/src/openrct2/platform/platform.h b/src/openrct2/platform/platform.h index df2181f2c5..535b33fedf 100644 --- a/src/openrct2/platform/platform.h +++ b/src/openrct2/platform/platform.h @@ -224,6 +224,7 @@ void core_init(); HWND windows_get_window_handle(); void platform_setup_file_associations(); void platform_remove_file_associations(); + bool platform_setup_uri_protocol(); // This function cannot be marked as 'static', even though it may seem to be, // as it requires external linkage, which 'static' prevents __declspec(dllexport) sint32 StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, sint32 nCmdShow); diff --git a/src/openrct2/platform/windows.c b/src/openrct2/platform/windows.c index fa568c323d..e46fbbd84b 100644 --- a/src/openrct2/platform/windows.c +++ b/src/openrct2/platform/windows.c @@ -1040,7 +1040,8 @@ utf8* platform_get_username() { // File association setup /////////////////////////////////////////////////////////////////////////////// -#define SOFTWARE_CLASSES L"Software\\Classes" +#define SOFTWARE_CLASSES L"Software\\Classes" +#define MUI_CACHE L"Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache" static void get_progIdName(wchar_t *dst, const utf8 *extension) { @@ -1183,4 +1184,50 @@ void platform_remove_file_associations() } /////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// URI protocol association setup +/////////////////////////////////////////////////////////////////////////////// + +bool platform_setup_uri_protocol() +{ + log_verbose("Setting up URI protocol..."); + + // [HKEY_CURRENT_USER\Software\Classes] + HKEY hRootKey; + if (RegOpenKeyW(HKEY_CURRENT_USER, SOFTWARE_CLASSES, &hRootKey) == ERROR_SUCCESS) { + // [hRootKey\openrct2] + HKEY hClassKey; + if (RegCreateKeyA(hRootKey, "openrct2", &hClassKey) == ERROR_SUCCESS) { + if (RegSetValueA(hClassKey, NULL, REG_SZ, "URL:openrct2", 0) == ERROR_SUCCESS) { + if (RegSetKeyValueA(hClassKey, NULL, "URL Protocol", REG_SZ, "", 0) == ERROR_SUCCESS) { + // [hRootKey\openrct2\shell\open\command] + wchar_t exePath[MAX_PATH]; + GetModuleFileNameW(NULL, exePath, MAX_PATH); + + wchar_t buffer[512]; + swprintf_s(buffer, sizeof(buffer), L"\"%s\" handle-uri \"%%1\"", exePath); + if (RegSetValueW(hClassKey, L"shell\\open\\command", REG_SZ, buffer, 0) == ERROR_SUCCESS) { + // Not compulsory, but gives the application a nicer name + // [HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache] + HKEY hMuiCacheKey; + if (RegCreateKeyW(hRootKey, MUI_CACHE, &hMuiCacheKey) == ERROR_SUCCESS) { + swprintf_s(buffer, sizeof(buffer), L"%s.FriendlyAppName", exePath); + RegSetKeyValueW(hMuiCacheKey, NULL, buffer, REG_SZ, L"OpenRCT2", sizeof(L"OpenRCT2") + 1); + } + + log_verbose("URI protocol setup successful"); + return true; + } + } + } + } + } + + log_verbose("URI protocol setup failed"); + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + #endif