diff --git a/LICENSE.txt b/LICENSE.txt index 3f56a63..5ff3ae3 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2020 LoRd_MuldeR +Copyright 2023 LoRd_MuldeR Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index e532a5f..c3c0059 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Launch5j executables come in a number of variants, allowing you to pick the most 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) - - [AdoptOpenJDK](https://adoptopenjdk.net/) + - [Eclipse Adoptium](https://adoptium.net/) - [Liberica OpenJDK](https://bell-sw.com/) - [Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/) @@ -109,24 +109,24 @@ It is ***not*** necessary to re-build the executable files for that purpose. Ins Some options can be configured via the launcher executable's [STRINGTABLE](https://docs.microsoft.com/en-us/windows/win32/menurc/stringtable-resource) resource: -* **`ID_STR_HEADING` (#1)** +* **`ID_STR_HEADING` (0x1)** Specifies a custom application title that will be used, e.g., as the heading of message boxes. -* **`ID_STR_JVMARGS` (#2)** +* **`ID_STR_JVMARGS` (0x2)** Specifies *additional* options JVM options to be passed, such as `-Xmx2g` or `-Dproperty=value`. See here for a list of available options: -* **`ID_STR_CMDARGS` (#3)** +* **`ID_STR_CMDARGS` (0x3)** Specifies *additional* fixed command-line parameters to be passed to the Java application. -* **`ID_STR_JREPATH` (#4)** +* **`ID_STR_JREPATH` (0x4)** Specifies the path to the Java runtime (`javaw.exe`) relative to the launcher executable location. If not specified, then the *default* runtime path `runtime\\bin\\javaw.exe` is assumed. (This option does **not** apply to the “registry” variant of Launch5j) -* **`ID_STR_MUTEXID` (#5)** +* **`ID_STR_MUTEXID` (0x5)** Specifies the application ID to be used when creating the [*single-instance*](http://www.bcbjournal.org/articles/vol3/9911/Single-instance_applications.htm) mutex. The ID **must** be at least 5 characters in length and **should** be a *unique* string for each application! If not specified, then **no** mutex will be created and thus *multiple* instances will be allowed. @@ -135,7 +135,19 @@ Some options can be configured via the launcher executable's [STRINGTABLE](https (This option does **not** apply to the “nowait” variant of Launch5j) -* **`ID_STR_JAVAMIN` (#6)** +* **`ID_STR_HEAPMIN` (0x6)** + Specifies the the ***minimum*** Java heap size (i.e. JVM option `-Xms`), as percentage of the total physical memory. + This must be an integral value in the `1` to `100` range, and it must be less than or equal to `ID_STR_HEAPMAX`. + + (This option **must** be specified together with `ID_STR_HEAPMAX`) + +* **`ID_STR_HEAPMAX` (0x7)** + Specifies the the ***maximum*** Java heap size (i.e. JVM option `-Xmx`), as percentage of the total physical memory. + This must be an integral value in the `1` to `100` range, and it must be greater than or equal to `ID_STR_HEAPMIN`. + + (This option **must** be specified together with `ID_STR_HEAPMIN`) + +* **`ID_STR_JAVAMIN` (0x8)** Specifies the ***minimum*** supported JRE version, in the **`w.x.y.z`** format (e.g. `11.0.0.0`). This values is *inclusive*, i.e. the specified JRE version or any newer JRE version will be accepted. If not specified, then the *default* minimum supported JRE version `8.0.0.0` applies. @@ -144,7 +156,7 @@ Some options can be configured via the launcher executable's [STRINGTABLE](https (This option only applies to the “registry” variant of Launch5j) -* **`ID_STR_JAVAMAX` (#7)** +* **`ID_STR_JAVAMAX` (0x9)** Specifies the ***maximum*** supported JRE version, in the **`w.x.y.z`** format (e.g. `12.0.0.0`). This values is *exclusive*, i.e. only JRE versions *older* than the specified JRE version will be accepted. If not specified, then there is **no** upper limit on the supported JRE version. @@ -153,15 +165,15 @@ Some options can be configured via the launcher executable's [STRINGTABLE](https (This option only applies to the “registry” variant of Launch5j) -* **`ID_STR_BITNESS` (#8)** +* **`ID_STR_BITNESS` (0xA)** Specifies the required ***bitness*** of the JRE. This can be either **`32`** (x86, aka i586) or **`64`** (x86-64). If not specified, then 32-Bit *and* 64-Bit JREs are accepted, with a preference to 64-Bit. (This option only applies to the “registry” variant of Launch5j) -* **`ID_STR_JAVAURL` (#9)** +* **`ID_STR_JAVAURL` (0xB)** The Java download URL that will ne suggested, if **no** suitable JRE could be detected on the machine. - If not specified, wes suggest downloading OpenJDK as provided by the [AdoptOpenJDK](https://adoptopenjdk.net/) project. + If not specified, wes suggest downloading OpenJDK, as provided by the [Eclipse Adoptium](https://adoptium.net/) project. *Hint:* The URL must begin with a `http://` or `https://` prefix; otherwise the URL will be ignored! @@ -284,7 +296,7 @@ This project is partly inspired by the “Launch4j” project, even though it ha This work has been released under the MIT license: - Copyright 2020 LoRd_MuldeR + Copyright 2023 LoRd_MuldeR Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/res/common.rc b/res/common.rc index 03327be..8502e26 100644 --- a/res/common.rc +++ b/res/common.rc @@ -42,6 +42,8 @@ BEGIN ID_STR_CMDARGS L"?" /*additional command-line args*/ ID_STR_JREPATH L"?" /*relative path to JRE*/ ID_STR_MUTEXID L"?" /*single instance mutex ID*/ + ID_STR_HEAPMIN L"?" /*min. heap size, in percent of phys. memory*/ + ID_STR_HEAPMAX L"?" /*max. heap size, in percent of phys. memory*/ END ///////////////////////////////////////////////////////////////////////////// diff --git a/src/head.c b/src/head.c index 48374df..678bad3 100644 --- a/src/head.c +++ b/src/head.c @@ -65,6 +65,7 @@ static const wchar_t *const JRE_DOWNLOAD_LINK_DEFAULT = L"https://adoptium.net/" static const wchar_t *const JRE_RELATIVE_PATH_DEFAULT = L"runtime\\bin"; static const wchar_t *const JRE_EXECUTABLE_NAME = L5J_ENABLE_GUI ? L"javaw.exe" : L"java.exe"; static const size_t MIN_MUTEXID_LENGTH = 5U; +static const size_t BYTES_PER_MEGABYTE = 1024U * 1024U; static const DWORD SPLASH_SCREEN_TIMEOUT = 30000U; // Check platform @@ -323,6 +324,18 @@ static BOOL running_on_64bit(void) #endif } +static ULONGLONG get_physical_memory_size() +{ + MEMORYSTATUSEX memory_status; + ZeroMemory(&memory_status, sizeof(MEMORYSTATUSEX)); + memory_status.dwLength = sizeof(MEMORYSTATUSEX); + if (GlobalMemoryStatusEx(&memory_status)) + { + return memory_status.ullTotalPhys; + } + return 0L; +} + /* ======================================================================== */ /* File name routines */ /* ======================================================================== */ @@ -521,7 +534,7 @@ static DWORD load_uint32(const HINSTANCE hinstance, const UINT id, const DWORD f { DWORD value = fallback; const wchar_t *const str = load_string(hinstance, id); - if(NOT_EMPTY(str)) + if(AVAILABLE(str)) { value = wcstoul(str, NULL, 10); } @@ -1201,6 +1214,26 @@ static const wchar_t *encode_commandline_str(const wchar_t *const command_line) return encoded; } +const wchar_t *create_heap_size_parameters(const DWORD jvm_heap_percent_min, const DWORD jvm_heap_percent_max, const wchar_t *const jvm_extra_args) +{ + if ((jvm_heap_percent_min > 0U) && (jvm_heap_percent_max >= jvm_heap_percent_min)) + { + const ULONGLONG physical_memory_size = get_physical_memory_size(); + if (physical_memory_size > 0ULL) + { + const DWORD heap_size_mbytes_min = (DWORD)((((ULONGLONG)((jvm_heap_percent_min / (double)100U) * physical_memory_size)) + (BYTES_PER_MEGABYTE - 1U)) / BYTES_PER_MEGABYTE); + const DWORD heap_size_mbytes_max = (DWORD)((((ULONGLONG)((jvm_heap_percent_max / (double)100U) * physical_memory_size)) + (BYTES_PER_MEGABYTE - 1U)) / BYTES_PER_MEGABYTE); + if ((heap_size_mbytes_min > 0U) && (heap_size_mbytes_max >= heap_size_mbytes_min)) + { + return AVAILABLE(jvm_extra_args) + ? aswprintf(L"-Xms%um -Xmx%um %s", heap_size_mbytes_min, heap_size_mbytes_max, jvm_extra_args) + : aswprintf(L"-Xms%um -Xmx%um", heap_size_mbytes_min, heap_size_mbytes_max); + } + } + } + return NULL; +} + static const wchar_t *build_commandline(const DWORD pid, const wchar_t *const java_runtime_path, const wchar_t *const jar_file_path, const wchar_t *const jvm_extra_args, const wchar_t *const cmd_extra_args, const wchar_t *const cmd_input_args) { const wchar_t *command_line; @@ -1549,6 +1582,11 @@ static void destroy_window(HWND *const hwnd) } } +static DWORD bound_value(const DWORD min_value, const DWORD value, const DWORD max_value) +{ + return max(min_value, min(max_value, value)); +} + /* ======================================================================== */ /* MAIN */ /* ======================================================================== */ @@ -1562,7 +1600,7 @@ static int launch5j_main(const HINSTANCE hinstance, const wchar_t *const cmd_lin const wchar_t *app_heading = NULL, *mutex_name = NULL, *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, *java_runtime_path = NULL, *jre_relative_path = NULL, *jvm_extra_args = NULL, *cmd_extra_args = NULL, *command_line = NULL; HANDLE mutex_handle = NULL; - DWORD java_required_bitness = 0U; + DWORD java_required_bitness = 0U, jvm_heap_percent_min = 0U, jvm_heap_percent_max = 0U; ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL; HGDIOBJ splash_image = NULL; BOOL have_screen_created = FALSE; @@ -1693,6 +1731,19 @@ static int launch5j_main(const HINSTANCE hinstance, const wchar_t *const cmd_lin jvm_extra_args = load_string(hinstance, ID_STR_JVMARGS); cmd_extra_args = load_string(hinstance, ID_STR_CMDARGS); + // Set minimum/maximum Java heap size + jvm_heap_percent_min = bound_value(0U, load_uint32(hinstance, ID_STR_HEAPMIN, 0U), 100U); + jvm_heap_percent_max = bound_value(0U, load_uint32(hinstance, ID_STR_HEAPMAX, 0U), 100U); + if ((jvm_heap_percent_min != 0U) && (jvm_heap_percent_max != 0U)) + { + const wchar_t *const jvm_heap_size_args = create_heap_size_parameters(jvm_heap_percent_min, jvm_heap_percent_max, jvm_extra_args); + if (jvm_heap_size_args) + { + free((void*)jvm_extra_args); + jvm_extra_args = jvm_heap_size_args; + } + } + // Make sure command-line was created command_line = build_commandline(pid, java_runtime_path, jarfile_path, jvm_extra_args, cmd_extra_args, cmd_line_args); if (!command_line) diff --git a/src/resource.h b/src/resource.h index ddb94e0..f00bbc4 100644 --- a/src/resource.h +++ b/src/resource.h @@ -31,14 +31,16 @@ #define ID_BITMAP_SPLASH 1 // STRINGS -#define ID_STR_HEADING 1 -#define ID_STR_JVMARGS 2 -#define ID_STR_CMDARGS 3 -#define ID_STR_JREPATH 4 -#define ID_STR_MUTEXID 5 -#define ID_STR_JAVAMIN 6 -#define ID_STR_JAVAMAX 7 -#define ID_STR_BITNESS 8 -#define ID_STR_JAVAURL 9 +#define ID_STR_HEADING 0x1 +#define ID_STR_JVMARGS 0x2 +#define ID_STR_CMDARGS 0x3 +#define ID_STR_JREPATH 0x4 +#define ID_STR_MUTEXID 0x5 +#define ID_STR_HEAPMIN 0x6 +#define ID_STR_HEAPMAX 0x7 +#define ID_STR_JAVAMIN 0x8 +#define ID_STR_JAVAMAX 0x9 +#define ID_STR_BITNESS 0xA +#define ID_STR_JAVAURL 0xB #endif