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

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

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

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

Windows API

ウィンドウ管理の紹介

このトピックでは、 Win32のUSER要素について説明し、 あわせてWindowsの16ビット関数に関連する変更部分についても説明します。はじめに、 32ビットのUSER要素で利用可能な拡張機能を説明し、 その次に、 USER32で利用可能な高レベルの機能の概要について説明します。

USER要素とはユーザー インターフェイスの機能を指し、 ウィンドウの管理やダイアログ ボックスの管理、 入力処理などを指します。

次の各トピックでは、 Win32におけるUSERの拡張および変更について説明します。

Win32 APIにおけるUSERの拡張

Win3とPMの入力処理の問題

Win32における入力処理の目標

複数の実行スレッド

入力処理の流れ

局所化される入力状態

局所化された入力状態の影響を受ける関数

アクティブ化に関するZ順序

ハング アップしたアプリケーションのウィンドウの枠やアイコンの消去と表示

国別言語サポート (NLS)

Unicode

通知メッセージ

ホット キー

Windowsのフックの変更

USER32関数におけるそのほかの変更部分について

 

USERの機能の概要

アクセラレータ

キャレット

クリップボード

コモン ダイアログ

マウス カーソル

DDE管理ライブラリ (DDEML)

ダイアログ ボックス

ドラッグ アンド ドロップ

エラー

フック

アイコン

キーボード

MDI

メニュー

メッセージ

マウス

オブジェクトのリンクと埋め込み (OLE)

描画

プロパティ

長方形

スクロール

文字列

ウィンドウ管理

Win32 APIにおけるUSERの拡張

このトピックでは、 32ビット版のUSERにおける仕様の拡張について説明します。

USER32における入力

 

ウィンドウ クラスの概要

どのようなウィンドウも、 あるウィンドウ クラスに属します。「ウィンドウ クラス」とは、 アプリケーションの中でウィンドウを作成するときにMicrosoft(R) Windows(TM) がそのテンプレートとして使用する、 属性の集まりのことです。ウィンドウ クラスには必ずウィンドウ プロシージャが関連付けられ、 同じクラスのウィンドウは同じウィンドウ プロシージャを共有します。ウィンドウ プロシージャは、 そのクラスに属するすべてのウィンドウに送られるメッセージを処理し、 それらのウィンドウの動作や外観を制御します。ウィンドウ プロシージャについて詳しくは、 ウィンドウ プロシージャの概要を参照してください。

アプリケーションは、 あるクラスのウィンドウを作成する前に、 そのウィンドウ クラスを登録しなければなりません。ウィンドウ クラスを登録することにより、 ウィンドウ プロシージャ、 クラス スタイルなどのクラス属性がクラス名に関連付けられます。アプリケーションがCreateWindow関数やCreateWindowEx関数の中でクラス名を指定すると、 オペレーティング システムはそのクラス名に関連付けられているウィンドウ プロシージャ、 スタイルなどの属性を持ったウィンドウを作成します。

次の各トピックには、 ウィンドウ クラスについて詳しい説明があります。

ウィンドウ クラスの種類

Windowsはどのようにクラスを特定するか?

クラスの所有権

ウィンドウ クラスの構成要素

クラス デバイス コンテキストとプライベート デバイス コンテキスト

ウィンドウ クラス関数

ウィンドウ クラスの種類

ウィンドウ クラスには、 システム グローバルアプリケーション グローバル アプリケーション ローカルの、 3種類のクラスがあります。これらのクラスは、 その適用範囲や、 登録と破棄の時期およびその方法がそれぞれ異なります。

 

システム グローバル クラス

Windowsを起動すると、 Windowsは、 ボタン、 コンボ ボックス、 リスト ボックス、 スクロール バー、 エディット コントロール、 およびスタティック コントロールなどのコントロールのために、 1組の「システム グローバル クラス」を登録します。コントロールについて詳しくは、 コントロールの概要ボタンの概要リスト ボックスの概要エディット コントロールの概要コンボ ボックスの概要スクロール バーの概要スタティック コントロールの概要を参照してください。

システム グローバル クラスは、 任意のアプリケーションがいつでも使うことができます。Windowsはすべてのアプリケーションのためにシステム グローバル クラスを登録しているため、 アプリケーションがこれらのクラスを破棄することはできません。

 

アプリケーション グローバル クラス

「アプリケーション グローバル クラス」は、 ダイナミック リンク ライブラリ (DLL) が登録するウィンドウ クラスであり、 システム内のすべてのアプリケーションから利用できます。たとえば、 カスタム コントロールをアプリケーション グローバル クラスとして定義するウィンドウ クラスを登録すれば、 すべてのアプリケーションがそのカスタム コントロールのインスタンスを作成できるようになります。

Windowsでは、 ウィンドウ クラスはすべてプロセス固有のものになります。アプリケーシは、 DLL内でウィンドウ クラスを作成し、 そのDLLの名前を登録データベースの次のキーの下に登録することにより、 グローバル クラスを作成できます。

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\
CurrentVersion\Windows\APPINIT_DLLSプロセスが起動すると、 システムは新しく起動したプロセスのコンテキスト内で指定のDLLをロードしてから、 プロセス内のmain関数を呼び出します。DLLはその初期化処理の間にクラスを登録し、 CS_GLOBALCLASSスタイルを指定しなければなりません。クラス スタイルについて詳しくは、 クラス スタイルを参照してください。クラスが登録されると、 アプリケーションはそれを使って、 そのクラスに属するウィンドウをいくつでも作成できるようになります。

Windowsは、 アプリケーション グローバル クラスを登録したDLLがアンロードされるときに、 そのクラスを破棄します。このため、 そのクラスに属するウィンドウを使用しているすべてのアプリケーションは、 DLLがアンロードされる前に、 そのウィンドウを破棄しなければなりません。これには、 UnregisterClass関数を使ってアプリケーション グローバル クラスを削除し、 クラスに関連付けられていたメモリ領域を解放します。

 

アプリケーション ローカル クラス

「アプリケーション ローカル クラス」は、 アプリケーションが専用のクラスとして登録するウィンドウ クラスです。アプリケーションはローカル クラスをいくつでも登録できますが、 通常は1つだけを登録します。このウィンドウ クラスは、 アプリケーションのメイン ウィンドウのウィンドウ プロシージャをサポートします。

ローカル クラスの登録はアプリケーション グローバル クラスのそれと同様ですが、 WNDCLASS構造体のstyleメンバにCS_GLOBALCLASSスタイルを指定しない点が異なります。

Windowsは、 ローカル クラスを登録したアプリケーションがクローズされると、 そのクラスを破棄します。また、 アプリケーションはUnregisterClass関数を使ってローカル クラスを削除し、 クラスに関連付けられていたメモリ領域を解放することもできます。

Windowsはどのようにクラスを特定するか?

Windowsは、 3種類のウィンドウ クラスごとにWNDCLASS構造体のリストを管理しています。アプリケーションがCreateWindow関数またはCreateWindowEx関数を呼び出して指定されたクラスを持つウィンドウを作成するとき、 Windowsは次の手順でクラスの種類を特定します。

1.Windowsはアプリケーション ローカル クラスのリストの中で、 指定された名前を持つクラスを検索します。

2.クラス名がアプリケーション ローカル リストになければ、 Windowsはアプリケーション グローバル クラスのリストの中を検索します。

