1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

時代遅れな .mui による多言語対応 .exe の作り方

Last updated at Posted at 2025-09-01

まえがき

筆者は、高校生2年生のときに WinUI/C# オープンソースプロジェクトである Files App の開発に参加し始め、学部 1 年生の現在は Native AoT デプロイの有効化に向けてソースコードアーキテクチャの再開発を主導しています。

この記事は、高校 1 年生の時に作ったツール(後述)をもとに執筆した Gist の完全版です。内容に不備がありましたらご容赦ください。

導入

Windows を触っていると、C:\Windows\System32\ja-JP\ のようなフォルダの中に、exe ファイルの名前を冠した .mui ファイルを見かけたことはありませんか?実はあのファイル、単なる謎の付属物ではなく、多言語対応のために用意された .exe と同じ形式(PE 形式)のバイナリファイルなのです。

.mui ファイルは「多言語ユーザーインターフェイス (Multilingual User Interface)」用のリソースファイルで、対応する .exe 本体のメッセージや文字列といったローカライズリソースを提供します。ユーザーが使用する Windows のほとんどの .exe.dll ファイルで使われています。

ところが、古いソースコードや資料で .mui を使った多言語対応に出会うと、具体的にどう作って、どう読み込ませるのかが分からず困ることが多いはずです。Microsoft Learn は *いつも通り* まったく意味が分かりませんし。

ここでは特に文字列リソースの多言語化に重きをおいて、.mui ファイルの作成からリンク、読み込みまでの一連の流れを体系的に整理して説明します。

1. .mc ファイルを作る

.mc ファイルは .mui に埋め込む文字列リソースの原型となります。

en-US/myapp.mc
;// ヘッダー セクション

MessageIdTypedef=DWORD

SeverityNames=(
  Success=0x0:STATUS_SEVERITY_SUCCESS
  Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
  Warning=0x2:STATUS_SEVERITY_WARNING
  Error=0x3:STATUS_SEVERITY_ERROR
)

FacilityNames=(
  System=0x0:FACILITY_SYSTEM
  Runtime=0x2:FACILITY_RUNTIME
  Stubs=0x3:FACILITY_STUBS
  Io=0x4:FACILITY_IO_ERROR_CODE
)

LanguageNames=(English=0x409:msg0409)

;// 文字列リソース定義

MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.

MessageId=7006
SymbolicName=MSG_ATTRIB_PARAMETER_NOT_CORRECT
Language=English
Parameter format not correct -
.

MessageId=7007
SymbolicName=MSG_ATTRIB_NOT_RESETTING_SYS_FILE
Language=English
Not resetting system file - %1
.

一つの .mc ファイルに言語はいくつか追加できますが、普通は 1 ファイルにつき 1 言語ですのでこのまま進みます。注意すべき点はメッセージの最後にドットを挿入することです。サンプルファイルも参照してください。

2. mc.exe でコンパイル

.mc ファイルが出来上がれば、mc.exe でコンパイルしていきます。

mc.exe ./en-US/myapp.mc

すると

myapp.h
myapp.rc
msg0409.bin

が生成されます。.bin ファイルの名前は .mc ファイルの LanguageNames の値に依存します。

3. rc.exe で中間リソースコンパイル

次に作るものは .mui にリンクさせるものリスト(.rcconfig)です。今回は文字列リソースのみを .mui にリンクさせるので、それを記述していきます。

app.rcconfig
<?xml version="1.0" encoding="utf-8"?>
<localization>
  <resources>
    <win32Resources fileType="Application">
      <localizedResources>
        <resourceType typeNameId="#11"/> <!-- MESSAGETABLE -->
      </localizedResources>
    </win32Resources>
  </resources>
</localization>

そして、myapp.rcmyapp.rcconfigrc.exe を使って

rc.exe /fo common.res /fm msg0409.res /q myapp.rcconfig myapp.rc

すると

common.res
msg0409.res

ができます。

4. バージョン情報等のリソースもコンパイルする(任意)

バージョン情報等のリソースも .mui にリンクさせたい場合は、Visual Studio で version.rcresource.h を自動生成させて、version.rc にバージョンを書き終えたら、

rc.exe version.rc

すると

version.res

ができます。resource.hversion.rc 内ですでにインクルードされているので指定する必要はありません。

5. common.res.exe にリンクする

.mui が存在することを .exe に知らせる必要があるにで、リンクします。

link.exe myapp.exe common.res

Resource Hacker.exe の中身を見るとリソースツリーにMUIができているのがわかります。

6. msg0409.res.mui に変換する

ここで .mui を作成します。

link.exe /out:myapp.exe.mui /nodefaultlib /noentry /dynamicbase /nxcompat /dll msg0409.res version.res

ファイルフォーマットは .exe と同じ PE ですが、エントリーポイントなしを指定しているので、実行できないタイプです。version.res は作ったのならこれもリンクします。

7. ほかの言語のリソースを作成(これは省略可)

同じように同じ手順で作成しますが、途中で common.res が再生成されているので、

rc.exe /fm msg0411.res /q myapp.rcconfig msg0411.rc

で OK です。

8. muirct.exe を使ってチェックサムを結ぶ

これで最後大詰めです。一番大事な作業、チェックサムを結ぶことです。.mui は物理ファイルパスではなく、チェックサムでメッセージテーブルを呼び出します。

muirct.exe -c myapp.exe -e en-US\myapp.exe.mui

これで外部メッセージテーブル呼び出しが可能になりました。今回は外部に置きましたが、もちろん内部でも可能です。途中リンクコマンドで msg0409.res から .mui ファイルを生成するようにしていますが、common.res のように .exe にもリンクできます。

結果のテスト

メッセージテーブルを呼び出します。

myapp.c
BOOL DisplayFormattedMessage(DWORD dwMsgId, DWORD nArgs, ...)
{
    va_list args = NULL;
    va_start(args, nArgs);

    LPWSTR pwszMessage = NULL;

    if (!FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMsgId, 0, &pwszMessage, 10, &args))
        return FALSE;

    va_end(args);

    return TRUE;
}

重要なのは FORMAT_MESSAGE_FROM_HMODULE をフラグに指定しているところです。これでチェックサムが結ばれたメッセージテーブルを探しに行きます。もしなければエラーで終了します。

まとめ

信じられないくらいすごくめんどくさいです。cmake で自動化させるしかないですね。

ちなみに C を勉強したての頃、コマンドプロンプトを自分で一から作ってみたいと思い、既存の .exe.dll(例えば attrib.exe)からメッセージテーブルを抽出し .mc ファイルを作成するツールを作りました。参考までにご覧ください。

今回は時代遅れな .mui の作り方と .exe からの呼び出し方について取り上げました。Windows の様々なことについて取り上げていくつもりですので、お楽しみにお待ち下さい!

関連文献

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?