レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API ペイントと描画の概要

ほとんどのアプリケーションは、 扱うデータを画面を使って表示します。アプリケーションは、 イメージをペイントしたり、 図形を描画したり、 テキストを描画して、 ユーザーが作成、 編集、 印刷するデータを見ることができるようにします。Microsoft(R) Windows(TM) には高機能なペイントと描画の環境が用意されていますが、 Windowsはマルチタスク オペレーティング システムであるため、 画面にアクセスするアプリケーションは、 ほかのアプリケーションと協調しなければなりません。

すべてのアプリケーションが問題なく協調して動作できるようにするため、 Windowsは、 画面への出力をすべて管理しています。アプリケーションは、 画面ではなくウィンドウを主な出力デバイスとして使います。Windowsは、 ウィンドウに一意に対応する「ディスプレイ デバイス コンテキスト」(「ディスプレイDC」) を用意しています。アプリケーションは、 ディスプレイDCを使って、 出力を特定のウィンドウに送ります。ウィンドウに描画する (出力を送る) ことによって、 アプリケーションの出力がほかのアプリケーションの出力に干渉するのを防ぐことができ、 Windowsのグラフィック機能をすべて利用する複数のアプリケーションが共存できます。

次に示すトピックでは、 ペイントと描画について説明しています。

ウィンドウに描画する場合

WM_PAINTメッセージ

WM_PAINTメッセージによらない描画

ウィンドウ座標系

ウィンドウのリージョン

ウィンドウ背景

アイコン化ウィンドウ

ウィンドウのサイズ

非クライアント領域

子ウィンドウ

ディスプレイ デバイス コンテキスト

ウィンドウ更新ロック

境界長方形の蓄積

WM_PAINTメッセージの使用

クライアント領域への描画

クライアント領域全体の再描画

更新リージョンでの再描画

クライアント領域の無効化

アイコン化ウィンドウの描画

カスタムのウィンドウ背景の描画

GetDC関数の使用

マウスによる描画

周期的な描画

関数とメッセージ

 

 

ウィンドウに描画する場合

アプリケーションは、 さまざまな場合にウィンドウに描画します。ウィンドウを最初に作成するとき、 ウィンドウのサイズを変更するとき、 ウィンドウをほかのウィンドウの後ろから移動するとき、 ウィンドウをアイコン化または最大化するとき、 オープンされているファイルのデータを表示するとき、 表示データの一部をスクロール、 変更、 選択するときなどに、 ウィンドウに描画します。

Windowsは、 ウィンドウの移動やサイズ変更などの動作を管理します。このような動作がウィンドウの内容に影響する場合、 Windowsは、 ウィンドウの関連する部分を更新用にマークし、 ウィンドウに対応するウィンドウ プロシージャにWM_PAINTメッセージを送ります。このメッセージは、 アプリケーションが更新の必要な部分を判断し、 必要な描画を実行するためのシグナルです。

オープンされているファイルの表示や表示データの選択などの動作は、 アプリケーションが管理します。このような動作の場合、 アプリケーションは、 動作が影響するウィンドウの部分を更新用にマークしておいて、 次の機会にWM_PAINTメッセージが送られるようにできます。動作にすぐにフィードバックが必要ならば、 アプリケーションは、 WM_PAINTメッセージを待たずに、 動作を実行しているときに描画を実行できます。たとえば、 通常のアプリケーションは、 ユーザーが選択した領域を、 次のWM_PAINTメッセージを待たずに強調表示します。

どの場合でも、 アプリケーションは、 作成したウィンドウにすぐに描画できます。ウィンドウに描画するには、 まず、 ウィンドウのディスプレイDCのハンドルを取得します。理想的には、 アプリケーションはWM_PAINTメッセージを処理するときにほとんどの描画操作を実行します。この場合、 アプリケーションは、 BeginPaint関数を呼び出してディスプレイDCを取得します。WinMain関数や、 キーボード メッセージやマウス メッセージの処理中など、 これ以外の場合に描画するときは、 GetDC関数かGetDCEx関数を使ってディスプレイDCを取得します。

 

 

WM_PAINTメッセージ

通常、 アプリケーションは、 WM_PAINTメッセージを受け取ったときにウィンドウに描画します。ウィンドウへの変更によってクライアント領域の内容が変化すると、 Windowsは、 このメッセージをウィンドウ プロシージャに送ります。Windowsは、 アプリケーションのメッセージ キューにほかのメッセージがないときだけこのメッセージを送ります。

アプリケーションは、 WM_PAINTメッセージを受け取ったら、 BeginPaintを呼び出してクライアント領域のディスプレイDCを取得し、 そのDCを使ってGDI関数を呼び出してクライアント領域の更新に必要な描画操作を実行します。描画操作を完了したら、 EndPaint関数を呼び出して、 ディスプレイDCを解放してください。

Windowsは、 BeginPaintがディスプレイDCを返す前に、 ウィンドウのDCを準備します。特に、 ウィンドウの更新が必要な部分とユーザーに見える部分の交差部分を、 DCのクリッピング リージョンに設定します。変更されたウィンドウのうち、 この部分だけが再描画されます。この領域の外への描画はクリップされ、 画面には表示されません。

また、 Windowsは、 BeginPaintが戻る前に、 WM_NCPAINTメッセージとWM_ERASEBKGNDメッセージをウィンドウ プロシージャに送ります。これらのメッセージは、 非クライアント領域とウィンドウ背景を描画するようにアプリケーションに指示します。「クライアント領域」とは、 ウィンドウのクライアント領域の外側の部分です。この領域には、 タイトル バー、 コントロール メニュー (システム メニュー)、 スクロール バーなどがあります。通常、 アプリケーションは、 デフォルト ウィンドウ プロシージャのDefWindowProcにWM_NCPAINTメッセージを渡して、 非クライアント領域を描画させます。「ウィンドウ背景」とは、 描画操作を開始する前にウィンドウを塗りつぶすときの色やパターンです。背景は、 ウィンドウやその下の画面の以前のイメージを消去します。クラス背景ブラシを持つウィンドウ クラスにウィンドウが属する場合、 DefWindowProc関数は、 ウィンドウ背景を自動的に描画します。

BeginPaintは、 ウィンドウの更新部分の寸法やウィンドウ背景が描画されているかを示すフラグなどの情報をPAINTSTRUCT構造体に設定します。アプリケーションは、 この情報を使って描画を最適化できます。たとえば、 rcPaintメンバが示す更新リージョンの寸法を使って、 描画をウィンドウの更新領域だけに限定できます。アプリケーションの出力が非常に単純ならば、 更新領域を無視してウィンドウ全体に描画し、 不要な出力のクリップをWindowsに任せることができます。システムはクリッピング リージョン外の描画を廃棄 (クリップ) するため、 更新リージョン内の描画だけが表示されます。

BeginPaintは、 ウィンドウの更新リージョンをNULLに設定します。これによって更新リージョンは空になり、 WM_PAINTメッセージはそれ以降生成されなくなります。アプリケーションがWM_PAINTメッセージを処理し、 BeginPaintを呼び出さずにほかの方法で更新リージョンを空にすると、 更新リージョンが空にならない限りWM_PAINTメッセージが送られ続けます。どの場合でも、 アプリケーションは、 WM_PAINTメッセージの処理から戻る前に更新リージョンを空にしなければなりません。

アプリケーションは、 描画を終了したら、 EndPaintを呼び出してください。ほとんどのウィンドウでは、 EndPaintはディスプレイDCを解放して、 ディスプレイDCをほかのウィンドウが利用できるようにします。また、 EndPaintは、 キャレットが以前にBeginPaintで非表示になっていればキャレットを表示します。BeginPaintは、 キャレットを非表示にして、 描画操作とキャレットが干渉しないようにします。

 

更新リージョン

「更新リージョン」は、 ウィンドウの古くなったり無効になった部分や、 再描画が必要な部分を識別します。Windowsは、 更新領域を使って、 アプリケーションに対するWM_PAINTメッセージを生成し、 ウィンドウの内容をアプリケーションが更新するのに必要な時間を最小限にします。Windowsは、 ウィンドウの無効部分だけを更新領域に追加するため、 その部分しか描画する必要はありません。

Windowsは、 更新が必要なウィンドウを調べるとき、 ウィンドウの無効部分の寸法を更新リージョンの寸法に設定します。更新リージョンを設定しても、 アプリケーションがすぐに描画するわけではありません。アプリケーションは、 描画メッセージ以外のメッセージがなくなるまで、 ほかのメッセージをアプリケーション メッセージ キューから取得し続けます。メッセージ キューにほかのメッセージがなくなると、 Windowsは更新リージョンを調べて、 更新リージョンが空 (NULL) でなければ、 WM_PAINTメッセージをウィンドウ プロシージャに送ります。

アプリケーションが更新リージョンを利用するには、 自分でWM_PAINTメッセージを生成します。たとえば、 オープンされているファイルからデータをロードするアプリケーションは、 ロード時に更新リージョンを設定して、 次のWM_PAINTメッセージの処理のときに新しいデータが描画されるようにします。一般に、 データを変更したときに描画せずに、 描画操作はすべてWM_PAINTメッセージを通じて行ってください。

 

更新リージョンの無効化と有効化

