Criar um iniciador EXE do Windows

Ao empacotar, você pode mandar gerar um iniciador nativo do Windows para o aplicativo protegido. É um executável Win32 puro que abre com dois cliques, de modo que seus usuários não precisam instalar o Java nem lidar com o run.bat.

O EXE é opcional e só é criado quando pedido. Com ele ativado, o pacote continua trazendo run.sh, run.command e run.bat. As duas formas de inicialização usam exatamente a mesma estrutura de arquivo, o mesmo classpath, a mesma classe principal e as mesmas opções de inicialização da JVM.

1. Onde se aplica

Tipos de aplicativoAplicação Java, Spring Boot (as três disposições), Tomcat
Plataformas-alvowindows-x64, windows-x86, windows-aarch64
Sem suporteCriptografia de bibliotecas — um único arquivo .p4jx não é uma pasta de aplicativo executável

É preciso marcar pelo menos uma plataforma-alvo Windows. Incluir também alvos Linux e macOS não é problema: os pacotes deles são gerados normalmente, sem EXE, e iniciam pelo script de sempre. Se nenhum alvo Windows for marcado, a tarefa falha na hora.

2. Pela interface gráfica

  1. Na página do arquivo de entrada e das plataformas-alvo, marque Gerar um EXE de aplicação para Windows (x64/x86/ARM64) e escolha pelo menos uma plataforma Windows.
  2. Essa caixa fica antes da bifurcação entre modo simples e avançado, então ambos podem gerar um EXE.
  3. Ao marcá-la, surge uma página Iniciador EXE do Windows onde você informa o nome do arquivo, o modo do iniciador, o ícone e as informações de versão do Windows. Sem marcá-la, o assistente vai direto para a página final.
  4. Com o EXE ativado, o campo Opções de inicialização JVM aparece só nessa página do iniciador, para que a mesma opção não possa ser digitada em dois lugares. O que você informar é gravado tanto no EXE quanto nos scripts de inicialização.
  5. A página final lista as plataformas que de fato receberão um EXE, junto com os campos do iniciador que você preencheu.

3. Exemplos de linha de comando

A forma mínima precisa apenas de --windows-exe:

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

Definir o nome do arquivo e o modo de janela:

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

Gerar as três arquiteturas do Windows de uma vez, com os recursos de versão completos:

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.'

Os pacotes do Tomcat também funcionam; o EXE gerado sobe o Tomcat embutido em primeiro plano:

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

4. Opções

OpçãoDescrição
--windows-exeGera um EXE de aplicação para Windows
--exe-name <name>Nome do arquivo EXE; por padrão o do arquivo de entrada, ou tomcat nos pacotes do Tomcat
--exe-mode <mode>console (padrão) ou gui
--exe-icon <ico>Ícone do Windows opcional, no formato .ico
--exe-file-version <a.b.c.d>Versão de arquivo do PE: de um a quatro números, cada um entre 0 e 65535. Em branco equivale a 0.0.0.0
--exe-product-version <a.b.c.d>Versão de produto do PE, com as mesmas regras
--exe-company <text>Nome da empresa
--exe-product <text>Nome do produto
--exe-description <text>Descrição do arquivo, visível no Gerenciador de Tarefas e nas propriedades
--exe-copyright <text>Aviso de direitos autorais

Qualquer opção --exe-* já ativa a geração do EXE por si só, então não é preciso acrescentar --windows-exe.

O nome tem de ser só um nome de arquivo, sem /, \ nem componente de pasta. Se você omitir o sufixo .exe, ele é acrescentado.

Os dois campos de versão seguem a mesma regra: de um a quatro números separados por pontos, cada um entre 0 e 65535, por exemplo 1.0.0.1. O Windows guarda cada parte como um inteiro sem sinal de 16 bits, de modo que valores com letras ou espaços, como v1.0 ou 1.0-beta, são recusados. Um campo em branco significa 0.0.0.0. Ambos são validados antes de o empacotamento começar, então um erro aparece de imediato e não no meio do processo.

