Window Klasse (WinAPI) schreiben - Message forwarding
-
Hi,
ich will eine Klasse für meine Programme schreiben die ein Fenster (HWND) repräsentiert. Klappt soweit ganz gut, nur suche ich immernoch nach einer guten Methode um die Messages zu forwarden. Also anfangs hab ich einfach einen globalen std::vector und eine globale WndProc gehabt. Bei der WM_NCCREATE message wurde dann aus dem Window Handle ein Objekt erstellt und dessen Adresse im vector gespeichert. Bei jeder anderen Message wurde das aktuelle Window Handle mit dem Window Handle dass im Objekt gespeichert war verglichen.
Keine sehr elegante Lösung. Dann hab ich im Internet die Methode gefunden das ganze im Prinzip so zu übernehmen nur dass der Pointer auf das Objekt per SetWindowLong mit GWLP_USERDATA gespichert wird und bei jeder anderen message als WM_NCCREATE wird das ganze mit GetWindowLong retrieved und über den Pointer der Message Handler aufgerufen.
Finde ich ganz gut. Das einzige was halt scheiße ist, ist dass der userdata belegt wird, also er nicht mehr frei ist. Man kann also kein userdata wert mehr setzen und gleichzeitig meine Klasse benutzen.Deswegen jetzt meine Frage: Habt ihr ne bessere Lösung für das ganze? Ich bin für alle Vorschläge offen.
Oder weiß vielleicht jemand wie es in MFC gemacht wird? (vom Prinzip würde auch schon reichen)MFG
-
MFC: keine Ahnung. Guck nach

ATL verwendet dazu Thunks.
Das sind kleine Funktionen, die zur Laufzeit erstellt werden.
So ein Thunk macht dabei im Prinzip folgendes:LRESULT __stdcall WndProcTrampoline(void* that, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT __stdcall WndProcThunk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return WndProcTrampoline( additionalParameter, // <- grosse dicke Magie hier hWnd, message, wParam, lParam); }Der "additionalParameter" wird dabei direkt in der zur Laufzeit erstellten Thunk-Funktion abgelegt.
Auf x86 Plattform, mit __stdcall Calling-Convention, ist das relativ einfach. Bei __stdcall werden alle Parameter am Stack abgelegt, und die aufgerufene Funktion kümmert sich darum den Stack-Pointer wiederherzustellen. Und Parameter werden "verkehrt herum" auf den Stack gelegt, also von rechts nach links.
Da die Thunk-Funktion und WndProcTrampoline die selbe calling convention verwenden, und WndProcTrampoline einfach nur ein parameter mehr hat, reicht folgender Code:
push additionalParameter jmp WndProcTrampoline"additionalParameter" ist dabei entweder Teil des Codes selbst ("immediate value"), oder wird über eine Adresse aus dem Speicher geladen ("memory", in dem Fall muss der Zeiger und der Inhalt der "Variable" im Speicher im Thunk angepasst werden).
Man fordert also ein paar Bytes Speicher an, kopiert die Thunk-Funktion da rein, und setzt den "additionalParameter" in der kopierten Thunk-Funktion auf den benötigten Wert (üblicherweise ein Zeiger auf irgendein Objekt).
Dann muss man lediglich noch sicherstellen dass die "Data Execution Prevention" nicht greift (=Speicherseite wo man den Thunk reinkopiert hat als "executable" markieren), und dass die CPU nicht alte Daten im Instruction-Cache stehen hat.
Und dann kann man die so erstellte Thunk-Funktion als Window-Procedure setzen.
Und nachdem man die letzte Nachricht des Fensters erhalten und weitergeleitet hat (WM_NCDESTROY IIRC), gibt man den Speicher für die Thunk-Funktion einfach wieder frei.
(Da der Thunk direkt per "jmp" weiterpsringt, das "return" in der "WndProcTrampoline" Funktion also direkt zum ursprünglichen Aufrufer zurückspringt (ohne Zwischenstopp im Thunk zu machen) kann man den Thunk direkt in "WndProcTrampoline" löschen, sobald sichergestellt ist, dass keine Messages mehr kommen)Da das ganze abhängig von der verwendeten CPU ist, ist es natürlich so überhaupt nicht portabel. Da der Code aber sowieso nur im Zusammenhang mit Windows gebraucht wird, ist das wohl weniger ein Problem.
-
Die MFC verwendet eine Map die die HWNDs auf CWnd* abbildet.
BTW: Es gibt auch Windows Porperties, die Du verwenden kannst.
SetProp/GetProp
http://msdn.microsoft.com/en-us/library/ms633564(VS.85).aspxBitte lies die MSDN genau, was das entsorgen angeht...
