ユーニックス総合研究所

  • home
  • archives
  • windows-rs-font-size

フォントのサイズの変更 - Rustで作るWindowsアプリ

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

フォントのサイズの変更

ラベルなどの静的コントロールのフォントのサイズを変更するには以下の手順で行います。

  • SendMessageW関数でウィンドウからフォントを取得する
  • GetObjectW関数でフォントのロジカル情報を取得する
  • CreateFontIndirectW関数で新しいフォントを作成する
  • SendMessageW関数でウィンドウに新しいフォントを設定する

ウィンドウというのはハンドルのことでラベルの場合はラベルのハンドルがそうです。実際のフォントのサイズの変更にはフォントのロジカル情報を取得する必要があり、これにはGetObjectW関数を使います。フォントサイズを変更したらそのロジカル情報をもとに新しいフォントをCreateFontIndirectW関数で作成し、それをウィンドウにセットします。

WM_CREATEの編集

    // ウィンドウの作成時に呼ばれる  
    WM_CREATE => {  
        // ラベルの作成  
        HWND_LABEL = CreateWindowExW(  
            WINDOW_EX_STYLE::default(),  
            w!("STATIC"), // ラベルのウィンドウクラス名  
            w!("0回描画されました。"), // ラベルに表示するテキスト  
            WS_VISIBLE | WS_CHILD, // スタイル  
            50, 50, // XおよびY座標  
            400, 48, // 幅および高さ  
            window, // 親ウィンドウのハンドル  
            None, // メニューハンドル(使用しない)  
            None, // インスタンスハンドル  
            None // 追加のアプリケーションデータ  
        );  

        // フォントの取得  
        let lresult: LRESULT = SendMessageW(  
            HWND_LABEL, WM_GETFONT,  
            WPARAM::default(), LPARAM::default()  
        );  

        // フォントのロジカル情報の取得  
        let mut lf: LOGFONTW = LOGFONTW::default();  
        GetObjectW(  
            HGDIOBJ(lresult.0),  
            std::mem::size_of::<LOGFONTW>() as i32,  
            Some(&mut lf as *mut LOGFONTW as *mut std::os::raw::c_void),  
        );  
        lf.lfHeight = 48;  // フォントサイズの変更  

        // 新しいフォントの作成  
        let h_new_font = CreateFontIndirectW(&lf);  

        // 新しいフォントをウィンドウに設定  
        SendMessageW(  
            HWND_LABEL, WM_SETFONT,  
            WPARAM(h_new_font.0 as usize), LPARAM::default()  
        );  

        LRESULT(0)  
    }  

フォントのサイズの設定はウィンドウの作成時に行えばいいので、ここではWM_CREATEを編集します。ラベルの大きさもフォントのサイズに合わせて変更していますので注意してください。
注目してほしいのはGetObjectW関数です。この関数はRustではかなりunsafeなコードを書かないと実行できません。第3引数にポインタを指定するのですが、このポインタへの変更にいくらかキャストが必要です。もっとも、unsafeと言ってもC言語などではごくごく一般的なコードになります。あくまでRustのメモリ安全のレベルから言うとunsafeなだけで古のC言語使いはこういったコードをずっと書いてきたはずです。
std::os::raw::c_voidはC言語で言うとvoid型に当たります。voidとは「何もない」ことを表すC言語の型です。C言語では型の抽象化の際にこのvoid型を使うことがあります。特にvoid型のポインタは何にでもキャストできるいわゆる「何でもあり」なポインタです。言語の安全機能の外にあるポインタなので扱いには注意が必要となります。
GetObjectW関数では第2引数に第3引数のサイズを渡しています。このサイズが適当じゃないとメモリの読み書きに「こっそり」失敗することもあるので注意が必要です。

SendMessageW関数

pub unsafe fn SendMessageW<P0, P1, P2>(  
    hwnd: P0,  // ウィンドウへのハンドル  
    msg: u32,  // 送信するメッセージ  
    wparam: P1,  // 追加のメッセージの情報  
    lparam: P2  // 追加のメッセージの情報  
) -> LRESULT  
where  
    P0: IntoParam<HWND>,  
    P1: IntoParam<WPARAM>,  
    P2: IntoParam<LPARAM>,  