3.クラス名がアプリケーション グローバル リストになければ、 Windowsはシステム グローバル クラスのリストの中を検索します。

アプリケーションが作成するウィンドウは、 ダイアログ ボックスなどアプリケーション専用としてWindowsが作成するウィンドウも含めて、 すべてこの手順でクラスが特定されます。システム グローバル クラスは、 ほかのアプリケーションに影響を与えずに、 それを変更することが可能です。つまり、 アプリケーションはシステム グローバル クラスと同じ名前を持つアプリケーション ローカル クラスを登録することができます。この操作によりアプリケーションのコンテキスト内でシステム グローバル クラスが置き換えられますが、 このときに、 ほかのアプリケーションがそのシステム グローバル クラスを使えなくなるということはありません。

 

クラスの所有権

クラスのオーナーは、 そのクラスを登録したアプリケーションまたはDLLになります。Windowsは、 クラスの登録時にRegisterClass関数に渡されるWNDCLASS構造体のhInstanceメンバから、 クラスの所有権を決定します。Windows DLLでは、 hInstanceメンバは必ずDLLのインスタンス ハンドルでなければなりません。クラスは、 そのオーナーがクローズするときやアンロードされるときに破棄されます。このため、 クラスに属するウィンドウを使用しているアプリケーションは、 クローズする前、 またはDLLがアンロードされる前に、 それらのウィンドウをすべて破棄しなければなりません。

 

ウィンドウ クラスの構成要素

ウィンドウ クラスの構成要素は、 そのクラスに属するウィンドウのデフォルトの動作を定義するものです。ウィンドウ クラスを登録するアプリケーションは、 WNDCLASS構造体のメンバを適切に設定し、 それをRegisterClass関数に渡すことにより、 クラスの構成要素を割り当てを決めます。指定されたウィンドウ クラスに関する情報を取得するには、 GetClassInfo関数およびGetClassLong関数を使います。アプリケーションがすでに登録したローカル クラスやグローバル クラスの構成要素を変更するには、 SetClassLong関数を使います。

ウィンドウ クラスの完全な定義は多くの構成要素からなりますが、 Windowsはアプリケーションに対して、 クラス名ウィンドウ プロシージャ アドレス、 およびインスタンス ハンドルの指定を要求するだけです。マウス カーソルの形状やウィンドウのメニュー内容などのクラスを定義する場合は、 ほかの構成要素を使ってそのようなクラスに対するデフォルトの属性を定義します。

 

要素目的

クラス名すでに登録済みのクラスと新しく登録されるクラスを区別します。

ウィンドウ プロシージャ アドレスあるクラスのウィンドウに送られるすべてのメッセージを処理する関数を指すポインタです。ウィンドウの動作を定義します。

インスタンス ハンドルクラスを登録したアプリケーションまたはDLLを識別します。

クラス カーソルあるクラスのウィンドウ内で表示されるマウス カーソルを定義します。

クラス アイコンあるクラスに属するウィンドウがアイコン化されたときの大きいアイコンの形状を定義します。

小さいクラス アイコンあるクラスに属するウィンドウのタイトル バーに表示される、 小さいアイコンを定義します。

クラス背景ブラシウィンドウのオープン時または描画時にクライアント領域を塗りつぶす色とパターンを定義します。

クラス メニューメニューを明示的に定義していないウィンドウに対するデフォルトのメニューを指定します。

クラス スタイルウィンドウが移動またはサイズ変更された後の更新方法、 マウスのダブルクリックの処理方法、 デバイス コンテキスト用のメモリ領域の割り当て方法など、 ウィンドウに関する種々のアスペクトを定義します。

補足クラス メモリWindowsが特定のクラス用として予約すべき補足メモリの量を、 バイト単位で指定します。補足メモリを持つクラスのウィンドウはすべてこの補足メモリを共有し、 アプリケーションは独自の目的でそれを使うことができます。Windowsはこのメモリを0に初期化します。

補足ウィンドウ メモリWindowsが特定のクラスに属する各ウィンドウ用として予約すべき補足メモリの量を、 バイト単位で指定します。アプリケーションは、 独自の目的でこの補足メモリを使うことができます。Windowsはこのメモリを0に初期化します。

クラス名

すべてのウィンドウ クラスには、 ほかのクラスと区別するための「クラス名」が必要です。クラス名は、 その名前を示すNULLで終わる文字列のアドレスをWNDCLASS構造体のlpszClassNameメンバに設定することにより、 割り当てます。Windowsではウィンドウ クラスはプロセス固有となるため、 同じプロセスの内部ではウィンドウ クラス名を一意にする必要があります。

GetClassName関数は、 指定されたウィンドウが属するクラスの名前を取得します。

 

ウィンドウ プロシージャ アドレス

すべてのクラスには、 そのクラスのウィンドウに送られるすべてのメッセージを処理するために使われるウィンドウ プロシージャのエントリ ポイントを定義する、 ウィンドウ プロシージャ アドレスが必要です。Windowsは、 ウィンドウのクライアント領域の描画やユーザーからの入力の応答などのタスクを実行するようウィンドウに対して要求するときに、 そのプロシージャにメッセージを渡します。一方、 アプリケーションは、 ウィンドウ プロシージャ アドレスをWNDCLASS構造体のlpfnWndProcメンバにコピーすることにより、 ウィンドウ プロシージャをクラスに割り当てます。ウィンドウ プロシージャは、 モジュール定義ファイル (.DEF) の中でエクスポートしなければなりません。ウィンドウ プロシージャについて、 詳しくはウィンドウ プロシージャの概要を参照してください。

 

インスタンス ハンドル

すべてのウィンドウ クラスには、 クラスを登録したアプリケーションやDLLを識別するためのインスタンス ハンドルが必要です。マルチタスキング システムとしてのWindowsは、 いくつかのアプリケーションやDLLを同時に実行させますが、 このときにそれらすべてのインスタンスを管理するためにインスタンス ハンドルが必要になります。Windowsは、 実行中のアプリケーションやDLLのコピー (インスタンス) ごとにハンドルを割り当てます。

同じアプリケーションやDLLの複数のインスタンスは同じコード セグメントを使用しますが、 データ セグメントは独自のものを持っています。Windowsは、 アプリケーションやDLLの特定のインスタンスに対応するデータ セグメントを識別するために、 インスタンス ハンドルを使用します。

ウィンドウは、 アプリケーションの起動時にインスタンス ハンドルをアプリケーションやDLLに渡します。アプリケーションやDLLは、 WNDCLASS構造体のhInstanceメンバにこのインスタンス ハンドルをコピーすることにより、 それをクラスに割り当てます。

 

クラス カーソル

「クラス カーソル」は、 あるクラスに属するウィンドウのクライアント領域内に表示されるマウス カーソルの形状を定義するものです。マウス カーソルがウィンドウのクライアント領域内に置かれると、 Windowsはマウス カーソルに規定の形状を自動的に設定し、 マウス カーソルがクライアント領域内にある間は必ずその形状が保持されるようにします。マウス カーソルの形状をウィンドウ クラスに割り当てるには、 LoadCursor関数を使って定義済みのマウス カーソルの形状をロードし、 関数が返すマウス カーソル ハンドルをWNDCLASS構造体のhCursorメンバに割り当てます。また、 カスタム マウス カーソル リソースを用意しておき、 LoadCursor関数を使ってアプリケーションのリソースからそれをロードする方法もあります。

