次の方法で共有


ウィンドウ プロシージャについて

各ウィンドウは、特定のウィンドウ クラスのメンバーです。 window クラスは、個々のウィンドウがそのメッセージを処理するために使用する既定のウィンドウ プロシージャを決定します。 同じクラスに属するすべてのウィンドウは、同じ既定のウィンドウ プロシージャを使用します。 たとえば、コンボ ボックス クラス (COMBOBOX) のウィンドウ プロシージャがシステムによって定義されます。すべてのコンボ ボックスは、そのウィンドウ プロシージャを使用します。

アプリケーションは通常、少なくとも 1 つの新しいウィンドウ クラスとそれに関連付けられているウィンドウ プロシージャを登録します。 クラスを登録すると、アプリケーションはそのクラスの多くのウィンドウを作成でき、そのすべてが同じウィンドウ プロシージャを使用します。 これは、複数のソースが同じコードを同時に呼び出すことができることを意味するため、ウィンドウ プロシージャから共有リソースを変更するときは注意する必要があります。 詳細については、「ウィンドウ クラス」を参照してください。

ダイアログ ボックスのウィンドウ プロシージャ (ダイアログ ボックス プロシージャと呼ばれます) は、通常のウィンドウ プロシージャと同様の構造と機能を持ちます。 このセクションのウィンドウ プロシージャを参照するすべてのポイントは、ダイアログ ボックス のプロシージャにも適用されます。 詳細については、「 ダイアログ ボックス」を参照してください。

このセクションでは、次のトピックについて説明します。

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

ウィンドウ プロシージャは、4 つのパラメーターを持ち、符号付き値を返す関数です。 パラメーターは、ウィンドウ ハンドル、 UINT メッセージ識別子、および WPARAM および LPARAM データ型で宣言された 2 つのメッセージ パラメーターで構成されます。 詳細については、「 WindowProc」を参照してください。

多くの場合、メッセージ パラメーターには、低順序と高次の両方の単語の情報が含まれます。 アプリケーションでメッセージ パラメーターから情報を抽出するために使用できるマクロがいくつかあります。 たとえば、 LOWORD マクロは、メッセージ パラメーターから下位ワード (ビット 0 から 15) を抽出します。 その他のマクロには、 HIWORDLOBYTEHIBYTE マクロがあります。

戻り値の解釈は、特定のメッセージによって異なります。 適切な戻り値を決定するには、各メッセージの説明を参照してください。

ウィンドウ プロシージャを再帰的に呼び出す可能性があるため、使用するローカル変数の数を最小限に抑える必要があります。 個々のメッセージを処理する場合、アプリケーションは、ローカル変数を過剰に使用しないように、ウィンドウ プロシージャの外部で関数を呼び出す必要があります。これにより、深い再帰中にスタックがオーバーフローする可能性があります。

既定のウィンドウ プロシージャ

既定のウィンドウ プロシージャ関数 DefWindowProc は、すべてのウィンドウで共有される特定の基本的な動作を定義します。 既定のウィンドウ プロシージャは、ウィンドウの最小限の機能を提供します。 アプリケーション定義ウィンドウ プロシージャは、既定の処理のために DefWindowProc 関数に処理しないメッセージを渡す必要があります。

Window プロシージャのサブクラス化

アプリケーションがウィンドウを作成すると、ウィンドウのメッセージを処理するウィンドウ プロシージャのアドレスなど、ウィンドウに固有の情報を格納するためのメモリ ブロックがシステムによって割り当てられます。 システムは、ウィンドウにメッセージを渡す必要がある場合、ウィンドウ固有の情報を検索してウィンドウ プロシージャのアドレスを検索し、そのプロシージャにメッセージを渡します。

サブクラス化 は、特定のウィンドウに送信または投稿されたメッセージを処理する前に、アプリケーションがメッセージをインターセプトして処理できるようにする手法です。 ウィンドウをサブクラス化することで、アプリケーションはウィンドウの動作を拡張、変更、監視できます。 アプリケーションは、編集コントロールやリスト ボックスなど、システム グローバル クラスに属するウィンドウをサブクラス化できます。 たとえば、アプリケーションは編集コントロールをサブクラス化して、コントロールが特定の文字を受け入れないようにすることができます。 ただし、別のアプリケーションに属するウィンドウまたはクラスをサブクラス化することはできません。 すべてのサブクラス化は、同じプロセス内で実行する必要があります。