ウィンドウの一部を無効化して更新リージョンを設定するには、 InvalidateRect関数かInvalidateRgn関数を使います。これらの関数は、 (クライアント座標系で指定された) 長方形またはリージョンを更新リージョンに追加し、 Windowsやアプリケーションが以前に更新リージョンに追加した長方形やリージョンと組み合わせます。

InvalidateRect関数とInvalidateRgn関数は、 WM_PAINTメッセージを生成しません。Windowsは、 ウィンドウがメッセージ キューのほかのメッセージを処理している間、 これらの関数による変更やWindowsによる変更を蓄積します。変更を蓄積することによって、 ウィンドウ プロシージャは、 更新を細切れに行わずに、 変更部分を一度に処理できます。

ValidateRect関数とValidateRgn関数は、 指定された長方形やリージョンを更新リージョンから削除して、 ウィンドウの一部を有効化します。通常、 これらの関数は、 ウィンドウがWM_PAINTメッセージを受け取る前に更新リージョンの一部を先に更新したときに使われます。

 

更新リージョンの取得

GetUpdateRect関数とGetUpdateRgn関数は、 ウィンドウの現在の更新リージョンを取得します。GetUpdateRectは、 更新リージョン全体を囲む最小の長方形をクライアント座標系で取得します。GetUpdateRgnは、 更新リージョン自体を取得します。更新リージョンの現在のサイズを計算して、 描画操作を実行する部分を判断するには、 これらの関数を使います。

また、 BeginPaintは、 現在の更新リージョンを囲む最小の長方形を取得し、 その寸法をPAINTSTRUCT構造体のrcPaintメンバに設定します。BeginPaintは更新リージョンを有効化するため、 BeginPaintを呼び出した直後にGetUpdateRectGetUpdateRgnを呼び出すと、 空のリージョンが返されます。

 

更新リージョンの除外

ExcludeUpdateRgn関数は、 ディスプレイDCのクリッピング リージョンから更新リージョンを除外します。この関数は、 WM_PAINTメッセージを使わずにウィンドウに描画するときに役立ちます。この関数によって、 次のWM_PAINTメッセージで更新される領域には描画が行われなくなります。

 

同期描画と非同期描画

WM_PAINTメッセージの処理で行われる描画のほとんどは非同期です。つまり、 ウィンドウの一部を無効化してからWM_PAINTメッセージが送られるまでに時間があります。通常、 この間は、 アプリケーションはキューからメッセージを取得して、 ほかの作業を行います。この時間は、 Windowsがウィンドウへの描画を優先順位の低い処理として扱い、 ユーザー入力メッセージやウィンドウの位置とサイズに影響するメッセージをWM_PAINTメッセージより先に処理するために発生します。

アプリケーションは、 同期して描画しなければならない (ウィンドウの一部を無効化した直後にウィンドウに描画する) 場合があります。通常、 アプリケーションは、 ウィンドウを作成した直後に、 アプリケーションが正常に起動したことをユーザーに示すシグナルをメイン ウィンドウに描画します。ボタンなどの一部のコントロール ウィンドウはユーザー入力のフォーカスとして動作するため、 Windowsは、 そのようなコントロールを同期的に描画します。簡単な描画ルーチンを持つウィンドウは同期的に描画してもかまいませんが、 そのような描画はすぐに終わるものでなければならず、 ユーザー入力への応答に影響がないようにしてください。

同期描画を行うには、 UpdateWindow関数やRedrawWindow関数を使います。更新リージョンが空でなければ、 UpdateWindowは、 WM_PAINTメッセージをウィンドウに直接送ります。また、 RedrawWindowもWM_PAINTメッセージを送りますが、 非クライアント領域とウィンドウ背景の描画や更新リージョンが空かどうかにかかわらず描画するかなど、 ウィンドウを描画する方法をアプリケーションがより詳細に制御できます。これらの関数は、 アプリケーションのメッセージ キューにほかのメッセージがあっても、 WM_PAINTメッセージをウィンドウに直接送ります。

ウィンドウの描画時に未処理のメッセージがブロックされないようにするため、 時間のかかる描画操作が必要なウィンドウは非同期的に描画してください。また、 ウィンドウの小さな部分を頻繁に無効化するアプリケーションは、 同期WM_PAINTメッセージを何度も送らずに、 無効部分を1つの非同期WM_PAINTメッセージにまとめてください。

 

 

WM_PAINTメッセージによらない描画

アプリケーションはWM_PAINTメッセージを処理するときにほとんどの描画操作を実行しますが、 WM_PAINTメッセージを使わずにウィンドウに直接描画した方が効率的な場合もあります。たとえば、 テキストの選択やオブジェクトのドラッグやサイズ変更などがその例です。このような場合、 アプリケーションは、 キーボード メッセージやマウス メッセージを処理するときに描画を実行します。

WM_PAINTメッセージを使わずにウィンドウに描画するには、 GetDC関数かGetDCEx関数を使って、 ウィンドウのディスプレイDCを取得します。アプリケーションは、 このディスプレイDCを使って、 ほかのウィンドウに干渉せずにウィンドウに描画できます。アプリケーションは、 描画を終了したら、 ReleaseDC関数を呼び出してディスプレイDCを解放し、 ほかのアプリケーションがディスプレイDCを使えるようにします。

通常、 WM_PAINTメッセージを使わずに描画するときは、 ウィンドウを無効化せずに、 後で簡単に描画内容を取り消してウィンドウを復元できるような方法で描画します。たとえば、 ユーザーがテキストやオブジェクトを選択すると、 アプリケーションは、 ウィンドウにすでにある内容を反転表示して、 選択を描画します。選択を解除してウィンドウの元の内容を復元するには、 もう一度反転表示するだけです。

アプリケーションは、 ウィンドウへの変更を注意深く管理しなければなりません。特に、 アプリケーションが選択を描画して、 その部分に関連するWM_PAINTメッセージが発生した場合、 アプリケーションは、 WM_PAINTメッセージで選択部分が破壊されないように描画しなければなりません。通常、 アプリケーションは、 このような事態を避けるため、 選択を消去してから通常の描画操作を実行し、 それが完了してから選択を復元します。

 

 

 

ウィンドウ座標系

ウィンドウの座標系は、 ディスプレイ デバイスの座標系に基づいています。基本単位はデバイス単位 (通常はピクセル) です。画面上の点は、 x座表とy座標の組み合わせで表現します。x座標の正の方向は右向きです。y座標の正の方向は下向きです。座標系の原点 (0, 0) は、 使われている座標系の種類によって異なります。

Windowsやアプリケーションは、 画面上のウィンドウの位置を「画面座標」で指定します。画面座標の原点は、 画面の左上隅です。ウィンドウの完全な位置を示すには、 RECT構造体がよく使われます。この構造体は、 ウィンドウの左上隅と右下隅を定義する2つの点の画面座標を示します。

Windowsやアプリケーションは、 ウィンドウ内の点の位置を「クライアント座標系」で指定します。クライアント座標系の原点は、 ウィンドウまたはクライアント領域の左上隅です。アプリケーションは、 クライアント座標系によって、 画面上でのウィンドウの位置にかかわらず、 同じ座標系でウィンドウに描画できます。

また、 クライアント領域の寸法は、 クライアント領域のクライアント座標を示すRECT構造体でも表現されます。どの場合でも、 長方形の左上隅の座標はウィンドウやクライアント領域に含まれますが、 右下隅の座標は含まれません。ウィンドウやクライアント領域でのグラフィック操作では、 操作対象を囲む長方形の右と下の辺は除外されます。

場合によっては、 あるウィンドウの座標をほかのウィンドウの座標にマップしなければならないことがあります。座標をマップするには、 MapWindowPoints関数を使います。ウィンドウのいずれかがデスクトップ ウィンドウならば、 画面座標とクライアント座標の間で変換することになります。デスクトップ ウィンドウは、 必ず画面座標で指定されます。

 

 

ウィンドウのリージョン

各ウィンドウには、 更新リージョンのほかに、 ウィンドウのユーザーに見える部分を定義する「可視リージョン」があります。ウィンドウのサイズが変化したり、 ほかのウィンドウが移動してウィンドウの一部が隠されたり表に出ると、 システムは、 ウィンドウの可視リージョンを変更します。可視リージョンをアプリケーションが直接変更することはできませんが、 Windowsは、 自動的に可視リージョンを使って、 ウィンドウ用のディスプレイDCのクリッピング リージョンを作成します。

「クリッピング リージョン」は、 システムが描画できる部分を示します。アプリケーションがBeginPaint関数、 GetDC関数、 GetDCEx関数を使ってディスプレイDCを取得するとき、 システムは、 可視リージョンと更新リージョンの交差をDCのクリッピング リージョンに設定します。クリッピング リージョンを変更するには、 SelectClipPathSelectClipRgnなどの関数を使って、 描画を更新領域の特定の部分にさらに限定します。

WS_CLIPCHILDRENスタイルやWS_CLIPSIBLINGSスタイルは、 Windowsがウィンドウの可視リージョンを計算する方法を指定します。ウィンドウにこれらのスタイルが設定されていれば、 子ウィンドウや兄弟ウィンドウ (同じ親ウィンドウを持つウィンドウ) は可視リージョンから除外されます。このため、 ほかのウィンドウにはみ出す描画は常にクリップされます。

 

 

