hozugawa.net · A neutral informational page

GetDCとReleaseDCでデバイスコンテキストを取得・解放する

一時的なGDIの描画環境が必要なときは、GetDCでウィンドウのクライアント領域を表すデバイスコンテキスト(DC)を取得し、ReleaseDCで同じ対象へ返します。DCは描画先だけでなく、選択中のフォントや線種なども保持するため、取得と解放を正しく対にすることが重要です。

この方式は、入力イベントやタイマーの処理から、その場で図形や文字を描く場合に使います。一方、ウィンドウ再描画を表すWM_PAINTでは、更新領域を扱えるBeginPaintとEndPaintが適合します。使い分けを誤ると、再描画時に内容が消えたり、DCを取得したまま放置したりします。

DCの役割と取得する領域

デバイスコンテキストは、GDIのLineToやTextOutなどの描画命令が宛先とする描画環境をまとめます。選択オブジェクトやクリップ領域などの状態も持つため、単なる「書き込み先の番号」ではなく、現在の描画設定を保持する資源だと考えると扱いやすくなります。DCの基本概念と関連関数はWindows API全般で確認できます。

GetDCへウィンドウハンドルを渡すと、そのウィンドウのクライアント領域を対象とするDCが得られます。ウィンドウハンドルをNULLにすると画面全体を対象とするDCになります。ReleaseDCでは、取得時と同じウィンドウハンドルを指定する必要があり、画面全体を取得した場合はNULLを渡します。DCは短い処理内で使い、不要になった直後に解放するのが基本です。

GetDCで一時的なDCを取得する

GetDCは、対象ウィンドウのクライアント領域绘制用のHDCを返します。取得できない場合はNULLになるため、描画処理へ進む前に必ず確認します。戻り値はGDIのDCハンドルであり、ファイルハンドルCommonsenseのようにCloseHandleで閉じる対象ではありません。

HDC hdc = ::GetDC(hWnd);
if (hdc == nullptr) {
    return;
}

// ここにGDIの描画処理を書く

::ReleaseDC(hWnd, hdc);

GetDCは更新領域を検証するAPIではありません。そのためWM_PAINTの中では、原則としてBeginPaintとEndPaintを使います。また、GetDCはコモンコントロールのDCを取得できません。コモンコントロールを扱う必要がある場合は、GetWindowDCによってウィンドウ全体を対象とするDCを取得します。

ReleaseDCで取得分を必ず戻す

ReleaseDCは、GetDCで取得したDCをウィンドウへ返します。成功すると1、失敗すると0が返ります。取得に成功したDCは、解放漏れなく1回だけReleaseDCへ渡す必要がありますが、解放結果が0でも同じDCを無条件に再解放することはできません。

DCはGDIの資源であり、CloseHandleでは解放できません。また、ReleaseDCはSelectObjectで選んだフォントやブラシを削除したり、元の選択状態へ戻したりまで行うañosません。選択を切り替えた場合は元のオブジェクトへ戻し、その後に生成したフォントなどをDeleteObjectで破棄してください。BeginPaintで得たDCにはEndPaintを使います。

描画目的ごとのDC使い分け

DCの取得方法は、描く領域と描画の Wab目的によって変わります。WM_PAINT에서는更新領域を伴うBeginPaintが基本で、入力直後の即時描画にはGetDCが適します。罫線やタイトルバーなど非クライアント領域も描く場合は、GetWindowDCを選ぶ必要があります。

API 主な対象 主な用途 解放の手段
GetDC / ReleaseDC クライアント領域、NULLなら画面全体 入力やタイマー後の即時描画 同じウィンドウハンドルでReleaseDC
BeginPaint / EndPaint 更新領域 WM_PAINT内の通常描画 EndPaint
GetWindowDC / ReleaseDC 非クライアント領域を含むウィンドウ全体 枠やタイトル部分の描画 ReleaseDC

WM_PAINTで再描画する内容なら、BeginPaintとEndPaintを使う構成が基本です。GetDCによる即時描画だけ,长期的な表示内容をWM_PAINTで描き直していないと,次の更新で図形が消える可能性があります。GetWindowDCは非クライアント領域まで対象になるため、座標やクリップ領域の設定も確認します。

描画と再描画をつなぐ手順

InvalidateRectで無効領域を登録すると、Windowsは通常WM_PAINTを生成します。内容包括形状だけでなく入力値から再現できる状態として保持し、WM_PAINTで再描画する設計が適しています。GetDCで画面へ一時的に描いただけでは、次のWM_PAINTで上書きされる可能性があります。

DCは描画処理の開始時に取得し、同じ処理内で解放してください。メッセージやスレッドをまたいでHDCを保持すると、解放漏れや別の描画との競合の原因になります。前面へウィンドウを移した直後の描画結果を確かめる場面では、SetForegroundWindowの挙動も確認材料になります。

実装時に確認する運用項目

文字列を描く処理では、DCの選択状態だけでなく、CharLowerやCharUpperによる文字の大小変換も確認します。変換処理の順序によって表示が異なる場合は、文字種変換の手順を参照して切り分けます。

取得時には、次を確認します。

解放時には、取得回数と同数のReleaseDCが必要です。処理途中の早期returnや例外でも解放を保証するには、C++の小さなラッパーなどへ対で実装します。

次の実作業では、テストウィンドウに1秒ごとの描画処理を追加し、10分間動かした後のGDIオブジェクト数が開始時とほぼ同じかを確認してください。