🪟 windows-rsの文字列操作を理解する

🦀「文字列ってnつあんねん」🪟「文字列ってmつあんねん」
🐑「文字列がいっぱい...なにこれ...」
Rustを使ったWindows APIプログラミングでは、Rustの文字列に関連する型とWindows API固有の文字列型の扱い方を両方理解する必要がある。この記事では、windows-rsに入門する上でのガイドになるよういろいろな型の扱い方を整理してみる。

🦀 Rust の基本的な文字列に関連する型のおさらい
基本的な文字列型
-
String
:
ヒープに確保される可変の文字列型。Rust において最も一般的に使用される文字列型であり、常にUTF-8でエンコードされている。 -
&str
:
文字列スライス。通常String
や文字列リテラルの一部を参照する。UTF-8 エンコードされたバイト列への不変参照。文字列のリテラルを作ると&str
になる。
OSのネイティブ文字列
std::ffi
名前空間には、OSネイティブな文字列を統合的に扱うための型である OsString
と OsStr
が用意されている。OS固有のインタラクション例えば、ファイルパス、環境変数などにおける低レベルな操作に使われる。
内部的にはWindowsではUTF-16 (Vec<u16>
)が、Unixでは(システムのロケールに依存するが一般には)UTF-8 Vec<u8>
が使われる。
-
OsString
:
OS ネイティブの文字列を表す可変な型。String
や&str
への変換が比較的安価。 -
OsStr
:
OS ネイティブの文字列のスライスを表す不変の型。&str
やString
への変換は不可逆で、効率的に扱えるが、非 Unicode のデータが含まれている可能性がある。
ファイルパス
std::path
名前空間には、OSに依存しない形でファイルパスを扱えるようにするための専用の型である Path
と PathBuf
が用意されている。
-
&Path
:
ファイルシステム上のパスを表す不変参照型。Rust のstd::path::Path
で使用され、プラットフォームに依存しない方法でパスを管理できる。 -
PathBuf
:
&Path
の可変で所有権を持つバージョン。パスの操作や変更が可能で、&Path
に変換できる。
バイト列

windows_strings
クレート)
🪟 Windows 固有の文字列型 (Windows API との相互運用のためにいろいろな文字列が仕様される。以下は Windows でよく使われる windows_strings
クレートの文字列型。
WinRT 文字列
-
HSTRING
Windows Runtime (WinRT) で使用される、参照カウントされた不変の UTF-16 文字列。API 間で効率的に共有されるよう設計されている。
COM (Component Object Model) 文字列
-
BSTR
COM プログラミングで使用される、長さが前置された可変の UTF-16 文字列。BSTR
は、null 文字を含むことができるのが特徴。
C++では通常、BSTRのメモリ確保には SysAllocString
や SysAllocStringLen
を、メモリの解放には SysFreeString
を明示的に呼び出す必要があった。
一方、Rustの場合はBSTRの作成時に SysAllocString
が呼び出され、drop時に自動で SysFreeString
が呼び出されるらしい。便利!
impl BSTR {
// -- 中略 --
pub fn from_wide(value: &[u16]) -> Self {
if value.is_empty() {
return Self::new();
}
// BSTRの作成時にSysAllocStringLenを呼び出している
let result = unsafe {
Self(bindings::SysAllocStringLen(
value.as_ptr(),
value.len().try_into().unwrap(),
))
};
if result.is_empty() {
panic!("allocation failed");
}
result
}
}
impl Drop for BSTR {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { bindings::SysFreeString(self.0) } // drop時にSysFreeStringを呼び出している
}
}
}
C スタイルの文字列 (null 終端文字列ポインタ)
低レベルの Windows API 呼び出しや相互運用で広く使用される。
-
PSTR
可変の ANSI 文字列へのポインタ (*mut u8
)。レガシーな Windows API で使用される ANSI エンコーディング (Windows-1252 やシステムロケール) を表す。 -
PCSTR
不変の ANSI 文字列へのポインタ (*const u8
)。読み取り専用の ANSI 文字列が必要な関数で使用。 -
PWSTR
可変の UTF-16 ワイド文字列へのポインタ (*mut u16
)。Windows API で Unicode 文字列 (ファイルパス、レジストリ値など) に使用。 -
PCWSTR
不変の UTF-16 ワイド文字列へのポインタ (*const u16
)。読み取り専用のワイド文字列が必要な関数で使用。

🦀→🪟 Rust の文字列型からWindows固有の文字列型への変換
- Rustの文字列からnull終端ワイド文字列(
PWSTR
,PCWSTR
)を作るには、HSTRING
を経由することで実現できる。 -
windows::core
には文字列リテラルからWindowsで使われる文字列型への変換を行えるh!
,s!
,w!
マクロが用意されている。
それぞれの型の変換方法を図にすると次のようになる。