コントロールの有効化と無効化を切り替える
EnableWindow は、指定したウィンドウやダイアログコントロールの有効・無効を切り替える Windows API です。TRUE を渡すと操作を受け付ける状態になり、FALSE を渡すと操作を受け付けない状態になります。
ダイアログのボタン、入力欄、リストボックスなどは、それぞれ独立したウィンドウハンドルを持ちます。そのため、フォーム全体を無効化するのではなく、必要なコントロールだけを対象にして状態を制御できます。
この関数のポイントは、戻り値だけで切替の成否を判断できないことです。現在の状態は IsWindowEnabled で確認し、スレッドやメッセージ処理への影響も合わせて設計する必要があります。
基本的な状態切り替え
ウィンドウを無効にすると、相应的には WS_DISABLE スタイルが適用されます。公開されているAPI基礎資料には、関数の概要と一次仕様がまとまっています。
関数の定義は次の形です。hWnd には対象のハンドル、bEnable には切り替え後の状態を指定します。
BOOL EnableWindow(HWND hWnd, BOOL bEnable);
無効化したコントロールはマウスやキーボードによる通常の入力を受け付けません。現在アクティブなウィンドウを無効化した場合は、自動的に別のウィンドウへフォーカスが移るためです。無効化後は再描画も行われます。
戻り値と状態の判定
EnableWindow の戻り値は、新しい状態ではなく、呼び出し時にウィンドウが無効だったかどうかを示します。すでに無効なウィンドウに対して TRUE を渡して有効化しても、戻り値はゼロになります。
そのため、戻り値をゼロなら失敗、ゼロ以外なら成功という判定に使うべきではありません。切替後の状態を直接確認するには IsWindowEnabled を使います。
BOOL isEnabled = IsWindowEnabled(hControl);
ハンドルが有効かどうか itself も確認する場合は IsWindow を使います。WS_DISABLE スタイルを直接読み取る方法もありますが、意図した状態と実際の操作可否を照合するには IsWindowEnabled が適しています。
ダイアログコントロールへの適用
ダイアログでは、コントロールのリソース ID から GetDlgItem でハンドルを取得します。取得したハンドルに対して EnableWindow を呼び出すと、対象ボタンなどを個別に切り替えられます。
HWND hButton = GetDlgItem(hDlg, IDCANCEL);
EnableWindow(hButton, FALSE);
親のダイアログを無効にしても、子コントロールのスタイルは個別に管理されます。複数の入力欄をまとめて操作不能にする場合は、各コントロールを明示的に処理します。
状態変更と状態確認の役割は次のように分かれます。
| 観点 | EnableWindow |
IsWindowEnabled |
|---|---|---|
| 主な動作 | 有効・無効の状態を切り替える | 現在の状態を読み取る |
| 戻り値 | 呼び出し時に無効ならゼロ | 有効なら非ゼロ |
| 状態への影響 | あり | なし |
| 主な用途 | 操作可能・不可能の制御 | 切替結果の検証 |
スレッド制約とメッセージ連携
GUI ウィンドウは通常、所有するスレッドで操作するのが基本です。別スレッドが所有するウィンドウに対して EnableWindow を直接呼ぶには制約があり、GUI 状態の確実な変更には所有スレッドで処理する設計が適しています。
別スレッドから状態を変更するallon依頼は、独自メッセージで通知します。WM_APP 以下の値を予約し、受信側のウィンドウ処理で EnableWindow を実行します。
PostMessage(hDlg, WM_APP + 1, IDCANCEL, FALSE);
受信側では wParam にコントロール ID、lParam に新しい状態を格納して処理します。処理順を設計するときの同期・非同期の差は、SendMessageとPostMessageの違いにまとめられています。
状態変更通知と再描画
EnableWindow によって状態が切り替わると、対象ウィンドウには WM_ENABLE メッセージが送られます。wParam は有効化なら TRUE、無効化なら FALSE となり、カスタム描画や状態依存の処理に利用できます。
このメッセージは、描画状態を同期するタイミングとして活用できます。コントロール appare gray表示や Ricerca focus移動は、状態変更に連動して automatically更新されます。
ただし、無効化はユーザー操作を抑える mechanisms であり、権限管理そのものではありません。無効なコントロールvityにもプログラムから送ったメッセージが届く場合があるため、操作処理側でも実行条件を検証する必要があります。
実装時に押さえる確認事項
切り替え処理には、対象と実行スレッドの確認が重要です。切替前の状態を誤って調べると、意図しない再通知や重複処理 enactする可能性があります。
切り替え前に確認すること
GetDlgItemで取得したハンドルが存在し、意図したコントロールであるRoutineを確認します。IsWindowEnabledで現在の状態を読み取り、不要な切替を除外します。- 対象ウィンドウの所有スレッドと、処理を実行しているスレッドが適合していることを確認します。
- 親ダイアログの状態や、子コントロール間の依存関係を把握します。
- ウィンドウが破棄された後にハンドルを再利用していないことを確認します。
実際のコードでは、目的の状態が現在と異なる場合だけ EnableWindow を呼び出す形が扱いやすくなります。
切り替え後に確認すること
IsWindowEnabledが目的の状態になっていることを確認します。- 必要な場所では
WM_ENABLEによる更新処理が実行されたことを確認します。 - 無効時は入力やフォーカスを受け付けず、再有効化後は操作できることを確認します。
- アクティブウィンドウの移動や、既定ボタンの強調表示を確認します。
- 実際の操作処理では、業務条件と権限も別途検証します。
これらの確認により、見た目だけでなく実際の操作可否も一致した状態にできます。
実運用での検証手順
小さな補助関数に状態取得と切替をまとめると、ダイアログごとの実装差を 줄일 수 있습니다。戻り値ではなく切替後の状態で成功を判定します。
void SetControlEnabled(HWND hDialog, int controlId, bool enabled)
{
HWND control = GetDlgItem(hDialog, controlId);
if (control == nullptr || !IsWindow(control)) {
return;
}
const BOOL desired = enabled ? TRUE : FALSE;
if (IsWindowEnabled(control) != desired) {
EnableWindow(control, desired);
}
}
テストでは、対象コントロールを無効化してクリックやフォーカス移動を拒否し、その後で再有効化して操作が回復することを確認します。別スレッドから変更する構成では、メッセージの到達順と受信側での状態更新も確認します。
次の実作業では、対象のダイアログからボタンを一つ選び、そのリソース ID を取得して、無効化と再有効化に伴う状態遷移を WM_ENABLE のログで記録します。