Windowsにはクラス カーソルは必ずしも必要ではありません。アプリケーションがWNDCLASS構造体のhCursorメンバにNULLを設定した場合は、 クラス カーソルは定義されません。この場合、 Windowsは、 マウス カーソルがウィンドウの中に移動されるたびにその形状が設定されるものとみなします。ウィンドウは、 WM_MOUSEMOVEメッセージを受け取るたびに、 SetCursor関数を呼び出してマウス カーソルの形状を設定できます。カーソルについて、 詳しくはカーソルの概要を参照してください。

 

クラス アイコン

「大きいクラス アイコン」は、 指定されたクラスのウィンドウがアイコン化されるときに使われるアイコンを定義するものです。「小さいクラス アイコン」は、 指定されたクラスのウィンドウのタイトル バーで使われるアイコンを定義します。大きいアイコンと小さいアイコンをウィンドウ クラスに割り当てるには、 LoadIcon関数を使ってアプリケーションのリソースからアイコンをロードし、 関数が返すアイコン ハンドルをWNDCLASS構造体のhIconメンバとhIconSmメンバに割り当てます。アイコンについて、 詳しくはアイコンの概要を参照してください。

Windowsは、 ウィンドウ クラスに大きいクラス アイコンと小さいクラス アイコンを持たせることを必ずしも要求しません。アプリケーションがWNDCLASS構造体のhIconメンバとhIconSmメンバにNULLを設定した場合は、 対応するクラス アイコンは定義されません。大きいアイコンが定義されない場合、 Windowsは、 アイコンの背景を描画しなければならなくなるたびに、 そのクラスのウィンドウにWM_ICONERASEBKGNDメッセージを送ります。ウィンドウがWM_ICONERASEBKGNDメッセージを処理しない場合には、 Windowsはウィンドウがアイコン化されたときに、 そのクライアント領域の内容をアイコンの中に描画します。

 

クラス背景ブラシ

「クラス背景ブラシ」は、 後でアプリケーションが描画するときのウィンドウのクライアント領域を準備するものです。Windowsはこのブラシを使い、 クライアント領域を純色またはパターンで塗りつぶします。これにより、 以前のイメージは、 それがウィンドウに属するかどうかに応じてすべて消去されます。Windowsは、 WM_ERASEBKGNDメッセージを送ることにより、 ウィンドウの背景を描画すべきことをウィンドウに通知します。ブラシについて、 詳しくはブラシの概要を参照してください。

背景ブラシをクラスに割り当てるには、 適切なグラフィック デバイス インターフェイス (GDI) 関数を使ってブラシを作成してから、 関数が返すブラシ ハンドルをWNDCLASS構造体のhbrBackgroundメンバに割り当てます。

また、 ブラシを作成する代わりに、 アプリケーションはhbrBackgroundメンバに標準のシステム カラー値の1つを設定することもできます。

アプリケーションで標準のシステム カラーを使うには、 背景色の値を1つ増やすことが必要です。つまり、 COLOR_BACKGROUND + 1がシステムの背景色になります。

Windowsでは、 ウィンドウ クラスが必ずしもクラス背景ブラシを持っている必要はありません。このパラメータをNULLに設定した場合は、 ウィンドウはWM_ERASEBKGNDメッセージを受け取ったときに、 必ず自分の背景を描画しなければなりません。

 

クラス メニュー

「クラス メニュー」は、 あるクラスのウィンドウの作成時に特にメニューを定義しない場合に、 そのウィンドウが使用するデフォルトのメニューを定義するものです。メニューとはコマンドの一覧のことであり、 ユーザーはそれらのコマンドを選んでアプリケーションに動作を実行させることができます。

メニューをクラスに割り当てるには、 WNDCLASS構造体のlpszMenuNameメンバに、 メニューのリソース名を示すNULLで終わる文字列のアドレスを設定します。メニューは、 指定されたアプリケーションのリソースであるとみなされ、 Windowsは必要に応じてメニューを自動的にロードします。メニュー リソースが名前ではなく整数によって識別される場合は、 lpszMenuNameメンバに値を割り当てる前に、 MAKEINTRESOURCEマクロを使って整数を設定することもできます。

Windowsは、 クラス メニューを必ずしも必要としません。アプリケーションがWNDCLASS構造体のlpszMenuNameメンバにNULLを設定した場合は、 Windowsはそのクラスのウィンドウがメニュー バーをまったく持たないものとみなします。ただし、 クラス メニューを指定しない場合でも、 アプリケーションはウィンドウの作成時にウに対してメニュー バーを定義することができます。

Windowsでは、 メニュー バーに子ウィンドウを持たせることはできません。あるクラスに対するメニューが与えられ、 そのクラスの子ウィンドウが作成された場合、 メニューは無視されます。メニューについて、 詳しくはメニューの概要を参照してください。

 

クラス スタイル

クラス スタイルは、 ウィンドウ クラスの要素を補助的に定義するものです。2つ以上のスタイルは、 ビットごとのOR演算子 (|) を使って組み合わせることができます。スタイルをウィンドウ クラスに割り当てるには、 WNDCLASS構造体のstyleメンバに、 スタイルを割り当てます。クラス スタイルには、 次のものがあります。

スタイル動作

CS_BYTEALIGNCLIENT描画操作の性能を向上させるために、 ウィンドウのクライアント領域を (x方向の) バイト境界にそろえます。このスタイルは、 ウィンドウの幅とディスプレイ上の水平位置に影響を与えます。

CS_BYTEALIGNWINDOWウィンドウの移動やサイズ変更を必要とする操作の性能を向上させるために、 ウィンドウを (x方向の) バイト境界にそろえます。このスタイルは、 ウィンドウの幅とディスプレイ上の水平位置に影響を与えます。

CS_CLASSDCあるクラスのすべてのウィンドウが共有する1つのデバイス コンテキストを割り当てます。デバイス コンテキストについて詳しくは、 クラス コンテキストとプライベート デバイスコンテキスト、 およびデバイス コンテキストの概要を参照してください。

CS_DBLCLKSマウス カーソルがそのクラスに属するウィンドウの中に置かれている間ユーザーがマウスをダフルクリックしたときに、 ダブルクリック メッセージをウィンドウ プロシージャに送ることをWindowsに指示します。マウスのクリックについて、 詳しくはマウス入力の概要を参照してください。

CS_GLOBALCLASSウィンドウ クラスがアプリケーション グローバル クラスであることを指定します。詳しくは、 アプリケーション グローバル クラスを参照してください。

CS_HREDRAWウィンドウの移動やサイズ変更によってクライアント領域の幅が変更されたときに、 ウィンドウ全体を再描画することを指定します。

CS_NOCLOSE[閉じる]コマンドとコントロール メニューを使用不能にします。

CS_OWNDCあるクラスに属する各ウィンドウに対して、 一意なデバイス コンテキストを割り当てます。デバイス コンテキストについて詳しくは、 クラス コンテキストとプライベート デバイスコンテキスト、 およびデバイス コンテキストの概要を参照してください。

