diff --git a/README.md b/README.md index 420f323..8e21d69 100644 --- a/README.md +++ b/README.md @@ -10,26 +10,49 @@ There currently are two different ways to use Launch5j with your application code: -* ***Use the launcher executable with a separate JAR file*** +* **Use the launcher executable with a separate JAR file** Simply put the launcher executable (`launch5j.exe`) and your JAR file into the same directory. Launch5j will automatically detect the path of the JAR file based on the location of the executable file. More specifically, Launch5j detects the full path of the executable file and then replaces the `.exe` file extension with a `.jar` file extension. Of course, you can rename the `launch5j.exe` executable to whatever you prefer. - *For example:* If you application's JAR file is called `bazinga.jar`, pick the Launch5j variant of your choice, rename the Launch5j executable to `bazinga.exe`, and put these two files (JAR + EXE) into the “install”directory. + ***For example:*** Assuming your application's JAR file is called `thingamabob.jar`, pick the Launch5j launcher variant of your choice (**no** `wrapped` variant though!), rename the launcher executable to `thingamabob.exe`, and put these two files into the “install” directory. Also, the Java runtime should be located in the `runtime` sub-directory within the “install” directory – unless you are using the `registry` variant of Launch5j. -* ***Combine the launcher executable and the JAR file (“wrapping”)*** + ``` + install_dir + ├── thingamabob.exe + ├── thingamabob.jar + ├── runtime + │ └── bin + │ ├── java.exe + │ ├── javaw.exe + │ └── [...] + └── [...] + ``` + +* **Combine the launcher executable and the JAR file (“wrapping”)** - In order to combine the launcher executable (`launch5j_wrapped.exe`) and the JAR file to a *single* file, you can simply concatenate these files. The executable launcher must go before the JAR file content. There are many ways to achieve this, but one method is by running the following **copy** command-line in the terminal: + In order to combine the Launch5j launcher executable and the JAR file to a ***single*** file, you can simply *concatenate* these two files. For this purpose, you have to choose one of the `wrapped` variants of Launch5j. Also, the executable launcher code must go before the JAR file content. There are many ways to achieve this, but probably the most simple method is running the following **copy** command-line in the terminal: - copy /B launch5j_wrapped.exe + bazinga.jar bazinga.exe + copy /B launch5j_wrapped.exe + thingamabob.jar thingamabob.exe - If you are building you application with [**Apache Ant**](https://ant.apache.org/), consider using the `concat` task like this: + If you are building your application with [**Apache Ant**](https://ant.apache.org/), consider using the `concat` task like this: - + - + - The resulting `bazinga.exe` will be fully self-contained and is the only file you'll need to ship. + The resulting `thingamabob.exe` is fully self-contained, **no** separate JAR file needs to be shipped. Still, a Java runtime is required to run the application! The Java runtime should be located in the `runtime` sub-directory within the “install” directory – unless you are using the `registry` variant of Launch5j. + + ``` + install_dir + ├── thingamabob.exe + ├── runtime + │ └── bin + │ ├── java.exe + │ ├── javaw.exe + │ └── [...] + └── [...] + ``` **Warning:** Code signing, as with Microsoft®'s `SignTool`, probably does **not** work with the “wrapped” executable file! If code signing is a requirement, please use a *separate* JAR file and just sing the launcher executable. @@ -38,11 +61,16 @@ There currently are two different ways to use Launch5j with your application cod Launch5j executables come in a number of variants, allowing you to pick the most suitable one for your project: +* **`nogui`** + No graphical user interface is created and the Java application is launched via the `java.exe` (console mode) program; default variant launches the Java application via the `javaw.exe` (windowed mode) program. + + *Note:* If using this variant, the program should be called from within a terminal window! + * **`wrapped`** Expects that the JAR file and the executable launcher have been combined to a *single* file; default variant expects that a separate JAR file is present in the same directory where the executable launcher resides. * **`registry`** - Tries to automatically detect the install path of the JRE from the Windows registry; default variant expects the JRE to be located in the `/runtime` path relative to the location of the executable launcher. + Tries to automatically detect the install path of the JRE from the Windows registry; default variant expects the JRE to be located in the `runtime` path relative to the location of the executable launcher. At this time, the following Java distributions can be detected from the registry: - [Oracle JDK (JavaSoft)](https://www.oracle.com/java/technologies/javase-downloads.html) @@ -51,7 +79,7 @@ Launch5j executables come in a number of variants, allowing you to pick the most - [Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/) Regarding the different available distributions of Java, please refer to this document: - [*Java Is Still Free*](https://docs.google.com/document/d/1nFGazvrCvHMZJgFstlbzoHjpAVwv5DEdnaBr_5pKuHo/preview) + [***Java Is Still Free***](https://docs.google.com/document/d/1nFGazvrCvHMZJgFstlbzoHjpAVwv5DEdnaBr_5pKuHo/preview) * **`nowait`** Does **not** keep the launcher executable alive while the application is running; default variant keeps the launcher executable alive until the application terminates and then forwards the application's exit code. diff --git a/src/head.c b/src/head.c index 4cabc90..2e98651 100644 --- a/src/head.c +++ b/src/head.c @@ -21,6 +21,7 @@ #include #include #include +#include // Win32 API #include @@ -1356,7 +1357,7 @@ static const wchar_t *describe_system_error(const DWORD error_code) #if L5J_ENABLE_GUI #define show_message(HWND, FLAGS, TITLE, TEXT) MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS)) #else -#define show_message(HWND, FLAGS, TITLE, TEXT) ({ const int _retval = __ms_fwprintf(stderr, L"%s\n", (TEXT)); fflush(stderr); _retval; }) +#define show_message(HWND, FLAGS, TITLE, TEXT) ({ __ms_fwprintf(stderr, L"%s\n", (TEXT)); fflush(stderr); IDCANCEL; }) #endif static int show_message_format(HWND hwnd, const DWORD flags, const wchar_t *const title, const wchar_t *const format, ...) @@ -1417,17 +1418,17 @@ static void show_about_dialogue(const HWND hwnd) const wchar_t *const CPU_ARCH = L"x86"; #endif show_message_format(hwnd, MB_ICONINFORMATION, L"About Launch5j", - L"Launch5j (%s), by LoRd_MuldeR \n" - L"v%u.%u.%u, build %u, created %s %s\n\n" + L"Launch5j, by LoRd_MuldeR \n" + L"Version: %u.%u.%u (%s), Build: #%u, %s\n\n" L"This work has been released under the MIT license.\n" L"For details, please see:\n" L"https://opensource.org/licenses/MIT\n\n" L"Check the project website for news and updates:\n" L"https://github.com/lordmulder/\n\n" L"Build options:\n" - L"JAR_FILE_WRAPPED=%d, DETECT_REGISTRY=%d, ENABLE_SPLASH=%d, STAY_ALIVE=%d, ENCODE_ARGS=%d, WAIT_FOR_WINDOW=%d", - CPU_ARCH, L5J_VERSION_MAJOR, L5J_VERSION_MINOR, L5J_VERSION_PATCH, L5J_BUILDNO, TEXT(__DATE__), TEXT(__TIME__), - L5J_JAR_FILE_WRAPPED, L5J_DETECT_REGISTRY, L5J_ENABLE_SPLASH, L5J_STAY_ALIVE, L5J_ENCODE_ARGS, L5J_WAIT_FOR_WINDOW); + L"L5J_ENABLE_GUI=%d, JAR_FILE_WRAPPED=%d, DETECT_REGISTRY=%d, ENABLE_SPLASH=%d, STAY_ALIVE=%d, ENCODE_ARGS=%d, WAIT_FOR_WINDOW=%d", + L5J_VERSION_MAJOR, L5J_VERSION_MINOR, L5J_VERSION_PATCH, CPU_ARCH, L5J_BUILDNO, TEXT(__DATE__), + L5J_ENABLE_GUI, L5J_JAR_FILE_WRAPPED, L5J_DETECT_REGISTRY, L5J_ENABLE_SPLASH, L5J_STAY_ALIVE, L5J_ENCODE_ARGS, L5J_WAIT_FOR_WINDOW); } static void enable_slunk_mode(const HWND hwnd) @@ -1541,7 +1542,6 @@ static int launch5j_main(const HINSTANCE hinstance, const wchar_t *const cmd_lin HANDLE mutex_handle = NULL; DWORD java_required_bitness = 0U; ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL; - HWND hwnd = NULL; HGDIOBJ splash_image = NULL; BOOL have_screen_created = FALSE; PROCESS_INFORMATION process_info; @@ -1563,9 +1563,7 @@ static int launch5j_main(const HINSTANCE hinstance, const wchar_t *const cmd_lin app_heading = load_string(hinstance, ID_STR_HEADING); // Create the window -#if L5J_ENABLE_GUI - hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, L"STATIC", APP_HEADING, WS_POPUP | SS_BITMAP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance, NULL); -#endif + HWND hwnd = L5J_ENABLE_GUI ? CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, L"STATIC", APP_HEADING, WS_POPUP | SS_BITMAP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance, NULL) : NULL; // Show about screen? if (starts_with(cmd_line_args, L"--l5j-about")) @@ -1657,7 +1655,7 @@ static int launch5j_main(const HINSTANCE hinstance, const wchar_t *const cmd_lin } #else jre_relative_path = load_string(hinstance, ID_STR_JREPATH); - if (!(java_runtime_path = get_java_full_path(executable_path, jre_relative_path))) + if (!(java_runtime_path = get_java_full_path(executable_directory, jre_relative_path))) { show_message(hwnd, MB_ICONERROR | MB_TOPMOST, APP_HEADING, L"The path of the Java runtime could not be determined!"); goto cleanup; @@ -1761,9 +1759,28 @@ cleanup: /* Entry points */ /* ======================================================================== */ +#define THE_NUMBER_OF_THE_BEAST 666 + +static LONG WINAPI unhandeled_exception(EXCEPTION_POINTERS *ExceptionInfo) +{ + static const wchar_t *const ERROR_MESSAGE = L"\nUnhandeled exception error encountered. Exiting!"; +#if L5J_ENABLE_GUI + FatalAppExitW(0U, ERROR_MESSAGE); +#else + DWORD chars_written; + WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), ERROR_MESSAGE, lstrlenW(ERROR_MESSAGE), &chars_written, NULL); +#endif + TerminateProcess(GetCurrentProcess(), THE_NUMBER_OF_THE_BEAST); + return EXCEPTION_EXECUTE_HANDLER; +} + #if L5J_ENABLE_GUI int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { +#ifdef NDEBUG + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + SetUnhandledExceptionFilter(unhandeled_exception); +#endif return launch5j_main(hInstance, pCmdLine); } #else @@ -1771,6 +1788,11 @@ extern HINSTANCE __mingw_winmain_hInstance; extern LPWSTR __mingw_winmain_lpCmdLine; int wmain(int argc, wchar_t **argv, wchar_t **envp) { +#ifdef NDEBUG + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + SetUnhandledExceptionFilter(unhandeled_exception); +#endif + _setmode(_fileno(stderr), _O_U8TEXT); return launch5j_main(__mingw_winmain_hInstance, __mingw_winmain_lpCmdLine); } #endif diff --git a/src/resource.h b/src/resource.h index 0c00247..55a687f 100644 --- a/src/resource.h +++ b/src/resource.h @@ -21,8 +21,8 @@ // VERSION #define L5J_VERSION_MAJOR 0 -#define L5J_VERSION_MINOR 6 -#define L5J_VERSION_PATCH 2 +#define L5J_VERSION_MINOR 7 +#define L5J_VERSION_PATCH 0 // ICON #define ID_ICON_MAIN 1