diff --git a/Makefile b/Makefile index 6d75d50..65f9c73 100644 --- a/Makefile +++ b/Makefile @@ -29,14 +29,22 @@ resources: init windres -o obj/splash_screen.o res/splash_screen.rc headers: init resources - $(CC) $(CFLAGS) -o bin/head.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o - $(CC) $(CFLAGS) -o bin/head_nosplash.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o - $(CC) $(CFLAGS) -o bin/head_nowait.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o - $(CC) $(CFLAGS) -o bin/head_nowait_nosplash.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o - $(CC) $(CFLAGS) -o bin/head_wrapped.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o - $(CC) $(CFLAGS) -o bin/head_wrapped_nosplash.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o - $(CC) $(CFLAGS) -o bin/head_wrapped_nowait.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o - $(CC) $(CFLAGS) -o bin/head_wrapped_nowait_nosplash.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_nosplash.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_nowait.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_nowait_nosplash.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_wrapped.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_wrapped_nosplash.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_wrapped_nowait.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_wrapped_nowait_nosplash.exe -DDETECT_REGISTRY=0 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_registry.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_registry_nosplash.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_registry_nowait.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_registry_nowait_nosplash.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_registry_wrapped.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_registry_wrapped_nosplash.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o + $(CC) $(CFLAGS) -o bin/head_registry_wrapped_nowait.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o + $(CC) $(CFLAGS) -o bin/head_registry_wrapped_nowait_nosplash.exe -DDETECT_REGISTRY=1 -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o strip bin/head.exe strip bin/head_nosplash.exe strip bin/head_nowait.exe @@ -45,6 +53,14 @@ headers: init resources strip bin/head_wrapped_nosplash.exe strip bin/head_wrapped_nowait.exe strip bin/head_wrapped_nowait_nosplash.exe + strip bin/head_registry.exe + strip bin/head_registry_nosplash.exe + strip bin/head_registry_nowait.exe + strip bin/head_registry_nowait_nosplash.exe + strip bin/head_registry_wrapped.exe + strip bin/head_registry_wrapped_nosplash.exe + strip bin/head_registry_wrapped_nowait.exe + strip bin/head_registry_wrapped_nowait_nosplash.exe clean: init rm -f bin/*.exe diff --git a/src/head.c b/src/head.c index 313ce6e..a65b28e 100644 --- a/src/head.c +++ b/src/head.c @@ -13,18 +13,26 @@ #define WIN32_LEAN_AND_MEAN 1 -#include +// CRT #include #include #include #include #include #include + +// Win32 API +#include +#include + +// Resources #include "resource.h" // Const -static const DWORD SPLASH_SCREEN_TIMEOUT = 30000U; static const wchar_t *const JRE_RELATIVE_PATH = L"runtime\\bin\\javaw.exe"; +static const wchar_t *const JRE_DOWNLOAD_LINK = L"https://adoptopenjdk.net/"; +static const DWORD SPLASH_SCREEN_TIMEOUT = 30000U; +static const ULONGLONG JAVA_MINIMUM_VERSION = 0x0008000000000000ull; // Options #ifndef ENABLE_SPLASH @@ -39,18 +47,27 @@ static const wchar_t *const JRE_RELATIVE_PATH = L"runtime\\bin\\javaw.exe"; #ifndef STAY_ALIVE #define STAY_ALIVE 1 #endif +#ifndef DETECT_REGISTRY +#define DETECT_REGISTRY 0 +#endif +#ifndef PREFER_X64 +#define PREFER_X64 1 +#endif /* ======================================================================== */ /* String routines */ /* ======================================================================== */ #define NOT_EMPTY(STR) ((STR) && ((STR)[0U])) +#define SET_STRING(DST,SRC) do \ +{ \ + if((DST)) { free((void*)(DST)); } \ + (DST) = (SRC); \ +} \ +while(0) -static wchar_t *awprintf(const wchar_t *const fmt, ...) +static wchar_t *vawprintf(const wchar_t *const fmt, va_list ap) { - va_list ap; - va_start(ap, fmt); - const int str_len = _vscwprintf(fmt, ap); if (str_len < 1) { @@ -70,6 +87,16 @@ static wchar_t *awprintf(const wchar_t *const fmt, ...) buffer = NULL; } + return buffer; +} + +static wchar_t *awprintf(const wchar_t *const fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + wchar_t *const buffer = vawprintf(fmt, ap); + va_end(ap); return buffer; } @@ -93,6 +120,30 @@ static wchar_t *wcsndup (const wchar_t *const str, const size_t n) return result; } +/* ======================================================================== */ +/* System information */ +/* ======================================================================== */ + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +static BOOL running_on_64bit(void) +{ +#ifndef _M_X64 + BOOL is_wow64_flag = FALSE; + const LPFN_ISWOW64PROCESS is_wow64_process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandleW(L"kernel32"),"IsWow64Process"); + if (is_wow64_process) + { + if (!is_wow64_process(GetCurrentProcess(), &is_wow64_flag)) + { + is_wow64_flag = FALSE; + } + } + return is_wow64_flag; +#else + return TRUE; +#endif +} + /* ======================================================================== */ /* File name routines */ /* ======================================================================== */ @@ -148,6 +199,18 @@ static wchar_t *remove_file_extension(const wchar_t *const path) return wcsdup(path); } +static void trim_trailing_separator(wchar_t *const path) +{ + if(NOT_EMPTY(path)) + { + size_t len = wcslen(path); + while ((len > 0U) && ((path[len-1U] == L'\\') || (path[len-1U] == L'/'))) + { + path[--len] = L'\0'; + } + } +} + static BOOL file_exists(const wchar_t *const filename) { struct _stat buffer; if (_wstat(filename, &buffer) == 0) @@ -157,6 +220,128 @@ static BOOL file_exists(const wchar_t *const filename) { return FALSE; } +/* ======================================================================== */ +/* Registry routines */ +/* ======================================================================== */ + +typedef BOOL (*reg_enum_callback_t)(const wchar_t *const key_name, const ULONG_PTR user_data); + +static DWORD get_registry_view(const BOOL view_64bit) +{ +#ifndef _M_X64 + return view_64bit ? KEY_WOW64_64KEY : 0U; +#else + return view_64bit ? 0U : KEY_WOW64_32KEY; +#endif +} + +static wchar_t *reg_read_string(const HKEY root_key, const wchar_t *const path, const wchar_t *const name, const BOOL view_64bit) +{ + HKEY key = NULL; + if(RegOpenKeyEx(root_key, path, 0U, KEY_QUERY_VALUE | get_registry_view(view_64bit), &key) != ERROR_SUCCESS) + { + return FALSE; + } + + DWORD buffer_len = MAX_PATH; + BYTE *buffer = (BYTE*) malloc(sizeof(wchar_t) * buffer_len); + if(!buffer) + { + RegCloseKey(key); + return NULL; + } + + DWORD type = 0U, size = sizeof(wchar_t) * buffer_len; + LSTATUS status = RegQueryValueExW(key, name, NULL, &type, buffer, &size); + while (status == ERROR_MORE_DATA) + { + buffer_len = (buffer_len < 512U) ? 512U : (2U * buffer_len); + BYTE *buffer = (BYTE*) realloc(buffer, size = (sizeof(wchar_t) * buffer_len)); + if(!buffer) + { + RegCloseKey(key); + return NULL; + } + status = RegQueryValueExW(key, name, NULL, &type, buffer, &size); + } + if ((status != ERROR_SUCCESS) || (size < sizeof(wchar_t)) || ((type != REG_SZ) && (type != REG_EXPAND_SZ))) + { + free(buffer); + RegCloseKey(key); + return NULL; + } + + const size_t char_count = size / sizeof(wchar_t); + if (((wchar_t*)buffer)[char_count - 1U]) + { + while (char_count >= buffer_len) + { + BYTE *buffer = (BYTE*) realloc(buffer, sizeof(wchar_t) * (buffer_len = char_count + 1U)); + if(!buffer) + { + RegCloseKey(key); + return NULL; + } + } + ((wchar_t*)buffer)[char_count] = L'\0'; + } + + RegCloseKey(key); + return (wchar_t*) buffer; +} + +static BOOL reg_enum_subkeys(const HKEY root_key, const wchar_t *const path, const BOOL view_64bit, const reg_enum_callback_t callback, const ULONG_PTR user_data) +{ + HKEY key = NULL; + if(RegOpenKeyEx(root_key, path, 0U, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | get_registry_view(view_64bit), &key) != ERROR_SUCCESS) + { + return FALSE; + } + + DWORD max_len = 0U; + if(RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &max_len, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + { + RegCloseKey(key); + return FALSE; + } + + wchar_t *buffer = (wchar_t*) malloc(sizeof(wchar_t) * (max_len + 1U)); + if (!buffer) + { + RegCloseKey(key); + return FALSE; + } + + BOOL result = TRUE; + for (DWORD index = 0U; index < MAXDWORD; ++index) + { + DWORD len = max_len + 1U; + switch (RegEnumKeyExW(key, index, buffer, &len, NULL, NULL, NULL, NULL)) + { + case ERROR_SUCCESS: + if (!callback(buffer, user_data)) + { + goto exit_loop; + } + break; + case ERROR_MORE_DATA: + result = FALSE; + break; + case ERROR_NO_MORE_ITEMS: + goto exit_loop; + default: + result = FALSE; + goto exit_loop; + } + } + +exit_loop: + + RegCloseKey(key); + free(buffer); + return result; +} + /* ======================================================================== */ /* Path detection */ /* ======================================================================== */ @@ -235,6 +420,163 @@ static const BOOL set_current_directory(const wchar_t *const path) } } +/* ======================================================================== */ +/* Java detection (from registry) */ +/* ======================================================================== */ + +typedef struct +{ + const BOOL flag_x64; + const HKEY root_key; + const wchar_t *const base_reg_path; + ULONGLONG version; + const wchar_t *runtime_path; +} +java_home_t; + +static ULONGLONG parse_java_version(const wchar_t *const version_str) +{ + ULONGLONG version = 0ULL; + UINT level = 0U; + + if (NOT_EMPTY(version_str)) + { + wchar_t *const temp = wcsdup(version_str); + if (temp) + { + static const wchar_t *const delimiters = L".,_"; + BOOL first_token = TRUE; + const wchar_t *token = wcstok(temp, delimiters); + while (token) + { + const DWORD component = wcstoul(token, NULL, 10); + if (!(first_token && (component == 1U))) + { + version = (version << 16) | (component & 0xFFFF); + ++level; + } + token = wcstok(NULL, delimiters); + first_token = FALSE; + } + } + free(temp); + } + + while(level < 4U) + { + version <<= 16; + ++level; + } + + return version; +} + +static const wchar_t *detect_java_runtime_verify(const BOOL flag_x64, const HKEY root_key, const wchar_t *const full_reg_path) +{ + static const wchar_t *const REL_PATHS[] = + { + L"%ls\\jre\\bin\\javaw.exe", L"%ls\\bin\\javaw.exe", NULL + }; + + BOOL is_valid = FALSE; + wchar_t *const java_home_path = reg_read_string(root_key, full_reg_path, L"JavaHome", flag_x64); + trim_trailing_separator(java_home_path); + if (NOT_EMPTY(java_home_path)) + { + for (size_t i = 0U; REL_PATHS[i]; ++i) + { + wchar_t *const java_executable_path = awprintf(REL_PATHS[i], java_home_path); + if (java_executable_path) + { + if (file_exists(java_executable_path)) + { + free(java_home_path); + return java_executable_path; + } + free(java_executable_path); + } + } + } + + free(java_home_path); + return NULL; +} + +static BOOL detect_java_runtime_callback(const wchar_t *const key_name, const ULONG_PTR user_data) +{ + const ULONGLONG version = parse_java_version(key_name); + if(version > JAVA_MINIMUM_VERSION) + { + java_home_t *const ptr = (java_home_t*) user_data; + if(version > ptr->version) + { + wchar_t *const full_reg_path = awprintf(L"%ls\\%ls", ptr->base_reg_path, key_name); + if (full_reg_path) + { + const wchar_t *const java_runtime_path = detect_java_runtime_verify(ptr->flag_x64, ptr->root_key, full_reg_path); + if(java_runtime_path) + { + SET_STRING(ptr->runtime_path, java_runtime_path); + ptr->version = version; + } + free(full_reg_path); + } + } + } + return TRUE; +} + +static const wchar_t *detect_java_runtime_loop(const BOOL flag_x64) +{ + static const wchar_t *const REG_KEY_PATHS[2U][3U] = + { + { L"SOFTWARE\\JavaSoft\\Java Runtime Environment", L"SOFTWARE\\JavaSoft\\JRE", NULL }, + { L"SOFTWARE\\JavaSoft\\Java Development Kit", L"SOFTWARE\\JavaSoft\\JDK", NULL } + }; + + ULONGLONG version = 0U; + const wchar_t *runtime_path = NULL; + + for (size_t i = 0; i < 2U; ++i) + { + for (size_t j = 0; REG_KEY_PATHS[i][j]; ++j) + { + java_home_t state = { flag_x64, HKEY_LOCAL_MACHINE, REG_KEY_PATHS[i][j], version, runtime_path }; + reg_enum_subkeys(HKEY_LOCAL_MACHINE, REG_KEY_PATHS[i][j], flag_x64, detect_java_runtime_callback, (ULONG_PTR)&state); + version = state.version; + runtime_path = state.runtime_path; + } + if ((version > JAVA_MINIMUM_VERSION) && runtime_path) + { + return runtime_path; + } + } + + return NULL; +} + +static const wchar_t *detect_java_runtime(void) +{ + const wchar_t *java_runtime; +#if PREFER_X64 + if(java_runtime = running_on_64bit() ? detect_java_runtime_loop(TRUE) : NULL) + { + return java_runtime; + } +#endif + if(java_runtime = detect_java_runtime_loop(FALSE)) + { + return java_runtime; + } +#if !PREFER_X64 + if(java_runtime = running_on_64bit() ? detect_java_runtime_loop(TRUE) : NULL) + { + return java_runtime; + } +#endif + return NULL; +} + /* ======================================================================== */ /* Splash screen */ /* ======================================================================== */ @@ -370,22 +712,23 @@ static const wchar_t *describe_system_error(const DWORD error_code) return error_test; } -#define show_message(HWND, FLAGS, TITLE, TEXT) \ -{ \ - MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS)); \ -} \ -while(0) +#define show_message(HWND, FLAGS, TITLE, TEXT) MessageBoxW((HWND), (TEXT), (TITLE), (FLAGS)) -#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) +static int show_message_format(HWND hwnd, const DWORD flags, const wchar_t *const title, const wchar_t *const format, ...) +{ + int result = -1; + va_list ap; + va_start(ap, format); + + const wchar_t *const text = vawprintf(format, ap ); + if(NOT_EMPTY(text)) + { + result = MessageBoxW(hwnd, text, title, flags); + } + + free((void*)text); + return result; +} /* ======================================================================== */ /* Utilities */ @@ -439,9 +782,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine // Show the splash screen #if ENABLE_SPLASH - if(splash_image = LoadImage(hInstance, MAKEINTRESOURCE(ID_SPLASH_BITMAP), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE)) + if (splash_image = LoadImage(hInstance, MAKEINTRESOURCE(ID_SPLASH_BITMAP), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE)) { - if(create_splash_screen(hwnd, splash_image)) + if (create_splash_screen(hwnd, splash_image)) { process_window_messages(hwnd); } @@ -449,62 +792,76 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine #endif // Find executable path - if(!(executable_path = get_executable_path())) + if (!(executable_path = get_executable_path())) { show_message(hwnd, MB_ICONERROR | MB_TOPMOST, 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))) + if (!(executable_directory = get_executable_directory(executable_path))) { show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"System Error", L"The executable directory could not be determined!"); goto cleanup; } // Set the current directory - if(_wcsicmp(executable_directory, L".") != 0) + 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))) + if (!(jarfile_path = get_jarfile_path(executable_path, executable_directory))) { show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"System Error", L"The path of the JAR file could not be determined!"); goto cleanup; } - // Find the Java runtime executable path - if(!(java_runtime_path = awprintf(L"%ls\\%ls", executable_directory, JRE_RELATIVE_PATH))) - { - show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"System Error", L"The path of the Java runtime could not be determined!"); - goto cleanup; - } - // Does the JAR file exist? #if !JAR_FILE_WRAPPED - if(!file_exists(jarfile_path)) + if (!file_exists(jarfile_path)) { show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, 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; } #endif - // Does the Java runtime executable exist? - if(!file_exists(java_runtime_path)) + // Find the Java runtime executable path (possibly from the registry) +#if DETECT_REGISTRY + if (!(java_runtime_path = detect_java_runtime())) { - show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, 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); + show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"JRE not found", L"Java Runtime Environment (JRE) could not be found!"); + if(show_message_format(hwnd, MB_ICONWARNING | MB_OKCANCEL | MB_TOPMOST, L"JRE not found", + L"This application requires the Java Runtime Environment, version 8.0 (1.8.0) or a compatible newer version.\n\n" + L"We recommend downloading the OpenJDK runtime here:\n%ls", JRE_DOWNLOAD_LINK) == IDOK) + { + ShellExecuteW(hwnd, NULL, JRE_DOWNLOAD_LINK, NULL, NULL, SW_SHOW); + } goto cleanup; } + show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"java_runtime_path Error", java_runtime_path); +#else + if (!(java_runtime_path = awprintf(L"%ls\\%ls", executable_directory, JRE_RELATIVE_PATH))) + { + show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"System Error", L"The path of the Java runtime could not be determined!"); + goto cleanup; + } + if (!file_exists(java_runtime_path)) + { + show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, L"JRE 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; + } +#endif // 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) + if (!command_line) { show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"System Error", L"The Java command-line could not be generated!"); goto cleanup; } + show_message(hwnd, MB_ICONERROR | MB_TOPMOST, L"command_line Error", command_line); // Process pending window messages #if ENABLE_SPLASH @@ -512,10 +869,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine #endif // Now actually start the process! - if(!CreateProcessW(NULL, (LPWSTR)command_line, NULL, NULL, FALSE, 0U, NULL, executable_directory, &startup_info, &process_info)) + 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) + if (error_text) { show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, 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); @@ -538,10 +895,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine // Wait for process to exit, then get the exit code #if STAY_ALIVE - if(signaled_or_failed(WaitForSingleObject(process_info.hProcess, INFINITE))) + if (signaled_or_failed(WaitForSingleObject(process_info.hProcess, INFINITE))) { DWORD exit_code = 0U; - if(GetExitCodeProcess(process_info.hProcess, &exit_code)) + if (GetExitCodeProcess(process_info.hProcess, &exit_code)) { result = (int) exit_code; } @@ -556,7 +913,7 @@ cleanup: close_handle(&process_info.hProcess); destroy_window(&hwnd); - delete_object(splash_image); + delete_object(&splash_image); free((void*)command_line); free((void*)java_runtime_path);