はじめに
つくったJavaアプリをWindows環境向けにexe化していきます。私が選んだものをメモしておきます。
何種類か存在しますが、下記を試しました。
- launch4j
- exewrap
- jpackage
launch4j
もともとMabiIccoの1.0系はこれをつかっていました。
ツールの起動自体にJava 1.8 系を必要とするようで、ちょっと うーん という感じです。せっかくJava8からJava17にあげたのに・・・。
このツールでEXE化した場合、EXEのアイコンは変更できるのですが、タスクマネージャーのところまでは変更されていないようでした。
exewrap
JARファイルをEXEへ変換してくれるツールのようです。ドキュメントをみるといろいろなオプションがありますが、通常のアプリなのでとりあえず作成してみます。
-a が、アプリケーションに指定するVM引数ということなので、下記のようにしてみました。
exewrap.exe -g -e NOLOG; -i icon2.ico -v 1.2.67 -l APPDIR -a "--add-exports java.desktop/com.sun.media.sound=ALL-UNNAMED --add-exports java.desktop/sun.swing=ALL-UNNAMED" -t 17 MabiIcco.jar
が、、、。
–add-exportsの指定が効いてなく、起動できません。
モジュールシステムに対応していればいいのですが、JARで起動するのはちょっとできない?かなということで断念しました。
jpackage
最近のJDKについているコマンドです。
ドキュメントをみると、MSIなどのインストーラにもできるようですが、EXEでとめておきます。
jpackage -t app-image -n MabiIcco -d package -i make-package --main-jar mabiicco.jar --java-options "--add-exports java.desktop/com.sun.media.sound=ALL-UNNAMED --add-exports java.desktop/sun.swing=ALL-UNNAMED" --add-modules java.base,java.datatransfer,java.desktop --icon icon3.ico --app-version 1.2.70
できました。
アイコンも反映されていますし、タスクマネージャーの表示もアプリケーション名&アイコン反映されるようです。EXE化するだけの用途でとりあえず使っていきたいと思います。
ただ、launch4のときには日本語環境で韓国語のファイル名を引数で渡せていたのですが、jpackageで作ったexeだと文字化けしてファイルが開けないという問題が発生しました。
JPackageでexe化したアプリケーション引数が文字化けする
検索してみると既知の?問題らしいですね。
ためしにと、最新のJava18でやってみたりしましたが、だめでした。(JDK21でもだめ)
結論としては、JNAでやることにしました。
コマンドライン全体をとれるようなので、これなら日本語環境での韓国語ファイル名も問題なく渡せました。コマンド全部とってくるようなので、後ろのところだけ切り取るようにしています。
interface Kernel32 extends StdCallLibrary { Kernel32 INSTANCE = (Kernel32) Native.load("kernel32", Kernel32.class); WString GetCommandLineW(); Pointer LocalFree(Pointer pointer); } interface Shell32 extends StdCallLibrary { Shell32 INSTANCE = (Shell32) Native.load("shell32", Shell32.class); Pointer CommandLineToArgvW(WString command_line, IntByReference argc); } public static String[] getCommandLineArgs(int n) { IntByReference argc = new IntByReference(); var ptr = Shell32.INSTANCE.CommandLineToArgvW(Kernel32.INSTANCE.GetCommandLineW(), argc); String[] argv = ptr.getWideStringArray(0, argc.getValue()); Kernel32.INSTANCE.LocalFree(ptr); if (argv.length > 0) { return Arrays.copyOfRange(argv, argv.length-n, argv.length); } return null; }
まとめ
結果としては、jpackageでexe化することにしました。ただ引数に関しては文字コードが適切に扱えないようなので注意です。
MabiIcco 1.0 系:launch4j
MabiIcco 1.2 系:jpackage