產生 Windows EXE 啟動器

打包時可以為受保護的應用程式產生一個原生 Windows 啟動程式。它是純 Win32 執行檔,按兩下即可執行,你的使用者不需要先安裝 Java,也不必接觸 run.bat

EXE 是選用項目,預設不會產生。啟用後,產生的包裡仍然保留 run.shrun.commandrun.bat。兩種啟動方式使用完全相同的歸檔結構、類別路徑、主類與 JVM 啟動選項。

1. 適用範圍

應用程式類型Java 應用、Spring Boot(三種佈局皆可)、Tomcat
目標平臺windows-x64windows-x86windows-aarch64
不支援類庫加密 —— 單一 .p4jx 歸檔不是可啟動的應用程式目錄

必須至少選擇一個 Windows 目標平臺。同時選擇 Linux 與 macOS 目標並無問題:這些平臺的包照常產生,只是不帶 EXE,仍透過原有指令碼啟動。如果一個 Windows 目標都沒選,任務會直接失敗。

2. GUI 操作

  1. 在輸入檔案與目標平臺頁面勾選產生 Windows 應用程式 EXE(x64/x86/ARM64),並至少選擇一個 Windows 目標平臺。
  2. 這個選項位於簡單模式與進階模式的分歧之前,因此兩種模式都可以產生 EXE。
  3. 勾選後會多出一個 Windows EXE 啟動器頁面,用於填寫檔案名稱、啟動器模式、圖示與 Windows 版本資訊。不勾選則直接進入最終確認頁。
  4. 啟用 EXE 後,JVM 啟動選項輸入欄位只會出現在這個啟動器頁面上,這樣同一個選項就不會有兩個入口。填寫的內容會同時寫入 EXE 與啟動指令碼。
  5. 最終確認頁會列出實際會產生 EXE 的平臺,以及你填寫過的啟動器欄位。

3. CLI 範例

最簡形式,只需要 --windows-exe

p4j --target-platform windows-x64 javaapp app.jar dist --windows-exe

指定檔案名稱與視窗模式:

p4j --target-platform windows-x64 javaapp app.jar dist \
  --windows-exe \
  --exe-name MyApp.exe \
  --exe-mode gui \
  --exe-icon assets/app.ico

一次產生三種 Windows 架構,並填寫完整的版本資源:

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 包同樣支援,產生的 EXE 會在前景啟動內嵌的 Tomcat:

p4j --target-platform windows-x64 tomcat app.war dist --context /demo --windows-exe

4. 選項說明

選項說明
--windows-exe產生 Windows 應用程式 EXE
--exe-name <name>EXE 檔案名稱;留空時使用輸入檔案的名稱,Tomcat 包使用 tomcat
--exe-mode <mode>console(預設)或 gui
--exe-icon <ico>選用的 Windows 圖示,.ico 格式
--exe-file-version <a.b.c.d>PE 檔案版本:1 到 4 段數字,每段取值 0 到 65535。留空表示 0.0.0.0
--exe-product-version <a.b.c.d>PE 產品版本,規則同上
--exe-company <text>公司名稱
--exe-product <text>產品名稱
--exe-description <text>檔案說明,顯示於工作管理員與檔案內容對話方塊
--exe-copyright <text>版權聲明

任何一個 --exe-* 選項都會自動啟用 EXE 產生,因此不必再額外寫 --windows-exe

檔案名稱必須是純檔名,不能包含 /\ 或任何目錄成分;如果省略了 .exe 字尾,工具會自動補上。

兩個版本號欄位遵循同一條規則:1 到 4 段以半形句點分隔的數字,每段取值 0 到 65535,例如 1.0.0.1。Windows 把每一段存成 16 位元不帶正負號的整數,因此像 v1.01.0-beta 這類含字母或空格的寫法會被拒絕。留空表示 0.0.0.0。這兩個欄位在打包開始前就會驗證,因此填錯會立刻反映,而不是打到一半才失敗。

5. 輸出結構

以 Java 應用程式為例,EXE 與啟動指令碼一起放在包的根目錄下:

dist/
├── MyApp.exe             # 新增的 Windows 啟動程式
├── app.p4jx
├── vlxjre/
├── lib/
├── run.sh
├── run.command
├── run.bat
└── README.md

包內的 README.md 會列出已產生的 EXE 檔案名稱,以及程式碼簽章方面的提示。

6. 執行行為

EXE 所在的目錄就是應用程式的根目錄。啟動器只接受根目錄之內的執行時、歸檔、類別路徑與工作目錄;指向包外的路徑,以及被符號連結或 junction 替換過的路徑,都會被拒絕,行程不會啟動。因此整個包可以隨意搬移或改名,但不能把 EXE 單獨複製出去使用。

面向行為
執行時一律使用包內的 vlxjre\bin\java.exe,不使用系統 Java,也不讀取 JAVA_HOME
命令列參數傳給 EXE 的參數會接在應用程式自身參數之後。
主控台模式沿用目前主控台的標準輸入輸出,等待應用程式結束,並回傳它的結束代碼。
GUI 模式不建立主控台視窗,適合桌面應用程式。
環境變數啟動前清除 JAVA_TOOL_OPTIONS_JAVA_OPTIONSJDK_JAVA_OPTIONSCLASSPATH,避免外部注入改變啟動參數。

EXE 的 JVM 啟動選項在打包時就已固定,並與參數區塊一起簽章、在執行時驗證,部署後無法修改。APP_JAVA_OPTS 只對 run.bat 有效,EXE 不會讀取它。需要修改 EXE 的 JVM 啟動選項,請重新打包。

基於同樣的原因,-javaagent-agentlib-agentpath-Xbootclasspath--patch-module 不允許寫入 EXE 的啟動參數。試圖用 --jvm-option 傳入這些參數,打包會立即失敗。

7. 程式碼簽章

Protector4J 不會為產生的 EXE 加上發行者簽章,也不會接觸任何 Authenticode 憑證。圖示、版本資源、啟動參數等所有 PE 修改都在打包階段完成,因此簽章必須放在最後一步。

  1. 完成打包,並確認 EXE 能夠正常啟動應用程式。
  2. 使用你自己的憑證做 Authenticode 簽章,並附上 RFC3161 時間戳記。
  3. 依 Windows 的 /pa 原則驗證簽章。

簽章完成後不要再修改這個 PE 檔案,任何改動都會讓簽章失效。需要更換圖示或版本號時,請重新打包並重新簽章。

8. 任務檔案欄位

匯出的 p4j-task.yml 使用第 2 版格式,啟用 EXE 時會儲存以下欄位。第 1 版的任務檔案仍然可以正常讀取。

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. 常見問題

現象原因與處理
提示需要選擇 Windows 目標平臺已啟用 EXE,但沒有選取 windows-x64windows-x86windows-aarch64
提示版本號格式不正確版本欄位中含有字母或空格,或超過 4 段,或某一段不在 0 到 65535 之間。
提示 EXE 名稱只能是檔名檔案名稱中含有路徑分隔符號,請改成不帶目錄的純檔名。
提示找不到圖示檔案--exe-icon 指向的 .ico 不存在,請檢查路徑。
按兩下後沒有視窗,應用程式立即結束應用程式在 GUI 模式下啟動失敗。改用主控台模式重新打包,以檢視錯誤輸出。
單獨複製出來的 EXE 無法執行啟動器要求執行時與歸檔位於同一個包目錄中,請複製整個輸出目錄。

完整的選項列表請見 CLI 參數參考;GUI 精靈流程請見 GUI 使用指南