ウィンドウ背景

ウィンドウ背景とは、 ウィンドウが描画を開始する前にクライアントを塗りつぶすのに使われる色やパターンです。ウィンドウ背景は、 ウィンドウを移動する前に表示されていたものをすべて覆い、 既存のイメージを消去して、 アプリケーションの新しい出力と不要な情報が混ざらないようにします。

アプリケーションがBeginPaintを呼び出すと、 Windowsは、 自分でウィンドウの背景を描画したりアプリケーションが背景を描画できるようにするため、 WM_ERASEBKGNDメッセージをアプリケーションに送ります。アプリケーションがこのメッセージを処理せずにDefWindowProc関数に渡すと、 Windowsは、 ウィンドウのクラスで指定されている背景ブラシのパターンで背景を塗りつぶし、 消去します。クラスに背景ブラシがないときや、 ブラシが有効でないとき、 Windowsは、 BeginPaintが返すPAINTSTRUCT構造体のfEraseメンバをセットしますが、 それ以外の処理は実行しません。これによって、 アプリケーションは、 必要ならばウィンドウ背景を描画できます。

WM_ERASEBKGNDメッセージを処理するアプリケーションは、 メッセージのwParamパラメータを使って背景を描画してください。このパラメータは、 ウィンドウのディスプレイDCのハンドルを示します。アプリケーションは、 背景を描画したら、 0以外の値を返してください。これによって、 以降のWM_PAINTメッセージをアプリケーションが処理するときに、 BeginPaintPAINTSTRUCT構造体のfEraseメンバに (背景を消去しなければならないことを示す) 0以外の値を設定してしまうことがなくなります。

クラス背景ブラシを定義するには、 WNDCLASS構造体のhbrBackgroundメンバにブラシ ハンドルかシステムの色の値を設定して、 RegisterClass関数でクラスを登録します。ブラシ ハンドルを作成するには、 GetStockObject関数やCreateSolidBrush関数を使います。システムの色の値には、 SetSysColors関数用に定義されている値のいずれかを指定できます (色の値には、 設定する前に1を加算してください)。

クラス背景ブラシが定義されていても、 アプリケーションはWM_ERASEBKGNDメッセージを処理できます。同じクラスのほかのウィンドウの背景を変更せずに特定のウィンドウの背景の色やパターンをユーザーが変更できるようにするには、 この方法をよく使います。このような場合、 アプリケーションは、 DefWindowProcにメッセージを渡してはいけません。

システムはウィンドウの原点を参照点としてブラシを描画するため、 アプリケーションがブラシを合わせる必要はありません。このため、 ユーザーがウィンドウを移動しても、 パターン ブラシのずれは発生しません。

 

 

アイコン化ウィンドウ

ユーザーがコントロール メニューから[アイコン化]コマンドを選択したり、 アプリケーションがSW_MINIMIZEなどの値を指定してShowWindowを呼び出すと、 Windowsは、 アプリケーションの (オーバーラップ スタイルの) メイン ウィンドウを、 アイコン化ウィンドウにします。ウィンドウをアイコン化すると、 アプリケーションがメインウィンドウを更新するのに必要な作業が減るため、 システムの性能が向上します。

通常のアプリケーションでは、 ウィンドウをアイコン化すると、 クラス アイコンと呼ばれるアイコンとウィンドウの名前をシステムが描画します。クラス アイコンは、 アプリケーションを表す動かないイメージで、 アプリケーションがウィンドウ クラスを登録するときに指定します。アプリケーションは、 クラス アイコンのハンドルをWNDCLASS構造体のhIconメンバに設定してから、 RegisterClassを呼び出します。アイコン ハンドルを取得するには、 LoadIcon関数を使います。

Windowsは、 クラス アイコンを描画する前に、 ウィンドウ プロシージャにWM_ICONERASEBKGNDメッセージを送って、 アプリケーションがアイコンに適した背景色を設定してアイコンの背景の描画を準備できるようにします。これは、 アイコンと現在の背景色を組み合わせるときに役立ちます。このメッセージを処理するアプリケーションは、 メッセージで渡されたディスプレイDCを使って背景を描画してください (wParamパラメータがディスプレイDCのハンドルです)。WM_ICONERASEBKGNDを処理しないアプリケーションは、 メッセージをDefWindowProcに渡してください。この関数は、 現在のデスクトップの色とパターンでアイコン領域を塗りつぶします。Windowsは、 WM_ICONERASEBKGNDを送った後、 WM_PAINTICONメッセージをウィンドウ プロシージャに送ります。アプリケーションは、 この内部メッセージをそのままDefWindowProcに渡してください。

ウィンドウのクラスには、 クラス アイコンがなくてもかまいません。アプリケーションがWNDCLASS構造体のhIconメンバにNULLを設定すると、 クラス アイコンは定義されません。この場合、 アイコンの背景の描画が必要になると、 Windowsは、 (WM_ICONERASEBKGNDメッセージではなく) WM_ERASEBKGNDメッセージをそのクラスのウィンドウに送ります。そして、 WindowsはWM_PAINTメッセージを送り、 アプリケーションはアイコン化ウィンドウを表すアイコンなどのイメージを描画します。この場合、 アプリケーションは、 ウィンドウがアイコン化されているか調べて、 それに従って描画しなければなりません。ウィンドウがアイコン化されているか調べるには、 IsIconic関数を呼び出します。この関数がTRUEを返した場合は、 ウィンドウはアイコン化されています。クラス アイコンを持たないアプリケーションがWM_ERASEBKGNDメッセージやWM_PAINTメッセージを処理しなければ、 Windowsがアプリケーションのアイコン用に予約している領域には、 画面の以前の内容がそのまま残ります。

 

 

ウィンドウのサイズ

ユーザーがコントロール メニューから[サイズ変更][最大表示]などのメニュー コマンドを選択したり、 アプリケーションがSetWindowPosなどの関数を呼び出すと、 Windowsは、 ウィンドウのサイズを変更します。Windowsは、 ウィンドウのサイズを変更するとき、 ウィンドウの以前の可視部分の内容に影響がなく、 再描画する必要がないと仮定します。Windowsはウィンドウの新しく可視になった部分しか無効化しないため、 アプリケーションによるWM_PAINTメッセージの処理時間が減ります。この場合、 ウィンドウのサイズを小さくしたときにはWM_PAINTメッセージは生成されません。

しかし、 ウィンドウによっては、 ウィンドウのサイズを変更すると内容が必ず無効になる場合があります。たとえば、 時計の表示がウィンドウにちょうど収まるようにする時計アプリケーションは、 ウィンドウのサイズが変化するたびに時計を再描画しなければなりません。ウィンドウが垂直や水平に変更されたときにWindowsにクライアント領域全体を無効化させるには、 ウィンドウ クラスを登録するときにCS_VREDRAWスタイルやCS_HREDRAWスタイルを指定してください。このスタイルを持つウィンドウ クラスに属するウィンドウは、 ユーザーやアプリケーションがウィンドウのサイズを変更するたびに無効化されます。

 

 

非クライアント領域

タイトル バーやメニュー バー、 ウィンドウ枠などの非クライアント領域の更新が必要になると、 Windowsは、 WM_NCPAINTメッセージをウィンドウに送ります。また、 Windowsは、 クライアント領域の一部をウィンドウに更新させるメッセージを送る場合もあります。たとえば、 ウィンドウがアクティブまたは非アクティブになると、 Windowsは、 タイトル バーを更新するためにWM_NCACTIVATEメッセージを送ります。一般に、 非クライアント メッセージをアプリケーションが処理しようとすると、 非クライアント領域の必要な部分をすべて描画しなければならなくなるため、 通常のウィンドウでは非クライアント メッセージは処理しないでください。このため、 ほとんどのアプリケーションは、 非クライアント メッセージをDefWindowProc関数に渡してデフォルト処理を行わせます。

ウィンドウの非クライアント領域をカスタムに作成するアプリケーションは、 このメッセージを処理しなければなりません。非クライアント メッセージを処理するには、 ウィンドウDCを使ってウィンドウに描画しなければなりません。「ウィンドウDC」を使えば、 ウィンドウの非クライアント領域を含むウィンドウのすべての部分に描画できます。ウィンドウDCを取得するには、 GetWindowDC関数かGetDCEx関数を使います。また、 描画が完了したら、 ReleaseDC関数を使ってウィンドウDCを解放してください。

Windowsは、 非クライアント領域用の更新リージョンを管理しています。アプリケーションが受け取るWM_NCPAINTメッセージのwParamパラメータは、 更新リージョンの寸法を定義するリージョンのハンドルです。更新リージョンをウィンドウDCのクリッピング リージョンに組み合わせるには、 このハンドルを使います。アプリケーションがリージョン ハンドルとDCX_INTERSECTRGNフラグを指定してGetDCExを呼び出していなければ、 Windowsは、 ウィンドウDCを取得するときに更新リージョンとクリッピング リージョンを自動的には組み合わせません。アプリケーションが更新リージョンを組み合わせなければ、 ウィンドウ外にはみ出す描画操作だけがクリップされます。アプリケーションは、 リージョンを使ったかどうかにかかわらず、 更新リージョンを消去する必要はありません。

