Subclassing Problem / Logische abfolge beim erstellen von Fenstern



  • Hallo Zusammen,

    um mir die WinApi-Programmierung etwas zu erleichtern bin ich dabei mir einen Wrapper zu erstellen (natürlich auch zu Übungszwecken).

    Nun habe ich die Klasse "BaseWindow" als Basisklasse für alle Widgets. Diese hat eine Funktion "WndProc" die wie folgt aussieht:

    LRESULT BaseWindow::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    { 
    	BaseWindow* pWindow(0);
    
    	if( Msg == WM_NCCREATE )
    	{
    		pWindow = reinterpret_cast<BaseWindow *>(LPCREATESTRUCT(lParam)->lpCreateParams);
    		::SetWindowLong(hWnd, GWL_USERDATA, reinterpret_cast<long>(pWindow));
    
    		// save window handle
    		pWindow->SetWindowHandle(hWnd);
    
    	}
    	else
    	// retrieve associated Window 
    	pWindow = reinterpret_cast<BaseWindow*>(::GetWindowLong(hWnd, GWL_USERDATA));
    
    	if(pWindow)
    	{
    		return pWindow->ChildWndProc( Msg, wParam, lParam );
    	}
    
    	return DefWindowProc(hWnd, Msg, wParam, lParam);
    };
    

    Meinem Verständnis nach wir diese Funktion mit der Notification Msg == WM_NCCREATE aufgerufen, noch bevor die Funktion CreateWindow(Ex) zurückkehrt. Darum ist es notwendig den bereits erhaltenen Handle auf das Fenster zu speichern (noch bevor das Fensterobjekt diesen (auf "natürlichem" Weg als Rückgabewert von CreateWindow(Ex) erhält).

    Eine Klasse "MainWindow" (public abgeleitet von BaseWindow und entsprechend erweitert) funktioniert mit diesem Prinzip super, die Funktion "ChildWndProc()" des entsprechenden Objekts wird wie gewünscht aufgerufen.

    Als zweites habe ich also eine Klasse "Button" erstellt, diese ebenfalls public von "BaseWindow" erben lassen. Nun möchte ich, dass auch für das entsprechende Button-Objekt die Funktion "ChildWndProc()" aufgerufen wird. Da der Button jedoch eine WinApi-"Klasse" ist, kann man dieser nicht explizit mitteilen, dass es die o.a. WndProc benutzen soll, daher mein versuch mit dem Subclassing. des Weiteren wird die Notification WM_NCCREATE anscheinend von Windows nocht versendet, darum habe ich auch noch den this-Pointer als GWL_USERDATA abgespeichert (folgendes Listing Zeile 20)
    Nun habe ich folgenden Code für die Button-Klasse aufgesetzt:

    bool BaseButton::Create( const std::wstring Caption, unsigned int Width, unsigned int Height, unsigned int PosX, unsigned int PosY, HWND Parent )
    .
    .
    .
    		HWND hWnd = CreateWindow(	L"BUTTON",
    									m_Caption.c_str(),
    									WS_VISIBLE /*| BS_NOTIFY*/ | WS_CHILD,
    									m_PosX,
    									m_PosY,
    									m_Width, 
    									m_Height,
    									Parent,
    									NULL,
    									GetModuleHandle(0),
    									this							);
    
            //this->SetWindowHandle(hWnd); // 
    
    		// subclass the Button:
    		SetWindowLongPtr( hWnd, GWL_USERDATA, (LONG_PTR)this );
    		SetWindowLongPtr ( hWnd, GWLP_WNDPROC, (LONG_PTR)BaseWindow::WndProc);
    		return true;
    }
    

    Das Ergebnis ist nun, dass zwar Nachrichten ankommen, der Button aber nicht gezeichnet wird. Auch ShowWindow() bringt leider keinen Erfolg.

    Lasse ich das Subclassing (Zeile 20 & 21) weg, wird zwar der Button gezeichnet, erhält aber natürlich keine Nachrichten mehr.

    Der Fehler liegt, nehme ich an in der logik. Hat da jemand genug durchblick auszuhelfen?
    Weiterhin interessant ist, dass CreateWindow anscheinend _kein_ gültiges Handle zurück gibt.

    Vielen Dank vorweg, Suchmaschinen sowie MSDN habe ich bereits bemüht. Wegen des Riesenposts - ich wusste nicht wie ich das mit weniger erklären sollte.


  • Mod

    Nein! Dein Fehler liegt darin, dass dies kein korrektes Subclassing ist.
    Ich sehe keinen Aufruf der ursprünglichen WindowProc mit CallWindowProc
    http://msdn.microsoft.com/en-us/library/ms633571(VS.85).aspx

    BTW: Den ganzen Quark kannst Du mit der ATL oder MFC weitaus einfacher haben.


Anmelden zum Antworten