CS_PARENTDC子ウィンドウが親ウィンドウのデバイス コンテキスト継承します。デバイス コンテキストについて詳しくは、 クラス コンテキストとプライベート デバイスコンテキスト、 およびデバイス コンテキストの概要を参照してください。

CS_SAVEBITSあるウィンドウによって隠された画面イメージの一部分をビットマップとして保存します。Windowsは、 ウィンドウが削除されたときに、 この保存されたビットマップを使って画面イメージを再作成します。ほかの画面操作によって格納されたイメージが無効化されていなければ、 Windowsはビットマップを元の位置に表示して、 ほかのウィンドウによって隠されたウィンドウにWM_PAINTメッセージを送りません。このスタイルは、 メニューやダイアログ ボックスのように、 短時間だけ表示されてほかの画面操作が起こる前にすぐに消去されるような小さなウィンドウで使うと便利です。このスタイルを使った場合、 システムは最初にビットマップを格納するためのメモリを割り当てるので、 ウィンドウの表示に多少時間がかかります。

CS_VREDRAWウィンドウの移動やサイズ変更によりクライアント領域の高さが変更されたときに、 ウィンドウ全体を再描画することを指定します。

 

補足クラス メモリ

Windowsは、 システム内の各ウィンドウ クラスごとに、 内部的にWNDCLASS構造体を管理しています。アプリケーションは、 ウィンドウ クラスを登録するときに、 Windowsにメモリを割り当てるよう指示し、 WNDCLASS構造体の末尾に指定量の追加メモリを付加させることができます。このメモリは「補足クラス メモリ」と呼ばれ、 そのクラスに属するすべてのウィンドウによって共有されます。クラスに関係のある情報を格納するには、 補足クラス メモリを使うと便利です。

SetClassWord関数およびSetClassLong関数は、 補足クラス メモリに値をコピーします。補足クラス メモリから値を取得するには、 GetClassWord関数およびGetClassLong関数を使います。WNDCLASS構造体のcbClsExtraメンバには、 割り当てる補足クラス メモリの量を指定します。補足クラス メモリを使わないアプリケーションは、 cbClsExtraメンバを0に初期化しなければなりません。

 

補足ウィンドウ メモリ

Windowsは、 各ウィンドウごとに内部データ構造体を管理しています。アプリケーションは、 ウィンドウ クラスを登録するときに、 「補足ウィンドウ メモリ」と呼ばれる指定量の追加メモリを付加させることができます。Windowsは、 そのクラスのウィンドウを作成するときに指定量の補足ウィンドウ メモリを割り当て、 それをウィンドウ構造体の末尾に付加します。ウィンドウ固有のデータを格納するには、 この補足ウィンドウ メモリを使うと便利です。

SetWindowWord関数およびSetWindowLong関数は、 補足ウィンドウ メモリに値をコピーします。GetWindowWord関数およびGetWindowLong関数は、 補足ウィンドウ メモリから値を取得します。WNDCLASS構造体のcbWndExtraメンバには、 割り当てる補足ウィンドウ メモリの量を指定します。補足ウィンドウ メモリを使わないアプリケーションは、 cbWndExtraメンバを0に初期化しなければなりません。

 

クラス デバイス コンテキストとプライベート デバイス コンテキスト

デバイス コンテキストとは、 アプリケーションが自分のウィンドウのクライアント領域を描画する際に使用する、 1組の特殊な値のことです。Windowsは画面上の各ウィンドウに対してデバイス コンテキストを要求しますが、 オペレーティング システムによるデバイス コンテキストの格納方法とその扱い方については、 若干の柔軟性が許されています。

デバイス コンテキストのスタイルを特に指定しない場合、 各ウィンドウが使用するデバイス コンテキストは、 Windowsが管理するコンテキスト プールから取得されるものとみなされます。このような場合、 各ウィンドウは描画の前にデバイス コンテキストの取得と初期化を行い、 描画後にそれを解放しなければなりません。

ウィンドウ内を描画する必要が生じるたびにデバイス コンテキストを取得するような手間を省くため、 アプリケーションはウィンドウ クラスにCS_OWNDCスタイルを指定することができます。このクラス スタイルは、 プライベートなデバイス コンテキスト、 すなわちそのクラスの各ウィンドウに対して一意に割り当てられるデバイス コンテキストを作成するよう、 Windowsに指示します。この場合、 アプリケーションはコンテキストを1回だけ取得するだけでよく、 後続の描画操作でそのコンテキストを使うことができます。CS_OWNDCスタイルは便利ですが、 デバイス コンテキストはシステム リソースのかなりの部分を占めるので、 使うときには注意してください。

CS_CLASSDCスタイルを指定することにより、 アプリケーションはクラス デバイス コンテキストを作成できます。クラス デバイス コンテキストはあまり使われない機能ですが、 このコンテキストは、 1つのプロセス内の同じウィンドウ クラスから作成される複数のウィンドウが、 描画の際にまったく同じデバイス コンテキストを使用することを可能にするものです。

アプリケーションは、 親ウィンドウのデバイス コンテキストを継承する子ウィンドウを作成するために、 CS_PARENTDCスタイルを指定することができます。このスタイルにより、 子ウィンドウがその親ウィンドウのクライアント領域内で描画できるようになります。

デバイス コンテキストについて詳しくは、 デバイス コンテキストの概要を、 描画についてはペイントと描画の概要を参照してください。

ウィンドウ クラス関数

ウィンドウ クラスとともに使われる関数を次に示します。

GetClassInfo

GetClassLong

GetClassName

GetClassWord

GetWindowLong

GetWindowWord

RegisterClass

SetClassLong

SetClassWord

SetWindowLong

SetWindowWord

UnregisterClass

 

ウィンドウ プロシージャの概要

Microsoft(R) Windows(TM) では、 ウィンドウはすべて関連する「ウィンドウ プロシージャ」を持っています。ウィンドウ プロシージャとは、 あるクラスのすべてのウィンドウに送信またはポストされるすべてのメッセージを処理する関数のことです。ウィンドウの外観と動作は、 これらのメッセージに対するウィンドウ プロシージャの応答によって決まります。

どのようなウィンドウも、 特定のウィンドウ クラスに属します。ウィンドウ クラスにより、 個々のウィンドウに送られてくるメッセージを処理する際に使われるウィンドウ プロシージャが決まります。同じクラスに属するウィンドウは、 すべて同じウィンドウ プロシージャを使用します。たとえば、 システムはコンボ ボックス クラス (COMBOBOX) に対してウィンドウ プロシージャを定義しており、 すべてのコンボ ボックスがそのウィンドウ プロシージャを使用しています。

通常、 アプリケーションは最低1つの新しいウィンドウ クラスと、 それに関連付けられるウィンドウ プロシージャを登録します。クラスを登録した後、 アプリケーションはそのクラスのウィンドウをいくつでも作成でき、 それらはすべて同じウィンドウ プロシージャを使用します。このような動作によってプロシージャのコードの同一部分が複数の呼び出し元から同時に呼び出される可能性があるため、 ウィンドウ プロシージャから転用した共有リソースを修正するときには、 注意しなければなりません。ウィンドウのクラスについて詳しくは、 ウィンドウ クラスの概要を参照してください。

