【C++/Win32】Win32 を極めるための極意

C++
この記事は約6分で読めます。

WinUI3(Windows App SDK) に期待していたんですが、Windows 11 のメモ帳をみると、どうも僕が作りたいものと違ったので C++/Win32 でテキストエディタを作成を再開しました。その際に得た気付きやポイントをまとめたものです。知らないと私のように何回も作り直すことになるので記録しています。

Win32 の UI はほんと古いですが、やっぱり、軽量で高速なのは何ものにも代え難いですね。無くならないことを祈るばかりですね。

ダイアログ系

DPI 変更時に自動的にサイズ変更してくれるのか?

対応しています。ただし、ダイアログが親ウィンドウになっているコントロールのみ DPI が変更されると、フォントサイズに応じたウィンドウサイズに変更されます。ダイアログではなく、何かのウィンドウの子ウィンドウになっていると、残念ながら手動でサイズ変更する必要があります。

ダイアログのサイズはダイアログ単位(DLU)です。ダイアログ単位とはフォントサイズをベースにウィンドウやコントロールのサイズが決まります。

ダイアログの標準フォントは何なのか?

Tahoma です。ダイアログの設定でシステムフォントを使用するを選択すると MS Shell Dlg が選択されますが内部では Tahoma が利用されます。

タブキーで子コントロールにフォーカス移動するには?

C# のパネルコントロールのような例えばスタティックコントロールを親にしてテキストボックスなどを配置すると、WS_TABSTOP が設定されていてもタブキーでテキストボックスにフォーカス移動しません。フォーカス移動させるには、CreateWindowEx の dwExStyle に WS_EX_CONTROLPARENT を設定するとフォーカス移動するようになります。

ダイアログに独自クラスを適用することはできるのか?

下記で可能です。これでダイアログでも通常ウィンドウで発生するメッセージ(例:WM_NCCALCSIZEなど)も処理できるようになります。

  • 独自クラス作成時の WNDCLASSEXW の cbWndExtra に DLGWINDOWEXTRA を設定する
  • リソースエディタでダイアログのクラス名に独自クラス名を設定する
  • ダイアログのデフォルトプロシージャは DefDlgProc に渡す

詳細は下記を参照してください。

コントロール系

文字色や背景色の設定で親ウィンドウにメッセージが送られるコントロールは?

下記コントロールは文字色や背景色の設定時に親ウィンドウにメッセージが送信されます。

  • WM_CTLCOLORBTN:ボタン
  • WM_CTLCOLOREDIT:エディットコントロール
  • WM_CTLCOLORLISTBOX:リスト ボックス
  • WM_CTLCOLORSTATIC:静的コントロール

スタティック(静的)コントロールでキー入力を受け付けるコントロールは作成できるのか?

可能です。スタティックコントロールにキー入力処理を追加しようとしても、実際にキーを入力するするとキンキンとビープ音が鳴ります。スタティックコントロールはキー入力を受け付けていないからですね。下記のようにスタティックコントロールの WM_GETDLGCODE で例えば DLGC_WANTALLKEYS(すべてのキーボード入力) を返すとキー入力してもビープ音が鳴らなくなります。

LRESULT StaticClass::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_GETDLGCODE: return DLGC_WANTALLKEYS;
    }
    return ::DefSubclassProc(hWnd, message, wParam, lParam);
}

その他の戻り値は下記を参照してください。

スタティック(静的)コントロールのスクロールバーは利用できるのか?

利用できます。初期の状態ではスタティックコントロールにスクロールバーを表示しても、サム(つまみ)をドラッグすることができません。ドラッグできるようにするには、いくつかのウィンドウメッセージを DefSubclassProc ではなく、DefWindowProc に渡す必要があります。下記はその例です。これでスクロールバーが有効になります。

LRESULT StaticClass::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_NCHITTEST:              return ::DefWindowProc(hWnd, message, wParam, lParam);
        case WM_NCLBUTTONDOWN:          return ::DefWindowProc(hWnd, message, wParam, lParam);
        case WM_NCLBUTTONUP:            return ::DefWindowProc(hWnd, message, wParam, lParam);
    }
    return ::DefSubclassProc(hWnd, message, wParam, lParam);
}

詳細は下記を参照してください。

スクロールバーコントロールの設定値の制限は?

SetScrollInfo で SCROLLINFO 構造体に設定する際の制限です。スクロールバーを自作する時に役に立ちます。

ページサイズ(nPage)の制限

nPage に設定可能な値です。例えば、最小が 0 で最大が 100 なら、nPage に設定可能な最大値は 101 です。

0 から nMaxnMin + 1

スクロールボックスの位置(nPos)の制限

nPos に設定可能な値です。nMax が最大ではない点に注意です。例えば、最小が 0 で最大が 100 でページサイズが 10なら、nPos に設定可能な最大値は 91 です。

nMin から nMax – max(nPage – 1, 0)

詳細は下記を参照してください。

コメント

タイトルとURLをコピーしました