windows-rsのメモ
追記(2021/03/21)
雑多な新しい情報はスクラップのほうに書いています。
windows-rs
windows-rsはRust向けにWin32 APIの関数や構造体などを自動生成してくれるWin32 API本家本元のMicrosoftが作っているクレートで、クレート名はwindows
になっています。win32metadataで作られたwinmdファイルをwindows-rsのbuild
マクロでRustの関数や構造体を生成します。使い方はwindows-rsのGetting startedをご覧ください。
以下のIssueでwindows-rsはwinapi-rsを置き換えるように取り組んでいることがわかります。
ちなみにwinrt-rsを改名してwindows-rsになったようです。
winapi-rsとどっちがいいの?(0.7.0 2021/04/08の話)
windwos-rsが0.7.0において少なくとも自分が使った範囲ではとなりますが、ウィンドウやDirect2D、Direct3Dのようなよく使われるAPIではインポート時点でエラーが出るようなことはなく動作で問題がありませんでした。2021年1月の頃に比べると各段に使いやすくなっておりwinapi-rsの置き換えを考え始めてもいいのではないかと思います。また、winapi-rsは2020年11月の終わり頃を最後にコミットがなく足りないAPIが追加されるかどうかも正直わからないような状況です。したがって、winapi-rsよりwindows-rsを使っていく方向でいいのではないかと思います。ただし、windows-rsやwin32metadataのリリースは2021年末の見込み[1]で安定版ではない事を留意してください。
2021/01/23の話
2021/01/23においては、下記のようにコンパイル失敗することがあったりしてまだ安定していないのでwinapi-rsのほうが使いやすいと思います。しかし、winapi-rsは足りないAPIがあったり最新のWindows SDKに追従できていないので、現状でも自分でwindows-rsに修正を加えたりして対処できるならwindows-rsのほうが使える場面があるでしょう。win32metadataやwindows-rsが安定してくればwindows-rsを使うほうがよくなるかなと思いますが、win32metadataのリリースは2021年末の見込み[1:1]なので安定板はまだ待たなければなりません。
あれこれ
BOOL
BOOL
はwindows::BOOL
で定義されており、is_ok
などのRustに合わせた便利な関数が定義されていますが、is_ok
はself.0 != 0
、is_err
はself.0 == 0
となっているので、例えばGetMessageW
のようなBOOL
が-1
を返す関数では注意してください。
また、From<bool>
が定義されているのでtrue.into()
のようにinto
で変換することができます。
bindings::Windows::Win32::SystemServices::BOOL
になりました。
ok()
でResult<()>
にできたり、From<bool>
も定義されているのでinto
でbool
に変換もできます。
HRESULT
返り値の返り値のHRESULT
がwindows::ErrorCode
になっており、is_ok
などいくつかRustに合わせた便利な関数が定義されています。i32
をinto
で変換することはできません。
NewTypeパターンの型
WPARAM
、LPARAM
、LRESULT
などの型がNewTypeパターンになっており、例えばLRESULT
で0
を返そうする場合LRESULT(0)
のようにする必要があります。
(2021/04/08更新) 以下のエラーはなくなりました
UCharIterator
などの関数ポインタを持つ構造体でmap
がないと言われる
UCharIterator
などの関数ポインタを持つ構造体でmap
がないと言われるwindows::win32::intl::UCharIterator
のように*mut Option<関数ポインタの型>
を持つ構造体でコンパイルが失敗します。Issueを出してみたところ、win32metadata側の問題のようです。
https://github.com/microsoft/windows-rs/issues/438
https://github.com/microsoft/win32metadata/issues/132
(2021/01/29追記)
windows-rs
側でworkaroundを出そうという動きがあります。
api-ms-win-
で始まるlibをリンクしようとして失敗する
api-ms-win-
で始まるlibをリンクしようとして失敗するwinmdファイルにはWin32 APIの関数がどのDLLにあるか書かれているのですが、windows-rsがそのままDLL名を#[link(name = "...")]
のname
に入れて生成するために起こります。以下のwindows-rsのコメントによるとRustでDLLに対する動的リンクのサポートまでDLL名を対応したlib名に書く必要があるようです。
https://github.com/microsoft/windows-rs/blob/master/crates/gen/src/function.rs
// TODO: need to generate libs until Rust supports dynamic linking against DLLs.
// This is actually the DLL name
ちなみに上記のコメントの下に次のコードがあり、既に書かれたコードと同様に必要なDLLとlibの対応を書き足すとリンクを通せるようになります。
let mut link = self.signature.method.impl_map().unwrap().scope().name();
if link == "ext-ms-win-core-iuri-l1-1-0" {
link = "urlmon";
} else if link == "api-ms-win-core-winrt-l1-1-0" {
link = "onecoreuap";
}
Discussion