Generate a Windows EXE launcher
When packaging, a native Windows launcher can be created for the protected application. It is a pure Win32 executable that can be run by double-clicking, without requiring the user to install Java first or to see run.bat.
The EXE is optional and not generated by default. Once enabled, the original run.sh / run.command / run.bat files are retained in the resulting package. Both startup methods use exactly the same archive structure, classpath, main class, and JVM parameters.
1. Scope of application
| Project | Support status |
|---|---|
| Application type | Java Application, Spring Boot (all three layouts), Tomcat |
| Target Platform | windows-x64, windows-x86, windows-aarch64 |
| Not supported | Library Encryption (a single .p4jx archive does not contain a runnable application directory) |
At least one Windows target platform must be selected. Selecting both Linux and macOS platforms will not cause the task to fail: sub-packages for these platforms are still generated, but without EXE files, and the original startup script is used. If no Windows target platforms are selected, the task will immediately report an error.
2. GUI Operations
- On the page for selecting the input file and target platform, check Generate Windows application EXE (x64/x86/ARM64) and select at least one Windows target platform.
- This switch is located before the split between simple mode and advanced mode, so EXE files can be generated in both modes.
- Checking this option adds a Windows EXE launcher page where you can enter the file name, launcher mode, icon, and Windows version information. If it is not checked, you go directly to the final confirmation page.
- After enabling the EXE, the JVM startup parameters input field appears only on this launcher page to prevent two separate entries for the same parameter. The entered parameters are written to both the EXE and the startup script.
- The final confirmation page lists the platforms where the EXE will actually be generated, along with the fields filled in the launcher.
3. CLI example
Minimal form, requiring only --windows-exe:
p4j --target-platform windows-x64 javaapp app.jar dist --windows-exe
Specify file name and window mode:
p4j --target-platform windows-x64 javaapp app.jar dist \
--windows-exe \
--exe-name MyApp.exe \
--exe-mode gui \
--exe-icon assets/app.ico
Generate three Windows architectures at once and fill in complete version resources:
p4j --target-platform windows-x64,windows-x86,windows-aarch64 \
springboot app.jar dist \
--windows-exe \
--exe-name MyService \
--exe-file-version 1.4.2.0 \
--exe-product-version 1.4.2.0 \
--exe-company 'Example Inc.' \
--exe-product 'Example Service' \
--exe-description 'Example background service' \
--exe-copyright 'Copyright (C) 2026 Example Inc.'
Tomcat packages are also supported; the generated EXE starts the embedded Tomcat in foreground mode:
p4j --target-platform windows-x64 tomcat app.war dist --context /demo --windows-exe
4. Parameter description
| Options | Description |
|---|---|
--windows-exe | Enable EXE generation |
--exe-name <name> | EXE filename; if left blank, the input filename is used. Tomcat uses tomcat. |
--exe-mode <mode> | console (default) or gui |
--exe-icon <ico> | Windows icon file, in .ico format, optional |
--exe-file-version <a.b.c.d> | PE file version |
--exe-product-version <a.b.c.d> | PE product version |
--exe-company <text> | Company Name |
--exe-product <text> | Product Name |
--exe-description <text> | File description, displayed in Task Manager and file properties |
--exe-copyright <text> | Copyright notice |
Any --exe-* option will automatically enable EXE generation, so there is no need to manually enter --windows-exe.
The file name should be purely a filename only, without including /, \, or any directory components; if no .exe suffix is provided, it will be added automatically.
The rules for both version number fields are the same: numbers separated by English periods in 1 to 4 segments, with each segment ranging from 0 to 65535, such as 1.0.0.1. Windows stores each segment as a 16-bit unsigned integer, so formats like v1.0 or 1.0-beta containing letters or spaces are not accepted. Leaving it blank indicates 0.0.0.0. These two fields are validated before packaging begins, so errors are detected early rather than during the process.
5. Output structure
Taking the Java Application as an example, the EXE and startup script are placed in the root directory of the package:
dist/
├── MyApp.exe # The newly added Windows launcher
├── app.p4jx
├── vlxjre/
├── lib/
├── run.sh
├── run.command
├── run.bat
└── README.md
The README.md inside the package lists the names of the generated EXE files along with code signing prompts.
6. Operation behavior
The directory where the EXE is located is the root directory of the application. The launcher only accepts runtime, archive, classpath, and working directory paths within the root directory; paths outside the package, as well as those replaced by symbolic links or junctions, will be rejected, and the process will not start. This means the entire package can be moved or renamed, but the EXE cannot be copied out separately for use.
| Behavior | Explanation |
|---|---|
| Runtime | Always use vlxjre\bin\java.exe from within the package, do not use the system Java, and do not read JAVA_HOME. |
| Command-line parameters | Append the parameters passed to the EXE directly after the application’s parameters. |
| Console mode | Inherit the standard input and output of the current console, wait for the application to finish, and return its exit code. |
| GUI mode | Do not create a console window; suitable for desktop applications. |
| Environment variables | Clear JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS, and CLASSPATH before startup to prevent external injections from altering startup parameters. |
The JVM parameters of the EXE are fixed during packaging and signed along with the parameter block, with verification occurring at runtime; they cannot be modified after deployment. APP_JAVA_OPTS is only valid for run.bat and is not read by the EXE. If you need to change the JVM parameters of the EXE, repack it.
For the same reason, -javaagent, -agentlib, -agentpath, -Xbootclasspath, and --patch-module do not allow writing to the EXE’s startup parameters. Attempting to pass these parameters using --jvm-option will cause the packaging process to fail immediately.
7. Code signing
Protector4J does not add a publisher signature to the generated EXE nor does it access any Authenticode credentials. All PE modifications, such as icons, version resources, and startup parameters, are completed during packaging; therefore, the signing step should be performed last.
- Complete the packaging process and verify that the EXE can start the application properly.
- Perform Authenticode signing using your own certificate and include an RFC3161 timestamp.
- Verify the signature using Windows’
/papolicy.
Do not modify this PE file after signing is complete, as any changes will invalidate the signature. If you need to change the icon or version number, please repack and resign it.
8. Task file fields
The exported p4j-task.yml uses version 2; save the following fields when enabling EXE. Task files from version 1 can still be read normally.
windowsExe: true
exeName: MyApp.exe
exeMode: console
exeIcon: assets/app.ico
exeFileVersion: 1.4.2.0
exeProductVersion: 1.4.2.0
exeCompany: Example Inc.
exeProduct: Example Service
exeDescription: Example background service
exeCopyright: Copyright (C) 2026 Example Inc.
9. Frequently asked questions
| Symptoms | Causes and solutions |
|---|---|
| A Windows target platform is required. | EXE is enabled, but no windows-x64, windows-x86, or windows-aarch64 targets have been selected. |
| Error: The version number format is incorrect. | The version field contains letters, spaces, or more than 4 segments; additionally, one of the segments is outside the range of 0 to 65535. |
| Error: The EXE name can only be the filename. | The filename contains path separators. Change it to a name without directories. |
| Error: The icon file cannot be found. | --exe-icon points to a non-existent .ico. Check the path. |
| The application crashes immediately after double-clicking with no window appearing. | The application fails to start in GUI mode. Repack it using console mode to view error output. |
| The EXE file copied separately cannot run. | The launcher requires that the runtime and archive be in the same package directory; please copy the entire output directory. |
For complete CLI options, see CLI Parameters Reference; for the GUI wizard process, see GUI User Guide.