ダイアログ ボックス プロシージャも、 ウィンドウ プロシージャと同じ構造と関数を持っています。このトピックで説明されているウィンドウ プロシージャに関することがらは、 すべてダイアログ ボックス プロシージャにも当てはまります。ダイアログ ボックスについて詳しくは、 ダイアログ ボックスの概要を参照してください。

次の各トピックでは、 Win32のウィンドウ プロシージャについて説明します。

ウィンドウ プロシージャの構造

デフォルト ウィンドウ プロシージャ

ウィンドウ プロシージャのサブクラス化

ウィンドウ プロシージャのスーパクラス化

ウィンドウ プロシージャの設計

ウィンドウ プロシージャへのウィンドウ クラスの関連付け

ウィンドウのサブクラス化

ウィンドウ プロシージャ関数

ウィンドウ プロシージャの構造

ウィンドウ プロシージャは、 4つのパラメータを持ち、 32ビットの符号付き数値を返す関数です。パラメータは、 ウィンドウ ハンドル、 UINT型メッセージID、 WPARAM型およびLPARAM型として宣言されている2つのメッセージ パラメータの4つからなります。オペレーティング システムは、 WPARAM値を32ビット符号なし整数値として、 また、 LPARAM値を32ビット符号付き整数として、 それぞれ定義しています。

ウィンドウ プロシージャの各パラメータについて、 次の表で説明します。

パラメータ説明

hwndメッセージを受け取っているウィンドウのハンドルです。

uMsgメッセージIDです。このIDは、 システムのヘッダー ファイルで定義されている定義済み定数の1つ (WM_CREATEなど) か、 または、 アプリケーション定義のメッセージIDに対応します。

wParamlParamメッセージ パラメータです。このパラメータの意味は、 uMsgパラメータの値により異なります。

メッセージ パラメータにはしばしば情報が格納され、 下位ワードにも上位ワードにも格納されます。Win32アプリケーション プログラミング インターフェイス (API) には、 メッセージ パラメータから情報を抜き出すためのいくつかのマクロが含まれています。たとえば、 LOWORDマクロは、 メッセージ パラメータの下位ワード (ビット0からビット15まで) を抜き出します。このほか、 HIWORDLOBYTE、 およびHIBYTEがあります。

ウィンドウ プロシージャの戻り値は、 LRESULT型として宣言されています。この型は、 32ビットの符号付き数値として定義されているものです。戻り値の意味は個々のメッセージにより異なります。正しい戻り値の意味については、 各メッセージの説明を参照してください。

ウィンドウ プロシージャは再帰的に呼び出すことが可能であるため、 使用するローカル変数の数を最小限に抑えることが大切です。アプリケーションで個々のメッセージを処理するときには、 ウィンドウ プロシージャの外部から関数を呼び出すようにします。このようにすれば、 ローカル変数を必要以上に使わずに済み、 再帰が深くなるためにスタック オーバーフローが起こることも少なくなります。

デフォルト ウィンドウ プロシージャ

デフォルト ウィンドウ プロシージャ関数DefWindowProcは、 すべてのウィンドウが共有する特定の基本的な動作を定義しています。「デフォルト ウィンドウ プロシージャ」は、 ウィンドウに対する最小限度の機能を提供するものです。アプリケーション定義のウィンドウ プロシージャでは、 その中で処理しないメッセージをすべてDefWindowProc関数に渡し、 デフォルト処理されるようにしてください。

ウィンドウ プロシージャのサブクラス化

アプリケーションがウィンドウを作成すると、 オペレーティング システムは、 ウィンドウに送られるメッセージを処理するウィンドウ プロシージャのアドレスなどのウィンドウ固有の情報を格納するために、 メモリ ブロックを割り当てます。Windowsがウィンドウにメッセージを渡す必要が生じたときは、 ウィンドウ固有の情報の中からウィンドウ プロシージャのアドレスを探し出し、 そのプロシージャにメッセージを渡します。

「サブクラス化」とは、 特定のウィンドウに送信またはポストされてくるメッセージがウィンドウで処理される前に、 アプリケーションがそれらを横取りして処理することを可能にするテクニックのことです。ウィンドウをサブクラス化することにより、 アプリケーションはウィンドウの動作の拡張や変更、 または監視が可能になります。アプリケーションは、 システム グローバル クラスに属するエディット コントロールやリスト ボックスなどのウィンドウを含む、 任意のウィンドウをサブクラス化できますが、 これはお勧めしません。たとえば、 アプリケーションはエディット コントロールをサブクラス化して、 コントロールが特定の文字を受け付けなくなるようにすることができます。この方法を使った場合の危険性については、 次の節を参照してください。

アプリケーションでは、 ウィンドウの元のウィンドウ プロシージャのアドレスを新しいウィンドウ プロシージャのアドレスに置き換えることにより、 ウィンドウをサブクラス化します。この新しいウィンドウ プロシージャは「サブクラス プロシージャ」と呼ばれ、 これにより、 サブクラス プロシージャはウィンドウに送信またはポストされてくるメッセージを受け取るようになります。

サブクラス プロシージャは、 メッセージを受け取ったときに、 次の3つの動作を実行することができます。

・元のウィンドウ プロシージャにメッセージをそのまま渡す。

・メッセージを修正してから元のウィンドウ プロシージャにそのメッセージを渡す。

・メッセージを処理し、 元のウィンドウ プロシージャにはそのメッセージを渡さない。

サブクラス プロシージャがメッセージを処理する場合は、 そのメッセージを元のウィンドウ プロシージャに渡す前、 渡した後、 または渡す前と渡した後の両方で処理することができます。

Windowsは、 インスタンスおよびグローバルの2種類のサブクラス化を提供しています。「インスタンスのサブクラス化」では、 アプリケーションはウィンドウの単一インスタンスのウィンドウ プロシージャ アドレスを置き換えます。既存のウィンドウをサブクラス化する場合は、 インスタンスのサブクラス化を使わなければなりません。「グローバルなサブクラス化」では、 アプリケーションはウィンドウ クラスのWNDCLASS構造体の中のウィンドウ プロシージャ アドレスを置き換えます。この後、 このクラスを使って作成されるウィンドウはサブクラス プロシージャのアドレスを持ちますが、 そのクラスの既存のウィンドウには影響を与えません。

インスタンスのサブクラス化

ウィンドウのインスタンスをサブクラス化するには、 SetWindowLong関数を使います。アプリケーションは、 GWL_WNDPROCフラグ、 サブクラス化するウィンドウのハンドル、 およびサブクラス プロシージャのアドレスを、 SetWindowLongに渡します。サブクラス プロシージャはアプリケーションのモジュールかダイナミック リンク ライブラリ (DLL) の中に常駐させることができます。アプリケーションは、 アプリケーションやDLLのモジュール定義ファイル (.DEF) の中でサブクラス プロシージャの名前を列挙しなければなりません。

SetWindowLongは、 ウィンドウの元のウィンドウ プロシージャのアドレスを返します。アプリケーションはこのアドレスを保存しておく必要があり、 後続のCallWindowProc呼び出しの中でそのアドレスを使い、 横取りしたメッセージを元のウィンドウ プロシージャに渡します。また、 アプリケーションは、 ウィンドウからサブクラスを削除するときにも元のウィンドウ プロシージャ アドレスを必要とします。これには、 SetWindowLongをもう一度呼び出し、 GWL_WNDPROCフラグ、 ウィンドウ ハンドルとともに、 元のウィンドウ プロシージャ アドレスを渡します。

