Improved error handling + updated README file.

This commit is contained in:
LoRd_MuldeR 2020-10-05 16:11:31 +02:00
parent 9e73dfa2c5
commit d95313cd98
3 changed files with 74 additions and 24 deletions

View File

@ -10,26 +10,49 @@
There currently are two different ways to use Launch5j with your application code: 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. 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:
<concat destfile="bazinga.exe" binary="true"> <concat destfile="thingamabob.exe" binary="true">
<fileset file="launch5j_wrapped.exe"/> <fileset file="launch5j_wrapped.exe"/>
<fileset file="bazinga.jar"/> <fileset file="thingamabob.jar"/>
</concat> </concat>
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 &ndash; 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&reg;'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. **Warning:** Code signing, as with Microsoft&reg;'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: 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`** * **`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. 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`** * **`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: 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) - [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/) - [Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/)
Regarding the different available distributions of Java, please refer to this document: 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`** * **`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. 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.

View File

@ -21,6 +21,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <direct.h> #include <direct.h>
#include <fcntl.h>
// Win32 API // Win32 API
#include <Windows.h> #include <Windows.h>
@ -1356,7 +1357,7 @@ static const wchar_t *describe_system_error(const DWORD error_code)
#if L5J_ENABLE_GUI #if L5J_ENABLE_GUI
#define show_message(HWND, FLAGS, TITLE, TEXT) MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS)) #define show_message(HWND, FLAGS, TITLE, TEXT) MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS))
#else #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 #endif
static int show_message_format(HWND hwnd, const DWORD flags, const wchar_t *const title, const wchar_t *const format, ...) 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"; const wchar_t *const CPU_ARCH = L"x86";
#endif #endif
show_message_format(hwnd, MB_ICONINFORMATION, L"About Launch5j", show_message_format(hwnd, MB_ICONINFORMATION, L"About Launch5j",
L"Launch5j (%s), by LoRd_MuldeR <MuldeR2@GMX.de>\n" L"Launch5j, by LoRd_MuldeR <MuldeR2@GMX.de>\n"
L"v%u.%u.%u, build %u, created %s %s\n\n" L"Version: %u.%u.%u (%s), Build: #%u, %s\n\n"
L"This work has been released under the MIT license.\n" L"This work has been released under the MIT license.\n"
L"For details, please see:\n" L"For details, please see:\n"
L"https://opensource.org/licenses/MIT\n\n" L"https://opensource.org/licenses/MIT\n\n"
L"Check the project website for news and updates:\n" L"Check the project website for news and updates:\n"
L"https://github.com/lordmulder/\n\n" L"https://github.com/lordmulder/\n\n"
L"Build options:\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", 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",
CPU_ARCH, L5J_VERSION_MAJOR, L5J_VERSION_MINOR, L5J_VERSION_PATCH, L5J_BUILDNO, TEXT(__DATE__), TEXT(__TIME__), L5J_VERSION_MAJOR, L5J_VERSION_MINOR, L5J_VERSION_PATCH, CPU_ARCH, L5J_BUILDNO, TEXT(__DATE__),
L5J_JAR_FILE_WRAPPED, L5J_DETECT_REGISTRY, L5J_ENABLE_SPLASH, L5J_STAY_ALIVE, L5J_ENCODE_ARGS, L5J_WAIT_FOR_WINDOW); 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) 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; HANDLE mutex_handle = NULL;
DWORD java_required_bitness = 0U; DWORD java_required_bitness = 0U;
ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL; ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL;
HWND hwnd = NULL;
HGDIOBJ splash_image = NULL; HGDIOBJ splash_image = NULL;
BOOL have_screen_created = FALSE; BOOL have_screen_created = FALSE;
PROCESS_INFORMATION process_info; 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); app_heading = load_string(hinstance, ID_STR_HEADING);
// Create the window // Create the window
#if L5J_ENABLE_GUI 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;
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
// Show about screen? // Show about screen?
if (starts_with(cmd_line_args, L"--l5j-about")) 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 #else
jre_relative_path = load_string(hinstance, ID_STR_JREPATH); 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!"); show_message(hwnd, MB_ICONERROR | MB_TOPMOST, APP_HEADING, L"The path of the Java runtime could not be determined!");
goto cleanup; goto cleanup;
@ -1761,9 +1759,28 @@ cleanup:
/* Entry points */ /* 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 #if L5J_ENABLE_GUI
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) 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); return launch5j_main(hInstance, pCmdLine);
} }
#else #else
@ -1771,6 +1788,11 @@ extern HINSTANCE __mingw_winmain_hInstance;
extern LPWSTR __mingw_winmain_lpCmdLine; extern LPWSTR __mingw_winmain_lpCmdLine;
int wmain(int argc, wchar_t **argv, wchar_t **envp) 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); return launch5j_main(__mingw_winmain_hInstance, __mingw_winmain_lpCmdLine);
} }
#endif #endif

View File

@ -21,8 +21,8 @@
// VERSION // VERSION
#define L5J_VERSION_MAJOR 0 #define L5J_VERSION_MAJOR 0
#define L5J_VERSION_MINOR 6 #define L5J_VERSION_MINOR 7
#define L5J_VERSION_PATCH 2 #define L5J_VERSION_PATCH 0
// ICON // ICON
#define ID_ICON_MAIN 1 #define ID_ICON_MAIN 1