Windows APIでウィンドウのサブクラス化

naohiro19
記事: 256
登録日時: 14年前
住所: 愛知県

Windows APIでウィンドウのサブクラス化

投稿記事 by naohiro19 » 11年前

Windows APIで独自のウィンドウのサブクラス化したいと思って調べると「SetWindowSubclass」関数なるものがあります。「猫でもわかるプログラミング」のSDK編の「第37章 ウィンドウのサブクラス化 その2」で紹介している方法よりも使えます。

これを使うには
  1. 「プロジェクト」の「プロパティ」を開いて「リンカー」の入力にある「追加の依存ファイル」で「comctl32.lib」を入力します。
  2. ソースファイルもしくはヘッダーファイルで「#include 」を入力すれば使えるようになります。
  3. WNDCLASS 構造体またはWNDCLASSEX構造体の「lpfnWndProc」に「DefWindowProc」を渡します。
  4. ウィンドウが作成された直後にSetWindowSubclass関数を呼び出す

CODE:

BOOL SetWindowSubclass(
  _In_  HWND hWnd, 					//サブクラス化するウィンドウハンドル                    
  _In_  SUBCLASSPROC pfnSubclass, 	//サブクラス化するコールバック関数
  _In_  UINT_PTR uIdSubclass, 		//サブクラスのID
  _In_  DWORD_PTR dwRefData			//サブクラスのIDと異なる値(通常は0を指定すればOK)
);
コールバック関数関数はCommCtrl.hに以下のように定義されています。

CODE:

//
// subclassing stuff
//
typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
よくウィンドウプロシージャーでは

CODE:

LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam); 
のように定義しているように自由にユーザーがサブクラス化のプロシージャの名前を付けられるようになっています。

以下がメインウィンドウをサブクラス化したときのコールバック関数になります。WinSubclassProcをSetWindowSubclassの第2引数に渡します。

CODE:

LRESULT WinSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM, LPARAM lParam, UINT_PTR uidSubClass ,DWORD_PTR dwRefData)
{
	switch(msg){
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefSubclassProc(hWnd, msg, wParam, lParam, uidSubClass, dwRefData);
	}
	return 0;
}
最後に編集したユーザー naohiro19 on 2014年7月18日(金) 19:35 [ 編集 1 回目 ]

アバター
へろりくしょん
記事: 92
登録日時: 14年前

Re: Windows APIでウィンドウのサブクラス化

投稿記事 by へろりくしょん » 11年前

便利ですよね。 NT4.0時代には無かった API です。

出てきたのは12~13年ぐらい前でしょうか。
Windows 2000ぐらいから?

それはそうと、猫でも分かる人のコードって大分アレだと思うのですが、なぜだか人気ありますね。
かのH氏のファンとか言う方々もいらっしゃるようなので、驚きには価しませんが。

YuO
記事: 947
登録日時: 14年前

Re: Windows APIでウィンドウのサブクラス化

投稿記事 by YuO » 11年前

naohiro19 さんが書きました:WNDCLASS 構造体またはWNDCLASSEX構造体の「lpfnWndProc」に「DefWindowProc」を渡します。
SetWindowSubclassを使うのに,Window Classに対する制限は存在しません。
というか,自分でWindow Classを定義できるのであれば,サブクラス化して処理する必要はないです。
naohiro19 さんが書きました:ウィンドウが作成された直後にSetWindowSubclass関数を呼び出す
直後である必要も無いです。
naohiro19 さんが書きました: _In_ DWORD_PTR dwRefData //サブクラスのIDと異なる値(通常は0を指定すればOK)
このdwRefDataは,サブクラス化した時のコールバック関数に対して渡される,ユーザーが渡したい値を指定します。
SUBCLASSPROC function pointerのページでは,サブクラスに紐付くthisポインタを渡すのに利用できる,というのが例示されています。
dwRefDataは,「ウィンドウハンドル,コールバック関数,サブクラスID」の組に対して紐付けられます。
naohiro19 さんが書きました:

CODE:

LRESULT WinSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM, LPARAM lParam, UINT_PTR uidSubClass ,DWORD_PTR dwRefData)
呼び出し規約が間違っているので,コンパイル時にエラーになります。

CODE:

LRESULT CALLBACK WinSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM, LPARAM lParam, UINT_PTR uidSubClass ,DWORD_PTR dwRefData)
と,関数名の前にCALLBACKの指定が必要です。
へろりずむ さんが書きました:便利ですよね。 NT4.0時代には無かった API です。
出てきたのは12~13年ぐらい前でしょうか。
Windows 2000ぐらいから?
MSDNによるとWindows XPだそうです。
オフトピック
Win3.1時代から存在するCreateWindow functionを見るとMinimum supportは2000以降という記述なので,XP以降と書かれたこのAPIは少なくとも公式にサポートされたのは2000ではなくXPの模様です
私は従来のSetWindowLong(Ptr)による方法では,一度サブクラス化すると解除が困難である,という問題があるので作られたAPIという認識ですね。

アバター
nullptr
記事: 239
登録日時: 13年前

Re: Windows APIでウィンドウのサブクラス化

投稿記事 by nullptr » 11年前

SetWindowLongだと解除が困難ってのもそうですけど、個人的にはDWORD_PTRだから32bitから64bitで移植の問題が起きないのがありがたかったりする。


猫でもわかる、ではなく、猫にしかわからない、だと思っています。個人的には全く参考にならない。
最後に編集したユーザー nullptr on 2014年7月19日(土) 09:39 [ 編集 1 回目 ]