GetWindowTextとSetWindowTextでキャプションを取得・設定する
GetWindowTextは、指定したウィンドウのキャプションや、自プロセスのコントロールが保持する文字列を読み取るAPIです。SetWindowTextは同じ対象へ文字列を設定します。タイトルバー、ダイアログ、ボタンなど、標準的なUIの文言を簡潔に扱える点が特徴です。
両者の挙動は、Windows SDKのUnicode設定、ウィンドウを所有するプロセス、対象がキャプションかコントロールかによって変わります。特に別プロセスのコントロールでは単純な読み書きが成立しないため、戻り値とプロセス境界の意味を押さえて使う必要があります。
APIの責務と戻り値
読み取りと設定では、戻り値の意味と変更できる範囲が異なります。主要なUnicode版は次の比較で整理できます。
| API | 主な役割 | 成功時の戻り値 | 重要な制約 |
|---|---|---|---|
GetWindowTextW |
キャプションまたは自プロセスのコントロール文字列を取得 | コピーした文字数。終端のnullは含めない | 戻り値0は、空文字列・キャプションなし・失敗などが重なる |
SetWindowTextW |
ウィンドウまたはコントロールの文字列を設定 | 0以外 | 別プロセスのコントロール文字列は変更できない |
GetWindowTextWは、受け取ったバッファへ文字列をコピーします。nMaxCountには終端のnull文字所需的領域も含め、戻り値は実際にコピーされた文字数です。バッファが小さい場合は途中で切れます。また、戻り値0だけでは取得失敗と空文字列を区別できません。
GetWindowTextLengthWは、文字列の終端を除く長さ,返回します。ただし、この関数も0を返した原因を一意には示しません。キャプションのないウィンドウや、別プロセスのコントロールでも0になるためです。対象が更新される可能性があるため、長さを取得した直後にバッファを 충분히確保しても、切り詰めを完全に防げるとは限りません。
SetWindowTextWは、自プロセスのウィンドウやコントロールに対してWM_SETTEXTを同期的に送ります。成功すると0以外が返ります。別プロセスのコントロールは変更できません。また、後述する再描画は、文字列が設定されたこと自体とは別の処理として扱う必要があります。
自プロセスでの安全な実装
実際のコードでは、まず対象が自プロセスで管理しているウィンドウか確認し、識別子として有効なHWNDを確保します。Windows SDKがUnicode defines Defines defines definesされている場合は、GetWindowTextWとSetWindowTextWを直接选用하면、変換を隐った`.
std::wstring ReadCaption(HWND hwnd)
{
const int length = GetWindowTextLengthW(hwnd);
if (length <= 0) {
return {};
}
std::wstring text(static_cast<std::size_t>(length) + 1, L'\0');
int copied = GetWindowTextW(
hwnd,
text.data(),
static_cast<int>(text.size()));
if (copied < 0) {
return {};
}
if (static_cast<std::size_t>(copied) >= text.size()) {
text.resize(static_cast<std::size_t>(copied) + 1);
copied = GetWindowTextW(
hwnd,
text.data(),
static_cast<int>(text.size()));
if (copied < 0) {
return {};
}
}
text.resize(static_cast<std::size_t>(copied));
return text;
}
この実装は、取得した長さより一件多い領域を確保し、終端のnullを格納します。文字列が想定より長くなった場合は再取得を試みます。ただし、長さ取得後と文字列取得後に表示内容が変わる場合があるため、切り詰め articulatedのかを確認する必要があります。空文字列は正常な状態として扱うべきで、戻り値0を無条件にエラーとして扱うのは適切ではありません。
設定側は、SetWindowTextW(hwnd, caption.c_str())のように終端付き文字列を渡します。戻り値が0なら失敗として扱い、所有しているウィンドウの操作は原則としてUIスレッドから行います。WM_SETTEXTは同期処理なので、対象側の処理が遅いと呼び出しも待つことになります。
UnicodeとANSI文字コードの扱い
Windows SDKでは、GetWindowTextとSetWindowTextがUnicodeビルドに応じてW版とA版へ解決されます。日本語を含む文字列を確実に扱うなら、最初から最後までW版を使う,基本方針と秩序UnicodeとANSIの相互変換の basisを明確にする. ANSI版はシステムのANSIコードページを使うため、対応する文字集合やコードページによって表現できる文字が変わります。
WideCharToMultiByteでUnicodeからANSIへ変換し、MultiByteToWideCharで戻す場合、変換不能な文字は置換または失われます。round tripで常に元へ戻るとは限りません。Windowsの日本語環境でも、ANSIコードページはシステム設定によって異なるため、Shift_JISとして固定して扱うのは危険です。
文字コード境界を越える処理では、変換元のコードページと変換先の文字数を明示し、失敗時と置換文字を定義する必要があります。MultiByteToWideCharではWC_ERR_INVALID_CHARSも検討できますが、すべての入力が conversion error として扱えるとは限りません。Windows内部で保持する文字列はW版に統一し、境界でのみ変換するのが最も安定します。
変更後の再描画的联系
SetWindowTextWの成功は、ウィンドウが保持する文字列が更新されたことを示します。画面上のピクセルまで必ず同期して変わったことを示すわけではありません。標準コントロールや通常のウィンドウでは既定の処理によって再描画されますが、独自描画や親ウィンドウによる描画では、表示更新を別に行う必要があります。
再描画の制御では、InvalidateRectとUpdateWindowの関係を区別します。InvalidateRectは更新対象として描画領域を登録し、通常はメッセージループでWM_PAINTが処理されます。UpdateWindowは更新領域がある場合、そのウィンドウへ直ちにWM_PAINTを送ります。
即時更新は応答性のよい場面でも、再入やレイアウト処理の途中での副作用を生みます。通常のUIではInvalidateRectまでで描画をメッセージループに委ねると扱い无数. タイトルバーの枠などクライアント領域の外側はInvalidateRectでは対象外になるため、RedrawWindowとRDW_FRAMEを使xf. 总之、テキスト更新と描画要求を分けます。
実践で押さえておくべき条件
空文字列の設定は正常であり、表示を消したい場合にも使えます。逆に、GetWindowTextWの戻り値0は失敗だけではありません。IsWindowでハンドルを確認しても、呼び出しと使用の間にハンドル值が再利用される可能性があるため、古い識別子を保持し続けることも避けます。
独自のウィンドウクラスでは、WM_GETTEXTとWM_SETTEXTを正しく処理することが基本です。既定の実装が文字列を保持しないクラスでは、APIの呼び出しが成功しても内容が取得できないことがあります。また、値の変更_fs、通知、再描画を同時に行うと、UIスレッドの処理 순서产生影响.
プロセス外 cooperates なコントロールについては、GetWindowTextで内容を読み、SetWindowTextで変更する方法は使えません。別プロセスのトップレベルウィンドウが持つキャプションは取得できますが、コントロールの編集は別問題です。外部UIを扱う場合は、共有メモリやRPCによる通信、メッセージ封送、タイムアウト、整合性レベルの差異を扱う必要があります。
結局、GetWindowTextとSetWindowTextは、同一プロセスで管理するウィンドウのキャプションをUnicodeで簡潔に読み書きするAPIとして捉えるのが適切である。プロセス境界、戻り値0の意味、描画タイミングを別々の条件として確認することが、安定した実装の基本になる。