アプリケーションはシステム内の任意のウィンドウをサブクラス化できますが、 アプリケーションが所有していないウィンドウをサブクラス化する場合は、 サブクラス プロシージャの中でウィンドウの元の動作を破棄することがないようにしなければなりません。アプリケーションはウィンドウを制御しません。このため、 そのウィンドウに関する情報はウィンドウのオーナーが今後変更を加える可能性があり、 当てにすることはできません。

補足ウィンドウ バイトや補足クラス バイトは、 その正確な意味や、 元のウィンドウ プロシージャがそれらのバイトをどのように使用しているかがわからない場合には、 それらをアプリケーションで使わないようにしてください。また、 わかっている場合でも、 アプリケーションがそのウィンドウを所有しない場合には使わないでください。ほかのアプリケーションがウィンドウを所有し、 そのオーナーが補足バイトの一部を変更している場合に、 その補足ウィンドウ バイトを使うと、 サブクラス プロシージャの実行に失敗する場合があります。以上のような理由から、 システム グローバルなコントロール クラスに属するウィンドウはサブクラス化しないでください。Windowsはシステム グローバル クラスを所有しており、 それらのコントロールの意味は従来のバージョンから変更されている可能性があります。アプリケーションがシステム グローバル クラスに属するウィンドウをサブクラス化してしまうと、 新しいバージョンのWindowsがリリースされたときにアプリケーションを更新しなければならなくなることがあります。

インスタンスのサブクラス化はウィンドウの作成後に発生するため、 ウィンドウをサブクラス化しているアプリケーションはそのウィンドウに補足バイトを追加することができません。ウィンドウをサブクラス化するアプリケーションは、 ウィンドウのプロパティ リストを使い、 サブクラス化されたウィンドウのインスタンス用に必要なデータを格納してください。ウィンドウ プロパティについて詳しくは、 ウィンドウ プロパティの概要を参照してください。

アプリケーションがすでにサブクラス化されているウィンドウをサブクラス化する場合は、 実行された順序とは逆の順序でサブクラスを削除しなければなりません。逆順に削除しなかった場合、 修復不可能なシステム エラーが発生することがあります。

グローバルなサブクラス化

ウィンドウ クラスをグローバルにサブクラス化するには、 アプリケーションはそのクラスのウィンドウのハンドルを取得しなければなりません。また、 サブクラスを削除する際にもこのハンドルが必要になります。ハンドルを取得するには、 通常はサブクラス化するクラスの隠し (非表示) ウィンドウを作成します。ハンドルを取得した後、 そのハンドルと、 GCL_WNDPROCフラグ、 およびサブクラス プロシージャのアドレスを指定してSetClassLong関数を呼び出します。SetClassLong関数は、 元のクラス用のウィンドウ プロシージャのアドレスを返します。

元のウィンドウ プロシージャ アドレスは、 インスタンスのサブクラス化における使われ方と同じように、 グローバルなサブクラス化でも使われます。サブクラス プロシージャは、 CallWindowProc関数を呼び出して元のウィンドウ プロシージャにメッセージを渡します。アプリケーションは、 元のウィンドウ プロシージャのアドレス、 GCL_WNDPROCフラグ、 およびサブクラス化したクラスのウィンドウ ハンドルを指定してSetClassLongを再び呼び出し、 ウィンドウ クラスからサブクラスを削除します。コントロール クラスをグローバルにサブクラス化しているアプリケーションは、 その終了時にサブクラスを削除しなければなりません。削除しない場合、 修復不可能なシステム エラーが発生することがあります。

グローバルなサブクラス化には、 インスタンスのサブクラス化と同じ制限のほかに、 さらに制限事項があります。すなわち、 アプリケーションは、 元のウィンドウ プロシージャが補足バイトをどのように使用しているかがわからない場合には、 それらをクラス用やウィンドウ インスタンス用として使わないようにしてください。アプリケーションがデータをウィンドウに関連付ける必要がある場合には、 ウィンドウ プロパティを使ってください。

アプリケーションは、 システム グローバル クラスをグローバルにサブクラス化してはいけません。複数のアプリケーションがコントロール クラスをグローバルにサブクラス化した場合、 修復不可能なシステム エラーが発生することがあります。コントロール クラスをグローバルにサブクラス化することで恩恵を受けられるようなアプリケーションは、 次のトピックで説明するスーパクラス化のテクニックを使ってください。

ウィンドウ プロシージャのスーパクラス化

「スーパクラス化」とは、 既存のクラスの基本的な機能に加え、 アプリケーションが提供する拡張機能をも持ち合わせた、 新しいウィンドウ クラスを作成するテクニックのことです。スーパクラスは、 既存のウィンドウ クラス (「基本クラス」と呼ばれる) をベースにして構築されます。基本クラスは、 しばしばエディット コントロールなどのシステム グローバル ウィンドウ クラスとなることがありますが、 どのようなウィンドウ クラスでも基本クラスにすることができます。

注:システム グローバルなSCROLLBARクラスはスーパクラス化しないでください。

スーパクラスは、 スーパクラス プロシージャと呼ばれる独自のウィンドウ プロシージャを持ちます。「スーパクラス プロシージャ」は、 次の3つの動作を実行することができます。

・元のウィンドウ プロシージャにメッセージをそのまま渡す。

・メッセージを修正してから元のウィンドウ プロシージャにそのメッセージを渡す。

・メッセージを処理し、 元のウィンドウ プロシージャにはそのメッセージを渡さない。

スーパクラス プロシージャがメッセージを処理する場合は、 そのメッセージを元のウィンドウ プロシージャに渡す前、 渡した後、 または渡す前と渡した後の両方で処理することができます。

スーパクラス プロシージャはサブクラス プロシージャとは異なり、 ウィンドウ作成メッセージ (WM_NCCREATEWM_CREATEなど) を処理できます。しかし、 基本クラス ウィンドウ プロシージャがその初期化処理を実行できるようにするため、 それらのメッセージもまた元の基本クラス ウィンドウ プロシージャに渡さなければなりません。

ウィンドウ クラスをスーパクラス化するには、 まずGetClassInfo関数を呼び出して基本クラスに関する情報を取得します。GetClassInfoでは、 基本クラスのWNDCLASS構造体の値を新しいWNDCLASS構造体に設定します。次に、 アプリケーション自身のインスタンス ハンドルをWNDCLASS構造体のhInstanceメンバにコピーし、 スーパクラスの名前をlpszClassNameメンバにコピーします。基本クラスがメニューを持っている場合は、 それと同じメニューIDを持つ新しいメニューを用意し、 メニュー名をlpszMenuNameメンバにコピーする必要があります。しかし、 スーパクラス プロシージャがWM_COMMANDメッセージを処理し、 それを基本クラスのウィンドウ プロシージャに渡さない場合には、 対応するメニューIDをメニューに付ける必要はありません。GetClassInfo関数は、 WNDCLASS構造体のlpszMenuNamelpszClassName、 またはhInstanceの各メンバの値は返しません。