5. Estrutura da saída

Tomando um aplicativo Java como exemplo, o EXE fica na raiz do pacote, ao lado dos scripts de inicialização:

dist/
├── MyApp.exe             # o novo iniciador do Windows
├── app.p4jx
├── vlxjre/
├── lib/
├── run.sh
├── run.command
├── run.bat
└── README.md

O README.md do pacote lista os EXE gerados e traz observações sobre a assinatura de código.

6. Como o iniciador se comporta

A pasta onde está o EXE é a raiz do aplicativo. O iniciador só aceita caminhos de tempo de execução, arquivo, classpath e pasta de trabalho dentro dessa raiz; tudo que estiver fora do pacote, e tudo que for desviado por um link simbólico ou junção, é recusado e o processo não inicia. Você pode, portanto, mover ou renomear o pacote inteiro, mas não copiar o EXE sozinho.

AspectoComportamento
Tempo de execuçãoUsa sempre o vlxjre\bin\java.exe do pacote. Nunca o Java do sistema, e não lê JAVA_HOME.
Argumentos de linha de comandoOs argumentos passados ao EXE entram depois dos do próprio aplicativo.
Modo consoleHerda a entrada e a saída padrão do console atual, espera o aplicativo terminar e devolve o código de saída dele.
Modo gráficoNão cria janela de console, o que serve a aplicativos de desktop.
Variáveis de ambienteLimpa antes de iniciar JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS e CLASSPATH, para que nada de fora do pacote injete opções.

As opções da JVM do EXE ficam fixadas no empacotamento, são assinadas junto com o bloco de parâmetros e verificadas em tempo de execução; depois da implantação não há como alterá-las. APP_JAVA_OPTS só afeta o run.bat — o EXE não o lê. Para mudar as opções da JVM do EXE, empacote de novo.

Pela mesma razão, -javaagent, -agentlib, -agentpath, -Xbootclasspath e --patch-module não podem entrar nas opções de inicialização do EXE. Passá-los por --jvm-option faz o empacotamento falhar na hora.

7. Assinatura de código

O Protector4J não assina o EXE gerado nem acessa credenciais de Authenticode. Todas as alterações do PE — ícone, recursos de versão e opções de inicialização — acontecem durante o empacotamento, de modo que a assinatura tem de vir por último.

  1. Conclua o empacotamento e confirme que o EXE inicia o aplicativo corretamente.
  2. Aplique uma assinatura Authenticode com o seu próprio certificado, incluindo carimbo de tempo RFC3161.
  3. Verifique a assinatura pela diretiva /pa do Windows.

Não altere o arquivo PE depois de assinado: qualquer mudança invalida a assinatura. Para trocar o ícone ou o número de versão, empacote e assine de novo.

8. Campos do arquivo de tarefa

O p4j-task.yml exportado usa a versão 2 do formato e guarda estes campos quando o EXE está ativado. Os arquivos de tarefa na versão 1 continuam podendo ser lidos.

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. Solução de problemas

SintomaCausa e solução
Avisa que é preciso uma plataforma-alvo WindowsO EXE está ativado, mas não se marcou windows-x64, windows-x86 nem windows-aarch64.
Avisa que o formato da versão é inválidoUm campo de versão traz letras ou espaços, tem mais de quatro partes, ou alguma delas está fora de 0–65535.
Avisa que o nome do EXE deve ser só um nome de arquivoO nome contém um separador de caminho. Use um nome sem pastas.
Avisa que o arquivo de ícone não foi encontrado--exe-icon aponta para um .ico inexistente. Confira o caminho.
Depois dos dois cliques não aparece janela e o aplicativo se fechaO aplicativo falha ao iniciar em modo gráfico. Empacote de novo em modo console para ver a saída de erro.
Um EXE copiado para outro lugar não funcionaO iniciador exige o tempo de execução e o arquivo na mesma pasta do pacote. Copie a pasta de saída inteira.

A lista completa de opções está na Referência da linha de comando; o assistente gráfico é descrito no Guia da interface gráfica.