【D言語】exeにアイコンやバージョン情報を付与する
作ったソフトにアイコンが欲しい
ゲーム制作に使っている自作のマップエディタがあるのだが、アイコンが長らくデフォルトのままだった。
もちろん動作に影響はないのだが、なんかこう、見た目がちょっと寂しい。
そこで、ゲーム制作の合間にオリジナルのアイコンを作ってexeに埋め込んでみた。
ついでにバージョン情報も添付してみたので、このあたりの手順もあわせてご紹介したい。
なお、開発にはD言語を使っており、dmdのバージョンはv2.100.0である。
リソーススクリプトを書く
まず、アイコンやバージョン情報をexeに埋め込むためにリソーススクリプト(.rc
)を作る必要がある。
ここはC++とさほど変わりはない。
内容は以下のようになっている。
自分のソフト用の設定をそのまま持ってきているので、各項目の内容は適宜読み替えていただきたい。
#pragma code_page(65001)
#include <windows.h>
/* アイコン */
101 ICON "map_editor.ico"
/* バージョン情報 */
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0x0L
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "041104b0"
BEGIN
VALUE "CompanyName", "A3サイズの升目帖\0"
VALUE "FileDescription", "マップデータを編集するソフト\0"
VALUE "FileVersion", "1.0.0.0\0"
VALUE "InternalName", "mapeditor\0"
VALUE "LegalCopyright", "Copyright (C) 2022 えーさん ますめ\0"
VALUE "OriginalFilename", "mapeditor.exe\0"
VALUE "ProductName", "マップエディタ\0"
VALUE "ProductVersion", "1.0.0.0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x411, 0x4b0
END
END
リソーススクリプト自体は普通にテキストエディタで編集すればいいのだが、拡張子は.rc
にする必要がある。
あと、アイコンファイルは同じフォルダに入れておこう。
ICON
のリソースIDについて
アイコンのリソースIDを101
というふうにハードコーディングしているが、本当はresource.h
などの別ファイルに分けて定義するのが望ましい。
しかし、現時点ではImportCが#define
プリプロセッサに未対応なので、ヘッダファイルに分けてしまうとそれをD言語側からも参照するためにhtodなどのツールで変換しなければいけなくなる。
高々1個の定数のために変換を噛ませるのは費用対効果が低いので、これで済ませているというわけだ。
要約:横着しました♥
ちなみに、ImportCというのはD言語のコンパイラでC言語のソースコードを直接コンパイルできるようにしてしまおうとかいうとんでもない代物で、dmd v2.098.0でリリースされた目玉機能だ。
先述のとおり、プリプロセッサには未対応などまだまだ発展途上だが、#define
による定数定義には対応の兆しも見えており、今後が楽しみである。
2023/5/14追記
更新が遅くなってしまったが、dmd v2.101.0にて、ImportCが#define
による定数定義に対応したため、リソースIDを別ファイルで簡単に管理できるようになった。
リソースIDを定義するC言語ファイルとして、以下のようにresource.i
を作り、リソーススクリプトと同じディレクトリに置いておく。
#define IDI_APP 101
リソーススクリプト側にもresource.i
を追加し、リソースIDを定数に置き換える。
#include <windows.h>
#include "resource.i"
/* アイコン */
IDI_APP ICON "map_editor.ico"
続いて、dub.json
にresource.i
へのパスを追加しておく。
"sourceFiles": [
"../../my/path/resource.i"
],
あとは、Dのソース側でも定数を参照する。Cのソースはパスさえ通っていれば通常のDのソースと同じようにimport
できる。
import resource; // ←CのソースをDと同じようにimportできる!
HICON hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_APP));
ちなみに、Cのソースの拡張子をいつもの.c
ではなく、プリプロセス済みを表す.i
にしているのは、手元のcl.exe
がプリプロセスオプション(/Zc:preprocessor
)に未対応だったためであり、Visual Studio 2019以降を使っている人なら拡張子は.c
で問題ない。
リソーススクリプトをコンパイルする
リソーススクリプトはそのままではリンクできないので、rc.exe
でコンパイルする必要がある。
なお、rc.exe
の在り処だが、筆者の環境ではC:\Program Files (x86)\Windows Kits\10\bin\10.0.xxxxx.0\x64
あたりに入っていた。
たぶんVisual Studioをインストールした際に同梱されていたんだと思う。
コンパイルのコマンドは以下のとおり。
rc -fo"出力パス" "入力パス"
入力パス
には、先ほど作成したリソーススクリプト(.rc
)のパスを指定する。
出力パス
には、拡張子を.res
に変更したパスを指定する。
ファイル名をhoge
とするならこんな感じになる。
rc -fo"hoge.res" "hoge.rc"
ビルドと同時にコンパイルしたい場合は、これをdub.json
の"preBuildCommands"
に追加するのがいいかもしれない。
// 対象はWindowsだけなので、一応"-windows"サフィックスを付けている。
// また、筆者はファイルの更新を確認してコンパイルの要否を判断する、もうちょっと複雑なスクリプトを組んでいる。
"preBuildCommands-windows": [
"rc -fo\"hoge.res\" \"hoge.rc\""
]
なお、INCLUDE
環境変数にwindows.h
へのパスが登録されていないとコンパイルエラーになるぞ!(1敗)
リソースをリンクする
.res
ファイルをリンクする設定を追加する。
dub.json
の"lflags"
(リンカへのパラメータ)に、.res
ファイルのパスを指定すればOK。
"lflags": [
"hoge.res"
]
アイコンをウインドウの左上に表示する
ここまでの手順を踏めば、エクスプローラ上のexeには指定したアイコンが適用されているはずだ。
しかし、ウインドウの左上に表示されるアイコンはまだデフォルトのままだと思う。
ここにもアイコンを表示するには、ウインドウの生成時に明示的にアイコンを指定してやる必要がある。
ウインドウを表示する処理から、ポイントとなる個所を抜粋した。
HINSTANCE hInstance = GetModuleHandleA(null);
// アイコンハンドルを取得する。リソーススクリプトで定義したIDをここに指定する。
HICON hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(101));
// あとは、ウインドウ生成のパラメータ(hIcon)に設定する。
WNDCLASSEXA wc;
wc.hIcon = hIcon;
/* ... ほかのパラメータ色々 ... */
auto atom = RegisterClassExA(&wc);
/* ... ウインドウを表示する処理などが続く ... */
Win32APIでウインドウを表示する詳しい方法については今回は割愛…
出来上がりの例
上手くいけば、こんな風にアイコンが表示される。やっぱりアイコンがあると箔が付くなあ。
タスクバーはこうなってる。
アイコンは16x16
pxと32x32
pxの2種類を用意したが、タスクバーでは後者のほうが使われているようだ。
また、マップデータファイルをマップエディタに関連付けているので、エクスプローラ上のファイルにもアイコンが適用されていい感じだ。
今回得たノウハウは、今後ゲーム本体にアイコンやバージョン情報を付与する際にも役立つ。
収穫がたくさんあってよかった。