また、 アプリケーションはWNDCLASS構造体のlpfnWndProcメンバも設定する必要があります。GetClassInfo関数は、 基本クラスの元のウィンドウ プロシージャのアドレスをこのメンバに設定します。このアドレスは、 元のウィンドウ プロシージャにメッセージを渡すために、 必ず保存しておきます。そして、 スーパクラス プロシージャのアドレスをlpfnWndProcメンバにコピーします。必要ならば、 WNDCLASS構造体のほかのメンバも修正できます。WNDCLASS構造体の設定が終わったら、 アプリケーションは構造体のアドレスをRegisterClass関数に渡し、 スーパクラスを登録します。このようにして、 スーパクラス化を使ってウィンドウを作成することができます。

スーパクラス化は新しいウィンドウ クラスを登録することになるので、 アプリケーションは補足クラス バイトや補足ウィンドウ バイトに追加することができます。スーパクラスでは、 インスタンス サブクラスやグローバル サブクラスと同じ理由で、 元の基本クラスやウィンドウの補足バイトを使うことはできません。また、 アプリケーションが独自に使うために、 クラスまたはウィンドウ インスタンスのどちらかに補足バイトを追加した場合は、 元の基本クラスが使用する補足バイト数からの相対バイトを参照するようにしなければなりません。基本クラスが使用するバイト数はその基本クラスのバージョンごとに変わる場合があるため、 スーパクラス自身の補足バイトの開始オフセットもまた、 そのバージョンごとに変わる場合があります。

ウィンドウ プロシージャの使用

以下に示す処理をクリックすると、 その処理の実行方法が表示されます。

ウィンドウ プロシージャの設計

ウィンドウ プロシージャへのウィンドウ クラスの関連付け

ウィンドウのサブクラス化

ウィンドウ プロシージャの設計

次の例は、 典型的なウィンドウ プロシージャの構造を示したものです。ウィンドウ プロシージャでは、 switch文の中で、 別々のcase文で処理される個々のメッセージが引数として使われています。各case文では、 メッセージごとに特定の値を返していることに注意してください。ウィンドウ プロシージャで処理しないメッセージは、 DefWindowProc関数に渡されます。

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)
HWND hwnd;      /* handle of the window     */
UINT uMsg;      /* message identifier       */
WPARAM wParam;  /* first message parameter  */
LPARAM lParam;  /* second message parameter */
{

    switch (uMsg) {
        case WM_CREATE:
            /* Initialize the window. */
            return 0;

        case WM_PAINT:
            /* Paint the window's client area. */
            return 0;

        case WM_SIZE:
            /* Set the size and position of the window. */
            return 0;
        case WM_DESTROY:
            /* Clean up window-specific data objects. */
            return 0;        .
        . /* Process other messages. */
        .
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

ウィンドウ プロシージャでは、 少なくともウィンドウ自身を描画させるためにWM_PAINTメッセージを処理するようにします。通常は、 マウスやキーボードからのメッセージも同様に処理します。作成するウィンドウ プロシージャでメッセージを処理するかどうかを決める際には、 個々のメッセージの説明を参考にしてください。

アプリケーションは、 メッセージ処理の一部としてDefWindowProc関数を呼び出すことができます。この場合、 メッセージ パラメータを修正してからメッセージをDefWindowProcに渡したり、 またはアプリケーションで独自の操作を実行してからデフォルトの処理を続けることができます。

ダイアログ ボックス プロシージャの場合は、 WM_CREATEメッセージの代わりにWM_INITDIALOGメッセージを受け取り、 未処理のメッセージをDefDlgProc関数に渡しません。それ以外の点は、 ウィンドウ プロシージャとまったく同じです。ダイアログ ボックスについて詳しくは、 ダイアログ ボックスの概要を参照してください。

ウィンドウ プロシージャへのウィンドウ クラスの関連付け

クラスを登録するときは、 ウィンドウ プロシージャにウィンドウ クラスを関連付けます。WNDCLASS構造体にはクラスに関する情報を設定し、 lpfnWndProcメンバにはウィンドウ プロシージャのアドレスを指定します。クラスを登録するには、 WNDCLASS構造体のアドレスをRegisterClass関数に渡します。一度ウィンドウ クラスを登録すると、 そのクラスを使って新しく作成された各ウィンドウが、 ウィンドウ プロシージャに自動的に関連付けられます。

次の例は、 前述の例で示したウィンドウ プロシージャにウィンドウ クラスを関連付ける方法を示したものです。

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

    /* Register the main window class. */

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC) MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hinstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "MainMenu";
    wc.lpszClassName = "MainWindowClass";

    if (!RegisterClass(&wc))
       return FALSE;
    . /* Process other messages. */
    .
}

ウィンドウのサブクラス化

ウィンドウのインスタンスをサブクラス化するには、 GWL_WNDPROCフラグ、 サブクラス化するウィンドウのハンドル、 およびサブクラス プロシージャを指すポインタを指定して、 SetWindowLong関数を呼び出します。SetWindowLong関数は元のウィンドウ プロシージャを指すポインタを返します。このポインタは、 後で元のプロシージャにメッセージを渡すときに使います。

次の例は、 ダイアログ ボックス内のエディット コントロールのインスタンスをサブクラス化する方法を示したものです。サブクラス ウィンドウ プロシージャでは、 エディット コントロールが入力フォーカスを持つときに、 常にEnterキーやTabキーなどからのすべてのキーボード入力を受け取ることが可能になります。

WNDPROC wpOrigEditProc;

LRESULT APIENTRY EditBoxProc(hwndDlg, uMsg, wParam, lParam)
HWND hwndDlg;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
    HWND hwndEdit;
    switch(uMsg) {
        case WM_INITDIALOG:
            /* Retrieve the handle of the edit control. */
            hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
            /* Subclass the edit control. */
            wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,
                GWL_WNDPROC, (LONG) EditSubclassProc);            .
            . /* Continue the initializatio procedure. */            .
            return TRUE;
        case WM_DESTROY:
            /* Remove the subclass from the edit control. */
            SetWindowLong(hwndEdit, GWL_WNDPROC,
                (LONG) wpOrigEditProc);            .
            . /* Continue the cleanup procedure. */           .
            break;
    }
    return FALSE;
        UNREFERENCED_PARAMETER(lParam);
}
/*
 * Subclass procedure
 */
LRESULT APIENTRY EditSubclassProc(hwnd, uMsg, wParam, lParam)
HWND hwnd;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
    if (uMsg == WM_GETDLGCODE)
        return DLGC_WANTALLKEYS;

    return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
        wParam, lParam);
}

ウィンドウ プロシージャ関数

ウィンドウ クラスとともに使われる関数を、 次に示します。

CallWindowProc

DefWindowProc

WindowProc

 

ウィンドウ プロパティの概要

「ウィンドウ プロパティ」とは、 SetProp関数によってウィンドウに割り当てられる任意のデータのことです。通常、 ウィンドウ プロパティはウィンドウ固有のデータのハンドルですが、 任意の32ビット値になることもあります。ウィンドウ プロパティは、 それぞれ文字列名により識別されます。

ウィンドウ プロパティは、 サブクラス化されたウィンドウ、 またはマルチ ドキュメント インターフェイス (MDI) アプリケーション内のウィンドウに、 データを関連付けるために使われるのがふつうです。いずれの場合にも、 CreateWindow関数やクラス構造体で指定する補足バイトを使う方法と比べて、 次のような利点があります。