WM_NCACTIVATEメッセージを処理するアプリケーションは、 メッセージを処理したらTRUEを返して、 アクティブ ウィンドウの変更を完了するようにWindowsに指示しなければなりません。アプリケーションがWM_NCACTIVATEメッセージを受け取ったときにウィンドウがアイコン化されていれば、 アプリケーションは、 メッセージをDefWindowProcに渡してください。この場合、 デフォルト プロシージャがアイコンのラベルを再描画します。

 

 

子ウィンドウ

子ウィンドウは、 WS_CHILDスタイルかWS_CHILDWINDOWスタイルを持つウィンドウです。子ウィンドウは、 ほかのスタイルのウィンドウと同様に、 更新が必要になるとWM_PAINTメッセージを受け取ります。各子ウィンドウには更新リージョンがあり、 Windowsやアプリケーションは、 更新リージョンを設定して最終的なWM_PAINTメッセージを生成できます。

子ウィンドウの更新リージョンと可視リージョンは、 親ウィンドウの影響を受けます。子ウィンドウ以外のスタイルのウィンドウではそうではありません。通常、 Windowsは、 親ウィンドウの更新リージョンを設定するときに子ウィンドウの更新リージョンも設定して、 親ウィンドウがWM_PAINTメッセージを受け取るときに子ウィンドウもWM_PAINTメッセージを受け取るようにします。また、 Windowsは、 子ウィンドウの可視リージョンの位置を、 親ウィンドウのクライアント領域内に限定します。Windowsは、 子ウィンドウの親ウィンドウ外に出た部分をクリップします。

親ウィンドウの更新リージョンに子ウィンドウの一部が含まれていれば、 Windowsは、 子ウィンドウの更新リージョンを設定します。このような場合、 Windowsは、 WM_PAINTメッセージをまず親ウィンドウに送り、 それから子ウィンドウにメッセージを送って、 親ウィンドウが上書きした部分を子ウィンドウが復元できるようにします。

子ウィンドウの更新領域が設定されていれば、 Windowsは、 親ウィンドウの更新領域を設定しません。アプリケーションが子ウィンドウを無効化して親ウィンドウに対するWM_PAINTメッセージを生成することはできません。同様に、 子ウィンドウに完全に隠されている親ウィンドウのクライアント領域の一部をアプリケーションが無効化して子ウィンドウに対するWM_PAINTメッセージを生成することはできません。このような場合、 どのウィンドウもWM_PAINTメッセージを受け取りません。

親ウィンドウの更新リージョンが設定されたときに子ウィンドウの更新リージョンが設定されないようにするには、 WS_CLIPCHILDRENスタイルを指定して親ウィンドウを作成します。このスタイルが設定されていれば、 Windowsは親ウィンドウの可視リージョンから子ウィンドウを除外するため、 更新リージョンの子ウィンドウを含む部分は無視されます。アプリケーションが親ウィンドウに描画すると、 子ウィンドウに重なる部分はクリップされるため、 子ウィンドウに対する以降のWM_PAINTメッセージは不要になります。

また、 子ウィンドウの更新リージョンと可視リージョンは、 子ウィンドウの兄弟ウィンドウの影響も受けます。兄弟ウィンドウとは、 同じ親ウィンドウを持つウィンドウです。兄弟ウィンドウが重なっていれば、 あるウィンドウの更新リージョンを設定するとほかのウィンドウの更新リージョンにも影響があるため、 両方のウィンドウにWM_PAINTメッセージが送られます。兄弟ウィンドウは、 Z順序と逆の順番でWM_PAINTメッセージを受け取ります。このため、 Z順序の最上位の (いちばん前の) ウィンドウは、 最後にWM_PAINTメッセージを受け取ります。

兄弟ウィンドウは自動的にはクリップされません。ウィンドウは、 自分よりもZ順序が上位の重なっている兄弟ウィンドウにも描画できます。ほかの兄弟ウィンドウに描画しないようにするには、 WS_CLIPSIBLINGSスタイルを指定してウィンドウを作成してください。このスタイルが設定されていれば、 Windowsは、 Z順序が上位の重なっている兄弟ウィンドウ全体をウィンドウの可視リージョンから除外します。

注: WS_POPUPスタイルやWS_POPUPWINDOWスタイルを持つウィンドウの更新リージョンと可視リージョンは、 親ウィンドウの影響を受けません。

 

 

ディスプレイ デバイス コンテキスト

ディスプレイDCとは、 Windowsが作成するデバイス コンテキストで、 アプリケーションはこのDCを使ってウィンドウを描画します。Windowsは、 ウィンドウへの出力、 描画オブジェクトや色、 モードの設定をディスプレイ デバイスではなくウィンドウに対して準備します。アプリケーションがGDI関数を呼び出すときにディスプレイDCを指定すると、 GDIは、 ディスプレイDCの情報を使って、 ほかのウィンドウや画面のほかの部分に影響を与えずに出力を生成します。

Windowsには、 共通、 クラス、 親、 プライベート、 ウィンドウの5種類のディスプレイ デバイス コンテキストがあります。共通、 クラス、 プライベートの各DCでは、 ウィンドウのクライアント領域に描画できます。親DCとウィンドウDCでは、 ウィンドウの任意の部分に描画できます。親DCでは親ウィンドウにも描画できますが、 親DCはそのような目的に使うものではありません。

Windowsは、 ウィンドウのクラス スタイルで指定されているディスプレイDCの種類に基づいて、 共通DC、 クラスDC、 親DC、 プライベートDCのいずれかをウィンドウに割り当てます。Windowsは、 アプリケーションが (GetWindowDC関数やGetDCEx関数などで) 要求したときだけウィンドウDCを割り当てます。いずれの場合でも、 ディスプレイDCが表現しているウィンドウを調べるには、 WindowFromDC関数を使います。

 

ディスプレイ デバイス コンテキスト キャッシュ

Windowsは、 共通DC、 親DC、 ウィンドウDCを使うディスプレイDCに対してキャッシュを管理しています。アプリケーションがGetDC関数やBeginPaint関数を呼び出すと、 Windowsは、 キャッシュからDCを取得します。アプリケーションがReleaseDC関数やEndPaint関数を呼び出すと、 Windowsは、 DCをキャッシュに戻します。

Windows 3.xでは、 キャッシュには5つのディスプレイDCを設定でき、 キャッシュから一度にアクティブにできるDCは5つだけです。ほかのアプリケーションがDCにアクセスできるようにするため、 アプリケーションは、 デバイス コンテキストを使い終わったらすぐに解放してください。DCを解放しないと、 アプリケーションの実行が失敗することになります。

Windows NTでは、 キャッシュに保持できるDCの個数の制限はありません。Windows NTは、 キャッシュにDCがなければ、 新しいディスプレイDCをキャッシュに作成します。このため、 Win32ベースのアプリケーションは、 同時に5つ以上のDCをキャッシュからアクティブにできます。しかし、 DCを使い終わったら、 必ず解放してください。新しいディスプレイDCのキャッシュはアプリケーションのヒープ領域に割り当てられるため、 DCを解放しないと、 利用可能なヒープ領域がすべて消費しつくされてしまいます。Windows NTは、 新しいDCのための領域を割り当てられないとき、 エラーを返してこの状況を示します。また、 キャッシュに関係のない関数もエラーを返す場合があります。

移植上の問題: 移植に必要な労力を最小限にするため、 共通DCを使うアプリケーションは、 DCの個数を5個以下にして、 共通DCを使い終わったらすぐに解放してください。

 

ディスプレイ デバイス コンテキストのデフォルト

Windowsは、 ディスプレイDCを最初に作成するとき、 DCを構成する属性 (描画オブジェクトや色、 モードなど) にデフォルト値を設定します。ディスプレイDCの属性のデフォルト値を次の表に示します。

 

属性 デフォルト値

背景色 Windowsコントロール パネルで設定した背景色 (通常は白)

背景モード OPAQUE

ビットマップ なし

ブラシ WHITE_BRUSH

ブラシの原点 (0, 0)

クリッピング リージョン 更新リージョンで適切にクリップされたウィンドウまたはクライアント領域の全体。クライアント領域内の子ウィンドウやポップアップ ウィンドウもクリップされます。

パレット DEFAULT_PALETTE

ペンの現在位置 (0, 0)

デバイスの原点 ウィンドウまたはクライアント領域の左上隅

描画モード R2_COPYPEN

フォント SYSTEM_FONT (Windowsバージョン3.0以前用に作成されたアプリケーションの場合はSYSTEM_FIXED_FONT)

文字間の空白 0

マッピング モード MM_TEXT

ペン BLACK_PEN

多角形塗りつぶしモード ALTERNATE

伸縮モード BLACKONWHITE

テキストの色 Windowsコントロール パネルで設定したテキストの色 (通常は黒)

ビューポートの範囲 (1, 1)

ビューポートの原点 (0, 0)

ウィンドウの範囲 (1, 1)

ウィンドウの原点 (0, 0)

 

 

ディスプレイDCの属性の値を修正するには、 SelectObject SetMapModeSetTextColorなどの選択関数や属性関数を使います。たとえば、 座標系のデフォルトの計測単位を修正するには、 SetMapModeを使ってマッピング モードを変更します。