アプリケーションは、ウィンドウの元のウィンドウ プロシージャのアドレスをサブクラス プロシージャと呼ばれる新しいウィンドウ プロシージャのアドレスに置き換えることで、ウィンドウを サブクラス化します。 その後、サブクラス プロシージャは、ウィンドウに送信または投稿されたメッセージを受信します。

サブクラス プロシージャは、メッセージの受信時に 3 つのアクションを実行できます。メッセージを元のウィンドウ プロシージャに渡したり、メッセージを変更して元のウィンドウ プロシージャに渡したり、メッセージを処理して元のウィンドウ プロシージャに渡したりすることはできません。 サブクラス プロシージャがメッセージを処理する場合は、メッセージを元のウィンドウ プロシージャに渡す前、後、またはその両方で処理できます。

システムには、 インスタンスグローバルの 2 種類のサブクラス化が用意されています。 インスタンス サブクラス化では、アプリケーションはウィンドウの単一インスタンスのウィンドウ プロシージャ アドレスを置き換えます。 アプリケーションでは、インスタンス サブクラス化を使用して既存のウィンドウをサブクラス化する必要があります。 グローバル サブクラス化では、アプリケーションはウィンドウ クラスの WNDCLASSEX 構造体内のウィンドウ プロシージャのアドレスを置き換えます。 クラスで作成された後続のウィンドウはすべてサブクラス プロシージャのアドレスを持ちますが、クラスの既存のウィンドウは影響を受けません。

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

アプリケーションは 、SetWindowLongPtr 関数を使用してウィンドウのインスタンスをサブクラス化します。 アプリケーションは 、GWL_WNDPROC フラグ、サブクラス化するウィンドウへのハンドル、およびサブクラス プロシージャのアドレスを SetWindowLongPtr に渡します。 サブクラス プロシージャは、アプリケーションの実行可能ファイルまたは DLL のいずれかに配置できます。

GWL_WNDPROC フラグを渡すと、SetWindowLongPtr はウィンドウの元のウィンドウ プロシージャのアドレスを返します。 このアドレスは、後続の CallWindowProc 関数の呼び出しで使用して保存し、インターセプトされたメッセージを元のウィンドウ プロシージャに渡す必要があります。 アプリケーションには、ウィンドウからサブクラスを削除するための元のウィンドウ プロシージャ アドレスも必要です。 サブクラスを削除するために、アプリケーションは SetWindowLongPtr をもう一度呼び出し、元のウィンドウ プロシージャのアドレスを GWL_WNDPROC フラグとハンドルをウィンドウに渡します。

システムはシステム・グローバル・クラスを所有しており、コントロールの側面はシステムのあるバージョンから次のバージョンに変わる可能性があります。 アプリケーションがシステム グローバル クラスに属するウィンドウをサブクラス化する必要がある場合、開発者は、システムの新しいバージョンがリリースされたときにアプリケーションを更新する必要があります。

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

アプリケーションがサブクラス化されたウィンドウをサブクラス化するときは、実行された逆の順序でサブクラスを削除する必要があります。 削除順序が逆でない場合は、回復不能なシステム エラーが発生する可能性があります。

グローバル サブクラス化

ウィンドウ クラスをグローバルにサブクラス化するには、アプリケーションにクラスのウィンドウへのハンドルが必要です。 アプリケーションには、サブクラスを削除するためのハンドルも必要です。 ハンドルを取得するために、アプリケーションは通常、サブクラス化するクラスの非表示ウィンドウを作成します。 ハンドルを取得した後、アプリケーションは SetClassLongPtr 関数を呼び出し、ハンドル、 GCL_WNDPROC フラグ、およびサブクラス プロシージャのアドレスを指定します。 SetClassLongPtr は 、クラスの元のウィンドウ プロシージャのアドレスを返します。

元のウィンドウ・プロシージャー・アドレスは、インスタンス・サブクラス化で使用されるのと同じ方法でグローバル・サブクラス化で使用されます。 サブクラス プロシージャは 、CallWindowProc を呼び出して元のウィンドウ プロシージャにメッセージを渡します。 アプリケーションは、元のウィンドウ プロシージャのアドレス、GCL_WNDPROC フラグ、およびサブクラス化されているクラスのウィンドウへのハンドルを指定して、SetClassLongPtr を再度呼び出すことによって、ウィンドウ クラスからサブクラスを削除します。 コントロール クラスをグローバルにサブクラス化するアプリケーションは、アプリケーションが終了したときにサブクラスを削除する必要があります。そうしないと、回復不能なシステム エラーが発生する可能性があります。