・アプリケーションは、 利用できる補足バイトのバイト数やそのメモリ領域の使われ方を知らない場合がある。ウィンドウ プロパティを使えば、 アプリケーションは補足バイトにアクセスすることなく、 データをウィンドウに関連付けることができる。

・アプリケーションは、 補足バイトにアクセスするためにオフセットを使わなければならない。しかし、 ウィンドウ プロパティへは、 オフセットではなく文字列識別子を使ってアクセスできる。

サブクラス化について、 詳しくはウィンドウ プロシージャの概要を、 MDIウィンドウについてはマルチ ドキュメント インターフェイスの概要を参照してください。

Microsoft(R) Win32(TM) アプリケーション プログラミング インターフェイス (API) では、 アプリケーションでウィンドウ プロパティを利用できるようにするための関数がいくつか提供されています。SetProp関数は、 ウィンドウ プロパティとその文字列識別子をウィンドウに割り当てます。GetProp関数は、 指定された文字列により識別されるウィンドウ プロパティを取得します。RemoveProp関数は、 ウィンドウとウィンドウ プロパティとの間の関連付けを破棄しますが、 データ自身は破棄しません。EnumProps関数およびEnumPropsEx関数は、 アプリケーション定義のコールバック関数を使って、 ウィンドウの持つプロパティをすべて列挙します。EnumPropsExには、 コールバック関数で使われるアプリケーション定義のデータを指定するための補足パラメータがあります。

次のトピックでは、 ウィンドウ プロパティについて説明しています。

ウィンドウ プロパティの追加

ウィンドウ プロパティの取得

指定されたウィンドウのウィンドウ プロパティの列挙

ウィンドウ プロパティの削除

ウィンドウ プロパティ関数

ウィンドウ プロパティの追加

次の例では、 アイコンをロードしてからマウス カーソルをロードし、 バッファ用のメモリを割り当てています。ここでは、 その後にSetProp関数を呼び出し、 取得したアイコン、 マウス カーソル、 およびメモリの各ハンドルを、 hwndSubclassの値により識別されるウィンドウのウィンドウ プロパティとして割り当てています。各プロパティは、 PROP_ICON、 PROP_CURSOR、 PROP_BUFFERの各文字列により識別されます。

#define BUFFER 4096
HINSTANCE hinst;       /* handle of current instance     */
HWND hwndSubclass;     /* handle of a subclassed window */
HANDLE hIcon, hCursor;
HGLOBAL hMem;
char *lpMem;
TCHAR tchPath[] = "c:\\winnt\\samples\\winprop.c";
/* Load resources. */
hIcon = LoadIcon(hinst, MAKEINTRESOURCE(400));
hCursor = LoadCursor(hinst, MAKEINTRESOURCE(220));
/* Allocate and fill a memory buffer. */
hMem = GlobalAlloc(GPTR, BUFFER);
lpMem = GlobalLock(hMem);
lstrcpy(lpMem, tchPath);
GlobalUnlock(hMem);
/* Set the window properties for hwndSubclass. */

SetProp(hwndSubclass, "PROP_ICON", hIcon);
SetProp(hwndSubclass, "PROP_CURSOR", hCursor);
SetProp(hwndSubclass, "PROP_BUFFER", hMem); 

ウィンドウ プロパティの取得

ウィンドウは、 自分のウィンドウ プロパティ データを識別するハンドルを作成し、 そのデータを任意の目的で使用することができます。次の例では、 GetProp関数を使い、 PROP_ICON、 PROP_CURSOR、 PROP_BUFFERがそれぞれ識別するウィンドウ プロパティを識別するハンドルを取得しています。ここでは、 新しいプロパティ データを取得した後に、 メモリ バッファ、 マウス カーソル、 およびアイコンの内容をそれぞれウィンドウのクライアント領域に表示させています。

#define PATHLENGTH 256

HWND hwndSubclass;     /* handle of a subclassed window */
HANDLE hIconProp, hCursProp;
HGLOBAL hMemProp;
char *lpFilename;
TCHAR tchBuffer[PATHLENGTH];
int nSize;
HDC hdc;

/* Get the window properties, then use the data. */

hIconProp = (HICON) GetProp(hwndSubclass, "PROP_ICON");
TextOut(hdc, 10, 40, "PROP_ICON", 9);
DrawIcon(hdc, 90, 40, hIconProp);

hCursProp = (HCURSOR) GetProp(hwndSubclass, "PROP_CURSOR");
TextOut(hdc, 10, 85, "PROP_CURSOR", 9);
DrawIcon(hdc, 110, 85, hCursProp);

hMemProp = (HGLOBAL) GetProp(hwndSubclass, "PROP_BUFFER");
lpFilename = GlobalLock(hMemProp);
nSize = sprintf(tchBuffer,
    "Path to file: %s", lpFilename);
TextOut(hdc, 10, 10, tchBuffer, nSize); 

指定されたウィンドウのウィンドウ プロパティの列挙

次の例では、 EnumPropsEx関数により、 アプリケーション定義のhwndSubclass変数が識別するウィンドウのウィンドウ プロパティの文字列IDを列挙しています。この関数はアプリケーション定義のコールバック関数WinPropProcを使って、 ウィンドウのクライアント領域内に文字列を表示させています。

 
EnumPropsEx(hwndSubclass, WinPropProc, NULL);

/*
 * WinPropProc is an application-defined callback function that
 * lists a window property.
 */

BOOL CALLBACK WinPropProc(
    HWND hwndSubclass,         /* handle of window with property */
    LPCSTR lpszString,         /* property string or atom        */
    HANDLE hData)              /* data handle                    */
{
    static int nProp = 1;    /* property counter           */
    TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */
    int nSize;               /* size of string in buffer   */
    HDC hdc;                 /* device-context handle      */

    hdc = GetDC(hwndSubclass);

    /* Display the window property string in the client area. */

    nSize = sprintf(tchBuffer, "WinProp %d: %s", nProp++,
        lpszString);
    TextOut(hdc, 10, nProp * 20, tchBuffer, nSize);

    ReleaseDC(hwndSubclass, hdc);

    return TRUE;
} 

ウィンドウ プロパティの削除

ウィンドウを破棄するときは、 設定されているウィンドウ プロパティをすべて破棄しなければなりません。次の例では、 EnumPropsEx関数とアプリケーション定義のコールバック関数DelPropProcを使い、 アプリケーション定義のhwndSubclass変数により識別されるウィンドウに関連付けられているプロパティを破棄しています。ここでは、 RemoveProp関数を使ったコールバック関数の例も合わせて示します。

 

case WM_DESTROY:

    EnumPropsEx(hwndSubclass, DelPropProc, NULL);

    PostQuitMessage(0);
    break;

    .
    .
    .
/*
 * DelPropProc is an application-defined callback function that
 * deletes a window property.
 */

BOOL CALLBACK DelPropProc(
    HWND hwndSubclass,         /* handle of window with property */
    LPCSTR lpszString,         /* property string or atom        */
    HANDLE hData)              /* data handle                    */
{
    RemoveProp(hwndSubclass, lpszString);

    return TRUE;
}

ウィンドウ プロパティ関数

ウィンドウ プロパティとともに使われる関数を、 次に示します。

EnumProps

EnumPropsEx

GetProp

PropEnumProc

PropEnumProcEx

RemoveProp

SetProp

 

▲ページトップに戻る

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