通常DC、 親DC、 ウィンドウDCの属性値の変更は恒久的ではありません。アプリケーションがこれらのDCを解放すると、 マッピング モードやクリッピング リージョンなどの現在の選択は、 コンテキストがキャッシュに戻されるときに失われます。クラスDCやプライベートDCの変更は失われません。クラスDCやプライベートDCを元のデフォルト状態に戻すには、 明示的に各属性を設定してください。

 

参照

SelectObject SetMapModeSetTextColor

 

共通ディスプレイ デバイス コンテキスト

「共通DC」は、 ウィンドウのクライアントに描画するときに使います。Win32 APIは、 ウィンドウ クラスでディスプレイDCスタイルが明示的に指定されていないウィンドウに対して、 デフォルトで共通DCを割り当てます。通常、 共通DCは、 DC属性を大きく変更せずに描画できるウィンドウに使います。共通DCは余分なメモリやシステム リソースを必要としないため便利ですが、 DCを使う前に属性を大きく変更しなければならないときは不便です。

Windowsは、 共通DCをすべてディスプレイDCキャッシュから取得します。アプリケーションは、 ウィンドウを作成した直後から共通DCを取得できます。共通DCはキャッシュから取得されるため、 アプリケーションは、 描画が終わったらすぐにDCを解放しなければなりません。解放された共通DCは無効になり、 そのDCで描画することはできなくなります。もう一度描画するには新しい共通DCを取得しなければならず、 ウィンドウに描画するたびに共通DCを取得して解放しなければなりません。GetDC関数を使ってDCハンドルを取得したら、 ReleaseDC関数を使ってハンドルを解放しなければなりません。同様に、 BeginPaint関数を呼び出したら、 対応するEndPaint関数を呼び出さなければなりません。

アプリケーションがDCを取得するとき、 Windowsは、 DCの原点をクライアント領域の左上隅に設定します。また、 DCへの出力がクライアント領域でクリップされるようにクリッピング リージョンを設定します。クライアント領域の外側への出力はすべてクリップされます。アプリケーションがBeginPaintを使って共通DCを取得するとき、 Windowsは、 更新リージョンをクリッピング リージョンに追加して、 出力をさらに制限します。

アプリケーションが共通DCを解放すると、 Windowsは、 DCの属性にデフォルト値を復元します。属性値を修正するアプリケーションは、 共通DCを取得するたびに属性値を設定しなければなりません。DCを解放すると、 アプリケーションがDCで選択した描画オブジェクトはすべて解放されるため、 アプリケーションは、 DCを解放する前に描画オブジェクトを解放する必要はありません。どの場合でも、 アプリケーションは、 共通DCに解放前のデフォルト以外の選択がまだ設定されていると仮定してはいけません。

 

プライベート ディスプレイ デバイス コンテキスト

「プライベートDC」によって、 ウィンドウに描画するたびにディスプレイDCを取得して初期化する作業を省くことができます。プライベートDCは、 DCを描画用に準備するときに属性の値を広範囲に変更しなければならないウィンドウで役立ちます。プライベートDCによってDCの準備に必要な時間が少なくなるため、 ウィンドウへの描画に必要な時間も減ります。

ウィンドウにプライベートDCを割り当てるようにWindowsに指示するには、 ウィンドウ クラスにCS_OWNDCスタイルを指定します。Windowsは、 このスタイルを持つクラスに属する新しいウィンドウを作成するたびに、 一意なプライベートDCを作成します。プライベートDCの属性の初期値は共通DCのデフォルト値と同じですが、 アプリケーションはこの値をいつでも変更できます。ウィンドウが破棄されるか、 アプリケーションがさらに変更するまで、 WindowsはDCへの変更を保存します。

プライベートDCのハンドルを取得するには、 ウィンドウを作成してからGetDC関数を呼び出します。このハンドルは1つしか取得できません。このため、 同じハンドルを何度も再利用してください。プライベートDCはディスプレイDCキャッシュの一部ではないため、 ReleaseDC関数で解放する必要はありません。

Windowsは、 移動やサイズ変更などのウィンドウの変更を反映するため、 DCを自動的に調整します。これによって、 重なっているウィンドウが正しくクリップされます。つまり、 アプリケーションによるクリッピングは不要です。しかし、 Windowsは、 更新リージョンを含むようにDCを変更しません。このため、 アプリケーションは、 WM_PAINTメッセージを処理するとき、 BeginPaint関数を呼び出すか、 更新リージョンを取得して現在のクリッピング リージョンとの交差部分を求めて、 更新リージョンをクリッピング リージョンに組み入れなければなりません。BeginPaintを呼び出さないアプリケーションは、 ValidateRect関数かValidateRgn関数を呼び出して、 更新リージョンを明示的に有効化しなければなりません。アプリケーションが更新リージョンを有効化しなければ、 ウィンドウは、 WM_PAINTメッセージを際限なく受け取り続けることになります。

BeginPaintは、 ウィンドウにキャレットが表示されていればキャレットを非表示にするため、 BeginPaintを呼び出すアプリケーションは、 EndPaint関数を呼び出してキャレットを復元しなければなりません。EndPaintは、 プライベートDCにはこれ以外の影響は与えません。

プライベートDCは便利ですが、 システム リソースを多量に消費します (プライベートDCの格納には、 800バイト以上が必要です)。記憶域の制限よりも速度を優先するときは、 プライベートDCを使ってください。

Windowsは、 WM_ERASEBKGNDメッセージをアプリケーションに送るとき、 プライベートDCを送ります。マッピング モードなどのプライベートDCの現在の選択は、 アプリケーションやWindowsがこのメッセージを処理しているときに有効です。望ましくない結果を避けるため、 Windowsは、 背景を消去するときに論理座標を使います。たとえば、 Windowsは、 GetClipBox関数を使って消去する領域の論理座標を取得し、 その座標をFillRect関数に渡します。このメッセージを処理するアプリケーションでも同様の方法が使えます。WM_ICONERASEBKGNDメッセージの場合は、 ウィンドウがプライベートDCを持つかどうかにかかわらず、 Windowsは、 ウィンドウDCを渡します。

プライベートDCを持つウィンドウに対してWindowsが共通DCを返すようにするには、 GetDCEx関数を使います。これは、 プライベートDCの属性の現在値を変更せずにウィンドウを少しだけ変更するときに役立ちます。

 

クラス ディスプレイ デバイス コンテキスト

「クラスDC」によって、 アプリケーションは、 特定のクラスに属するすべてのウィンドウで1つの同じディスプレイDCを使うことができます。クラスDCは、 同じ属性値で描画されるコントロール ウィンドウでよく使われます。プライベートDCと同様に、 クラスDCによって、 DCを描画用に準備するのに必要な時間を最小限にできます。

Windowsは、 CS_CLASSDCスタイルを持つウィンドウ クラスに属するウィンドウにはクラスDCを割り当てます。Windowsは、 クラスに属する最初のウィンドウを作成するときにDCを作成し、 それ以降同じクラスで作成されるウィンドウには同じDCを使います。クラスDCの属性の初期値は共通DCのデフォルト値と同じですが、 アプリケーションは属性値をいつでも変更できます。Windowsは、 クラスの最後のウィンドウが破棄されるまで、 クリッピング リージョンとデバイス原点以外の変更をすべて保存します。あるウィンドウでの変更は、 そのクラスに属するウィンドウすべてに適用されます。

クラスDCのハンドルを取得するには、 最初のウィンドウを作成してからGetDC関数を呼び出します。クラスDCはディスプレイDCキャッシュの一部ではないため、 このハンドルは解放せずに取っておいて使うことができます。同じウィンドウ クラスの別のウィンドウを作成したら、 クラスDCをもう一度取得してください。DCを取得することによって、 新しいウィンドウを考慮した正しいデバイス原点とクリッピング リージョンが設定されます。アプリケーションが同じクラスの新しいウィンドウのクラスDCを取得すると、 もう一度DCを取得し直さない限り、 そのDCを使って元のウィンドウに描画することはできません。一般に、 ウィンドウに描画しなければならないときは、 ウィンドウのクラスDCを明示的に取得しなければなりません。

クラスDCを使うアプリケーションは、 WM_PAINTメッセージを処理するときは必ずBeginPaintを呼び出してください。この関数は、 ウィンドウの正しいデバイス原点とクリッピング リージョンを設定し、 更新リージョンを組み入れます。また、 BeginPaintでキャレットが非表示になっているときは、 EndPaintを呼び出してキャレットを復元してください。EndPaintは、 クラスDCに対してはこれ以外の影響を与えません。

Windowsは、 WM_ERASEBKGNDメッセージをアプリケーションに送るときにクラスDCを渡して、 アプリケーションやWindowsがこのメッセージを処理するときに実行する描画に現在の属性値が適用されるようにします。WM_ICONERASEBKGNDメッセージの場合は、 ウィンドウがクラスDCを持つかどうかにかかわらず、 Windowsは、 ウィンドウDCを渡します。アプリケーションは、 プライベートDCを持つウィンドウと同様に、 GetDCExを使って、 クラスDCを持つウィンドウに対してWindowsが共通DCを返すようにすることもできます。

クラスDCを使うことはお勧めしません。

 

