Microsoftは、あらゆる言語からWin32 APIを簡単に使用できるようにするために、Win32 Metadataプロジェクトを立ち上げた。自動化された慣用的なプロジェクションを通して完全なWin32言語バインディングを生成することを目的としている。このプロジェクトでは、初期にはC#、C++、Rustのプロジェクションが含まれている。
win32metadata
がもたらす主な利点は、Microsoftが公式にサポートしている言語(C#やF#など)以外の言語からアクセスできるようするために、Win32 APIを手動で再定義する必要がないことである。収集されたメタデータは、言語固有のプロジェクションを通じてオンザフライでバインディングを作成するために使用される。
このプロジェクトのアウトプットは、実質的にECMA-335準拠のWindowsメタデータファイル(
winmd
)である。このファイルは、Win32 APIサーフェス全体を記述するメタデータを含むNuget.orgにパブリッシュされる。
以前は、Win32 APIを別の言語からアクセスできるようにするには、.NETのPlatform Invoke(PInvoke)を利用して、署名、ユーザ定義タイプ、そして、Win32やその他のアンマネージAPIを呼び出すために必要となる情報を追加する必要があった。オープンwikiのPinvoke.netは、開発者にそのような定義をすべて提供しているため、開発者はWin32ヘッダーファイルを熟読する必要はないが、それらを別の言語に変換するプロセスは、面倒でエラーが発生しやすいものとなっている。
このプロジェクトでは、Windows SDKヘッダーをスクレイプしてC#ファイルを生成するために、ClangSharpを使用する。Windows SDKのライブラリを使用して、各API関数のDLLインポートが何であるかを把握する。プロジェクトは、パーティションに分割され、おおまかに言うと、それは名前空間に変換される。ClangSharpは、処理するパーティションごとに
.cs
ファイルを作成する。
生成されたメタデータは、APIの使用を容易にするために追加情報を含めようとする。例えば、uint
などの非特定の型を使って指定された定数を、明示的な列挙型に変換する。さらに、HANDLE
やGDIオブジェクトなどのopaque型は強く型付けされた構造体によって表される。そこには、対応するリソースを適切に破棄する方法も含まれる。
前述のように、このプロジェクトでは初期にはC#、C++、Rustの3つのプロジェクションを提供する。しかし、Microsoftは多くの言語の追加の予測している。すべてのプロジェクションは、プログラムと共に含まれているメタデータからオンザフライで生成されたコードを使用してWindows APIを呼び出すことができる。
C++プロジェクションは特に興味深く、win32metadata
がどのような可能性を開くかを理解できる。実際、開発者は長い間C++からWin32ヘッダーにアクセスできたが、Microsoftが強調しているように、これらのヘッダーは、履歴と互換性の制約により、最新のC++機能の使用を妨げている。新しいC++プロジェクションでは、C++17以降へのコンプライアンスを向上されると同時に、マクロや列挙型などを置き換えるために高レベルの抽象化が使用される。
RustからWin32 APIを使用する方法の慣用的な例として、Win32を呼び出すRustスニペットは次のようになる。
mod bindings {
::windows::include_bindings!();
}
use bindings::{
windows::data::xml::dom::*,
windows::win32::system_services::{CreateEventW, SetEvent, WaitForSingleObject},
windows::win32::windows_programming::CloseHandle,
};
fn main() -> windows::Result<()> {
let doc = XmlDocument::new()?;
doc.load_xml("<html>hello world</html>")?;
let root = doc.document_element()?;
assert!(root.node_name()? == "html");
assert!(root.inner_text()? == "hello world");
unsafe {
let event = CreateEventW(
std::ptr::null_mut(),
true.into(),
false.into(),
std::ptr::null(),
);
SetEvent(event).ok()?;
WaitForSingleObject(event, 0);
CloseHandle(event).ok()?;
}
Ok(())
}
将来の見込みがあるが、win32metadata
プロジェクトはまだ完了していない。
Win32 APIは長い間存在していたため、それらすべてを正確に説明できるようになるには、ある程度の反復による理解が必要となります。私たちは、このツールをオープンに開発しています。すべての言語にメリットとなるWin32 APIサーフェスの正確な表現を保証するためのコミュニティの貢献を歓迎します。
Microsoftは、特に、2021年末までにC#、C++、Rustの安定したプロジェクションをリリースし、それに加え、C#プロジェクションの.NET 5 TFM統合を行う予定である。また、追加の言語プロジェクションは2022年から公開される予定である。