WndProc in eine Klasse bekommen...



  • Original erstellt von Shade@work:
    **@Webfritzi:
    Die wndproc MUSS static sein, anders kann sie nicht in der klasse sein, was sie aber sein muss, sonst ist die kapselung im *****...

    deshalb machen wir sie static.
    **

    Das habe ich schon gemerkt, dass sie static sein MUSS. Aber wieso? Ich meine, ich wüsste gerne die Bedeutung des Schlüsselwortes static in diesem Zusammenhang. Und warum geht's nicht ohne static, was wieder Mis2coms Frage vom Anfang wäre.



  • die frage wurde doch schon beantwortet!

    Jeder Methode wird der this zeiger uebergeben.
    A a;
    a.b() == b(&a)
    von der funktionsweise her!

    eine static methode hat aber keinen this zeiger, deshalb ist
    a.b() nicht moeglich wenn b static ist.
    A::b() ist dann aber sehr wohl moeglich!
    A::b() == b()
    und somit sind wir das problem losgeworden, dass der compiler der wndproc den this pointer mitgeben wollte...

    Denn die wndproc darf keinen this zeiger bekommen, denn sie ist callback, was soviel heisst wie: windows ruft die funktion auf! und windows hat keine ahnung welchen this zeiger es mitgeben muss.



  • Wenn du ne Wrapperklasse schreiben willst kannst du bei jedem aufruf der funktion einfach eine funktion deiner Wrapperklasse starten, du legst in der funktion ne statische map an und öffnest immer jeweils die funktion zum HWND das ist dann fast das selbe... du musst halt noch den zwischenschritt machen...

    erm... schau mal in meinem Tut unter Entwicklung eines Steuerelements!
    ciaoy 🙂

    > Endy <<



  • da gibts ne viel einfachere lösung....

    class CWindow
    {
    static LRESULT CALLBACK BaseWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    };
    
    LRESULT CALLBACK BaseWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    return CWindow::WindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    LRESULT CALLBACK CWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    //hier kannste jetzt alles machen...
    }
    

    und bei der wndclass kannste jetzt die basewndproc als wndproc angeben.....

    mfg 5th

    [ Dieser Beitrag wurde am 16.06.2002 um 11:22 Uhr von 5thElement editiert. ]



  • Toll, das bringt's!!!!



  • Das geht doch gar nicht! :p
    Schonmal versucht das zu kompilieren?!

    <eigenwerbung>Hier gibts meine WinAPIWrapper inklusive Quelltext.</eigenwerbung>



  • eins vorweg:ich steige gerade um von c auf c++!
    es ist nur eine idee aber vielleicht kann man das problem als lösung verwenden!!
    vielleicht geht es das man die WndProc mit drei parametern deklariert(den indirekten this noch dazu sind es 4!)
    windows übergibt ja auch genau 4 parameter,ich hoffe das alle 4Byte lang sind(bei windows weis ichs, in der eigens definierten müssen dann alle 4Byte lang sein)
    ,wenn man den this dann in HWND castet müsste es gehen(falls der this der 1.param ist)
    ,den this muss man dann im konstruktor in einer "this" variable speichern(falls man ihn braucht).
    ich weis nich ob das geht aber ich bin mir fast sicher mit rumgecaste müsste es gehen.was sagt ihr dazu ich bin ja in c++ nich so bewandert,könnte es gehen?gebt mal euren senf dazu ab! :p 🙄 🕶 🙂



  • Original erstellt von cd9000:
    **Das geht doch gar nicht! :p
    Schonmal versucht das zu kompilieren?!

    <eigenwerbung>Hier gibts meine WinAPIWrapper inklusive Quelltext.</eigenwerbung>**

    na, dann weiss ich nicht wieso es in den directx samples geht 😉
    code-ausschnitt:

    //-----------------------------------------------------------------------------
    // Name: WndProc()
    // Desc: Static msg handler which passes messages to the application class.
    //-----------------------------------------------------------------------------
    LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
        return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
    }
    
    //-----------------------------------------------------------------------------
    // Name: MsgProc()
    // Desc: Message handling function.
    //-----------------------------------------------------------------------------
    LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
                                      LPARAM lParam )
    {
    //...
    }
    
    //klasse
       virtual LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
    


  • nagut wenn ihr keinen senf dazu abgeben wollt...
    ich habs probiert und meine mit meiner lösung auch weiter zu kommen(noch nich alles getestet läuft aber schonmal!!)
    etwas ASM konnte ich aber nich vermeiden...

    #include<windows.h>
    
    //LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
    
    class wrap
    {
    private:
    public:
    LRESULT CALLBACK WndProc(UINT,WPARAM,LPARAM);
    };
    
    wrap mytest;
    
    int WINAPI WinMain(HINSTANCE h1,HINSTANCE h2,LPSTR comline,int show)
    {
        HWND hwnd;
        MSG msg;
        WNDCLASS wnd;
        long (__stdcall *f2)(HWND,UINT,WPARAM,LPARAM);
        long (__stdcall wrap:: *f1)(UINT,WPARAM,LPARAM);
        char *appname = "Spielwiese";
        wnd.style=CS_VREDRAW|CS_HREDRAW;
        //wnd.lpfnWndProc=mytest.WndProc;
        f1=mytest.WndProc;
        __asm{
        mov eax,f1
            mov f2,eax
        }
        wnd.lpfnWndProc=f2;
        wnd.cbClsExtra=0;
        wnd.cbWndExtra=0;
        wnd.hInstance=h1;
        wnd.hIcon=LoadIcon(NULL,IDI_APPLICATION);
        wnd.hCursor=LoadCursor(NULL,IDC_ARROW);
        wnd.lpszMenuName=NULL;
        wnd.hbrBackground=(HBRUSH) GetStockObject(BLACK_BRUSH);
        wnd.lpszClassName=appname;
    
        RegisterClass(&wnd);
    
        hwnd=CreateWindow(appname,appname,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,h1,NULL);
        ShowWindow(hwnd,show);
        UpdateWindow(hwnd);
    
        while(TRUE)
            {
            if(!PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message==WM_QUIT)
                    break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            }
            else
            {
    
            }
            }
        return msg.wParam;
        }
    
    LRESULT CALLBACK wrap::WndProc(UINT message,WPARAM w,LPARAM l)
    {
        HWND hwnd;
        hwnd=(HWND)this;
        switch(message)
        {
        case WM_LBUTTONDOWN:
            MessageBox(NULL,"Hallo","nochmal hallo",MB_OK);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd,message,w,l);
    }
    


  • Kannste mal den Assembler-Code erklären, bitte?



  • ja kann ich.

    __asm{
        mov eax,f1
            mov f2,eax
        }
    

    mov eax,f1
    das bedeutet das in das register(eine statische hardware variable,sozusagen)der wert geschrieben wird der in f1 steht.
    eax=f1;//wäre es in c
    mov f2,eax
    das bedeutet das aus dem register der wert in f2 geschrieben wird.
    f2=eax;//in c

    das andere sind tags.
    ich gehe den umweg über das register weil direktes umkopieren nich geht,und weil in assembler keine typen prüfung statt findet!beide funktionspointer haben unterschiedliche parameter,das kann man in c++ nicht konvertieren,aber in ASM:)

    [ Dieser Beitrag wurde am 17.06.2002 um 19:07 Uhr von Bigor editiert. ]



  • na, dann weiss ich nicht wieso es in den directx samples geht
    code-ausschnitt: ...

    Dein directx Beispiel funktioniert, weil Du dort einen (offenbar) globalen Pointer (g_pD3D...) hast, um das nicht-statische WndProc aufzurufen. Geht also nur solange Du nur eine Instanz Deines Windows hast.



  • Ist ja jetzt auch egal. Scheinbar hat jetzt jeder für sich eine Methode gefunden, die er für die beste hält. 🙂



  • @Bigor:
    Gute Idee 🙂
    Aber das Grundproblem bleibt bestehen: Wie kann man auf Membervariablen der Klasse zugreifen?
    Der einzige vorteil bei dir ist, dass die Methode nicht mehr static ist. Obwohl: eigentlich ist sie es ja doch, oder? Sobald man versucht auf membervariablen zuzugreifen, stürzt das Programm ab. Also quasi eine static methode, deren static eigenschaft erst zur Laufzeit klar wird.



  • also ich habe dieses problem so gelöst:
    LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
    klasse* wnd = (klasse*)GetWindowLong(hWnd, GWL_USERDATA);

    switch(message){
    case WM_CREATE:
    wnd = (klasse*)((CREATESTRUCT*)lParam)->lpCreateParams;
    SetWindowLong(hWnd, GWL_USERDATA, long(wnd));}
    wnd->WndProc(hWnd,message,wParam,lParam);
    return DefWindowProc(hWnd,message,wParam,lParam);}

    diese funktion gibst du bei wndclass an,
    beim erstelllen des fensters musst du als param den this zeiger übergeben, diese funktion ruft von der klasse die funktion WndProc auf(von der richtigen klasse(des entsprechenden fensters)).
    Tadda feritg. Und dynamisch, beliebig viele instancen



  • @cd9000:
    ja das hab ich auch gerade gemerkt...:(
    aber ich versuche das so zu lösen indem ich den this pointer vom konstruktor speichere,und dann muss man auf die variablen vom this aus zugreifen,ich schaffe es allerdings im moment nichmal einen konstruktor zum laufen zu kriegen(muss nochmal nachlesen wie das geht),das objekt wird im speicher denke ich nich wild hinund her geschoben,desahlb sollten jedes mal der this den gleichen wert haben,aber wie gesagt:ich fange gerade an von c nach c++
    ausserdem isses 1:30 mittwoch morgen und ich muss noch in die schule zeugnis abholen,ich gucke mir das morgne nochmal alles an:D:D:D:D



  • Hi!
    Mein Internet ist die letzten tage abgestürzt.
    Eure Lösungen sind super.
    Ich habe mir mal die DX Doku angesehen.
    Die müssen Windows ja schließlich auch benutzen.
    Und ich habe nun rausgefunden, dass die die WndProc einfach global machen.
    Wenn man wie für DX nur ein Fenster benötigt, finde ich diese Lösung auch einfach.

    In den letzten tagen habe ich mir eine Windows-Klasse für Fenster und eine kleine DX-Klasse für Pixelzeichnung erstellt.

    for(short i = 0; i < 2 ^ sizeof(i); i++)
    {
    Vielen Dank für eure Hilfe!
    }



  • nur falls es noch interessiert:ich habs jetz komplett mit zugriff au membervariablen,ist noch experimentell aber wers benutzen will kann sich das unwichtige ja ausschneiden.
    Man kann von dieser Klasse keine anderen ableiten,man ist also darauf angewiesen das man mit dem was bereits zu Klasse gehört auskommt!!!!!!!

    #include<windows.h>
    #define GET_THIS static BaseWindow *pme=NULL;HWND hwnd=0;if(pme==NULL)pme=this;hwnd=(HWND)this;__asm{mov eax,pme};__asm{mov this,eax};
    #define GET_THIS_2 static BaseWindow *pme=NULL;HWND hwnd=0;if(pme==NULL){pme=this;return 0;}hwnd=(HWND)this;__asm{mov eax,pme};__asm{mov this,eax};
    
    class BaseWindow
    {
    private:
    
    public:
        char *appname;
        char trewq[100];
        MSG msg;
        CREATESTRUCT crStruct;
        HWND hWnd;
        HINSTANCE hInst;
        WNDCLASS wndclass;
        BaseWindow(char*,HINSTANCE);
        LRESULT CALLBACK WndProc(UINT,WPARAM,LPARAM);
        WPARAM Apploop();
    };
    
    int WINAPI WinMain(HINSTANCE h1,HINSTANCE h2,LPSTR comline,int show)
    {
        BaseWindow mytest("Geht schon sehr gut!!",h1);
        mytest.hWnd=CreateWindow(mytest.appname,mytest.appname,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,mytest.crStruct.hInstance,NULL);
        ShowWindow(mytest.hWnd,show);
        UpdateWindow(mytest.hWnd);
    
    return mytest.Apploop();
    }
    
    LRESULT CALLBACK BaseWindow::WndProc(UINT message,WPARAM w,LPARAM l)
    {
        GET_THIS;
        HDC hdc;
        PAINTSTRUCT ps;
    
        switch(message)
        {
        case WM_PAINT:
            hdc=BeginPaint(hWnd,&ps);
            SetPixel(hdc,300,300,RGB(0,255,0));
            EndPaint(hwnd,&ps);
           return 0;
        case WM_LBUTTONDOWN:
            wsprintf(trewq,"%d",5435);
            if(hwnd==this->hWnd)
            MessageBox(NULL,trewq,"nochmal hallo",MB_OK);
            MessageBox(NULL,"TEST","nochmal hallo",MB_OK);
            MessageBeep(0);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd,message,w,l);
    }
    
    WPARAM BaseWindow::Apploop()
    {
    while(GetMessage(&msg,NULL,0,0))
            {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            }
        return msg.wParam;
    }
    
    BaseWindow::BaseWindow(char* ApplicationName,HINSTANCE hInst)
    {
        long (__stdcall *f2)(HWND,UINT,WPARAM,LPARAM);
        long (__stdcall BaseWindow:: *f1)(UINT,WPARAM,LPARAM);
        this->WndProc(0,0,0);
        f1=WndProc;
        __asm{
        mov eax,f1;
        mov f2,eax
        }
        MessageBox(NULL,"TEST","nochmal hallo",MB_OK);
    wndclass.lpfnWndProc=f2;
    wndclass.style=CS_VREDRAW|CS_HREDRAW;
    wndclass.cbClsExtra=0;
    wndclass.cbWndExtra=0;
    wndclass.hInstance=hInst;
    wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndclass.lpszMenuName=NULL;
    wndclass.hbrBackground=(HBRUSH) GetStockObject(BLACK_BRUSH);
    wndclass.lpszClassName=ApplicationName;
    RegisterClass(&wndclass);
    appname=(char*)malloc(lstrlen(ApplicationName));
    strcpy(appname,ApplicationName);
    this->hInst=hInst;
    crStruct.hInstance=hInst;
    };
    

    [ Dieser Beitrag wurde am 06.07.2002 um 14:03 Uhr von Bigor editiert. ]

    [ Dieser Beitrag wurde am 24.07.2002 um 20:09 Uhr von Bigor editiert. ]

    [ Dieser Beitrag wurde am 11.01.2003 um 17:03 Uhr von Bigor editiert. ]

    [ Dieser Beitrag wurde am 11.01.2003 um 17:04 Uhr von Bigor editiert. ]


Anmelden zum Antworten