(Child-) Fenster erkennen anhand von HWND
-
Hallo Community,
ich habe ein Problem und komme nicht weiter. Folgendes Problem versuche ich zu lösen:
Ich habe eine Windows Anwendung, welche ein einziges Mal im TaskManager als Prozess auftaucht, aber mehrere Fenster offen hat. Kill ich den Prozess, sind natürlich alle Fenster zu.
Jetzt möchte ich das erste Fenster suchen (das mache ich mit FindWindow()) und anschließend die zu diesem Prozess gehörenden Fenster ermitteln.
Ich dachte nun, dass ich die Prozess-ID vom ersten HWND ermittel (GetWindowThreadProcessId) und dann darüber andere Fenster finden kann. Nur bekomme ich mit GetWindowTreadProcessID keine ID des erstes HWND.
Jetzt die Fragen:
1. Ist der Ansatz richtig oder viel zu umständlich für die eigentlich banale Aufgabe?
2. Hat jemand ein kleines Beispiel, wie GetWindowThreadProcessID richtig angewendet wird?Das Problem ist, dass ich aktuell mit einem Buch C++ lerne und parallel versuche mit learing by doing die WinAPI anzugewöhnen. Scheint nicht ganz so zu klappen
Vielen Dank für eure Hilfe!
Grüße,
Martin
-
Hallo,
schau dir mal die Funktion FindWindowEx() an...
Diese sucht auch alle Kindfenster einer Anwendung. FindWindow() nur die Toplevel-Fenster.MfG
Nicky
-
Hallo supernicky,
vielen Dank für deine Antwort.
Funktioniert FindWindowEx() auch, wenn das zweite (gesuchte) Fenster nicht unter dem ersten Fenster (hierarchisch gesehen) sich befindet?
Ein Beispiel, wo dies auftritt:
Ich öffne MS Outlook und der Prozess outlook.exe ist da. Jetzt suche ich alle offenen Fenster die dazu gehören (zum Beispiel wenn ich eine E-Mail doppelklicke oder eine E-Mail schreibe), es sind zum Prozess gehörene Fenster aber in Spy++ als separate Desktop-Fenster aufgelistet.Danke euch
Mfg
Martin
-
milchbart schrieb:
Ich dachte nun, dass ich die Prozess-ID vom ersten HWND ermittel (GetWindowThreadProcessId) und dann darüber andere Fenster finden kann. Nur bekomme ich mit GetWindowTreadProcessID keine ID des erstes HWND.
Wenn Du Dein erstes Fenster gefunden hast, kannst Du mit EnunChildWindos alle Kind-Fenster zu diesem Fenster finden. Falls der Prozess weitere Nicht-Kind - Fenster erzeugt, kannst Du mit EnumWindows alle Top-Level - Fenster finden, dazu jeweils mit GetWindowTreadProcessID die Prozess-ID des erzeugenden Prozesses ermitteln, und mit der Prozess-ID Deines ersten gefundenen Fensters vergleichen.
-
Belli schrieb:
milchbart schrieb:
Ich dachte nun, dass ich die Prozess-ID vom ersten HWND ermittel (GetWindowThreadProcessId) und dann darüber andere Fenster finden kann. Nur bekomme ich mit GetWindowTreadProcessID keine ID des erstes HWND.
Wenn Du Dein erstes Fenster gefunden hast, kannst Du mit EnunChildWindos alle Kind-Fenster zu diesem Fenster finden. Falls der Prozess weitere Nicht-Kind - Fenster erzeugt, kannst Du mit EnumWindows alle Top-Level - Fenster finden, dazu jeweils mit GetWindowTreadProcessID die Prozess-ID des erzeugenden Prozesses ermitteln, und mit der Prozess-ID Deines ersten gefundenen Fensters vergleichen.
Genau diesen Ansatz wollte ich verfolgen, da eben das erste (nennen wir es Main Fenster) kein Child im eigentlichen Sinne erzeugt, sondern ein neues Fenster welches dem selben Prozess zugeordnet ist.
Die Frage die sich mir stellt. Wie kann ich mit GetWindowTreadProcessID die ID von Fenstern vergleichen? Ich hatte Probleme mit den Datentypen, die GetWindowTreadProcessID ausgibt. Gibts da ein Beispiel? Falls nein, versuch ich es heute Abend und poste den Quellcode.
Grüße,
Martin
-
Ich verstehe Deine Frage nicht. Gleiche Prozess-ID bedeutet gleicher Prozess und die Prozess ID ist ein HANDLE/int/UINT/DWORD Wert den man direkt mit == vergleichen kann...
-
Vielleicht kommt mein Unverständnis aus der Lage, dass ich alle Werte auf die Console zu Debug-Zwecken ausgebe.
Wenn ich GetWindowTreadProcessID in eine INT Variable übergebe, kann ich diesen Wert nicht auf der Konsole ausgeben (bzw. der Wert lässt sich gar nicht erst in eine INT Variable speichern), d.h. zum eigentlichen Vergleichen von zweier HWND bin ich noch gar nicht gekommen da die Ausgabe auf der Konsole nicht geklappt hat.
Gibt es dafür einen Weg, diese Werte auf der Konsole auszugeben?
Danke im Voraus!
-
DWORD prozessID;
GetWindowThreadProcessId(..., &prozessID);
printf("ID = %d\n", prozessID);
-
Vielen Dank.
D.h. heute Abend 20 Uhr gibt's dann die Rückmeldung, ob alles geklappt hat.
Wollte mich an dieser Stelle noch einmal wahnsinnig für den genialen Support in diesem Forum bedanken, ganz große Klasse!!
-
Leute, ihr seid göttlich
Die Tipps waren alle Gold wert. Ich hatte vorher versucht DWORD prozessID immer mit printf() und dem Format %s auszugeben, weshalb immer komische Werte angezeigt wurden. Mit %d erhalte ich den Prozess bzw die Prozess ID, welche auch im Taskmanager angezeigt wird.
Mein Ablauf ist jetzt wie folgt:
1. Finde Fenster (findwindow()) mit Fenstertitel als regulärer Ausdruck, der bekannt ist
2. Merke Prozess ID von dem gefundenen Fenster
3. Führe rekursive Funktion aus, um alle Fenster nach Prozess ID zu filtern, die in etwa wie folgt ist:void printChildWindows(HWND h) { static int n; DWORD prozessID; GetWindowThreadProcessId(h, &prozessID); if(prozessID = ##gefundene ID##) { // Fenster gefunden. Weitere Aktionen } for(h = GetWindow(h, GW_CHILD); h != NULL; h = GetWindow(h, GW_HWNDNEXT)) { ++n; printChildWindows(h); --n; } }
4. Weiter arbeiten
Geht dies auch einfacher, alle Fenster durchzusuchen und mit der ProzessID zu vergleichen? Was wäre mit EnumWindows()?
Wie würdet ihr alle gefundenen Fenster (welche der Prozess ID entsprechen) speichern? In einer Liste des Typs HWND? Kann ich diese Liste dann dem gesamten Programm global zur Verfügung stellen?
Danke euch
-
Wäre es nicht einfache runs erstmal zu sagen was Du vorhast?
Was nützt bitte das Speichern von Fenster Handles?
-
Sorry, bin in Gedanken schon dabei und vergess deshalb das Vorhaben zu erwähnen.
Es geht darum, dass ich Daten aus Fenstern auslesen will und später ggf. auch GUI Steuerung übernehmen möchte (anfangs mit simplen Mausklicks). Diese Fenster muss ich, wie im Thema angesprochen, anhand von einem Hauptprozess finden und würde diese dann gerne in einer Liste ablegen, damit ich diese jederzeit vom Programm durchsuchen kann (statt Fenster wieder neu suchen zu müssen).
D.h.:
1. Hauptprozess finden
2. Fenster die relevant sind ausfindig machen und in Variable speichern
3. Bei Bedarf auf Fenster in Variable zurückgreifen
4. Sobald ein Fenster geschlossen wird, dieses aus der Variable mit Liste entfernen.Grüße,
Martin
-
Da Fenster, und vor allem Unterfenster sich so schnell ändern können, macht das Speichern in einer Liste wohl kaum Sinn.
Wie willst Du denn bitte auf Deine Feldliste zugreifen?
Wie willst Du denn ein Fenster identifizieren, wenn nicht in seinem Kontext, also dem Hierarchiebaum?Wenn benötigst Du eine "Sprache" die Dir hilft ein Control zu finden und es anzusteuern.
Ich frage mich nur warum Du das machst, weil es X-Makro/skript Tools bereits gibt: AutoHotKey, AutoIt etc...
Und wohl gemerkt, die sind extrem leistungsfähig.
-
Martin Richter schrieb:
Da Fenster, und vor allem Unterfenster sich so schnell ändern können, macht das Speichern in einer Liste wohl kaum Sinn.
Wie willst Du denn bitte auf Deine Feldliste zugreifen?
Wie willst Du denn ein Fenster identifizieren, wenn nicht in seinem Kontext, also dem Hierarchiebaum?Wenn benötigst Du eine "Sprache" die Dir hilft ein Control zu finden und es anzusteuern.
Ich frage mich nur warum Du das machst, weil es X-Makro/skript Tools bereits gibt: AutoHotKey, AutoIt etc...
Und wohl gemerkt, die sind extrem leistungsfähig.Hallo Martin,
das "Unterfenster" ist eigentlich ein reguläres Windows Fenster und bleibt die Anwendung über offen und ändert den Titel nicht. Es ist jedoch hierachisch nicht dem eigentlichen Fenster zugeordnet, weshalb ja dieser Thread entstanden ist.
Um auf die Fragen einzugehen:
- Zugriff über eine Liste mit einem Iterator, damit ich die Fenster nach und nach ansteuern kann und prüfe, ob es sich um ein gesuchtes Fenster handelt (in dem Fall wäre ein Childwindow anders und eindeutig identifzierbar)
- AutoHotKey usw kenne ich, jedoch ist das erst die Basis des Programms. Später würde ich gerne DLLs in den Prozess einschleusen und etwas mehr machen, Grundlage sind aber immernoch die jetzt gefundenen Fenster.Grüße,
Martin
-
milchbart schrieb:
das "Unterfenster" ist eigentlich ein reguläres Windows Fenster und bleibt die Anwendung über offen und ändert den Titel nicht. Es ist jedoch hierachisch nicht dem eigentlichen Fenster zugeordnet, weshalb ja dieser Thread entstanden ist.
Und das definierst Du?
Wenn Du es gefunden hast kannst Du Dir das Handle merken, das sollte genügen. Warum willst Du die ganze Struktur ablegen?
Zudem kannst Du dann von diesem Fenster ja wieder aus suchen.
-
Genau, das Handle wollte ich in einer Liste speichern, also lediglich die ID.
Das ist dann ein Vektor des Typs HWND? Oder kann das Handle noch weiter runtergebrochen werden.Wichtig ist nur, dass die Liste mit einem Iterator durchsucht werden kann um die Fenster anschlißend wieder zu laden bzw. gewöhnliche Funktionen darauf zu beziehen.
Grüße,
Martin
-
Das Handle eines Fensters ist keine ID, es its ein Handle, also ein Griff um Dinge mit dem Ding zu machen.
Ja man kann es in einem Vektor speichern und man kann es vergleichen.
Ein Handle ist (übertragen) nichts anderes als ein (void*)...Warum brauchst Du einen vector, wenn Du nur mit einem Fanster was tun möchtest?
-
Martin Richter schrieb:
Das Handle eines Fensters ist keine ID, es its ein Handle, also ein Griff um Dinge mit dem Ding zu machen.
Ja man kann es in einem Vektor speichern und man kann es vergleichen.
Ein Handle ist (übertragen) nichts anderes als ein (void*)...Warum brauchst Du einen vector, wenn Du nur mit einem Fanster was tun möchtest?
Einfach ausgedrückt möchte ich mit allen Fenstern die zu einer ProzessID gehören Dinge wie Auslesen der Texte, Simulieren von Keyboard/Mouse Events, ... machen.
Wenn das nicht empfehlenswert ist, wie würdest du da vorgehen? Mir fallen spontan nur folgende Alternativen ein:
1. Gesamten Prozess nach Zeit x erneut durchlaufen, d.h. Prozess-ID anhand von "Master Fenster" suchen, weitere Fenster mit der Prozess ID finden und arbeiten
2. Nur "Master Fenster" merken und Child Windows dynamisch ermitteln.Ich dachte nur, da die Fenster, einmal gefunden, sich nicht ändern (höchstens neue dazu kommen), kann ich den Handle in einer Liste ablegen die global für alle Programmteile zur Verfügung steht. So kann in einem Thread die "Such-Routine" laufen und sicherstellen, dass alle passenden Fenster in der Liste enthalten sind, und der eigentliche Thread mit dieser globalen Liste arbeiten und die Aktionen durchführen.
-
milchbart schrieb:
Einfach ausgedrückt möchte ich mit allen Fenstern die zu einer ProzessID gehören Dinge wie Auslesen der Texte, Simulieren von Keyboard/Mouse Events, ... machen.
Dann sollte Dir klar sein, dass man dazu gar kein Handle benötigt!
Tastatur und Mauseingaben können nur systemweit durch SendInput simuliert werden.Mir wird das Ganze zu abstrus...
-
Martin Richter schrieb:
milchbart schrieb:
Einfach ausgedrückt möchte ich mit allen Fenstern die zu einer ProzessID gehören Dinge wie Auslesen der Texte, Simulieren von Keyboard/Mouse Events, ... machen.
Dann sollte Dir klar sein, dass man dazu gar kein Handle benötigt!
Tastatur und Mauseingaben können nur systemweit durch SendInput simuliert werden.Mir wird das Ganze zu abstrus...
Zu abstrus? Vielleicht bin ich einfach nicht in der Lage, das ganze einfach darzustellen.
Das Handle benötige ich, um Daten zu sammeln, nicht um systemweit Input zu simulieren. Was ich jedoch bevorzuge, wenn ich das nötige Wissen habe, Buttons, die im Fenster erscheinen, nicht via Mauseklick zu drücken, sondern direkt über den Button und/oder der injezierten DLL. Da benötige ich das Handle, oder?