WndProc in klasse?



  • ich selber hab die WndProc schon lange in einer klasse - zwar noch gefrickel da ich das noch aendern will aber es geht

    mein derzeitiges problem ist allerdings das DLGPROC

    void CSettings::ShowDlg(HINSTANCE hInst, unsigned int uiDlgID, HWND mainHandle){
        if(m_Handle == 0){
            m_Handle = ::CreateDialog(hInst, MAKEINTRESOURCE(uiDlgID), mainHandle, dlgProc);
            ::ShowWindow(m_Handle, SW_SHOW);
        }
    }
    

    das dlgProc moechte ich in die klasse packen damit ich auch methoden aufrufen kann
    die ganzen techniken fuer das main window hab ich angeschaut und probiert, klappt aber bisher nicht

    kann jemand helfen ?!



  • Ich hats so gemacht:

    void Window::Show()
    {
    	static bool initialized = false;
    	if(!initialized)
    	{
    		DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCEA(this->iId), NULL, WndProc, (LPARAM)this);
    	}
    	else
    	{
    		Widget::Show();
    	}
    }
    
    private:
    	static BOOL CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    	{
    		if(message == WM_INITDIALOG)
    		{
    			SetWindowLongPtrA(hwnd, DWLP_USER, lParam);
    		}
    		Window* window = (Window*)GetWindowLongPtrA(hwnd, DWLP_USER);
    		return window->HandleMessage(hwnd, message, wParam, lParam);
    	}
    

    Dann natürlich noch die öffentliche HandleMessage Methode.



  • so aehnlich hab ich das bereits, also eine static message methode, nur ich moechte in dieser methoden aufrufen die nicht static sein koennen - das ist das problem



  • ? Les dir mal durch was der geschrieben hat ... HandleMessage ist sozusagen deine normale WindowProc in der Klasse ... die Static WindowProc leitet das sozusagen nur an die weiter ...

    aja ... reinterpret_cast wäre was schöner 😉



  • aaaaaaaaaaah - das is doch mal stylish - vielen vielen dank, der compiler schluckts, werds spaeter testen aber sieht gut aus {=



  • Mr Evil schrieb:

    ich selber hab die WndProc schon lange in einer klasse.

    Ich habs immer noch net hingekriegt.

    Wie, wie, wie?????

    Ich versteh garnichts

    memcpy(&Space,(const void*) &ASE::WndProc,(size_t) sizeof(LONG)) ;
    	SetWindowLong(hWnd, GWL_WNDPROC,(LONG) Space);
    

    geht auch net 😡 😡 😡

    Man, leute, hört auf, mich in die MFC zu schicken, o.ä. Wenn ich den Code nicht verstehe, dann verwende ich ihn nicht, weil ich im Falle eines Bugs nichts werde machen können.

    Kann mir den Niemand erklären, WARUM das nicht geht? Ich glaub, ich will das weniger hinkriegen, als es verstehen...

    Was ist ein Thunk?

    Kann mir denn keiner aus meiner Verzweiflung heraushelfen? 😞



  • Hmm du solltest dir mal das Problem von Funktionspointer usw angucken ... hmm und eines der Probleme kommt halt durch den this-Zeiger bei Methoden einer Klasse ... das hasse bei statischen Methoden net ^^



  • Azrael, il Meraz schrieb:

    Wenn ich den Code nicht verstehe, dann verwende ich ihn nicht, weil ich im Falle eines Bugs nichts werde machen können.

    Gesunde Einstellung. Respekt, Respekt. Hoffentlich kann ich mich verständlich ausdrücken.

    Um die "WinProc" in eine Klasse zu kriegen, braucht man immer zwei davon :

    -> eine die vom Betriebssystem aufgerufen wird (muss statisch sein) und
    -> eine die von der Instanz aufgerufen wird.

    Ausserdem braucht man eine Möglichkeit, um in einer statischen Funktion Zugriff auf den this-pointer der Instanz zu haben.

    Dazu gibt es viele Möglichkeiten.

    Eine davon geht mit Get/SetWindowLong() und einem "umdefinierten" Zeiger :

    #include <windows.h>
    //-----------------------------------------------------------------------------
    class ASE {
    //-----------------------------------------------------------------------------
     private   :
      static
      LRESULT WINAPI    WndProc_static  (HWND, UINT, WPARAM, LPARAM); // die statische WinProc, wird vom Betriebssystem aufgerufen
      LRESULT WINAPI    WndProc         (HWND, UINT, WPARAM, LPARAM); // die WinProc, die von der Instanz aufgerufen wird
     protected :
     public    :
      BOOL              CreateWClass    (HINSTANCE, TCHAR *);
    };
    //-----------------------------------------------------------------------------
    LRESULT WINAPI      ASE::WndProc_static  (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    //-----------------------------------------------------------------------------
    // Statische WndProc, wird vom Betriebssystem aufgerufen.
    
     if ( msg == WM_CREATE ) {
    // Normalerweise zeigt hier lParam bei WM_CREATE auf eine Struktur vom Typ CREATESTRUCT.
    // Aber da der Zeiger bei CreateWindowEx () mit dem this-pointer der Instanz initialisiert wurde,
    // zeigt nun lParam auf den this-pointer der Instanz.
    // Damit wird nun GWL_USERDATA des Fensters initialisiert.
      SetWindowLong (hwnd,GWL_USERDATA,(LONG)((LPCREATESTRUCT)lParam) -> lpCreateParams);
     }
    
    // Hier wird der Wert von GWL_USERDATA als this-pointer der Instanz interpretiert.
    // Dadurch kann man sich einen Zeiger auf die Instanz schaffen.
     ASE *pThis = (ASE *) GetWindowLong (hwnd,GWL_USERDATA);
    
     if ( pThis == 0 ) {
    // Dann konnte GWL_USERDATA noch nicht via SetWindowLong () initialisiert werden.
    // Auf alle Botschaften die vor WM_CREATE gesendet werden kann die Instanz nicht reagieren, deshalb DefWindowProc().
      return DefWindowProc (hwnd,msg,wParam,lParam);
     } else {
    // Dann kann die WndProc der Instanz aufgerufen werden.
      return pThis -> WndProc (hwnd,msg,wParam,lParam);
     }
    
    }
    //-----------------------------------------------------------------------------
    LRESULT WINAPI      ASE::WndProc         (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    //-----------------------------------------------------------------------------
    // WndProc der Instanz.
    // Hier gibt es Zugriff auf alle Eigenschaften und Methoden der Instanz.
    
     switch ( msg ) {
    
      case WM_CLOSE   : {
       PostQuitMessage (0);
       break;
      }
      case WM_COMMAND : {
       if ( HIWORD (wParam) == BN_CLICKED ) {
       if ( LOWORD (wParam) == 0x1234 ) {
        PostQuitMessage (0);
       }}
       break;
      }
      case WM_LBUTTONDOWN : {
       ReleaseCapture ();
       SendMessage    (hwnd,WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0); 
       break;
      }
    
     }
    
     return DefWindowProc (hwnd,msg,wParam,lParam);
    }
    //-----------------------------------------------------------------------------
    BOOL                ASE::CreateWClass    (HINSTANCE hInst, TCHAR *AppName) {
    //-----------------------------------------------------------------------------
     WNDCLASSEX    wcex;
     FillMemory  (&wcex,sizeof(wcex),0); wcex.cbSize = sizeof (wcex);
    
     if ( !GetClassInfoEx (hInst,AppName,&wcex) ) {
      wcex.style         = 0x0000;
      wcex.hIcon         = LoadIcon       (0,IDI_HAND);
      wcex.hCursor       = LoadCursor     (0,IDC_ARROW);
      wcex.hbrBackground = GetStockObject (LTGRAY_BRUSH);
      wcex.lpszClassName = AppName;
      wcex.hInstance     = hInst;
    
    // lpfnWndProc muss die statische WndProc sein.
      wcex.lpfnWndProc   = WndProc_static;
    
      if ( !RegisterClassEx(&wcex) ) return FALSE;
     }
    
    // Normalerweise zeigt der letzte Parameter von CreateWindowsEx () auf eine initialisierte CREATESTRUCT,
    // damit man bei WM_CREATE auf sie Zugriff hat.
    // Im letzen Parameter von CreateWindowEx () wird jetzt einfach der this-pointer übergeben.
     HWND hWnd =
     CreateWindowEx (0x00000208,AppName, 0,0x90CC0880,4,4,300,200,0,   0,            hInst,this);
     CreateWindowEx (0x00000208,"BUTTON",0,0x50000000,4,4,100, 30,hWnd,(HMENU)0x1234,hInst,0);
    
     return TRUE;
    }
    //-----------------------------------------------------------------------------
    WINAPI              WinMain              (HINSTANCE hInst, HINSTANCE, LPSTR, int) {
    //-----------------------------------------------------------------------------
    // Das übliche halt.
    
     ASE app;
    
     if ( app.CreateWClass (hInst,"WindowWClass") ) {
    
      MSG  msg;
    
      while ( GetMessage(&msg,0,0,0) ) {
       TranslateMessage (&msg);
       DispatchMessage  (&msg);
      }
    
     }
    
     return 0;
    }
    


  • Azrael, il Meraz schrieb:

    Ich habs immer noch net hingekriegt.

    Wie, wie, wie?????

    Bei mir ist das so - mir ist die ganze zeit bekannt wie die klasse heisst und ich kann diese instanziieren

    MyApp.h

    class CMyAPP{
    private:
        HWND hWnd;
        void OnPaint();
        void OnDestroy() { PostQuitMessage(0); };
    .
    .
    public:
        LRESULT Messages(HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam);
    }
    

    MyApp.cpp

    void CMyApp::OnPaint(){
        PAINTSTRUCT ps;
        HDC hDC;
        RECT rect;
        ::GetWindowRect(hWnd, &rect);
        hDC = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
    }
    LRESULT CMyApp::Messages(HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam){
        this->hWnd = hWnd;
        switch(message){
            case WM_PAINT:    OnPaint();   break;
            case WM_DESTROY:  OnDestroy();  break;
    		default:  return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    

    Main.cpp

    #include "MyApp.h"
    
    LRESULT CALLBACK WndProc(HWND, unsigned int, unsigned int, long);
    
    CMyApp myapp;
    
    .
    .
    .
    LRESULT CALLBACK WndProc(HWND hWnd, unsigned int message, unsigned int wParam, long lParam){
    	return myapp.Messages(hWnd, message, wParam, lParam);
    }
    

    beim generieren des fensters dann einfach das globale WndProc angeben



  • merker schrieb:

    [...] Um die "WinProc" in eine Klasse zu kriegen, braucht man immer zwei davon [...]

    Nop, eine reicht theoretisch aus, musst es halt via SetWindowLong(Ptr)/GetWindowLong(Ptr) machen.



  • ok, ich verstehs - man kann mit CreateWindowEx mit this den Zeiger auf die Instanz an den Wndproc Schicken.
    kompilieren lässt sich das jetzt, das programm zeigt jedoch eine Fehlermeldung und stirbt >.<. Beim Debuggen gibts eine Zugriffsverletzung beim Lesen, siehe hier:

    http://xcpp.de/ASE/mist.jpg

    hab schrittweise debuggt - er kommt ohne probleme bis zur CreateWindowEx Zeile, wenn er dann bei "...this)..." ankommt, springt in diese komische dbgheap Datei und stirbt, bzw. zeigt zugriffsverletzungsfehlermeldungsfenster an.

    irgendwie peil ich das doch net so ganz... 😞



  • Black Shadow schrieb:

    Hm kannst du das näher erläutern? Also bei meinem VC++ geht das wunderbar, genauso gehe ich davon aus dass das Visual Studio damit auch gut zurechtkommt. Wies bei anderen Marken aussieht kann ich nicht sagen.
    Und bei welchen Compiler-settings geht der Code nicht?

    Nicht x86 32 Bit? ZB Win64. Der von dir gepostete Code ist ein ziemlich übler Hack und absolut unnötig, da es hierfür elegantere Wege gibt. Beherzige Jochen's Rat und verwende sowas nicht.

    edit:
    @Azrael
    "Zugriffsverletzung beim Lesen an Position 0xcdcdcdcd"
    Das ist die typische Signatur beim MSC für nicht initialisierten Speicher im Debug Build. Ich würde mal stark vermuten, du hast einen nicht initialisierten Zeigen.



  • Azrael, il Meraz schrieb:

    hab schrittweise debuggt - er kommt ohne probleme bis zur CreateWindowEx Zeile, wenn er dann bei "...this)..." ankommt, (...)

    Der this-pointer hat so seine Tücken. Über den this-pointer könnte man ein ganzes Forum vollposten.

    Hast Du drauf geachtet, dass

    -> die statische WndProc,
    -> die Instanz-WndProc und
    -> der Aufruf von CreateWindowEx ()

    sich in ein und derselben Klasse befinden ?

    Falls ja und der gleiche Fehler tritt immer noch auf, dann füge dem Aufruf von CreateWindowEx () mal folgendes hinzu :

    CREATESTRUCT cstr;
     cstr.lpCreateParams = (LPVOID) this;
     HWND hWnd =
     CreateWindowEx (0x00000208,AppName,0,0x90CC0880,4,4,300,200,0,0,hInst,&cstr);
    

    Dadurch wird sichergestellt, dass dort wo der letzte Parameter von CreateWindowEx () hinzeigt, sich auch ausreichend gültiger Speicher befindet.



  • fehler tritt immer noch auf, nun springt er jedoch in eine andere DAtei. Am ende dieses codes:

    void __cdecl _unlock (
            int locknum
            )
    {
            /*
             * leave the critical section.
             */
            LeaveCriticalSection( _locktable[locknum].lock );
    }
    

    meldet der Debugger einen Fehler

    Bin noch ein bisschen schlauer geworden: die Zugriffsverletzung ist bei der adresse: 0xcdcdcdcd, das hWnd hat auch den Wert 0xcdcdcdcd. Na gut, damit bin ich zwar auch nicht schlauer, aber wenigstens etwas. Irgendwie kann ich diesen Fehler überhaupt nicht nachvollziehen.

    Ich weiß, ich bin manchmal etwas schwer von begriff. Aber irgendwie muss ich das ja lernen xD. Vielen Dank auch an alle, die bisher geholfen habe - mir fällt grad auf, dass ich mich noch kein einziges mal bedankt habe *blush*



  • hilfe! ^^"
    (sorry für doppelpost)



  • Woah - habs hingekriegt, hurrrrrrrraaaaaaa!!!!!!!!!!!!!!!!!

    hatte aus versehen in der Klassendefinition und in der funktionsdefinition ein WNDCLASSEX wcex stehen, lag doch nicht am this zeiger, muhaha. Danke an alle nochmal^^



  • so - ist zwar jetzt ein 4fach Post, aber es gibt immer noch ein Problem:
    Zwar lässt sich alles wunderbar kompilieren und starten, aber wenn ich versuche, irgendeine Nachricht zu verarbeiten, spuckt er mir eine "Debug assertion Fehler"meldung aus, das ist für mich vielzu tief in irgendetwas C-internem gebohrt, davon hab ich keine ahnung mehr, kann vllt. doch jemand ein tipp geben, worans liegen könnte?



  • Azrael, il Meraz schrieb:

    aber wenn ich versuche, irgendeine Nachricht zu verarbeiten, spuckt er mir eine "Debug assertion Fehler"meldung aus,

    Was denn für eine Nachricht ? Wenn sich das Programm starten lässt, dann hat es doch schon etliche Nachrichten verarbeitet (WM_CREATE, ...) ohne Fehlermeldung ?



  • WM_CHAR wird verarbeitet. sogar wenn die nachricht garnichts macht, kommt ein fehler, sobald man eine Taste drückt. alt-f4 verträgt er genauso schlecht....



  • Azrael, il Meraz schrieb:

    sobald man eine Taste drückt

    Kontrolliere mal WM_KEYDOWN, WM_KEYUP.


Anmelden zum Antworten