ユーニックス総合研究所

  • home
  • archives
  • windows-rs-hello-world

メッセージボックスを表示する - Rustで作るWindowsアプリ

  • 作成日: 2023-05-02
  • 更新日: 2023-12-24
  • カテゴリ: windows-rs

RustでWindowsアプリを作る

Rustはメモリ安全な言語として最近話題の言語です。
Linuxの開発にも導入されるなど徐々にその活躍の場を広げています。

しかしRustはまだ歴史の浅い言語だけあって、周辺ライブラリなどはそれほど充実しているとは言えません。
特にGUIライブラリはまだ発展途上で、Rustでウィンドウを出すプログラムを作ろうとすると選択肢も限られてきます。

しかしRustのモダンな機能を使ってウィンドウを表示できるアプリを作れればそれは素晴らしいことです。
特にRustの機能でWindowsアプリを作れればなかなか楽しそうです。

この本ではRustでWindowsアプリを作る方法を解説していきます。
具体的にはWindows APIを使ってウィンドウを表示するアプリを作ります。
Rustのインストール、windows-rsの導入から解説していきます。

この書籍では紹介するソースコードの動作確認は以下の環境で行っています。

  • Windows10(64ビット)
  • cargo 1.69.0
  • rustc 1.69.0
  • windows-rs 0.48

WindowsでRustを使うには?

Windows環境でRustを使うには https://rust-lang.org からrustup-init.exeをダウンロードしてパソコンにRustをセットアップします。

rustup-init.exeのダウンロードとインストール

rustup-init.exeのダウンロードは https://www.rust-lang.org/tools/install のページから行えます。
使っているWindowsが64ビットの場合は 64-BIT のrustup-init.exeをダウンロードしてください。

ダウンロードしたrustup-init.exeをダブルクリックして実行すると以下のような黒い画面(コマンドプロンプト)が出ます。

The Cargo home directory is located at:  

  C:\Users\myname\.cargo  

This can be modified with the CARGO_HOME environment variable.  

The cargo, rustc, rustup and other commands will be added to  
Cargo's bin directory, located at:  

  C:\Users\myname\.cargo\bin  

This path will then be added to your PATH environment variable by  
modifying the HKEY_CURRENT_USER/Environment/PATH registry key.  

You can uninstall at any time with rustup self uninstall and  
these changes will be reverted.  

Current installation options:  


   default host triple: x86_64-pc-windows-msvc  
     default toolchain: stable (default)  
               profile: default  
  modify PATH variable: yes  

1) Proceed with installation (default)  
2) Customize installation  
3) Cancel installation  

1) Proceed with installation (default)」と表示されているところに注目してください。
これはデフォルトではエンターキーを押せばインストールが開始するという意味です。
エンターキーを押してRustの周辺実行ファイルをインストールしてください。

このインストールが完了するとWindowsのコマンドプロンプトやPowerShellからcargoが使えるようになります。

> cargo --help  

インストールが完了してからコマンドプロンプトを開き上記のコマンドを実行するとcargoの使い方が表示されます。
cargoというのはRustの公式のパッケージ管理ツールのことです。
パッケージ管理ツールとはRustのパッケージの作成、ビルド、外部ライブラリのインストールと管理などをまとめて行ってくれるツールのことです。
実際のRustの開発ではこのcargoを使って開発していきます。

ちなみにこの本で使っているcargoは以下のバージョンになります。

> cargo -V  
cargo 1.69.0 (6e9a83356 2023-04-12)  

Windows APIとは?

Windows APIとはWindowsアプリケーションの作成やWindowsの機能を使うためのインターフェースです。
このWindows APIを使うとGUIアプリケーションやWindowsの機能を使ったアプリケーションが作れるようになります。

Windows 95/NTのころからある32ビット環境のAPIは特にWin32 APIと呼ばれます。
最近では64ビットへの移行が進んでいるのでWindows APIと言えば64ビットのAPIを含んでいます。

古(いにしえ)の時代よりWindowsプログラマはこのWindows APIを使ってWindowsアプリを開発してきた歴史があります。
つまりRustでWindows APIを使うということはRustという最新の言語を使ってその歴史に飛び込むということになります。

当然、Windows APIにはモダンとは言えないインターフェースも含まれています。
Windows APIはC言語が開発のメインだった時代から使われていますので、インターフェースもC言語から扱えるものになっています。

RustでWindows APIを利用するには?

マイクロソフト社がRustでWindows APIを使うためのライブラリを公開しています。
その名もwindows-rsというのがそうです。
これはオープンソースでソースコードはGitHubに公開されています。

microsoft/windows-rs: Rust for Windows
https://github.com/microsoft/windows-rs

このwindows-rsを使えばRustからWindows APIを使うことが可能になります。

またwindows-rsのドキュメントは以下にあります。

windows - Rust
https://microsoft.github.io/windows-docs-rs/doc/windows/index.html

windows-rsのクレートの種類

