メッセージボックスの型と構造体 - Rustで作るWindowsアプリ
- 作成日: 2023-05-04
- 更新日: 2023-12-24
- カテゴリ: windows-rs
メッセージボックスで使われる型について
先ほどのMessageBoxW()
の関数で見慣れない型がいくつか出てきました。それは以下のようなものです。
- HWND
- PCWSTR
- MESSAGEBOX_STYLE
- MESSAGEBOX_RESULT
Windows APIでは型が高度に抽象化されています。ですのでこのような型がたくさんあるわけです。
windows-rsで定義される文字列の種類
windows-rs
のwindows
クレートには以下のような文字列が準備されています。
- BSTR ... 長さがプレフィックスされたワイド文字列
- HSTRING ... 参照カウントされる不変文字列
- PCSTR ... ナル文字が付加された8ビット定数文字列へのポインタ
- PCWSTR ... ナル文字が付加された16ビット ユニコード定数文字列へのポインタ
- PSTR ... ナル文字が付加された8ビット文字列へのポインタ
- PWSTR ... ナル文字が付加された16ビット ユニコード文字列へのポインタ
この内、メッセージボックスで使用されるPCWSTR
の文字列はポインタをラップしたタプル構造体です。
Struct windows::core::PCWSTR
#[repr(transparent)]
pub struct PCWSTR(pub *const u16);
このPCWSTR
にはfrom_raw
メソッドやas_wide
メソッドなどが定義されています。
HWNDの正体
HWNDはWindows APIではウィンドウ・ハンドルと呼ばれるものになります。ウィンドウを識別するための整数がこのHWNDです。
Windowsのウィンドウにはこのようなハンドルが存在していて、このハンドルを通じてウィンドウを操作することができます。ですのでWindows APIプログラミングではこのHWNDはかなり大事なものになります。
windows-rs
ではHWNDはタプル型構造体として定義されています。
Struct windows::Win32::Foundation::HWND
#[repr(transparent)]
pub struct HWND(pub isize);
このHWND
はisize
のラッパーになっています。isize
はRustのプリミティブ型です。符号付き整数で、32ビットのターゲットでは4バイト、64ビットのターゲットでは8バイトになります。
このHWND
にはclone()
なども実装されています。以下の様なコードでHWND
の動作を確認できます。
[dependencies.windows]
version = "0.48"
features = [
"Win32_Foundation",
]
use windows::{
Win32::Foundation::HWND,
};
fn main() {
let h: HWND = HWND(10);
let hh: HWND = HWND::default();
let hhh: HWND = hh.clone();
println!("{} {} {}", h.0, hh.0, hhh.0);
// 10 0 0
}
MESSAGEBOX_STYLE
MessageBox
の最後の引数がこれですが、これにはメッセージボックスのスタイルを設定します。例えばMB_OK
と指定するとOKボタンが表示されるメッセージボックスが出ます。
MESSAGEBOX_STYLEもタプル型構造体として定義されています。
Struct windows::Win32::UI::WindowsAndMessaging::MESSAGEBOX_STYLE
#[repr(transparent)]
pub struct MESSAGEBOX_STYLE(pub u32);
これはu32
のラッパーでu32
はRustのプリミティブ型で32ビット(4バイト)の符号なし整数です。このタプル型構造体にはビット演算が実装されており、たとえば以下の様に複数の定数をスタイルに指定できます。
[dependencies.windows]
version = "0.48"
features = [
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
]
use windows::{
core::*,
Win32::UI::WindowsAndMessaging::*,
};
fn main() {
unsafe {
MessageBoxW(
None, w!("Hello, World!"), w!("日本から"),
MB_OK | MB_ICONINFORMATION
);
}
}
MESSAGEBOX_STYLE
はビット演算の他にも例えば以下のようなメソッドが実装されています。
impl Default for MESSAGEBOX_STYLE
// デフォルトのスタイルを返す
fn default() -> Self
impl Clone for MESSAGEBOX_STYLE
// スタイルをクローンする
fn clone(&self) -> Self
// selfにsourceをクローンする
fn clone_from(&mut self, source: &Self)
impl Not for MESSAGEBOX_STYLE
// !演算後の結果の型
type Output = MESSAGEBOX_STYLE
// !演算子
fn not(self) -> Self
impl PartialEq<MESSAGEBOX_STYLE> for MESSAGEBOX_STYLE
// ==演算子
fn eq(&self, other: &MESSAGEBOX_STYLE) -> bool
// !=演算子
fn ne(&self, other: &Rhs) -> bool
MESSAGEBOX_STYLE
に使える定数には例えば以下があります。
ボタンに関する定数:
- windows::Win32::UI::WindowsAndMessaging
- MB_OK ... OKボタンの表示(デフォルト)
- MB_OKCANCEL ... OKとキャンセルボタンの表示
- MB_RETRYCANCEL ... 再試行とキャンセルボタンの表示
- MB_YESNO ... はい、いいえボタンの表示
- MB_YESNOCANCEL ... はい、いいえ、キャンセルボタンの表示
アイコンに関する定数(一部):
- windows::Win32::UI::WindowsAndMessaging
- MB_ICONINFORMATION .... 情報アイコンの表示(iが表示される)
- MB_ICONQUESTION ... 疑問符(ハテナマーク)アイコンの表示
- MB_ICONWARNING ... 感嘆符(ビックリマーク)アイコンの表示
- MB_ICONSTOP ... 停止アイコンの表示
- MB_ICONERROR ... 同上
use windows::{
core::*,
Win32::UI::WindowsAndMessaging::*,
};
fn main() {
let def: MESSAGEBOX_STYLE = MESSAGEBOX_STYLE::default();
let ok: MESSAGEBOX_STYLE = MB_OK | MB_ICONINFORMATION;
let not = !ok;
let cloned = ok.clone();
println!("{}", def.0); // 0
println!("{}", ok.0); // 64
println!("{}", not == def); // false
println!("{}", not != def); // true
println!("{}", cloned.0); // 64
unsafe {
MessageBoxW(None, w!("hello"), w!("日本"), MB_OK);
MessageBoxW(None, w!("hello"), w!("日本"), MB_OKCANCEL);
MessageBoxW(None, w!("hello"), w!("日本"), MB_RETRYCANCEL);
MessageBoxW(None, w!("hello"), w!("日本"), MB_YESNO);
MessageBoxW(None, w!("hello"), w!("日本"), MB_YESNOCANCEL);
MessageBoxW(None, w!("hello"), w!("日本"), MB_ICONINFORMATION);
MessageBoxW(None, w!("hello"), w!("日本"), MB_ICONQUESTION);
MessageBoxW(None, w!("hello"), w!("日本"), MB_ICONWARNING);
MessageBoxW(None, w!("hello"), w!("日本"), MB_ICONSTOP);
MessageBoxW(None, w!("hello"), w!("日本"), MB_ICONERROR);
}
}
MESSAGEBOX_RESULT
MESSAGEBOX_RESULTはMessageBoxW()
の返り値です。これは同様にタプル構造体で定義されています。
Struct windows::Win32::UI::WindowsAndMessaging::MESSAGEBOX_RESULT
#[repr(transparent)]
pub struct MESSAGEBOX_RESULT(pub i32);
MESSAGEBOX_RESULT
には以下のようなメソッドが定義されています。
impl Clone for MESSAGEBOX_RESULT
// クローンしてコピーを返す
fn clone(&self) -> Self
// selfにsourceをクローンする
fn clone_from(&mut self, source: &Self)
impl Default for MESSAGEBOX_RESULT
// デフォルト値を返す
fn default() -> Self
impl PartialEq<MESSAGEBOX_RESULT> for MESSAGEBOX_RESULT
// ==演算子
fn eq(&self, other: &MESSAGEBOX_RESULT) -> bool
// !=演算子
fn ne(&self, other: &Rhs) -> bool
MESSAGEBOX_RESULT
はi32
のラッパーですがi32
は符号付きの32ビット(4バイト)整数です。
MESSAGEBOX_RESULT
は以下のいずれかになります。
- windows::Win32::UI::WindowsAndMessaging
- IDOK ... 「OK」ボタンが押された
- IDYES ... 「はい」ボタンが押された
- IDNO ... 「いいえ」ボタンが押された
- IDCANCEL ... 「キャンセル」ボタンが押された
- IDRETRY ... 「再試行」ボタンが押された
- IDABORT ... 「中止」ボタンが押された
- IDIGNORE ... 「無視」ボタンが押された
IDOK
やIDYES
はMESSAGEBOX_RESULT
型になっています。MessageBoxW()
の結果もMESSAGEBOX_RESULT
ですのでこれらは比較演算子(eq, ne)で比較することができます。
use windows::{
core::*,
Win32::UI::WindowsAndMessaging::*
};
fn main() {
unsafe {
let result = MessageBoxW(None, w!("hello"), w!("日本"), MB_OKCANCEL);
println!("{} {} {}", result.0, IDOK.0, IDCANCEL.0); // 1 1 2 (OKを押した場合)
if result == IDOK {
println!("OKが押されました。"); // OK!
} else if result == IDCANCEL {
println!("キャンセルしました。");
}
}
}
上記のコードをcargo run
で実行するとOKボタンとキャンセルボタンのメッセージボックスが出ます。OKを押すと端末に「OKが押されました。」と表示されキャンセルを押すと「キャンセルしました。」と表示されます。