hozugawa.net · A neutral informational page

GetDlgItemとSetDlgItemTextでダイアログコントロールを操作する

Windows APIでダイアログ画面を作ると、入力欄やラベル、ボタンなどの子ウィンドウを識別して操作する場面が多くなります。GetDlgItemはダイアログ内のコントロールからウィンドウハンドルを取得し、SetDlgItemTextは指定したコントロールへ文字列を設定するための基本的な関数です。

この2つの関数は、ダイアログプロシージャの初期化処理やボタン押下時の処理で特に役立ちます。リソースエディターで割り当てたコントロールIDを正しく使い、Unicode、戻り値、メッセージ処理を意識すると、安定した画面操作を実装できます。

ダイアログコントロールを識別する仕組み

ダイアログ上のエディットコントロールやスタティックコントロールは、それぞれ数値のコントロールIDを持っています。リソースファイルで定義した IDC_EDIT_NAME などの識別子を使うと、コード内でコントロールを明確に指定できます。

GetDlgItemの宣言は次のとおりです。

HWND GetDlgItem(
    HWND hDlg,
    int  nIDDlgItem
);

第1引数には親ダイアログのハンドル、第2引数には取得したいコントロールのIDを渡します。戻り値は対象コントロールの HWND です。対象が存在しない場合や親ダイアログが正しくない場合は NULL になるため、取得後にハンドルを検査すると原因を切り分けやすくなります。

実装前に確認する項目

ダイアログプロシージャでは、WM_INITDIALOG の段階で子コントロールが作成済みになっています。そのため、初期表示値を設定する処理はこのメッセージ内に置くのが一般的です。

SetDlgItemTextで表示文字列を設定する

SetDlgItemTextは、ダイアログのコントロールへ文字列を設定します。内部的には指定されたIDの子ウィンドウを探し、そのコントロールに対してテキスト設定処理を行います。

BOOL SetDlgItemTextW(
    HWND    hDlg,
    int     nIDDlgItem,
    LPCWSTR lpString
);

Unicode版では SetDlgItemTextW、ANSI版では SetDlgItemTextA を使用します。プロジェクトをUnicode設定で作成しているなら、std::wstring の c_str() やワイド文字列リテラルを渡す形が安全です。

INT_PTR CALLBACK DialogProc(
    HWND hDlg,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch (message) {
    case WM_INITDIALOG:
        SetDlgItemTextW(hDlg, IDC_STATIC_STATUS, L"準備が完了しました");
        SetDlgItemTextW(hDlg, IDC_EDIT_NAME, L"既定値");
        return TRUE;
    }
    return FALSE;
}

設定に成功すると戻り値はゼロ以外になり、失敗するとゼロになります。指定IDが間違っている場合や、対象コントロールが見つからない場合に失敗するため、重要な初期値や状態表示では戻り値を確認しておくとよいでしょう。

エディットコントロールの取得と更新

コントロールのウィンドウハンドルを直接扱いたい場合は、GetDlgItemの結果を利用します。たとえば、入力欄の有効・無効を切り替える処理は EnableWindow と組み合わせて実装できます。

HWND hEdit = GetDlgItem(hDlg, IDC_EDIT_NAME);
if (hEdit != NULL) {
    EnableWindow(hEdit, TRUE);
    SetFocus(hEdit);
}

単純に文字列を設定するだけなら、GetDlgItemを明示的に呼ばず、SetDlgItemTextW(hDlg, ID, text)を使えます。一方、文字列の取得、選択範囲の変更、フォント変更など、コントロール固有の操作が必要な場合は、取得した HWND に対してメッセージや関連APIを送ります。

入力内容を読み出すときは GetDlgItemText が対応します。設定と取得を一対として考えると、画面の状態をモデルや設定値へ反映しやすくなります。長い文字列では固定長バッファーのサイズ計算や終端文字の扱いにも注意が必要です。

文字列操作で検証する項目

SetDlgItemTextは文字列を設定するAPIであり、画面の再描画を個別に呼び出す必要は通常ありません。設定後に表示が更新されない場合は、対象ID、親ダイアログのハンドル、別の処理による上書きを確認します。

メッセージ処理で状態を同期する

ボタンが押されたことは、通常 WM_COMMAND で通知されます。通知元のコントロールIDを LOWORD(wParam) から取り出し、対象ボタンに応じた処理を分岐します。

case WM_COMMAND:
    switch (LOWORD(wParam)) {
    case IDOK:
        SetDlgItemTextW(hDlg, IDC_STATIC_STATUS, L"入力を受け付けました");
        return TRUE;

    case IDCANCEL:
        EndDialog(hDlg, IDCANCEL);
        return TRUE;
    }
    break;

エディットコントロールの内容を変更したときは、EN_CHANGE などの通知コードが HIWORD(wParam) に入る場合があります。LOWORD だけで判断すると、同じIDを持つ通知の種類を区別できないため、必要に応じて両方を確認します。

モーダルダイアログでは DialogBox の呼び出し元と EndDialog の関係を把握し、モードレスダイアログでは DestroyWindow やメッセージループとの関係を整理します。コントロール操作の不具合に見えても、実際にはダイアログの寿命が終わった後にハンドルを使っているケースがあります。

APIの使い分けとデバッグの要点

SetDlgItemTextはダイアログとコントロールIDを直接指定できるため、短い処理に向いています。複数のプロパティを変更する、通知メッセージを送る、サブクラス化したコントロールを扱うといった場合は、GetDlgItemで HWND を得てから専用APIを呼ぶ構成が適しています。

目的 主に使うAPI 確認する値
コントロールを取得する GetDlgItem 戻り値のHWND
文字列を設定する SetDlgItemTextW BOOLの成否
文字列を取得する GetDlgItemTextW 取得文字数
有効・無効を変更する EnableWindow BOOLの成否
フォーカスを移動する SetFocus 返された以前のフォーカス

不具合調査では、まず GetDlgItem の戻り値が有効か、IDがリソース定義と一致しているかを確認します。次に、WM_INITDIALOG や WM_COMMAND が実際に呼ばれているかをデバッガーで追跡します。文字化けが発生した場合は、APIのA/W版、ソースファイルの文字コード、プロジェクトの文字セット設定を順番に点検します。

基本形を小さなダイアログで確認すると、複雑な画面へ組み込む前に問題を発見できます。まず WM_INITDIALOG で IDC_EDIT_NAME に L"テスト" を設定し、WM_COMMAND の IDOK 処理で IDC_STATIC_STATUS の表示を更新するコードを実行してください。