windows-rsにはwindowsクレートとwindows-sysクレートがあります。windows-sysクレートはオーバヘッドを無くしたフォールバックな定義です。
この2つのクレートにはそれぞれWindows APIのラッパーなどが定義されていますが、両者の定義はそれぞれ違っています。
たとえばwindowsクレートのw!マクロはPCWSTR構造体を返しますが、windows-sysクレートのw!マクロはu16の配列のポインタを返すなど、仕様が違っています。
windows-sysを探検するときはこの両者のクレートが共存していることを意識して探検する必要があります。
この本ではおもにwindowsクレートの処理について取り上げています。つまりこの本で話すw!マクロの返り値はPCWSTR構造体になります。

windows-rsでHello, World!

ではさっそくwindows-rsで「Hello, World!」するところまでやってみます。
まずcargoで適当なフォルダに新規パッケージを作成します。
ここではコマンドプロンプトから以下のコマンドを打ちます。

> cargo new hello_world  
     Created binary (application) `hello_world` package  

cargo newはRustの新規パッケージを作成するコマンドになります。
これでhello_worldというパッケージを作ります。
パッケージを作ったらcdコマンドでパッケージフォルダの中に移動します。

> cd hello_world  
> dir  
Cargo.toml  
src  

dirコマンドでパッケージの中身を見ると上記のようにCargo.tomlsrcフォルダがあります。
Cargo.tomlはパッケージの設定や外部ライブラリの依存関係などを記述するファイルです。

> type Cargo.toml  
[package]  
name = "hello_world"  
version = "0.1.0"  
edition = "2021"  

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  

[dependencies]  

typeコマンドでファイルの中身を見ると上記のようになっていると思います。
[package]にはパッケージの名前やバージョンなどを書きます。
[dependencies]には外部ライブラリの依存関係を書きます。

srcフォルダ以下には実際のソースコードを配置します。
デフォルトではmain.rsというRsutのソースファイルが配置されています。

> dir src  
main.rs  

Cargo.tomlの編集

ではCargo.tomlファイルを以下のように編集します。

[package]  
name = "hello_world"  
version = "0.1.0"  
edition = "2021"  

[dependencies.windows]  
version = "0.48"  
features = [  
    "Win32_Foundation",  
    "Win32_UI_WindowsAndMessaging",  
]  

featuresに書かれているのがwindows-rsの外部ライブラリです。
基本となるパッケージとしてWin32_Foundation, それからMessageBoxW()を使うためのWin32_UI_WindowsAndMessagingを取り込んでいます。

続いてsrc\main.rsを以下のように編集します。

use windows::{  
    core::*,  
    Win32::UI::WindowsAndMessaging::*,  
};  

fn main() {  
    unsafe {  
        MessageBoxW(None, w!("Hello, World!"), w!("日本から"), MB_OK);  
    }  
}  

このソースコードは簡単なメッセージボックスを表示するためのコードです。
useしているのはwindows以下のcore::wWin32::UI::WindowsAndMessaging::{MessageBoxW, MB_OK}になります。ここではアスタリスク(*)で省略しています。

unsafe { }はRustで安全じゃないコードを書くときに使います。
多くのGUIアプリケーションは本質的には安全なアプリではないので、windows-rsを使った開発では全般的にこのunsafeを使います。
このunsafeを使うとメモリ安全じゃなくなり未定義の動作を起こすこともあるので注意してください。

MessageBoxW()はワイド文字列に対応したメッセージボックスです。

Function windows::Win32::UI::WindowsAndMessaging::MessageBoxW  

pub unsafe fn MessageBoxW<P0, P1, P2>(  
    hwnd: P0,  // ウィンドウのハンドル(HWND型)  
    lptext: P1,  // 表示するメッセージ(PCWSTR型)  
    lpcaption: P2,  // メッセージボックスのタイトル(PCWSTR型)  
    utype: MESSAGEBOX_STYLE  // メッセージボックスのスタイル(MESSAGEBOX_STYLE構造体)  
) -> MESSAGEBOX_RESULT  
where  
    P0: IntoParam<HWND>,  
    P1: IntoParam<PCWSTR>,  
    P2: IntoParam<PCWSTR>,  

w!()はマクロでnullターミネートされたUTF-16のワイド文字列の定義に使います。windowsクレートではPCWSTR構造体を返し、windows-sysクレートではu16の配列のポインタを返します。

Macro windows::w  

macro_rules! w {  
    ($s:literal) => { ... };  
}  

nullターミネートというのは文字列の末尾に0が番兵として配置されている状態を言います。
C言語などでは文字列を表現するために文字列の末尾にナル文字(\0)を配置します。
このナル文字は数値で言うと0になります。
Windows APIはC言語由来のものなのでこのように文字列にもナル文字が必要です。

コマンドプロンプトでCargo.tomlがあるフォルダに移動して以下のコマンドを実行します。

> cargo run  
   Compiling hello_world v0.1.0 (C:\src\windows-rs-hello-world\hello_world)  
    Finished dev [unoptimized + debuginfo] target(s) in 0.43s  
     Running `target\debug\hello_world.exe`  

すると以下のようなメッセージボックスが表示されると思います。