Win32のサブクラス化でつまってしまいました。
お知恵をお貸しください。
ボタンを作成、ボタンをサブクラス化し
ボタンが押された時の処理を置き換えたコールバック内で行う
というものです。
ボタンはメインウィンドウに配置します。
具体的な例だと置き換えたコールバック内でヘルプダイアログを呼び出します
以下 メインウィンドウコールバック
これは単純にすべてをメインウィンドウコールバック内に記述したものです
#define IDB_TEST_PUSH
(2000)
LRESULT CALLBACK MainWindowProcedure(HWND hWindow, UINT Message, UINT wParam,
LONG lParam)
{
switch ( Message ) {
case WM_CREATE:
// ボタン作成
CreateWindow(
TEXT(BUTTON),
TEXT(test button),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 90, 50, 20,
hWindow,
(HMENU) IDB_TEST_PUSH,
((LPCREATESTRUCT) (lParam))->hInstance,
NULL);
break;
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDB_TEST_PUSH:
// ボタンが押されるとヘルプダイアロ
グを表示
DialogBox(lvar_hInstance,
(LPCTSTR) IDD_ABOUTBOX, hWindow, (DLGPROC) HelpProcedure);
}
break;
default:
break;
}
return ( DefWindowProc(hWindow, Message, wParam, lParam) );
}
上記のものを以下のようにサブクラス化して
コールバック内でボタンがおされたかどうかのメッセージを拾おうとしています
#define IDB_TEST_PUSH
(2000)
LRESULT CALLBACK MainWindowProcedure(HWND hWindow, UINT Message, UINT wParam,
LONG lParam)
{
switch ( Message ) {
case WM_CREATE:
// ボタン作成
CreateWindow(
TEXT(BUTTON),
TEXT(test button),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 90, 50, 20,
hWindow,
(HMENU) IDB_TEST_PUSH,
((LPCREATESTRUCT) (lParam))->hInstance,
NULL);
break;
g_DefProcedure = (WNDPROC) GetWindowLong(hWindow,
GWL_WNDPROC);
SetWindowLong(hWindow, GWL_WNDPROC, (LONG)
TestButton_CallBackProcedure);
default:
break;
}
return ( DefWindowProc(hWindow, Message, wParam, lParam) );
}
LRESULT CALLBACK TestButton_CallBackProcedure(HWND hWindow, UINT uMessage,
LPARAM lParam, LPARAM lpData)
{
switch ( uMessage ) {
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDB_TEST_PUSH:
// ボタンが押されるとヘルプダイアロ
グを表示
DialogBox(g_hInstance, (LPCTSTR)
IDD_ABOUTBOX, hWindow, (DLGPROC) HelpProcedure);
}
break;
default:
return ( CallWindowProc(g_DefProcedure, hWindow,
uMessage, lParam, lpData) );
break;
}
return ( 0 );
}
しかし、これだとまったくメッセージが回ってきませんでした。(WM_COMMANDすら来ませんでし
た)
ユーザーのボタンに対するアクションはオーナーウィンドウにしか通知されないのでしょうか?
また、これらをコールバック内で解決する場合はどのようにすれば解決できるでしょうか?
以上よろしくお願いします
GetWindowLongとかが実行されてないですね。
break;がどういう働きをするかヘルプで調べて下さい。
あとウィンドウプロシージャの取得や設定を行っているところですが、どのウインドウの
ウィンドウプロシージャを取ろうとしているのでしょうか?
あちゃ、失礼しました。
ここに乗せるためにいろい消したときに混じってしまったのでしょう・・
紛らわしくてすみません。
こちらで使っている方にbreakが変な位置にきてGetWindowLongが実行されてない、
ということはありませんので、実行されていることを前提にお願いいたします
いちおう修正したものを張っておきます。
LRESULT CALLBACK MainWindowProcedure(HWND hWindow, UINT Message, UINT wParam,
LONG lParam)
{
switch ( Message ) {
case WM_CREATE:
// ボタン作成
CreateWindow(
TEXT(BUTTON),
TEXT(test button),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 90, 50, 20,
hWindow,
(HMENU) IDB_TEST_PUSH,
((LPCREATESTRUCT) (lParam))->hInstance,
NULL);
g_DefProcedure = (WNDPROC) GetWindowLong(hWindow,
GWL_WNDPROC);
SetWindowLong(hWindow, GWL_WNDPROC, (LONG)
TestButton_CallBackProcedure);
break;
default:
break;
}
return ( DefWindowProc(hWindow, Message, wParam, lParam) );
}
GetWindowLongとSetWindowLongに引き渡しているウインドウハンドルは
ボタンコントロールの物ではないように思えますが、
これではボタンをサブクラス化したことにはならないと思います。
このコードだとボタンの親ウインドウをサブクラス化しているように見えます。
あと疑問に思ったんですが、
ボタンをサブクラス化したいとして、ボタンにWM_COMMANDが来るもんでしょうか?
WM_COMMANDってボタンコントロールが親にBN_CLICKEDを通知した結果、
親ウインドウ側で送出するものではないかと思うんですが。
親がわざわざ通知元にWM_COMMANDを通知するとは思えないんですが、
詳しく調べてみたわけではないので単なる疑問なんですけれど。
>あとウィンドウプロシージャの取得や設定を行っているところですが、どのウインドウの
ウィンドウプロシージャを取ろうとしているのでしょうか?
すみません、乗せるときにコピペミスしまくりですね;;
えっと、CreateWindowで作成したボタンのプロシージャです
なので
hButton = CreateWindow(
TEXT(BUTTON),
TEXT(test button),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 90, 50, 20,
hWindow,
(HMENU) IDB_TEST_PUSH,
((LPCREATESTRUCT) (lParam))->hInstance,
NULL);
g_DefProcedure = (WNDPROC) GetWindowLong(hButton,
GWL_WNDPROC);
SetWindowLong(hButton, GWL_WNDPROC, (LONG)
TestButton_CallBackProcedure);
実際はこっちですね;;
>ボタンをサブクラス化したいとして、ボタンにWM_COMMANDが来るもんでしょうか?
>WM_COMMANDってボタンコントロールが親にBN_CLICKEDを通知した結果、
>親ウインドウ側で送出するものではないかと思うんですが。
登録したコールバック内でブレークポイントをしかけてチェックしてたときに
他のメッセージはいろいろ送られてくるけど、WM_COMMANDとかはさっぱり
送られてこないので、まさか、とはおもっていましたが・・・;;
あと同じような状況として
親の関係が
親ウィンドウ>プッシュボタン
という状況ならWM_COMMANDでボタンIDを拾えますが
親ウィンドウ>グループボックス(BS_GROUPBOX)>プッシュボタン
の場合などは 当然WM_COMMANDで拾えなくなってしまいます。
この場合はどこで拾えばよいのでしょうか?
グループボックスのプロシージャを置き換えてひろうのでしょうか?
こういう場合は、ボタンの親は親ウインドウにしませんか?
グループボックスとの関係はZオーダーで設定すればいい話ですし、
グループボックスがアクティブになるようなことが無ければ、
Zオーダーが変わることは無いと思うので特に問題は無いと思いますが。
どうやらそうした方がよさそうですね
結局ボタンの件はボタンクラスをつくってみました。
内部でボタン用の親ウィンドウを生成して、そこでさらにボタン生成。
サブクラス化はボタン用の親ウィンドウプロシージャを置換して
WM_COMMANDの件は解決しました。
いろいろありがとうございました。