Subclassing eines Buttons [gelöst]
-
Hallo,
ich habe mir gerade einen neuen Button als Fenster erstellt und versuche jetzt durch subclassing die Nachricht BN_CLICKED (und damit nätürlich auch WM_COMMAND) abzufangen.Dazu habe ich auch schon ein schönes Code-Beispiel gefunden:
http://blog.m-ri.de/?s=SubClass&submit=Suchenich habe den Code auch direkt mal an meinem Button (fast) unverändert getestet:
#include<iostream> #include<Windows.h> #include<windowsx.h> #include<cstdio> #include<CommCtrl.h>//für subclassing using namespace std; #pragma comment (lib, "Comctl32.lib")//für subclassing HINSTANCE hi; HWND button1_hwnd; LONG old_proc; LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_COMMAND: if(HIWORD(wparam) ==BN_CLICKED) { MessageBox(hwnd, TEXT("WM_COMMAND"), TEXT(""), MB_OK); } break; } WNDPROC pWndProc = (WNDPROC)GetWindowLongPtrW(hwnd,GWL_USERDATA); return CallWindowProc(pWndProc,hwnd,message,wparam,lparam); } DWORD WINAPI button1(LPVOID IpParameter) { button1_hwnd=CreateWindowW(TEXT("BUTTON"), TEXT("Click me!"),WS_CHILD| WS_VISIBLE|BS_PUSHBUTTON, 100, 100, 150, 50, GetConsoleWindow(), (HMENU) 1, hi, 0); UpdateWindow(button1_hwnd); ShowWindow(button1_hwnd, SW_NORMAL); SetParent(button1_hwnd, 0); MSG msg; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } int main() { DWORD button1_threadid; HANDLE button1_handle=CreateThread(0, 0, button1, 0, 0, &button1_threadid); Sleep(1000); LONG_PTR OldWndProc= SetWindowLongPtr(button1_hwnd, GWLP_WNDPROC, (LONG_PTR) WndProc); SetWindowLongPtr(button1_hwnd,GWL_USERDATA,OldWndProc); WaitForSingleObject(button1_handle, INFINITE); }Der Button ist sichtbar und lässt sich auch anklicken, nur dabei passiert leider einfach gar nichts wobei nun doch die Messagebox kommen sollte

Was mache ich denn falsch?
edit: habe auch noch ein Bsp aus der MSDN gefunden wo es genauso gemacht wird:
http://msdn.microsoft.com/en-us/library/bb773183(VS.85).aspxmsdn schrieb:
Subclassing Controls Prior to ComCtl32.dll version 6
You can put a control in a subclass and store user data within a control. You do this when you use versions of ComCtl32.dll prior to version 6 which ships with Windows XP. There are some disadvantages in creating subclasses with earlier versions of ComCtl32.dll.To make a new control it is best to start with one of the Windows common controls and extend it to fit a particular need. To extend a control, create a control and replace its existing window procedure with a new one. The new procedure intercepts the control's messages and either acts on them or passes them to the original procedure for default processing. Use the SetWindowLong or SetWindowLongPtr function to replace the WNDPROC of the control. The following code sample shows how to replace a WNDPROC.
CopyOldWndProc = (WNDPROC)SetWindowLongPtr (hButton, GWLP_WNDPROC, (LONG_PTR)NewWndProc);danke schonmal,
andi01.
-
WM_COMMAND wird nicht an den Button gesendet, sondern der Button sendet es an das Parent. Du müsstest also das Parent subclassen.
-
achso...
durch die Codezeile (Z.41)
SetParent(button1_hwnd, 0);wird ja das desktop-fenster als parent gesetzt. Deshalb habe ich die folgenden Codezeilen jetzt so abgeändert, dass praktisch der Desktop "gesubclasst" wird:
Z.61:
LONG_PTR OldWndProc= SetWindowLongPtr(GetDesktopWindow(), GWLP_WNDPROC, (LONG_PTR) WndProc);Z.63:
SetWindowLongPtr(GetDesktopWindow(),GWL_USERDATA,OldWndProc);allerdings passiert weiterhin einfach gar nichts obwohl das parrent gesubclasst wurde...
was ist denn diesmal falsch?
edit: in obigem beispiel aus der msdn wird doch auch der button gesubclasst
:msdn schrieb:
CopyOldWndProc = (WNDPROC)SetWindowLongPtr (hButton,
GWLP_WNDPROC, (LONG_PTR)NewWndProc);danke schonmal,
andi01.
-
Das Desktop Window gehört einem anderen Prozess!
Du kannst diesen nicht subclassen ohne einen DLL die Du in diesen Prozess injezierst.
-
ok, aufwnadsmäßig ist es also wahrscheinlich am besten ein neues fenster in meinem prozess als parent zu erstellen;
nur wie kriege ich es dann hin, dass das parent transparent wird und die childwindows (buttons) sichtbar bleiben? geht das überhaupt?
(denn dann würde es ja genauso aussehen als ob ich den desktop als parent verwendet hätte nur eben mit deutlich weniger Aufwand...)danke schonmal,
andi01.
-
Du möchtest also irgendwo auf dem Desktop einen "nackten" Button haben.
Habe ich Dich so richtig verstanden?Wenn ja, dann erstelle einfach eine Win32-Applikation mit einem Fenster OHNE Rand und ohne Titelleiste, und zwar in der Größe des Buttons.
In dieses Fenster legst Du ein Button als Child-Fenster rein, hat also die gleiche Größe wie der Parent.HTH,
Martin
-
Du möchtest also irgendwo auf dem Desktop einen "nackten" Button haben
Genau

