From 6a5ef7f6657e56a78435e7c900cb830cebac4b7d Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Sat, 26 Sep 2020 16:38:28 +0200 Subject: [PATCH] Initial commit. --- LICENSE.txt | 121 ++++++++++++++++++ src/main.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 LICENSE.txt create mode 100644 src/main.c diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..814dbf5 --- /dev/null +++ b/src/main.c @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN 1 +#include + +static const wchar_t *const JRE_RELATIVE_PATH = L"runtime\\bin\\javaw.exe"; + +/* ======================================================================== */ +/* String routines */ +/* ======================================================================== */ + +#define NOT_EMPTY(STR) ((STR) && ((STR)[0U])) + +static wchar_t *awprintf(const wchar_t *const fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + const int str_len = _vscwprintf(fmt, ap); + if (str_len < 1) + { + return NULL; + } + + wchar_t *buffer = (wchar_t*) malloc(sizeof(wchar_t) * (((size_t)str_len) + 1U)); + if (!buffer) + { + return NULL; + } + + const int result = vswprintf(buffer, ((size_t)str_len) + 1U, fmt, ap); + if (result < 1) + { + free(buffer); + buffer = NULL; + } + + va_end(ap); + return buffer; +} + +static wchar_t *wcsndup (const wchar_t *const str, const size_t n) +{ + size_t str_len = wcslen(str); + if (n < str_len) + { + str_len = n; + } + + wchar_t *const result = (wchar_t*) malloc(sizeof(wchar_t) * (str_len + 1U)); + if (!result) + { + return NULL; + } + + wcsncpy(result, str, str_len); + result[str_len] = '\0'; + return result; +} + +/* ======================================================================== */ +/* File name routines */ +/* ======================================================================== */ + +static wchar_t *get_directory_part(const wchar_t *const path) +{ + size_t lastsep = SIZE_MAX; + + if(NOT_EMPTY(path)) + { + for (size_t i = 0; path[i]; ++i) + { + if ((path[i] == L'\\') || (path[i] == L'/')) + { + lastsep = i; + } + } + } + + if (lastsep != SIZE_MAX) + { + return wcsndup(path, lastsep); + } + + return wcsdup(L"."); +} + +static wchar_t *remove_file_extension(const wchar_t *const path) +{ + size_t lastsep = SIZE_MAX; + size_t lastdot = SIZE_MAX; + + for (size_t i = 0; path[i]; ++i) + { + if ((path[i] == L'\\') || (path[i] == L'/')) + { + lastsep = i; + } + else if (path[i] == L'.') + { + lastdot = i; + } + } + + if (lastdot != SIZE_MAX) + { + if((lastsep == SIZE_MAX) || (lastdot > lastsep)) + { + return wcsndup(path, lastdot); + } + } + + return wcsdup(path); +} + +static BOOL file_exists(const wchar_t *const filename) { + struct _stat buffer; + if (_wstat(filename, &buffer) == 0) + { + return S_ISDIR(buffer.st_mode) ? FALSE : TRUE; + } + return FALSE; +} + +/* ======================================================================== */ +/* Path detection */ +/* ======================================================================== */ + +static const wchar_t *const DEFAULT_JARFILE_NAME = L"application.jar"; + +static const wchar_t *get_executable_path(void) +{ + if (_wpgmptr && _wpgmptr[0U]) + { + return wcsdup(_wpgmptr); + } + return NULL; +} + +static const wchar_t *get_executable_directory(const wchar_t *const executable_path) +{ + const wchar_t *const directory_part = get_directory_part(executable_path); + if (directory_part) + { + return directory_part; + } + + free((void*)directory_part); + return wcsdup(L"."); +} + +static const wchar_t *get_jarfile_path(const wchar_t *const executable_path, const wchar_t *const executable_directory) +{ + const wchar_t *jarfile_path = NULL; + + const wchar_t *const path_prefix = remove_file_extension(executable_path); + if (NOT_EMPTY(path_prefix)) + { + const size_t len = wcslen(path_prefix); + if (!((len > 0U) && ((path_prefix[len-1U] == L'\\') || (path_prefix[len-1U] == L'/')))) + { + jarfile_path = awprintf(L"%ls.jar", path_prefix); + } + } + + if (!jarfile_path) + { + jarfile_path = NOT_EMPTY(executable_directory) ? awprintf(L"%ls\\%ls", executable_directory, DEFAULT_JARFILE_NAME) : wcsdup(DEFAULT_JARFILE_NAME); + } + + free((void*)path_prefix); + return jarfile_path; +} + +/* ======================================================================== */ +/* Path manipulation */ +/* ======================================================================== */ + +static const BOOL set_current_directory(const wchar_t *const path) +{ + if(NOT_EMPTY(path)) + { + if(iswalpha(path[0U]) && (path[1U] == L':') && (path[2U] == L'\0')) + { + const wchar_t root_path[4U] = { path[0U], L':', L'\\', L'\0' }; + return SetCurrentDirectoryW(root_path); + } + else + { + return SetCurrentDirectoryW(path); + } + } + else + { + return SetCurrentDirectoryW(L"\\"); + } +} + +/* ======================================================================== */ +/* Message box */ +/* ======================================================================== */ + +static const wchar_t *describe_system_error(const DWORD error_code) +{ + const wchar_t *error_test = NULL, *buffer = NULL; + + const DWORD len = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&buffer, 0, NULL); + if((len > 0U) && NOT_EMPTY(buffer)) + { + error_test = wcsdup(buffer); + LocalFree((HLOCAL)buffer); + } + + return error_test; +} + +#define show_message(HWND, FLAGS, TITLE, TEXT) \ +{ \ + MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS)); \ +} \ +while(0) + +#define show_message_format(HWND, FLAGS, TITLE, FORMAT, ...) do \ +{ \ + const wchar_t *const _text = awprintf((FORMAT), __VA_ARGS__); \ + if(_text) \ + { \ + MessageBoxW((HWND), _text, (TITLE), (FLAGS)); \ + } \ + free((void*)_text); \ +} \ +while(0) + +/* ======================================================================== */ +/* MAIN */ +/* ======================================================================== */ + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) +{ + int exit_code = -1; + const wchar_t *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, *java_runtime_path = NULL, *command_line = NULL; + STARTUPINFOW startup_info; + PROCESS_INFORMATION process_info; + + // Initialize + SecureZeroMemory(&startup_info, sizeof(STARTUPINFOW)); + SecureZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); + + // Find executable path + if(!(executable_path = get_executable_path())) + { + show_message(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"The path of the executable could not be determined!"); + goto cleanup; + } + + // Find executable directory + if(!(executable_directory = get_executable_directory(executable_path))) + { + show_message(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"The executable directory could not be determined!"); + goto cleanup; + } + + // Set the current directory + if(_wcsicmp(executable_directory, L".") != 0) + { + set_current_directory(executable_directory); + } + + // Find the JAR file path + if(!(jarfile_path = get_jarfile_path(executable_path, executable_directory))) + { + show_message(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"The path of the JAR file could not be determined!"); + goto cleanup; + } + + // Find the Java runtime path + if(!(java_runtime_path = awprintf(L"%ls\\%ls", executable_directory, JRE_RELATIVE_PATH))) + { + show_message(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"The path of the Java runtime could not be determined!"); + goto cleanup; + } + + // Does JAR file exist? + if(!file_exists(jarfile_path)) + { + show_message_format(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"JAR not found", L"The required JAR file could not be found:\n\n%ls\n\n\nRe-installing the application may fix the problem!", jarfile_path); + goto cleanup; + } + + // Does the Java runtime exist? + if(!file_exists(java_runtime_path)) + { + show_message_format(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"Java not found", L"The required Java runtime could not be found:\n\n%ls\n\n\nRe-installing the application may fix the problem!", java_runtime_path); + goto cleanup; + } + + // Build the command-line + command_line = NOT_EMPTY(pCmdLine) ? awprintf(L"\"%ls\" -jar \"%ls\" %ls", java_runtime_path, jarfile_path, pCmdLine) : awprintf(L"\"%ls\" -jar \"%ls\"", java_runtime_path, jarfile_path); + if(!command_line) + { + show_message(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"The Java command-line could not be generated!"); + goto cleanup; + } + + // Now actually start the process! + if(!CreateProcessW(NULL, (LPWSTR)command_line, NULL, NULL, FALSE, 0U, NULL, executable_directory, &startup_info, &process_info)) + { + const wchar_t *const error_text = describe_system_error(GetLastError()); + if(error_text) + { + show_message_format(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"Failed to create the Java process:\n\n%ls\n\n\n%ls", command_line, error_text); + free((void*)error_text); + } + else + { + show_message_format(NULL, MB_ICONERROR | MB_SYSTEMMODAL, L"System Error", L"Failed to create the Java process:\n\n%ls", command_line); + } + goto cleanup; + } + +cleanup: + + if(process_info.hThread) + { + CloseHandle(process_info.hThread); + } + + if(process_info.hProcess) + { + CloseHandle(process_info.hProcess); + } + + free((void*)command_line); + free((void*)java_runtime_path); + free((void*)jarfile_path); + free((void*)executable_directory); + free((void*)executable_path); + + return exit_code; +}