はじめに
RustはC++に比べて以下のような特長があります。そのため、従来はC++を使用していた場面で、Rustを採用する事例が近年増えてきています。
・所有権・借用システムでメモリ安全性を保証
・コンパイル時のチェックでデータ競合やスレッドの安全性を確保
・ゼロコスト抽象化によりC++並みの高性能を実現
・ヘッダーファイル不要でコード管理とメンテナンスが容易
・Cargoによる統一されたビルド・依存管理で開発効率向上
・明快なエラーメッセージで学習・デバッグがしやすい
・モジュールシステムで型情報を効率的に管理し再解析を削減
・セキュリティ重視のシステム開発に適した設計
・Rust AnalyzerによるIDEフレンドリーな設計
では、従来C++で行われてきた、Windowsネイティブアプリケーションの開発をRustで行うと、どのようになるでしょうか。
WindowsネイティブアプリをRustで作る
現時点では、MFCやWindows Forms、WPFのようなWindows専用の大規模なGUIフレームワークはRustにはありません。ただし、iced や Slint、Tauri のようなクロスプラットフォーム対応のGUIライブラリを使ってWindows向けのアプリを作ることはできます。Rustではクロスプラットフォーム開発の需要が高いので、Windows専用の大規模なフレームワークの開発は活発ではありませんが、Windowsのネイティブアプリの開発はできなくはありません。
Win32アプリケーションをRustで作る
Win32アプリケーションをRustで作ることは、MicrosoftがGitHubで提供しているwindowsクレート(*1)を使うと可能です。ただしwindowsはRustからWin32やCOM, WinRTなどのAPIを使用できるようにするもので、MFCのような抽象化能力はありません。
(*1): Rustにおける、プロジェクトやライブラリを管理する単位のこと
基本的な例として、ウィンドウを表示するプログラムを見てみましょう。
use windows::{
core::*, Win32::Foundation::*, Win32::Graphics::Gdi::ValidateRect,
Win32::System::LibraryLoader::GetModuleHandleA, Win32::UI::WindowsAndMessaging::*,
};
fn main() -> Result<()> {
unsafe {
let instance = GetModuleHandleA(None)?;
let window_class = s!("window");
let wc = WNDCLASSA {
hCursor: LoadCursorW(None, IDC_ARROW)?,
hInstance: instance.into(),
lpszClassName: window_class,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc),
..Default::default()
};
let atom = RegisterClassA(&wc);
debug_assert!(atom != 0);
CreateWindowExA(
WINDOW_EX_STYLE::default(),
window_class,
s!("This is a sample window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
None,
None,
)?;
let mut message = MSG::default();
while GetMessageA(&mut message, None, 0, 0).into() {
DispatchMessageA(&message);
}
Ok(())
}
}
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match message {
WM_PAINT => {
println!("WM_PAINT");
_ = ValidateRect(Some(window), None);
LRESULT(0)
}
WM_DESTROY => {
println!("WM_DESTROY");
PostQuitMessage(0);
LRESULT(0)
}
_ => DefWindowProcA(window, message, wparam, lparam),
}
}
}
このように、C言語で生のWin32 APIを使ってプログラミングするのと同じようなものになります。ですが、Traitによるデフォルト設定や、再代入禁止変数、パターンマッチング式といった、明快でコードをシンプルに保てる記述ができることがわかります。
WinUI3アプリケーションをRustで作る
WinUI3のGUIアプリケーションを作るためのXAMLサポートは、以前のバージョンのwindowsクレートには実験的モジュールとして存在していましたが、最新版の0.59では削除されてしまいました。当面の間、XAMLがサポートされる予定はないため、GUIアプリケーションを作ることはできません。ただし、Windows App SDKの様々な機能を利用したライブラリやコマンドアプリケーションを作ることはできます。
最後に
今回は、WindowsネイティブアプリをRustで作るとどうなるか?を実践してみました。次回は、組み込みシステム向けのプログラムをRustで作るとどうなるかをご紹介したいと思います。