WndProc in Klasse! Instanzen Teilen sich eine WndProc! HELP!



  • Hi,

    ich habe versucht die WndProc in eine Klasse zu stecken, habe 4 Instanzen erstellt doch die Instanzen teilen sich die selbe WndProc????

    Hier der Code:

    #include <windows.h>
    
    class child
    {
    public:
    	child (void) {};
    	~child (void) {};
    
    	HWND init (HINSTANCE hInstance, HWND parent)
    	{
    		HWND result;
    
       MSG        msg;
       WNDCLASS   wc;
    
       char       szAppName[] = "Das Child Window000";
    
       wc.cbClsExtra          = 0;
       wc.cbWndExtra          = 0;
       wc.hbrBackground       = (HBRUSH) GetStockObject(WHITE_BRUSH);
       wc.hCursor             = LoadCursor(NULL, IDC_ARROW);
       wc.hIcon               = LoadIcon(NULL, IDI_APPLICATION);
       wc.hInstance           = hInstance;
       wc.lpfnWndProc         = WndProc;
       wc.lpszClassName       = szAppName;
       wc.lpszMenuName        = NULL;
       wc.style               = CS_HREDRAW | CS_VREDRAW;
    
       RegisterClass(&wc);
    
       result = CreateWindow(   szAppName,
                              szAppName,
                              WS_OVERLAPPEDWINDOW | WS_CHILD,
                              100,
                              100,
                              500,
                              200,
                              parent,
                              NULL,
                              hInstance,
                              NULL);
    
       ShowWindow(result, SW_SHOW);
       UpdateWindow(result);
    
    		return result;
    	}
    
    	static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    	{
    		child *temp;
    		switch (message)
    		{
    		case WM_CREATE:
    			{
    				temp = (child*)(((LPCREATESTRUCT) lParam)->lpCreateParams);
    			} break;
    		case WM_DESTROY:
    			{
    				PostQuitMessage(0);
    			}break;
    		}
    
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    };
    

    Was mache ich falsch? ich habe doch schon die params an die klasse übergeben? 😞



  • Dein Anliegen ist unverständlich.



  • mach dir mal gedanken über das schlüsselwort static
    http://tutorial.schornboeck.net/staticmember.htm



  • miller_m schrieb:

    mach dir mal gedanken über das schlüsselwort static
    http://tutorial.schornboeck.net/staticmember.htm

    mach ich das static weg compiliert er es nicht 😞



  • Ja, das ist so schon richtig. Die WndProc muss meines Wissens nach auch static sein. Du musst nur dafür sorgen, dass ein Zeiger auf die Instanz in der statischen WndProc landet, womit Du dann weiterarbeiten kannst.

    Hier Auszüge aus meinem Wrapper, der aber leider auch noch nicht fertig ist:

    // statische WndProc ruft die eine WndProc der Instanz auf
    // default windowproc for all objects based on this class
    LRESULT CALLBACK Widget::WindowProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    	if(Message == WM_CREATE) { // übergebenen this merken
    		::SetWindowLong(hWnd, GWL_USERDATA, (LONG)((CREATESTRUCT*)lParam)->lpCreateParams);
    	}
    
    	Widget* pReceiver = (Widget*)GetWindowLong(hWnd, GWL_USERDATA);
    
    	if (!pReceiver) {
    		return ::DefWindowProc(hWnd, Message, wParam, lParam);
    	}
    
        return pReceiver->DefWindowProc(Message, wParam, lParam);
    }
    
    // CreateWindow in einer Init-Funktion:
    this->Handle = ::CreateWindowEx(0, typeid(*this).name(), this->Text.c_str(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (pParent ? WS_CHILD : 0), x, y, width, height, (pParent ? ((Window*)pParent)->GetHandle() : 0), 0, 0, this);
    

    Als letzten Parameter übergibst Du also einfach den Zeiger auf die Instanz, der in der WndProc ausgelesen wird und wo Du dann mit arbeiten kannst.

    Der Source ist so ziemlich aus dem Kontext gerissen, aber die Vorgehensweise sollte klar sein.



  • (.)(.) schrieb:

    miller_m schrieb:

    mach dir mal gedanken über das schlüsselwort static
    http://tutorial.schornboeck.net/staticmember.htm

    mach ich das static weg compiliert er es nicht 😞

    weis ich auch. du sollst ja auch deinen code verstehen.

    benutz auch die forensuche dort wirst du verschiedene ansätze finden



  • @mantiz
    ich versteh deinen code nicht, jedenfalls die logik nicht 😞



  • hallo,

    Du erstellst ne Basisklasse mit statischer WndProc, in dem Fall
    Widget::WindowProc
    und virtueller WndProc in dem Fall DefWindowProc ( nicht zu verwechseln mit der
    API-Funktion DefWindowProc !)

    In der Init-Funktion wird
    this->Handle = ::CreateWindowEx(0, ... aufgerufen, der letzte Parameter ist this

    in der static WndProc wird bei
    if(Message == WM_CREATE) {

    der this-Zeiger durch
    ::SetWindowLong(hWnd, GWL_USERDATA, (LONG)((CREATESTRUCT*)lParam)->lpCreateParams);
    an das Fenster "gebunden", jedes Fenster hat eigene USER-DATEN, also seinen
    eignen this-Zeiger

    Mit
    (Widget*)GetWindowLong(hWnd, GWL_USERDATA);
    wird der this-Zeiger des Fensters geholt und die Methode DefWndProc der jeweiligen Instanz aufgerufen.

    Für jedes Fenster erstellt Du nun eine eigene Klasse abgeleitet von der Basisklasse und überschreibts die Methode DefWndProc

    MfG
    RB



  • Ja, genau, Danke für die Erläuterung, dann brauch' ich das nicht mehr machen. 🙂

    Das Problem ist ganz einfach das, dass man ja in der Nachrichten-Behandlung auf die Objektdaten zugreifen möchte, also braucht man eine Instanz der Klasse, womit man arbeiten kann. Wenn Du in Windows ein Fenster erstellst, so kannst Du jedem Fenster benutzerdefinierte Daten mitgeben. Per Default sind glaube ich immer 32 Bit dafür reserviert. Dieser Speicher ist ideal, um einen Zeiger zu übergeben, der auf 32-Bit-Systemen genau 32 Bit benötigt.

    Eine Alternative wäre, so, wie ich das auch vorher gemacht habe:
    1. Du rufst direkt vor CreateWindow(Ex) die statische Methode "WindowProc" mit einer eigenen Message auf, z.B. WMU_INITINSTANCE oder so, da kannst Du dann den this-Zeiger z.B. per wParam übergeben, dann speicherst Du den Zeiger temporär in einer static-Var und bei WM_CREATE speicherst Du dann den temp-Zeiger und das Handle in einer Map. Der Nachteil hier ist aber, dass Du bei jeder Nachricht die Map nach dem übergebenen Handle durchsuchen musst, um den Zeiger auf das Objekt zu bekommen. Also schematisch in der Form:

    WindowProc(0, WMU_INITINSTANCE, (WPARAM)this, 0);  // Erster Parameter 0, da wir noch kein Fenster-Handle haben
    CreateWindow(...); // ganz normal, ohne this-Zeiger
    
    // Innerhalb der WindowProc dann:
    static Window* pTemp = 0;
    if (Message == WMU_INITINSTANCE) {
        pTemp = (Window*)wParam;
    }
    if (Message == WM_CREATE) {
        // Hier haben wir das Handle in z.B. hWnd und den Temp-Zeiger in pTemp, also nun in Map speichern
    }
    
    Window* pReceiver = 0;
    // Handle in Map suchen und den gefunden Objekt-Zeiger in pReceiver speichern
    Wenn pReceiver nicht gefunden wurde, dann DefaultWindowProc von Windows aufrufen:
    if (!pReceiver) {
        return ::DefWindowProc(hWnd, Message, wParam, lParam);
    }
    // Ansonsten DefWindowProc des gefundenen Objektes aufrufen:
    return pReceiver->DefWindowProc(Message, wParam, lParam);
    

    Von dieser zweiten Variante hab' ich mich aber zeimlich schnell verabschiedet, als ich gelesen habe, dass es mit der ersten Version auch geht, so spart man sich die Map und das suchen bei jeder Nachricht. Macht das ganze übersichtlicher, und ich denke auch um einiges schneller. 🙂



  • Dennoch sehr unverständlich für mich 😞 Maps und so.

    Kannst du mir ein gutes Sample machen? Aus dem Dingen in der FAQ werd ich absolut nicht schlau! Die Hauen da mit Assembler rum und nix läuft 😞



  • oder noch besser: kann mir jemand meinen Code so erweitern das es funktionieren würde und noch erklären was er da gemacht hat? ich glaub das würd ich am ehesten kapieren.



  • Auch, wenn es jetzt schon sehr in die Richtung geht, dass ich Dir die Arbeit abgenommen habe, hier ist Dein Code, wie er funktionieren sollte, ist aber ungetestet:

    #include <windows.h>
    
    class child {
    public:
    	HWND     myHandle;
    
    	child () {};
    	~child () {};
    
    	HWND init (HINSTANCE hInstance, HWND parent) {
    		MSG      msg;
    		WNDCLASS wc;
    
    		char szAppName[] = "Das Child Window000";
    
    		wc.cbClsExtra          = 0;
    		wc.cbWndExtra          = 0;
    		wc.hbrBackground       = (HBRUSH) GetStockObject(WHITE_BRUSH);
    		wc.hCursor             = LoadCursor(NULL, IDC_ARROW);
    		wc.hIcon               = LoadIcon(NULL, IDI_APPLICATION);
    		wc.hInstance           = hInstance;
    		wc.lpfnWndProc         = WndProc;
    		wc.lpszClassName       = szAppName;
    		wc.lpszMenuName        = NULL;
    		wc.style               = CS_HREDRAW | CS_VREDRAW;
    
    		RegisterClass(&wc);
    
    		myHandle = CreateWindow(szAppName,
    		                        szAppName,
    		                        WS_OVERLAPPEDWINDOW | WS_CHILD,
    		                        100,
    		                        100,
    		                        500,
    		                        200,
    		                        parent,
    		                        NULL,
    		                        hInstance,
    		                        this);  // Hier wird der Zeiger auf das erzeugte Objekt übergeben
    
    		ShowWindow(myHandle, SW_SHOW);
    		UpdateWindow(myHandle);
    
    		return myHandle;
    	}
    
    	LRESULT CALLBACK DefWindowProc(UINT Message, WPARAM wParam, LPARAM lParam) {
    		switch (Message) {
    			case WM_DESTROY: {
    				PostQuitMessage(0);
    				break;
    			}
    		}
    		// Nachrichten an Default-Windows-WndProc weiterreichen:
    		return ::DefWindowProc(myHandle, Message, wParam, lParam);
       }
    
    	static LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    		if(Message == WM_CREATE) { // übergebenen this merken
    			::SetWindowLong(hWnd, GWL_USERDATA, (LONG)((CREATESTRUCT*)lParam)->lpCreateParams);
    		}
    
    		child* pReceiver = (child*)GetWindowLong(hWnd, GWL_USERDATA);
    
    		if (!pReceiver) {  // Windows-eigene WndProc aufrufen, falls kein Zeiger gespeichert ist
    			return ::DefWindowProc(hWnd, Message, wParam, lParam);
    		}
    
    		return pReceiver->DefWindowProc(Message, wParam, lParam);
    	}
    };
    

    Wenn Du das jetzt immer noch nicht verstehst, dann tut es mir leid, aber wenn Du sowas vor hast, dann solltest Du schon verstehen, wie die Nachrichten-Behandlung unter Windows funktioniert und entsprechende C++-Kenntnisse haben, und ich denke, ich habe Dir jetzt schon so ziemlich alles abgenommen.

    Wenn Du nichtmal weißt was Maps sind, dann lern' erstmal die Grundlagen, bevor Du da weitermachst, sonst fragst Du bei jedem nächsten Schritt wieder hier nach.



  • (.)(.) will euch verarschen.



  • Hab' ich mir auch schon gedacht, aber irgendwie habe ich heute meinen Samariter-Tag. 😛



  • @mantiz
    ich kenn nur <map>? Du schmeißt hier mit Map rum aber was das ist sagst du net? Ich mein, frag ich nach Frames denkt auch jeder: Meint der HTML-Frames oder WindowFrames?

    Aber trotzdem danke

    @hinweis:
    Wenn Du blödes Arschloch mal nicht weiter weißt und fragst dann sag ich auch das du die gemeinschaft verarschen willst! Idiot!



  • 😃



  • Ja, ich meinte std::map, ich dachte, das wär' klar. Wenn Du's kennst, um so besser. 🙂

    bzgl. der Frames: So dürfte in einem HTML-Forum klar sein, was Du meinst. Und unter Windows bzw. GUI-Toolkits spricht man da eher von SplitterWindows, soweit ich weiß.



  • mantiz schrieb:

    Ja, ich meinte std::map, ich dachte, das wär' klar. Wenn Du's kennst, um so besser. 🙂

    Siehste um ne std::map habe ich dort bei dir nicht gefunden



  • mantiz schrieb:

    Wenn Du in Windows ein Fenster erstellst, so kannst Du jedem Fenster benutzerdefinierte Daten mitgeben. Per Default sind glaube ich immer 32 Bit dafür reserviert. Dieser Speicher ist ideal, um einen Zeiger zu übergeben, der auf 32-Bit-Systemen genau 32 Bit benötigt.

    Für Zeiger sollte man aber besser GetWindowLongPtr/SetWindowLongPtr nehmen.



  • groovemaster schrieb:

    mantiz schrieb:

    Wenn Du in Windows ein Fenster erstellst, so kannst Du jedem Fenster benutzerdefinierte Daten mitgeben. Per Default sind glaube ich immer 32 Bit dafür reserviert. Dieser Speicher ist ideal, um einen Zeiger zu übergeben, der auf 32-Bit-Systemen genau 32 Bit benötigt.

    Für Zeiger sollte man aber besser GetWindowLongPtr/SetWindowLongPtr nehmen.

    grund?


Anmelden zum Antworten