(未解決)windows-rs経由のwin32APIでUTF-8を使ってみた

Published:2023-06-10

--- Rust から簡単に使用するために、 win32api で UTF-8 を使えるように設定してみた際の検討と結果 ---


前置き

現在開発中のアプリではRustから windows クレートを使用して win32API を利用しています。

Rust の文字列型にはString&strがありますがこれらは UTF-8 で処理されます。 一方、win32api は、言語によって異なる CodePage に対応した -A タイプの API と、UTF-16 に対応した -W タイプの API があります。

開発中のアプリでは -W タイプ(UTF-16)の API を使っていますが、 UTF-16 は Rust から扱うと少し不便なことが多いです。 そこで、プロセスの CodePage を UTF-8 にすることで実装を簡単にできるのでは、と思い、試してみました。

先に書いておきますが、ある程度はできたものの一部解決できてない問題があるため、結局 UTF-16 を使うように戻しました。

方法

Microsoft 公式にある下記記事を参考にします( fusion マニフェストのほう)。assemblyIdentity の name や version はアプリに合わせました。

Windows アプリで UTF-8 コード ページを使用する - Windows apps Microsoft Learn

開発環境への組み込み方

上記サイトにある通りマニフェストを適用するためには mt.exe を実行する必要があります(他の方法もあるとは思いますがこれが一番簡単そう)。

プログラムのデバッグ時は、デバッグビルド→マニフェスト適用→デバッグ実行という手順を踏むことになりますが、この手順は頻繁に行うため1操作でできるようにしたいところです。 最初はRustのビルドスクリプトで実現しようと思ったのですが、どうもビルド後のコマンド実行はできない(?)ようです。 それ用のツールもあるらしいのですが、今回は、開発環境として使っている VisualStduio Code のlaunch.jsonで設定できるタスク(tasks.json)で実現できそうなのでこれを使ってみました。

launch.json と tasks.json

私はデバッガとして Microsoft の C/C++ for Visual Studio Codeを使っています(なので CodeLLDB の場合と書き方が変わるかもしれません)。

launch.json に preLaunchTask としてタスクを登録します。タスクの内容は tasks.json に記載します。今回の場合は、デバッグビルドとマニフェスト適用がタスクとなります。 なお、preLaunchTask には複数のタスクは設定できないので、まとめるためのタスクをもう一つ追加で作り、それに dependsOn で複数のタスクを設定することで複数タスクの実行が可能になります(下記の参考リンク)。 また、デバッグビルド→ビルド後の実行ファイルにマニフェスト適用という流れなので、順番を指定する dependsOrder も設定する必要があります。

参考:Tasks in Visual Studio Code

launch.jsonの内容
{
    "version": "0.2.0",
    "configurations": [
        {
            ~ 略 ~
            "preLaunchTask": "debug tasks",
            ~ 略 ~
        }
    ],
}
tasks.jsonの内容
{
	"version": "2.0.0",
	"tasks": [
        {
            "label": "debug build",
            "type": "shell",
            "command": "cargo",
            "args": [
				"build"
			],
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "set codepage",
            "type": "shell",
            "command": "C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22000.0\\x64\\mt.exe",
            "args": [
                "-manifest",
                "${workspaceFolder}\\set_codepage_to_utf8.manifest",
                "-outputresource:${workspaceFolder}\\target\\debug\\my_app.exe;#1"
			],
        },
        {
            "label": "debug tasks",
            "dependsOrder": "sequence",
            "dependsOn": [
                "debug build",
                "set codepage",
            ]
        }
	]
}

できたけど問題あり

上記を設定しデバッグ実行します。すると、マニフェストが適用されたプロセスが UTF-8対応され、-AタイプのAPIを使って日本語などの表示が正しく表示などが行えるように、、、なったと思ったのですが、なぜか文字化けしている表示が一部出てきました。

正しく表示されたものは、ウィンドウの名前(CreateWindowExA()lpWindowName)やコンボボックスへの文字列追加(SendMessageA()CB_ADDSTRINGを送信)などです。 文字化けが起こってしまったものは、ステータスバーへのテキスト設定(SendMessageA()SB_SETTEXTAを送信)やスタティックコントロールへの文字列描画(DrawTextA())などです。

原因については調べたのですが、あまりわかっていません。一応、下記ページの内容が関連しているのではないかなと思っています。

メッセージの自動翻訳 - Win32 apps Microsoft Learn.htm

SB_SETTEXTAは下記ページに記載されていないメッセージなので対応されておらず、スタティックコントロールへの文字列描画(DrawTextA())は内部でどんなメッセージが使用されているか不明ですが、メインのウィンドウから呼ばれているためウィンドウクラスが違うのかなあと思っています。

その他(やってみてわかったことなど)

まとめ

ある程度実現できたものの残りの問題が解決できず今回は元に戻って UTF-16 を使うことにしました。

また、その他で書いたように、仮に問題が解決できたとしても UTF-16 を完全に使わないようにはできず、また、UTF-8 にしてもある程度の前処理が必要となるため、思ったほどの効果が得られないことがわかりました(UTF-16 を扱うための構造体を実装済みだったことも大きいです)。この取り組みはしばらく放置することになりそうです。

前の投稿: 最初の投稿 次の投稿: マウスを新調しました