Wenn ja, dann erstelle einfach eine Win32-Applikation mit einem Fenster OHNE Rand und ohne Titelleiste, und zwar in der Größe des Buttons.
In dieses Fenster legst Du ein Button als Child-Fenster rein, hat also die gleiche Größe wie der Parent.stimmt, auf die Idee bin ich noch gar nicht gekommen

aber wie geht das ohne rand und titelleiste? also winapi-Fenster erstellen kann ich, und bei CreateWindow() muss ich als Paramter WS_POPUP nehmen oder?
naja ich probiere es mal schnell aus und melde mich gleich wieder ob es geklappt hat...
-
danke nochmal an alle, hat perfekt funktioniert!

für alle die evtl. dasselbe Problem haben hier nochmal der komplette getestete Code:
#include<iostream> #include<Windows.h> #include<WindowsX.h> #include<cstdio> using namespace std; HWND hauptfenster_handle; HWND button1_handle; HINSTANCE hi; LRESULT CALLBACK HauptWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_COMMAND: //Wenn die Message ein Befehl ist löse das aus: if (HIWORD(wparam) == BN_CLICKED) //Wenn es sich um einen Button_click handelt { if (LOWORD(wparam) == 1) //das sind die oben ernannten Parameter, 1 & 2 hatten wir ja { cout<<"Button1 geklickt!\n"; //Meldung von Button-Klick 1 anzeigen } } break; } return DefWindowProc(hwnd, message, wparam, lparam); } DWORD WINAPI hauptfenster(LPVOID IpParameter) { WNDCLASS wc; wc.cbClsExtra=0; wc.cbWndExtra=0; wc.hbrBackground=(HBRUSH) GetStockObject(LTGRAY_BRUSH); wc.hCursor=LoadCursor(hi, IDC_ARROW); wc.hIcon=LoadIcon(hi, IDI_WINLOGO); wc.hInstance=hi; wc.lpfnWndProc=HauptWndProc; wc.lpszClassName=TEXT("Fensterklasse"); wc.lpszMenuName=0; wc.style=CS_HREDRAW|CS_VREDRAW; RegisterClass(&wc); hauptfenster_handle=CreateWindow(TEXT("Fensterklasse"), TEXT("Hauptfenster"), WS_VISIBLE|WS_POPUP, 100, 100, 140, 20, 0, 0, hi, 0); UpdateWindow(hauptfenster_handle); ShowWindow(hauptfenster_handle, SW_NORMAL); MSG msg; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } DWORD WINAPI button1(LPVOID IpParameter) { button1_handle=CreateWindow(TEXT("BUTTON"),TEXT("Button 1"),WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0,0 ,140,20,hauptfenster_handle,(HMENU) 1, hi, NULL); UpdateWindow(button1_handle); ShowWindow(button1_handle, SW_NORMAL); MSG msg; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } int main() { DWORD hauptfensterthread_id; HANDLE hauptfensterthread_handle=CreateThread(0, 0, hauptfenster, 0, 0, &hauptfensterthread_id); Sleep(1000); DWORD button1thread_id; HANDLE button1thread_handle=CreateThread(0, 0, button1, 0, 0, &button1thread_id); Sleep(1000); SetParent(button1_handle, hauptfenster_handle); RECT r; GetWindowRect(button1_handle, &r); SetWindowPos(hauptfenster_handle, HWND_NOTOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, 0); SetWindowPos(button1_handle, HWND_TOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, 0); WaitForSingleObject(hauptfensterthread_handle, INFINITE); WaitForSingleObject(button1thread_handle, INFINITE); }