Fensterklasse mit Get-/SetWindowLong: Zugriff innerhalb der WndProc?



  • Hi,

    ich verwende eine Klasse, die mit Hilfe von Get- bzw. SetWindowLong() die statische WndProc auf eine nichtstatische weiterleitet. Nun habe ich versucht aus der nichtstatische WndProc auf meine Member zuzgreifen, aber der Debugger findet kein this. 😮

    Ist das grundsätzlich so?

    Grüße,
    don_basto.



  • Hi,

    don_basto schrieb:

    Nun habe ich versucht aus der nichtstatische WndProc auf meine Member zuzgreifen, aber der Debugger findet kein this. 😮

    Das sieht konkret wie aus (GetWindowLong(Ptr) ?) ? ... Zeig mal den Codeabschnitt 😉 .



  • Statische Funktionen verfügen grundsätzlich über keinen This-Zeiger. Stell sie dir so vor, als dass sie wie Stand-Alone-Funktionen sind, also nicht in einer Klasse, die aber auf die protected- und private- Membervariablen zugreifen können.

    Du kannst das so lösen, dass du in deinem Fenster irgendwo einen Pointerauf die Klasse (praktisch den this-Zeiger) speicherst. Entweder per SetWindowLong mit GWL_USER oder SetProp.



  • Badestrand schrieb:

    Statische Funktionen verfügen grundsätzlich über keinen This-Zeiger. Stell sie dir so vor, als dass sie wie Stand-Alone-Funktionen sind, also nicht in einer Klasse, die aber auf die protected- und private- Membervariablen zugreifen können.

    Du kannst das so lösen, dass du in deinem Fenster irgendwo einen Pointerauf die Klasse (praktisch den this-Zeiger) speicherst. Entweder per SetWindowLong mit GWL_USER oder SetProp.

    Das stimmt zwar, aber ich glaube das meinte er nicht:

    don_basto schrieb:

    [...]Nun habe ich versucht aus der nichtstatische WndProc auf meine Member zuzgreifen, aber der Debugger findet kein this. 😮 [...]

    EDIT: Oder hab ich was übersehen, doch nicht oder 🙄



  • Hier der Kode:

    LRESULT CALLBACK Window::staticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	Window* wnd = (Window*)GetWindowLong(hWnd, GWL_USERDATA);
    
    	switch(uMsg) {
    		case WM_CREATE:
    			wnd = (Window*)((CREATESTRUCT*)lParam)->lpCreateParams;
    			SetWindowLong(hWnd, GWL_USERDATA, long(wnd));
    	}	
    	return wnd->wndProc(hWnd,uMsg,wParam,lParam);
    }
    
    LRESULT CALLBACK Window::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch (uMsg) {
    		case WM_SYSCOMMAND:
    			switch (wParam)	{
    				case SC_SCREENSAVE:
    				case SC_MONITORPOWER:
    				return 0;
    			}
    			break;
    		case WM_KEYDOWN:
    			// Fenster schließen
    			if (wParam==VK_ESCAPE) _exit = true; // Ausnahme !
    			break;		
    		case WM_CLOSE:
    			PostQuitMessage(0);
    			return 0;
    	}
    	return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }
    

    Der Debugger meldet eine Ausnahme, wenn auf _exit (ein Member) zugegriffen wird. Der this-Zeiger ist Null.



  • WM_CREATE ist nicht die erste Nachricht die ein Fenster erhält.
    Somit geht
    return wnd->wndProc(hWnd,uMsg,wParam,lParam);
    schief



  • Ich würde das:

    wnd = (Window*)((CREATESTRUCT*)lParam)->lpCreateParams;
    SetWindowLong(hWnd, GWL_USERDATA, long(wnd));
    

    mal direkt nach dem Erstellen, also nach deinem Aufruf von CreateWindow(Ex) machen; also in etwa so:

    _hWnd = CreateWindowEx(...);
    SetWindowLongPtr(_hWnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this));
    


  • Der Fehler liegt nicht an der Reihenfolge. Er tritt auch auf, wenn WM_CREATE vorher ausgelöst wurde.

    //EDIT:
    Der Aufruf von der von der statischen zur nicht-statische klappt immer, auch wenn WM_CREATE vorher nicht aufgerufen wurde. Nur ist das this der nicht-statischen Methode immer NULL.



  • Das Problem liegt beim Speichern des Zeigers:

    Window* wnd = (Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
    

    wnd ist danach 0.

    //EDIT:
    Ich hab den Fehler gefunden. Ich Idiot hatte vergessen, den this-Zeiger in CreateWindow() zu übergeben. Danke für Eure Mühe!

    Grüße,
    don_basto.



  • if(wnd)
    {
        return wnd->wndProc(hWnd,uMsg,wParam,lParam);
    }
    else
    {
        return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }
    


  • don_basto schrieb:

    Das Problem liegt beim Speichern des Zeigers:

    Window* wnd = (Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
    

    wnd ist danach 0.

    Wie sieht dein CreateWindow Aufruf aus?



  • Das war's. 🙄
    Hab's auch gerade rausgefunden... .



  • don_basto schrieb:

    Das war's. 🙄
    Hab's auch gerade rausgefunden... .

    Huh?!, was wars denn jetzt ? Du hast doch vorher schon geschrieben, dass dein Problem gelößt sei... *iritiert sei* 🙄



  • CodeFinder schrieb:

    don_basto schrieb:

    Das war's. 🙄
    Hab's auch gerade rausgefunden... .

    Huh?!, was wars denn jetzt ? Du hast doch vorher schon geschrieben, dass dein Problem gelößt sei... *iritiert sei* 🙄

    Jo, Problem scheint gelöst zu sein, hat wohl vergessen bei CreateWindow this als Param zu parsen^^ Das hat der Poster mit den 11 Fragezeichen wohl übersehen 😃



  • Ich hat den This-Zeiger bei CreateWindow() nicht mitgegeben. Nachdem ich den Fehler gefunden hatte und dann hier meinen alten Beitrag editiert, kam der ????-Beitrag zum CreateWindow(). 😉



  • Wegen mir aus hättest du auch nen Doppel-Post machen können, dann sieht man immerhin, dass du noch was geschrieben hast 😉 Sonst übersieht man sowas so leicht^^



  • Ahso, ok ok, so hatte ich's auch verstanden; war nur iritiert wg. dem Post von '???????????' 😉 .



  • Das "if(!wnd) dann DefaultWndProc" solltest du auf jeden Fall drinnen haben, sonst wird u.U. erst wieder 0 als this verwendet, nämlich bevor die WM_CREATE gekommen ist. Was zwar normal funktioniert solange man nicht über "this" zugreift (siehe GetSafeHwnd - *würg*), aber zumindest gefährlich ist (z.B. wenn man mal den Code ändert), und ich denke (bin aber nicht sicher) dass es auch laut C++ Std. nicht OK ist.



  • hustbaer schrieb:

    Das "if(!wnd) dann DefaultWndProc" solltest du auf jeden Fall drinnen haben, sonst wird u.U. erst wieder 0 als this verwendet, nämlich bevor die WM_CREATE gekommen ist.

    Jo das seh ich auch so 👍 .

    hustbaer schrieb:

    aber zumindest gefährlich ist (z.B. wenn man mal den Code ändert),

    Was sollte man denn am Code ändern, so dass es 'gefährlich' wird ? ( ➡ konkret ? ) 😉

    hustbaer schrieb:

    und ich denke (bin aber nicht sicher) dass es auch laut C++ Std. nicht OK ist.

    Was soll nicht dem C++-Standard entsprechen ?



  • CodeFinder schrieb:

    hustbaer schrieb:

    und ich denke (bin aber nicht sicher) dass es auch laut C++ Std. nicht OK ist.

    Was soll nicht dem C++-Standard entsprechen ?

    Afaik gehört es in den Bereich "undefiniertes Verhalten", wenn du eine Klassenmethode über den NULL-Zeiger aufrufen willst.


Log in to reply