ウィンドウ ディスプレイ デバイス コンテキスト

ウィンドウDCによって、 アプリケーションは、 非クライアント領域を含むウィンドウの任意の領域に描画できます。通常、 ウィンドウDCは、 カスタムの非クライアント領域を持つウィンドウに対するWM_NCPAINTメッセージやWM_NCACTIVATEメッセージを処理するアプリケーションで使われます。これ以外の用途にはウィンドウDCを使わないでください。

ウィンドウDCを取得するには、 DCX_WINDOWオプションを指定してGetWindowDC関数かGetDCEx関数を呼び出します。これらの関数は、 ディスプレイDCキャッシュからウィンドウDCを取得します。ウィンドウDCを使うウィンドウは、 描画が終わったら、 すぐにReleaseDC関数を使ってDCを解放しなければなりません。ウィンドウDCは、 常にキャッシュから取得されます。CS_OWNDCクラス スタイルやCS_CLASSDCクラス スタイルはクラスDCには影響しません。

アプリケーションがウィンドウDCを取得するとき、 Windowsは、 クライアント領域の左上隅ではなくウィンドウの左上隅をデバイス原点に設定します。また、 クライアント領域だけではなくウィンドウ全体を含むようにクリッピング リージョンを設定します。Windowsは、 共通DCと同じデフォルト値をウィンドウDCの現在の属性値に設定します。アプリケーションは属性値を変更できますが、 DCを解放すると、 Windowsは変更を保存しません。

 

親ディスプレイ デバイス コンテキスト

「親DC」によって、 アプリケーションは、 最小限の時間でウィンドウのクリッピング リージョンを設定できます。通常、 親DCは、 プライベートDCやクラスDCを必要としないコントロール ウィンドウの描画を高速化するために使われます。たとえば、 Windowsは、 プッシュ ボタンやエディット コントロールに親DCを使います。親DCは子ウィンドウ専用であり、 トップ レベル ウィンドウやポップアップ ウィンドウで使うことはできません。

Windowsは、 CS_PARENTDCスタイルのウィンドウ クラスに属するウィンドウに親DCを割り当てます。親DCを取得するには、 ウィンドウを作成した直後にGetDCを使います。Windowsは、 親ウィンドウがプライベートDCやクラスDCを使っていても、 常にディスプレイDCキャッシュから親DCを取得します。このため、 アプリケーションは、 描画が終わったらすぐにReleaseDCを使ってDCを解放しなければなりません。アプリケーションは、 WM_PAINTメッセージを処理するとき、 BeginPaintを使って親DCを取得し、 EndPaintを使って解放しなければなりません。

親DCを取得するとき、 Windowsは、 親ウィンドウが以前に使っていたディスプレイDCをキャッシュで検索します。ほとんどの場合、 子ウィンドウがディスプレイDCを取得しようとする前に親ウィンドウがディスプレイDCを取得して解放しているため、 親DCは通常はキャッシュにあります。Windowsは、 見つけたディスプレイDCとそれに対応するクリッピング リージョンを使います。このクリッピング リージョンは、 親ウィンドウ用に以前に計算したものです。このため、 クリッピング リージョンの定義に必要な計算が不要になるため、 時間を節約できます。親DCが見つからなければ、 Windowsは、 共通DCを取得し、 親ウィンドウ用ではなく対象とするウィンドウ用にクリッピング リージョンを計算します。

Windowsは、 子ウィンドウの左上隅を親DCのデバイス原点に設定します。親ウィンドウが設定した属性値は、 子ウィンドウには使われません。たとえば、 親ウィンドウは、 子ウィンドウのブラシを設定することはできません。子ウィンドウにもそのまま使われる属性はクリッピング リージョンだけです。ウィンドウは、 自分自身の出力をウィンドウの範囲内にクリップしなければなりません。親DCのクリッピング リージョンは親ウィンドウのクリッピング リージョンと同じであるため、 子ウィンドウは親ウィンドウ全体に描画できますが、 親DCはそのような目的には使わないでください。

親DCがプライベートDCやクラスDCを使っているとき、 親ウィンドウが子ウィンドウをクリップしているとき、 子ウィンドウが自分の子ウィンドウや兄弟ウィンドウをクリップしているときは、 Windowsは、 CS_PARENTDCスタイルを無視します。このような場合、 Windowsは、 ウィンドウに常に共通DCを割り当てます。

 

 

ウィンドウ更新ロック

「ウィンドウ更新ロック」とは、 ウィンドウへの描画を一時的に中断することです。ユーザーがウィンドウを移動したりサイズを変更するとき、 Windowsは、 更新をロックして、 ほかのウィンドウが追跡長方形の上に描画しないようにします。アプリケーションも、 更新をロックすることによって、 自分自身のウィンドウで同様な移動操作やサイズ変更操作を行うときにほかの描画が行われないようにできます。

ウィンドウ更新ロックを設定したり解除するには、 ロックするウィンドウを指定してLockWindowUpdate関数を呼び出します。ロックは、 指定したウィンドウのその子ウィンドウすべてに適用されます。ロックを設定すると、 GetDC関数やBeginPaint関数は、 可視リージョンが空のディスプレイDCを返します。これによって、 アプリケーションはウィンドウに描画し続けることができますが、 出力はすべてクリップされます。ロックは、 アプリケーションがウィンドウにNULLを指定してLockWindowUpdateを呼び出すまで解除されません。LockWindowUpdateは、 ウィンドウの可視リージョンを空にしますが、 指定されたウィンドウを不可視にしたりWS_VISIBLEスタイル ビットをクリアすることはありません。

ロックを設定したら、 DCX_LOCKWINDOWUPDATEを指定してGetDCEx関数を呼び出して、 ロックしたウィンドウに描画するためのディスプレイDCを取得できます。これによって、 アプリケーションは、 キーボード メッセージやマウス メッセージを処理するときに追跡長方形を描画できます。Windowsは、 ユーザーがウィンドウを移動したりサイズ変更するときにこの方法を使います。GetDCExはディスプレイDCをディスプレイDCキャッシュから取得するため、 アプリケーションは、 描画が終わったらすぐにDCを解放しなければなりません。

ウィンドウ更新ロックが設定されている間、 システムは、 ロックされている各ウィンドウについて、 境界長方形を蓄積します。ロックが解除されると、 Windowsは、 この境界長方形を使ってウィンドウとその子ウィンドウの更新リージョンを設定し、 WM_PAINTメッセージが1つだけ生成されるようにします。蓄積された境界長方形が空ならば (つまり、 ロックが設定されているときに描画が発生しなければ)、 更新リージョンは設定されません。

 

 

 

境界長方形の蓄積

「蓄積された境界長方形」とは、 ウィンドウやクライアント領域の最近の描画操作の影響を受けた部分を囲む最小の長方形です。この長方形を使って、 描画操作による変更の範囲を簡単に判断できます。蓄積された境界長方形とLockWindowUpdateを使うことによって、 更新ロックを解除した後に再描画しなければならないクライアント領域の部分を判断できます。

境界長方形の蓄積を開始するには、 DCB_ENABLEを指定してSetBoundsRect関数を呼び出します。この後、 Windowsは、 指定されたDCでアプリケーションが使った境界長方形の点を蓄積します。現在の境界長方形を取得するには、 GetBoundsRect関数を使います。蓄積を中止するには、 DCB_DISABLEを指定してもう一度SetBoundsRectを呼び出します。

 

 

WM_PAINTメッセージの使用

情報の表示に必要な描画を実行するには、 WM_PAINTメッセージを使います。Windowsは、 ウィンドウの更新が必要になったりアプリケーションが更新を明示的に要求するとWM_PAINTメッセージをアプリケーションに送るため、 描画用コードはウィンドウ プロシージャにまとめることができます。アプリケーションが新しい情報や既存の情報を描画しなければならないときは、 そのコードを使ってください。

以下の各トピックでは、 さまざまな方法でWM_PAINTメッセージを使ってウィンドウに描画する方法を示します。[>>]ボタンを使って以下に示すトピックを順番に読んでください。または、 各トピックをクリックすると、 そのトピックの内容を表示できます。

クライアント領域への描画

クライアント領域全体の再描画

更新リージョンでの再描画

クライアント領域の無効化

アイコン化ウィンドウの描画

カスタムのウィンドウ背景の描画

 

 

クライアント領域への描画

クライアント領域への描画を準備したり完了するには、 BeginPaint関数とEndPaint関数を使います。BeginPaintは、 クライアント領域への描画に使われるディスプレイDCのハンドルを返します。EndPaintは、 描画要求を終了し、 ディスプレイDCを解放します。

次のコード例のウィンドウ プロシージャは、 クライアント領域に“Hello, Windows!”というメッセージを表示します。ウィンドウを最初に作成したときに文字列が表示されるようにするため、 WinMain関数は、 ウィンドウを作成して表示した直後にUpdateWindow関数を呼び出します。これによって、 WM_PAINTメッセージがすぐにウィンドウ プロシージャに送られます。

 

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
PAINTSTRUCT ps;
HDC hdc;

switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 0, 0, "Hello, Windows!", 15);
EndPaint(hwnd, &ps);
return 0L;

.
.
.

}
}


int APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HINSTANCE hInstance; /* handle of current instance */
HINSTANCE hPrevInstance; /* handle of previous instance */
LPSTR lpCmdLine; /* address of command line */
int nCmdShow; /* show-window type (open/icon) */
{
HWND hwnd;


hwnd = CreateWindowEx( /* parameters */ );

ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);

.
.
.

return msg.wParam;
}

 

 

クライアント領域全体の再描画

ウィンドウのサイズが変化したときにアプリケーションがクライアント領域の内容全体を再描画するようにするには、 ウィンドウ クラスにCS_HREDRAWスタイルやCS_VREDRAWスタイルを指定します。ウィンドウのサイズに基づいて描画対象のサイズを調整するアプリケーションは、 これらのフラグを使って、 完全に空のクライアント領域で描画を開始できるようにします。

次に示すコードのウィンドウ プロシージャは、 クライアント領域にちょうど収まる星形を描画します。このウィンドウ プロシージャは共通DCを使っているため、 WM_PAINTメッセージを処理するたびに、 マッピング モードとウィンドウ範囲、 ビューポート範囲を設定しなければなりません。

 

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
POINT aptStar[6] = {50,2, 2,98, 98,33, 2,33, 98,98, 50,2};

.
.
.

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);
Polyline(hdc, aptStar, 6);
EndPaint(hwnd, &ps);
return 0L;

.
.
.

}


int APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HINSTANCE hInstance; /* handle of current instance */
HINSTANCE hPrevInstance; /* handle of previous instance */
LPSTR lpCmdLine; /* address of command line */
int nCmdShow; /* show-window type (open/icon) */
{
WNDCLASS wc;

.
.
.

wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;

.
.
.

RegisterClass(&wc);

.
.
.

return msg.wParam;
}

 

 

更新リージョンでの再描画

アプリケーションがWM_PAINTメッセージを処理するときに実行する描画の量を制限するには、 更新リージョンのサイズと位置を調べてください。Windowsは更新リージョンを使ってウィンドウのディスプレイDCのクリッピング リージョンを作成するため、 クリッピング リージョンを調べることによって更新リージョンを間接的に調べることができます。

次に示すコード例のウィンドウ プロシージャは、 三角形、 四角形、 五角形、 六角形を描画しますが、 図形が更新リージョンにまったく含まれていなければ描画しません。ウィンドウ プロシージャは、 100x100の長方形をRectVisible関数に指定して、 BeginPaint関数で取得した共通DCのクリッピング リージョン内に図形があるか調べます。

 

POINT aptTriangle[4] = {50,2, 98,86, 2,86, 50,2},
aptRectangle[5] = { 2,2, 98,2, 98,98, 2,98, 2,2},
aptPentagon[6] = {50,2, 98,35, 79,90, 21,90, 2,35, 50,2},
aptHexagon[7] = {50,2, 93,25, 93,75, 50,98, 7,75, 7,25, 50,2};
.
.
.

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetRect(&rc, 0, 0, 100, 100);

if (RectVisible(hdc, &rc))
Polyline(hdc, aptTriangle, 4);

SetViewportOrgEx(hdc, 100, 0, NULL);
if (RectVisible(hdc, &rc))
Polyline(hdc, aptRectangle, 5);

SetViewportOrgEx(hdc, 0, 100, NULL);
if (RectVisible(hdc, &rc))
Polyline(hdc, aptPentagon, 6);

SetViewportOrgEx(hdc, 100, 100, NULL);
if (RectVisible(hdc, &rc))
Polyline(hdc, aptHexagon, 7);
EndPaint(hwnd, &ps);
return 0L;

.
.
.

上記の例では、 各図形の座標は、 おなじ100x100の長方形内にあります。ウィンドウ プロシージャは、 図形を描画する前に、 SetViewportOrgEx関数を使ってビューポートの原点をクライアント領域の別の部分に設定します。これによって、 図形は重ならずに描画されます。ビューポート原点の変更はクリッピング リージョンには影響しませんが、 RectVisibleに渡した長方形の座標の解釈には影響します。また、 原点を変更することによって、 図形ごとに長方形を用意せずに、 1つの長方形で更新リージョンをチェックできます。

 

 

クライアント領域の無効化

WM_PAINTメッセージを送るのはWindowsだけではありません。InvalidateRect関数やInvalidateRgn関数は、 ウィンドウへのWM_PAINTメッセージを間接的に生成する可能性があります。これらの関数は、 クライアント領域の全体または一部を無効 (再描画が必要) としてマークします。

次のコード例のウィンドウ プロシージャは、 WM_CHARメッセージを処理するときにクライアント領域全体を無効化します。これによって、 ユーザーは、 数値を入力して図形を変更し、 結果を見ることができます。図形は、 アプリケーションのメッセージ キューにほかのメッセージがなくなると描画されます。

 

POINT aptPentagon[6] = {50,2, 98,35, 79,90, 21,90, 2,35, 50,2},
aptHexagon[7] = {50,2, 93,25, 93,75, 50,98, 7,75, 7,25, 50,2};
POINT *ppt = aptPentagon;
int cpt = 6;

.
.
.

case WM_CHAR:
switch (wParam) {
case '5':
ppt = aptPentagon;
cpt = 6;
break;
case '6':
ppt = aptHexagon;
cpt = 7;
break;
}
InvalidateRect(hwnd, NULL, TRUE);
return 0L;

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);
Polyline(hdc, ppt, cpt);
EndPaint(hwnd, &ps);
return 0L;

上記の例のInvalidateRectで使われているNULL引数は、 クライアント領域全体を指定しています。引数のTRUEは、 背景を消去することを指定しています。アプリケーションのメッセージ キューにほかのメッセージがなくなるまで待ちたくないときは、 UpdateWindow関数を使って、 WM_PAINTメッセージがすぐに送られるようにしてください。クライアント領域に無効な部分があれば、 UpdateWindowは、 指定されたウィンドウのウィンドウ プロシージャにWM_PAINTメッセージを直接送ります。

 

 

アイコン化ウィンドウの描画

アイコン化されたウィンドウには、 Windowsだけではなくアプリケーションも描画できます。通常、 アプリケーションは、 ウィンドウのウィンドウ クラスを登録するときにクラス アイコンを定義し、 Windowsはウィンドウをアイコン化したときにそのアイコンを描画します。しかし、 クラス アイコンにNULLを設定すると、 Windowsは、 ウィンドウがアイコン化されるとウィンドウ プロシージャにWM_PAINTメッセージを送り、 ウィンドウ プロシージャがアイコン化ウィンドウに描画できるようにします。

次のコード例のウィンドウ プロシージャは、 アイコン化ウィンドウに星を描画します。このプロシージャは、 IsIconic関数を使って、 ウィンドウがアイコン化されているか判断します。これによって、 ウィンドウがアイコン化されているときだけ星が描画されます。

 

POINT aptStar[6] = {50,2, 2,98, 98,33, 2,33, 98,98, 50,2};

.
.
.

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

/* Determine whether the window is minimized. */

if (IsIconic(hwnd)) {
GetClientRect(hwnd, &rc);
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);
Polyline(hdc, aptStar, 6);
} else {
TextOut(hdc, 0,0, "Hello, Windows!", 15);
}
EndPaint(hwnd, &ps);
return 0L;

クラス アイコンにNULLを設定するには、 WNDCLASS構造体のhIconメンバにNULLを設定してからRegisterClass関数を呼び出します。

 

 

カスタムのウィンドウ背景の描画

ウィンドウ背景は、 Windowsに描画させずにアプリケーション自身が描画することもできます。通常、 アプリケーションは、 ウィンドウ クラスを登録するとき、 クラス背景ブラシにブラシ ハンドルかシステムの色値を指定します。Windowsは、 このブラシや色を使って背景を描画します。しかし、 クラス背景ブラシにNULLを設定すると、 Windowsは、 ウィンドウ背景の描画が必要になるとWM_ERASEBKGNDメッセージをウィンドウ プロシージャに送って、 アプリケーションにカスタムの背景を描画させます。

次に示すコード例のウィンドウ プロシージャは、 ウィンドウにちょうど収まる大きな市松模様を描画します。このプロシージャは、 白ブラシでクライアント領域を塗りつぶして、 灰色のブラシで20x20の長方形を13個描画します。背景の描画に使われるディスプレイDCは、 メッセージのwParamパラメータが示します。

 

HBRUSH hbrWhite, hbrGray;

.
.
.

case WM_CREATE:
hbrWhite = GetStockObject(WHITE_BRUSH);
hbrGray = GetStockObject(GRAY_BRUSH);
return 0L;

case WM_ERASEBKGND:
hdc = (HDC) wParam;
GetClientRect(hwnd, &rc);
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 100, 100, NULL);
SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);
FillRect(hdc, &rc, hbrWhite);

for (i = 0; i < 13; i++) {
x = (i * 40) % 100;
y = ((i * 40) / 100) * 20;
SetRect(&rc, x, y, x + 20, y + 20);
FillRect(hdc, &rc, hbrGray);
}
return 1L;

また、 アプリケーションがアイコン化ウィンドウを自分自身で描画するとき、 Windowsは、 WM_ERASEBKGNDメッセージを送って、 アイコン化ウィンドウの背景を描画させます。ウィンドウがアイコン化されているか判断するには、 WM_PAINTメッセージと同じ方法が使えます。つまり、 IsIconic関数を呼び出して、 戻り値がTRUEかどうか調べます。

 

 

