Rust/WinRT を試す

はじめに

先日 Microsoft から preview がリリースされた Rust で WinRT API を使用できるようにするためのものです。 C++/WinRT の Rust 版、みたいなもののようです。 Microsoft は割と Rust に本気なのかもしれません。

個人的にかなり気になるものなので試してみました。

crate.io には以前から WinRT の Binding ライブラリがありますが、こちらとは別のものです。

WinRT とは

あまりご存じない方もいるかもしれないので軽く触れておきます。

WinRT は正確には "Windows Runtime" という Windows 8 と合わせて登場した (当時) 新しい API セットの総称で、現在 UWP と言われている "Windows ストアアプリ (Metro スタイルアプリ)" を開発するために提供されたのが最初でした。

ちなみに Windows 8 の ARM 版の名前が "Windows RT" であったため略称にするとどっちの事を言っているのよくわからないという問題がありました。

基本的な特徴としては

  • COM をベースにしたネイティブ API である (.NET ではない)
  • API 定義はテキスト (ヘッダーファイル) ではなくバイナリ (Windows Metadata / winmd) で提供される

かと思います (他にも非同期とか UI とかありますが、根幹はこの二つかなと) 。

winmd は COM 的には Type Library に相当するもので、バイナリ構造としては .NET と互換性のあるものとなっています。各言語から WinRT の API にアクセスする場合、この winmd からインターフェース情報を取得し、相互運用を実現しています。

Rust/WinRT を導入する

README.md の "Getting started" に書かれている通りです。

[dependencies]
winrt = { git = "https://github.com/microsoft/winrt-rs" }

Cargo.toml に winrt の crate を参照に追加するだけです。注意点として toolkit が msvc である必要があります。 gnu では通りません。これは UWP 用のバイナリをビルドするので当然かなあと思ったのですが、そういう理由ではなさそうです。

winmd ファイルのあるパスへの参照が解決できないため、というのが理由のようです。まあ確かに API 的に WinRT 互換で winmd で API 定義が公開されているならコンパイル時にはプラットフォーム依存はしていないと言えるのもしれません。いずれにせよ、現時点では toolkit に制約がありますので注意してください。

とりあえず README.md のサンプルをコピペしてビルド、実行をしてみると、動作することは確認できます。

コードを書いてみる

・・・ちょっと、いや大分厳しい。

端的に言うとコード補完がほぼききません。これは WindowsAPI 部分が winmd に定義されているためと思われます。

winmd のインポートは "winmd_macros" という crate に定義されている import マクロで行います。

winrt::import!(
    dependencies
        os
    modules
        "windows.data.xml.dom"
        "windows.foundation"
        "windows.ui"
);

この import というマクロですが、どうも "proc_macro" というもので定義されています。

"Procedural Macros" は通常のマクロのようにテンプレートに穴埋めするのではなく、コンパイル時に動的にコード生成をする仕組みの事のようです。なるほど。これでは winmd 部分を Rust の文法でコード補完をかけるのは専用の対応を入れないと不可能ですね・・・

関連した Issue は上がっているので、実用になるかどうかはこれ次第ですかね。

おわりに

現状ではコード補完がきかないのが致命的すぎるので、 Windows と Rust が相当好きでも使うにはかなりハードルが高いと思います。試すだけなら Rust らしくとても簡単ですが。

こちらのコードも読んでみましたが、ウィンドウを開くだけでもちょっと手続きが面倒くさそうな感じなので、また機会を改めて (Win32 での UWP UI の利用の仕方についての理解が必要そう?) 挑戦してみようと思います。