Wie kann ich die Quelle einer geposteten Nachricht ermitteln?
-
Hallo,
kennt jemand eine einfache Möglichkeit den Verursacher einer geposteten Nachricht zu ermitteln?Grundsätzlich kann ja jeder Thread im Windows System ein PostMessage() oder PostThreadMessage() an ein beliebiges Fenster oder einen beliebigen anderen Thread absetzen. In der MessageLoop kann ich zwar Nachrichten rausfiltern und verwerfen, ich würde aber gerne wissen, wann die Message von welchem Prozeß gepostet wurde.
Die einzige Lösung, die mir einfällt ist ein systemweiter API Hook auf alle PostMessageA() und PostMessageW() Funktionen. Geht das einfacher?
-
Das weiß das System auch nicht...
Warum auch? Die Nachricht wird in die Queue gestellt wie jede andere Nachricht auch und das war es...Mehr als in MSG drin steht erfährst Du nicht eigentlich nicht.
Was ist der Sinn Deiner Frage?
-
Hallo Martin, danke für die schnelle Reaktion.
Ich habe hier eine ziemlich umfangreiche Anwendung (ca. 3 Mio lines source code), modular, mehrere Entwickler. Für längere Berechnungen (mehrere Algorithen, die nacheinader laufen und Daten im Speicher ändern) wird ein Progressfenster modal geöffnet und die eigentliche Berechnung per Callback aufgerufen. Im Progressfenster wird der Fortschritt angezeigt und ein Cancel-Button erlaubt einen Abbruch. Normalerweise wird am Ende eines Algorithmus der modale Zustand verlassen und das Hauptfenster wieder aktiviert.Damit das Progressfenster zwischen den einzelnen Algorithmenstarts nicht ständig auf und zugeht (flimmert) wird es als nicht-modales Fenster erzeugt und bei einem Algo-Start modal gemacht, indem alle anderen Top-Level Fenster der Applikation diasabled und eine neue MessageLoop gestart wird. Bei Algo-Ende wird diese Message-Loop verlassen und ein 200ms Timer gesetzt. Falls innerhalb des Timers kein neuer Algo ausgeführt wird, wird das Fenster endgültig geschlossen.
Das ganze läuft seit Jahren stabil. Set Window 7 haben wir auf einigen Rechnern den Effekt, dass manchmal innerhalb der MessageLoop des modalen Progess-Fensters WM_ACTIVATE und andere Nachrichten für das MainWindow in der MessageQueue stehen. Bisher sehe ich, dass während des Algorithmenlaufes (periodischer Aufruf der inneren MessageLoop) das aktive Fenster vom Progress-Window auf das Main-Window wechselt und das ProgressWindow unsichtbar wird. Die WM_ACTIVATE message kommt aus der MessageLoop, also aus der Queue. Das ganze passiert ohne Nutzerinteraktion.
Nach einem Mausklick in das Main-Window wird das ProgressWindow wieder sichtbar und das aktive Fenster wechselt wieder vom Main-Window auf das Progress-Window.Ich suche jetzt die Ursache für das WM_ACTIVATE, das ca. 18 Sekunden nach Algorithmenstart den Wechsel vom modalen Progressfenster zum MainWindow signalisiert. Ich will wissen, was zum WM_ACTIVATE des Hauptfensters führt.
Die Nachrichten überwache ich per SetWindowsHookEx(WH_CALLWNDPROC,...). Ein Stackscan zeigt, dass die WM_ACTIVATE an das Hauptfenster aus der MessageLoop kommt. Ich kann im Moment nicht ausschließen, dass der Wechsel des aktiven Fensters durch einen anderen Thread oder Prozeß verursacht wird.
Zur Fehlersuche wäre es durchaus sinnvoll zu wissen, aus welchem Prozeß Nachrichten an das eigene Fenster oder den eigenen Thread gepostet werden. Lästige AddOn's ließen sich damit leichter identifizieren.
-
Aber wenn auf dem Mainframe ein WM_ACTIVATE ankommt, dann muss es auch ein Enable gebenm oder?
Der kommt mit Sicherheit vorher... Versuch doch mal da anzusetzen.
-
Ein WM_ENABLE habe ich im Log eben nicht gesehen. Ich werde jetzt mal vor und nach jder Message den Window-State von beiden Fenstern und ::GetActiveWindow()prüfen. Kann etwas dauern bis ich mich wieder melde.
-
kurzer Zwischenstand:
IsWindowEnabled(MainFrame) liefert FALSE, während es die Message WM_ACTIVATE für seine eigene Aktivierung abbekommt.
Die Message wird innerhalb von PeekMessage() direkt aus der user32.dll an die Window Procedure übergeben. Zwischen PeekMessage() und dem Aufruf der Window-Procedure liegen nur 4 oder 5 user32.dll Stack-Frames.
Der Zeitpunkt fällt zusammen mit dem ersten PeekMessage() nach einer längeren Unterbrechung der MessageLoop(). Ich habe die MessageLoop() absichtlich längere Zeit unterbrochen bis der (not responding) Zustand im Fenstertitel angezeigt wird. Innerhalb des ersten PeekMessage() danach wird das bis dahin aktive Progress-Fenster deaktiviert und in der Z-Order in den Hintergrund gelegt. Das MainFrame wird aktiviert und erhält von der user32.dll WM_ACTIVATE und WM_SETFOCUS obwohl es WS_DISABLED ist.
Ich werde mal versuchen die Situation mit einier kleinen Win32 Anwendung mit 2 Fenstern nachzubauen.
-
Hat auch Dein Progress Window wirklich den Focus und ist aktiv bevor Du das Main-Windows disablest?
-
Ob das Progress-Window schon aktiv ist, bevor ich das Main Window disable schaue ich mir heute nochmal an. Jedenfalls bekommt das Progress-Wnd die WM_ACTIVATE (false) Nachricht ab und GetActiveWindow() zeigt es bis zu diesem Zeitpunkt als aktives Fenster. Der Cancel-Button des Progress-Windows erhält auch die WM_KILLFOCUS unmittelbar bevor das disabled Main Window die WM_SETFOCUS erhält.
Was führt eigentlich zum "not responding" im Titel eines Fensters. Ich dachte bisher, eine lange Unterbrechung der Message-Loop würde reichen. Das konnte ich in einem einfachen Testprogramm nicht nachvollziehen. Auch nach 2 Minuten Unterbrechung der Message-Loop steht da nichts in der Titelzeile. Die Message Queue sollte eigentlich voller MOUSEMOVE Nachrichten sein.
Da der Active-Window Wechsel innerhalb des PeekMessage() calls passiert vermute ich im Moment eher ein wartendes Cross-Thread SendMessage oder eine wartende RPC/COM-Nachricht.Auch die Tatsache, das der Fehler nur auf einigen Rechnern und auch dort nur manchmal auftritt deutet auf ein asynchrones Inter-Thread Problem. Ich schaue mir nochmal die anderen Threads im Prozeß an, vielleicht wartet da ja einer auf Antwort.
-
Wundert mich. Eigentlich müsste ein fehlender GetMessage/PeekMessage das Problem auslösen.
Kan auch sein, dass dies in Windows 7 etwas geändert wurde. Insofern, dass dieses nicht reagieren nur kommt wenn eine LbuttonDown oder RButtonDown längere Zeit nicht abgearbeitet wird.
BTW: Windows 7 erzeugt dann sogeannte Shadow Fenster mit einem alten Abbild der Anwednung... Das Ganze damit DWM noch klar kommt...
-
An die Shadow Window Mechanik von DWM hatte ich nicht gedacht. Eigentlich hatte ich schon immer vermutet, dass in Windows Geister stecken
. Hier ist der Beweis:http://temp.bbglobal.de/GeisterBilder.png
Rot sind die Geister und die verhalten sich eben nicht wie richtige Fenster. Die Lösung besteht darin die Geister loszuwerden und das Message Processing nicht zu blockieren. Leider ist der Code teilweise 15 Jahre alt. Von Critical Sections, Multithreading und Background-Workern haben wir damals noch nicht einmal geträumt.
Danke nochmal für die Hilfe.
BTW: Hinreichend viele Doppelklicks (etwa 20) auf den Cancel-Button bringen auch im Testprogramm den Geist zum Erscheinen (Keine Rückmeldung).