Generelle "Design"-Frage
-
Servus Jungs,
ich habe mal eine generelle Frage zum Thema globale Variablen, Kapselung und ähnliches : Man sollte ja möglichst globale Variablen vermeiden. Nur fällt mir das manchmal schwer. Nehmt euch mal als Beispiel den generellen Aufbau von einem WinApi GUI Programm :
int WinMain(...) { // Lauter Handles werden hier definiert // Und hier werden ( bei mir ) CreateWindow-Calls ausgeführ } LRESULT WindowProc(...) { // zum Beispiel : case WM_COMMAND : switch(HIWORD(wparam)) { // Problem wäre nur Beispielweise hier } }Das Problem an erwähnter Stelle : zb will man jetzt bei BN_CLICKED den Text von einem bestimmten Edit-Control auslesen. Nur sind die entsprechenden Handles in WinMain definiert. -> Alle Fenster in WindowProc deklarieren ? Dann hab ich wieder das Problem, dass der parent-Window Handle trotzdem in WinMain ist, hInstance ebenfalls.
Soll man die Handles eigends in Klassen packen ? Soll dann jede Klasse ihre eigene Callback-function haben? Soll ich dann für jeden Button, Edit, etc. eine Instanz entsprechender Klasse haben? Hört sich alles nicht so toll an.
Klar, man könnte einfach sagen : Interessiert mich nicht, ich nehm nen fertiges Framework, aber mich interessiert es.Sorry wenn die Frage blöd und die Antwort offensichtlich ist, für mich ist sie es leider nicht.
Mfg
-
FragenSteller_ schrieb:
Sorry wenn die Frage blöd und die Antwort offensichtlich ist, für mich ist sie es leider nicht.
Ganz und gar nicht, eher im Gegenteil. Ich finde die Frage, wie man diese C-APIs in ein schönes, sauberes Korsett packen kann gar nicht so uninteressant. Allerdings muss ich gestehen in diesem Fall irgendwann aufgegeben zu haben. Das Problem ist Folgendes: Die Callback-Funktion (WindowProc) kann nicht an ein Objekt gebunden werden. Wenn man aber brav sein C++ 1x1 gelernt hat, weiß man, dass OO und alles was dahinter hängt total fancy ist. Tja, kleines Problem: Irgendwie muss man die Nachrichten ja an Objekte weitergeben.
Das Einzige, was mir bis jetzt dazu eingefallen ist, (allzu lange habe ich zugegebenermaßen nicht damit aufgehalten) ist ein Singleton (google) zu erstellen, bei dem sich jedes Fenster an und abmeldet, und über das die Nachrichten dann entsprechend verteilt werden. (Über das HWND kann man ja identifizieren wo die Nachricht hin muss.) (Aufpassen bei Multithreading!)
Es würde mich in der Tat freuen zu lesen, ob hier jemand einen schöneren Weg gefunden hat.
-
cooky451 schrieb:
Es würde mich in der Tat freuen zu lesen, ob hier jemand einen schöneren Weg gefunden hat.
Du bindest die WndProc einfach an ein Objekt

CreateWindow erlaubt einen Wert an WM_CREATE zu haengen (lParam), diesen kann man auslesen und per SetWindowLongPtr in das Fenster eintragen. Dann kann man in der WndProc anhand des hwnd den Wert auslesen und Baemm - die WndProc ist an ein Objekt gebunden.
-
Shade Of Mine schrieb:
CreateWindow erlaubt einen Wert an WM_CREATE zu haengen (lParam), diesen kann man auslesen und per SetWindowLongPtr in das Fenster eintragen. Dann kann man in der WndProc anhand des hwnd den Wert auslesen und Baemm - die WndProc ist an ein Objekt gebunden.
Klingt nett (auch wenn man immer noch aufpassen muss bei Multithreading..), aber: Wie kann man SetWindowLongPtr sagen, dass es ein this + Funktionszeiger braucht? Ich kann mir gerade nicht so ganz vorstellen wie das laufen soll, kannst du dazu Code zeigen?
-
cooky451 schrieb:
Es würde mich in der Tat freuen zu lesen, ob hier jemand einen schöneren Weg gefunden hat.
Bei GLUT hat man ein ähnlich gelagertes Problem. Es ist schlicht und einfach nicht möglich, dies ohne einen globalen Programmzustand zu modellieren, da es ein globaler Programmzustand ist. Auf jeden Fall besteht aber keine Not, 50 Variablen global zu machen, eine handvoll Objekte mit guten Design (besonders beim Zugriff) tun's ebenfalls. Ob dann Singleton oder nicht hängt dann noch von weiteren Erwägungen ab, eventuell hat man ja auch den Fall, dass man mehrere von diesen Zuständen gleichzeitig verwalten muss.
Die perfekte Lösung wäre natürlich, die Bibliotheken komplett zu wrappen, so dass sie auch komplexere Callbacks anbieten können, als dies mit dem einfachen C-Interface möglich ist. Aber das ist vom Aufwand her eben einfach so groß, dass es meistens nicht in Frage kommt. Manchmal gibt es auch Projekte, wo dies schon zum Teil geschehen ist, dann kann man diese nutzen. Im Fall des Fensterlns für Windows soll es ja durchaus auch C++-orientierte Bibliotheken geben.
-
cooky451 schrieb:
Shade Of Mine schrieb:
CreateWindow erlaubt einen Wert an WM_CREATE zu haengen (lParam), diesen kann man auslesen und per SetWindowLongPtr in das Fenster eintragen. Dann kann man in der WndProc anhand des hwnd den Wert auslesen und Baemm - die WndProc ist an ein Objekt gebunden.
Klingt nett (auch wenn man immer noch aufpassen muss bei Multithreading..), aber: Wie kann man SetWindowLongPtr sagen, dass es ein this + Funktionszeiger braucht? Ich kann mir gerade nicht so ganz vorstellen wie das laufen soll, kannst du dazu Code zeigen?
Wo siehst du Probleme bei Multithreading? Du bekommst nur eine WM_CREATE Message und von ein paar spezialsachen abgesehen ist das die erste message die das Fenster bekommt. Und die Message kommt auch nur einmal. Also muss man da nicht wirklich was beachten.
Und du brauchst keinen Funktionszeiger - du haust den Zeiger auf dein Window-Objekt per SetWindowLongPtr in das Fenster.
Sobald nun eine Message kommt, liest du ihn aus und mappst die Messages auf das Objekt.Trivialer Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { Window* that=(Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(msg == WM_CREATE) { that = (Window*) (((LPCREATESTRUCT) lParam)->lpCreateParams); SetWindowLongPtr(hwnd, GWLP_USERDATA, that); } if(that) { return that->WndProc(msg, wParam, lParam); } else { return DefWindowProc(hwnd, msg, wParam, lParam); } }man muss nur darauf achten, dass WM_CREATE uU nicht die erste Message ist. Da gibts ein paar Sachen die tricky sind. Aber das ist so in etwa die Idee.
-
Ah ok, jetzt weiß ich wie du das meinst. Man kann sich dauerhaft Informationen mit schicken lassen. Nett.

-
Sieht also so aus als wäre das doch ein Stück komplexer, als man denkt ;P
Ich denke für den Moment begünüge ich mich mit globals und versuche die Anzahl aufs nötigste zu reduzieren, sollte gehen. Bei Gelegenheit kann ich ja nochmal über die Vorschläge hier reflektieren ;P
Danke fürs Posten auf jeden Fall !