指定したウィンドウに指定のメッセージを送信します。この関数はウィンドウのウィンドウ プロシージャを呼び出して処理させます。
第1引数のhwndHWND_BROADCASTである時、メッセージはシステム内のすべての最上位ウィンドウに送信されます。この時、メッセージは子ウィンドウには送信されません。

msgに指定できるメッセージですがフォントの取り扱いでは以下のメッセージを使用します。

  • WM_GETFONT ... コントロールが描画しているフォントの取得
  • WM_SETFONT ... コントロールに描画用のフォントを設定

返り値はメッセージによって変わりますが、WM_GETFONTを指定した場合はHFONTと互換性のある値になります。WM_SETFONTの場合は返り値を返しません。

LOGFONTW構造体

Struct windows::Win32::Graphics::Gdi::LOGFONTW  

#[repr(C)]  
pub struct LOGFONTW {  
    pub lfHeight: i32, // フォントの文字の高さ  
    pub lfWidth: i32,  // フォントの文字の平均幅  
    pub lfEscapement: i32,  // 文字送りの方向とx軸との角度  
    pub lfOrientation: i32,  // ベースラインとx軸との角度  
    pub lfWeight: i32,  // 0 ~ 1000の範囲のフォントの太さ  
    pub lfItalic: u8,  // TRUEの場合は斜体フォント  
    pub lfUnderline: u8,  // TRUEの場合は下線付きフォント  
    pub lfStrikeOut: u8,  // TRUEの場合は取り消し線フォント  
    pub lfCharSet: FONT_CHARSET,  // 文字セット  
    pub lfOutPrecision: FONT_OUTPUT_PRECISION,  // 出力精度  
    pub lfClipPrecision: FONT_CLIP_PRECISION,  // クリッピングの精度  
    pub lfQuality: FONT_QUALITY,  // 出力品質  
    pub lfPitchAndFamily: u8,  // フォントのピッチとファミリ  
    pub lfFaceName: [u16; 32],  // null終端されたフォントのタイプフェイス名  
}  

LOGFONTWはフォントの属性の定義の構造体です。上記の属性に値を指定することでフォントの属性を変更できます。フォントのサイズの変更では上記のlfHeightlfWidthなどを設定します。

GetObjectW関数

Function windows::Win32::Graphics::Gdi::GetObjectW  

pub unsafe fn GetObjectW<P0>(  
    h: P0,  // ハンドル  
    c: i32,  // pvのデータサイズ  
    pv: Option<*mut c_void>  // 保存先のポインタ  
) -> i32  
where  
    P0: IntoParam<HGDIOBJ>,  

この関数は指定したグラフィックス オブジェクトの情報を取得します。
返り値はpvに格納されたバッファーのバイト数です。pvがNoneの場合はバッファーに格納するために必要なバイト数を返します。関数が失敗したら0を返します。

std::mem::size_of関数

Function std::mem::size_of  

pub const fn size_of<T>() -> usize  

std::mem::size_of関数はTのバイト数を返します。この関数はC言語で言うところのsizeof演算子に当たります。

CreateFontIndirectW関数

Function windows::Win32::Graphics::Gdi::CreateFontIndirectW  

pub unsafe fn CreateFontIndirectW(  
    lplf: *const LOGFONTW  // フォントの属性情報  
) -> HFONT  

この関数は指定されたフォントの属性情報でフォントを作成します。作成したフォントはデバイス コンテキストなどで使うことができます。
返り値は作成したフォントへのハンドルです。関数が失敗した場合はHFONTis_invalidメソッドがtrueになります。

HFONT構造体

Struct windows::Win32::Graphics::Gdi::HFONT  

#[repr(transparent)]  
pub struct HFONT(pub isize);  

HFONTはフォントのハンドルでisizeのラッパーのタプル構造体です。
この型はC言語のコードで言うと

typedef HANDLE HFONT;  

になっており、HANDLE型のエイリアスです。