GetDC関数の使用

WM_PAINTメッセージを処理するときではなく、 即座に描画したいときは、 GetDC関数を使います。通常、 マウスによる選択や描画など、 ユーザーによる動作に応答して描画するときは、 この方法を使います。この場合、 視覚的なフィードバックをすぐにユーザーに示し、 表示のためにユーザーの選択操作や描画操作が中断されないようにしなければなりません。

 

 

 

マウスによる描画

ユーザーがマウスで直線を描画できるようにするには、 ウィンドウ プロシージャでWM_MOUSEMOVEメッセージを処理するときに描画を実行します。ユーザーがウィンドウ内でカーソルを動かすと、 Windowsは、 ウィンドウ プロシージャにWM_MOUSEMOVEメッセージを送ります。直線を描画するには、 ディスプレイDCを取得して、 現在のカーソル位置と以前のカーソル位置の間に直線を描画します。

次のコード例のウィンドウ プロシージャは、 ユーザーが左マウス ボタンを押したとき (WM_LBUTTONDOWNメッセージが送られたとき) に描画を準備します。ユーザーがウィンドウ内でカーソルを動かすと、 ウィンドウ プロシージャは、 一連のWM_MOUSEMOVEメッセージを受け取ります。ウィンドウ プロシージャは、 メッセージを受け取るごとに、 以前の位置と現在の位置を結ぶ直線を描画します。直線を描画するため、 プロシージャは、 GetDCを使ってディスプレイDCを取得します。描画が完了したら、 メッセージから戻る前に、 ReleaseDC関数を使ってディスプレイDCを解放します。ユーザーがマウス ボタンを離すと (WM_LBUTTONUPメッセージが送られると)、 ウィンドウ プロシージャはフラグをクリアし、 描画は行われなくなります。

 

BOOL fDraw = FALSE;
POINT ptPrevious;

.
.
.

case WM_LBUTTONDOWN:
fDraw = TRUE;
ptPrevious.x = LOWORD(lParam);
ptPrevious.y = HIWORD(lParam);
return 0L;

case WM_LBUTTONUP:
if (fDraw) {
hdc = GetDC(hwnd);
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, LOWORD(lParam), HIWORD(lParam));
ReleaseDC(hwnd, hdc);
}
fDraw = FALSE;
return 0L;

case WM_MOUSEMOVE:
if (fDraw) {
hdc = GetDC(hwnd);
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, ptPrevious.x = LOWORD(lParam),
ptPrevious.y = HIWORD(lParam));
ReleaseDC(hwnd, hdc);
}
return 0L;

通常、 上記の例のようにユーザーが描画できるようにする場合は、 点や直線を記録しておいて、 ウィンドウを更新するときに直線を再描画できるようにします。描画アプリケーションでは、 メモリDCとそのビットマップを使って、 マウスで描画された直線を格納することがよくあります。

 

 

周期的な描画

周期的に描画するには、 SetTimer関数でタイマを作成します。タイマを使ってWM_TIMERメッセージがウィンドウ プロシージャに定期的に送られるようにすれば、 ほかのアプリケーションを停止させずに、 クライアント領域で簡単なアニメーションを実行できます。

次のコード例は、 星をクライアント領域内で左右に跳ねさせます。ウィンドウ プロシージャは、 WM_TIMERメッセージを受け取ると、 現在位置の星を消去し、 新しい位置を計算してその位置に星を描画します。プロシージャは、 WM_CREATEメッセージを処理するときにSetTimerを呼び出してタイマを作成します。

 

RECT rcCurrent = {0,0,20,20};
POINT aptStar[6] = {10,1, 1,19, 19,6, 1,6, 19,19, 10,1};
int X = 2, Y = -1, idTimer = -1;
BOOL fVisible = FALSE;
HDC hdc;

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
PAINTSTRUCT ps;
RECT rc;

switch (message) {
case WM_CREATE:

/* Calculate the starting point. */

GetClientRect(hwnd, &rc);
OffsetRect(&rcCurrent, rc.right / 2, rc.bottom / 2);

/* Initialize the private DC. */

hdc = GetDC(hwnd);
SetViewportOrgEx(hdc, rcCurrent.left,
rcCurrent.top, NULL);
SetROP2(hdc, R2_NOT);

/* Start the timer. */

SetTimer(hwnd, idTimer = 1, 10, NULL);
return 0L;

case WM_DESTROY:
KillTimer(hwnd, 1);
PostQuitMessage(0);
return 0L;

case WM_SIZE:
switch (wParam) {
case SIZE_MINIMIZED:

/* Stop the timer if the window is minimized. */

KillTimer(hwnd, 1);
idTimer = -1;
break;

case SIZE_RESTORED:

/*
* Move the star back into the client area
* if necessary.
*/

if (rcCurrent.right > (int) LOWORD(lParam))
rcCurrent.left =
(rcCurrent.right =
(int) LOWORD(lParam)) - 20;
if (rcCurrent.bottom > (int) HIWORD(lParam))
rcCurrent.top =
(rcCurrent.bottom =
(int) HIWORD(lParam)) - 20;

/* Fall through to the next case. */

case SIZE_MAXIMIZED:

/* Start the timer if it had been stopped. */

if (idTimer == -1)
SetTimer(hwnd, idTimer = 1, 10, NULL);
break;
}
return 0L;

case WM_TIMER:

/* Hide the star if it is visible. */

if (fVisible)
Polyline(hdc, aptStar, 6);

/* Bounce the star off a side if necessary. */

GetClientRect(hwnd, &rc);
if (rcCurrent.left + X < rc.left ||
rcCurrent.right + X > rc.right)
X = -X;
if (rcCurrent.top + Y < rc.top ||
rcCurrent.bottom + Y > rc.bottom)
Y = -Y;

/* Show the star in its new position. */

OffsetRect(&rcCurrent, X, Y);
SetViewportOrgEx(hdc, rcCurrent.left,
rcCurrent.top, NULL);
fVisible = Polyline(hdc, aptStar, 6);

return 0L;

case WM_ERASEBKGND:

/* Erase the star. */

fVisible = FALSE;
return DefWindowProc(hwnd, message, wParam, lParam);

case WM_PAINT:

/*
* Show the star if it is not visible. Use BeginPaint
* to clear the update region.
*/

BeginPaint(hwnd, &ps);
if (!fVisible)
fVisible = Polyline(hdc, aptStar, 6);
EndPaint(hwnd, &ps);
return 0L;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

上記の例では、 プライベートDCを使って、 DCを描画用に準備するのに必要な時間を最小限にしています。ウィンドウ プロシージャは、 WM_CREATEメッセージを処理するときに、 プライベートDCを取得して初期化します。また、 バイナリ ラスタ オペレーション モードを設定して、 Polyline関数を1回呼び出すだけで星が消去されて描画されるようにします。さらに、 ウィンドウ プロシージャは、 ビューポート原点を設定して、 クライアント領域内での星の位置にかかわらず、 同じ点のセットで星を描画できるようにします。

アプリケーションは、 ウィンドウの更新が必要になると、 WM_PAINTメッセージを使って星を描画します。ウィンドウ プロシージャは、 星が見えなくなっている (WM_ERASEBKGNDメッセージで消去されている) ときだけ星を描画します。ウィンドウ プロシージャは、 WM_ERASEBKGNDメッセージを受け取るとfVisible変数を設定しますが、 Windowsがウィンドウ背景を描画できるようにするため、 WM_ERASEBKGNDメッセージをDefWindowProc関数に渡します。

アプリケーションは、 WM_SIZEメッセージを使って、 ウィンドウがアイコン化されるとタイマを停止し、 アイコン化されているウィンドウが復元されるとタイマを再開します。また、 ウィンドウ プロシージャは、 このメッセージを使って、 ウィンドウのサイズが小さくなったために星がクライアント領域内になくなったときに星の現在位置を更新します。アプリケーションは、 rcCurrent構造体を使って星の現在位置を追跡します。この構造体は、 星の境界長方形を定義します。長方形の各頂点がクライアント領域内にあるようにすれば、 星もクライアント領域内に入ります。ウィンドウ プロシージャは、 WM_CREATEメッセージを処理するとき、 最初に星をクライアント領域の中心に置きます。

 

 

関数とメッセージ

ウィンドウへの描画に関する関数とメッセージを次に示します。

 

関数

BeginPaint

DrawFocusRect

EndPaint

ExcludeUpdateRgn

GdiFlush

GdiGetBatchLimit

GdiSetBatchLimit

GetBkColor

GetBkMode

GetBoundsRect

GetROP2

GetUpdateRect

GetUpdateRgn

GetWindowDC

GrayString

InvalidateRect

InvalidateRgn

LockWindowUpdate

RedrawWindow

OutputProc

SetBkColor

SetBkMode

SetBoundsRect

SetRectRgn

SetROP2

UpdateWindow

ValidateRect

ValidateRgn

WindowFromDC

 

メッセージ

WM_ERASEBKGND

WM_PAINTICON

WM_ICONERASEBKGND

WM_NCPAINT

WM_PAINT

WM_SETREDRAW

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします
inserted by FC2 system