グローバル サブクラス化には、インスタンス サブクラス化と同じ制限と、いくつかの追加の制限があります。 アプリケーションでは、元のウィンドウ プロシージャで使用される方法を正確に知らなくても、クラスまたはウィンドウ インスタンスの余分なバイトを使用しないでください。 アプリケーションでデータをウィンドウに関連付ける必要がある場合は、ウィンドウのプロパティを使用する必要があります。

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

スーパークラス は、アプリケーションが既存のクラスの基本機能に加えて、アプリケーションによって提供される拡張機能を使用して新しいウィンドウ クラスを作成できるようにする手法です。 スーパークラスは、 基底クラスと呼ばれる既存のウィンドウ クラスに基づいています。 多くの場合、基本クラスは編集コントロールなどのシステム グローバル ウィンドウ クラスですが、任意のウィンドウ クラスを使用できます。

スーパークラスには、スーパークラス プロシージャと呼ばれる独自のウィンドウ プロシージャがあります。 スーパークラス プロシージャは、メッセージの受信時に 3 つのアクションを実行できます。メッセージを元のウィンドウ プロシージャに渡したり、メッセージを変更して元のウィンドウ プロシージャに渡したり、メッセージを処理して元のウィンドウ プロシージャに渡したりすることはできません。 スーパークラス プロシージャがメッセージを処理する場合は、メッセージを元のウィンドウ プロシージャに渡す前、後、またはその両方で処理できます。

サブクラス プロシージャとは異なり、スーパークラス プロシージャはウィンドウ作成メッセージ (WM_NCCREATEWM_CREATE など) を処理できますが、基底クラス ウィンドウ プロシージャが初期化プロシージャを実行できるように、元の基底クラス ウィンドウ プロシージャに渡す必要もあります。

ウィンドウ クラスをスーパークラス化するために、アプリケーションは最初に GetClassInfoEx 関数を呼び出して基底クラスに関する情報を取得します。 GetClassInfoEx、WNDCLASSEX 構造体に基底クラスの WNDCLASSEX 構造体の値を格納します。 次に、アプリケーションは独自のインスタンス ハンドルを WNDCLASSEX 構造体の hInstance メンバーにコピーし、スーパークラスの名前を lpszClassName メンバーにコピーします。 基底クラスにメニューがある場合、アプリケーションは同じメニュー識別子を持つ新しいメニューを提供し、メニュー名を lpszMenuName メンバーにコピーする必要があります。 スーパークラスプロシージャが WM_COMMAND メッセージを処理し、それを基底クラスのウィンドウプロシージャに渡さない場合、メニューには対応する識別子が必要ありません。 GetClassInfoEx は、WNDCLASSEX 構造体の lpszMenuNamelpszClassName、または hInstance メンバーを返しません。

アプリケーションでは、WNDCLASSEX 構造体の lpfnWndProc メンバーも設定する必要があります。 GetClassInfoEx 関数は、このメンバーに、クラスの元のウィンドウ プロシージャのアドレスを入力します。 アプリケーションはこのアドレスを保存し、メッセージを元のウィンドウ・プロシージャーに渡してから、スーパークラス・プロシージャーのアドレスを lpfnWndProc メンバーにコピーする必要があります。 アプリケーションは、必要に応じて 、WNDCLASSEX 構造体の他のメンバーを変更できます。 WNDCLASSEX 構造体がいっぱいになると、アプリケーションは RegisterClassEx 関数に構造体のアドレスを渡すことによってスーパークラスを登録します。 その後、スーパークラスを使用してウィンドウを作成できます。

スーパークラスは新しいウィンドウクラスを登録するため、アプリケーションは余分なクラスバイトと余分なウィンドウバイトの両方に追加できます。 スーパークラスは、インスタンスサブクラスまたはグローバルサブクラスがそれらを使用してはならないのと同じ理由で、基底クラスまたはウィンドウに元の余分なバイトを使用してはなりません。 また、アプリケーションがクラスまたはウィンドウ インスタンスに使用するために余分なバイトを追加する場合は、元の基底クラスで使用される余分なバイト数に対して余分なバイトを参照する必要があります。 基底クラスで使用されるバイト数は基底クラスのバージョンによって異なる場合があるため、スーパークラス独自の余分なバイトの開始オフセットも、基底クラスの 1 つのバージョンから次のバージョンに異なる場合があります。