Hauptfenster der eigenen Applikation bestimmen
-
So in etwa habe ich das schon, aber da die Funktion in einer Bibliothek landen wird und vermutlich nicht sooo häufig gebraucht wird möchte ich so viele Fehlerquellen wie möglich ausschließen. Eine davon könnte der fehlende Initialisierungsaufruf sein. Lieber jetzt ne Stunde Arbeit mehr investieren als später stundenlang mit dem Debugger rumzuwühlen.
-
Wenn das DataSource Objekt einem Grid zugehörig ist, lässt sich evtl. das Windows-Handle des Grids ermitteln? Dann kannst Du mit
GetWindowThreadProcessId die ID des Threads erfragen, die das Fenster erstellt hat.
-
Habe ich mir auch schon überlegt, aber dann wäre das ja an das Grid gebunden. Das GUI Framework enthält viel mehr Komponenten, die alle nicht threadsafe sind, daher möchte ich das universell halten. Ich glaube, ich muss wirklich per EnumWindows und GetWindowThreadProcessId alle Fenster durchlaufen, bis ich ein Fenster finde, das mit der aktuellen Prozess ID erstellt worden ist und da dann die Thread IDs vergleichen.
-
DocShoe schrieb:
Habe ich mir auch schon überlegt, aber dann wäre das ja an das Grid gebunden. Das GUI Framework enthält viel mehr Komponenten, die alle nicht threadsafe sind,
Aber die werden doch alle ein Windows-Handle haben, das man als Parameter an die Prüffunktion weitergeben kann ...?
-
Ja und? Was macht das? Verwende einfach kene UI Komponenten aus einem anderen Thread. Bei der MFC isr das genauso. Kommuniziere eben nur mit entsprechenden Nachrichten zwischen den Threads.
Wann willdu Du dasden prüfen?
Kritisch ist es eigentlich immer dann, wenn das HWND Handle Deines unsicheren Frameworks zu einem anderen Thread gehört, und dass kanst Du mit einfachen Bordmitteln prüfen, die hier schon genannt wurden.
-
Belli schrieb:
DocShoe schrieb:
Habe ich mir auch schon überlegt, aber dann wäre das ja an das Grid gebunden. Das GUI Framework enthält viel mehr Komponenten, die alle nicht threadsafe sind,
Aber die werden doch alle ein Windows-Handle haben, das man als Parameter an die Prüffunktion weitergeben kann ...?
Nein, leider nicht. Es gibt Komponenten, die Windows "Komponenten" kapseln und ein Windows Handle besitzen, aber auch andere, die´s nicht tun und daher auch kein Handle haben. Beim Framework ist ausserdem das MVC Konzept sauber umgesetzt, so dass ich im DataSource Objekt auch nicht weiß, zu welchem GUI Objekt ich eigentlich gehöre. Deshalb bin ich mir nicht sicher, ob ich überhaupt an das Handle des Grids herankomme, ohne das als Member anzulegen. Und da hört der Spaß dann auf.
Meine Lösung sieht jetzt so aus und funktioniert. Ist zwar doof, dass ich mich durch alle Fenster hangeln muss, aber einen Performanceeinbruch habe ich nicht feststellen können.
BOOL __stdcall assert_gui_main_thread_proc( HWND Window, LPARAM Param ) { DWORD ProcessID; unsigned int ThreadID = GetWindowThreadProcessId( Window, &ProcessID ); if( ProcessID == GetCurrentProcessId() && ThreadID != GetCurrentThreadId() ) { assert( false ); } return TRUE; } void assert_gui_main_thread() { #ifdef DEBUG ::EnumWindows( assert_gui_main_thread_proc, 0 ); #endif }
-
Mal was ganz anderes. Der GUI Thread ist in 99,99% aller Fälle auch er erste Thread der erzeugt wird. Warum also nicht die Thread-ID beim Start in einem Singleton merken und später prüfen...
Weitaus einfacher und nicht invasiv.
-
DocShoe schrieb:
Es gibt Komponenten, die Windows "Komponenten" kapseln und ein Windows Handle besitzen, aber auch andere, die´s nicht tun und daher auch kein Handle haben.
Die findest Du mit EnumWindows auch nicht.
-
Ich seh´ schon, da muss ich wohl noch weiter ausholen.
In meinem Projekt gibt es einige Datenobjekte, die Zustandsänderungen mittels des Observer Patterns mitteilen. Als Observer gibt es z.B. eine Datenquelle, die bei einer Statusänderung des Subjekts ihr zugehöriges Grid aktualisiert. Da die Zustandsänderung einen Datenobjekts allerdings auch durch einen Worker Thread geschehen kann findet die Benachrichtigung der Observer im Kontext des Worker Threads statt und alle Operationen, die irgendwie mit der GUI zu tun haben, dürfen in diesem Fall nicht ausgelöst werden bzw. müssen mit dem GUI Thread synchronisiert werden.Die assert Funktion erfüllt keine wichtige Funktion, sie soll lediglich das Debuggen zu erleichtern und die Fälle zu finden, wo eine Aktualisierung aus dem Worker Thread stattfindet und UB erzeugt.
Für eine möglichst einfache Benutzung möchte ich möglichst nur einen Funktionsaufruf ohne vorherige Initialisierung, um eine Fehlerquelle auszuschliessen. Natürlich kann ich eine Initialisierungsfunktion zu Programmstart aufrufen, aber das möchte ich durch einen Automatismus vermeiden.
@Belli:
Es geht mir auch nicht darum, jede einzelne Komponente zu finden, sondern lediglich das Hauptformular der Applikation. Das ist eine Windows Komponente, hat ein Windows Handle und kann also dazu benutzt werden, den GUI Thread zu identifizieren.PS:
Schlauer wäre es vielleicht, die Observer, die die GUI aktualisieren, mit dem GUI Hauptthread zu synchronisieren, um das Problem prinzipiell zu lösen.
-
Wie Du zum Schluß selber geschrieben hats, würde ich den Worker grundsätzlich entkoppeln.
Das Ganze kann doch einfach dadurch geschehen, dass Du Windows Messages aus dem DB-Worker an die UI sendest. Dadurch passiert autoamtsich eine korrekte Synchronisation und der Haptthread fürhrt dann die Änderung durch.
Aber das wurde ja schon geschrieben...