Autor |
Beitrag |
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 20.08.18 22:16
Hallo!
Ich verwende folgenden Code von Frühlingsrolle, um Fenster-Captions zu ermitteln, deren genauer Text unbekannt ist. Leider funktioniert das als 64-Bit-Code nicht, da gibt's eine Zugriffsverletzung. Was muss ich ändern? Es liegt definitiv an EnumWindows!
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| procedure GetSpecificWindowCaption(const AList: TStrings; const SubWindowCaption: string); function GetAllWindows(hWnd: HWND; const AList: TStrings): Boolean; stdcall; var captionLength: Word; wndCaption: string; begin captionLength := GetWindowTextLength(hWnd); SetLength(wndCaption, captionLength); GetWindowText(hWnd, PChar(wndCaption), captionLength + 1); Alist.Add(wndCaption); result := true; end; var tmp: TStringList; i: Integer; begin if (AList <> nil) and (SubWindowCaption <> '') then begin tmp := TStringList.Create; try EnumWindows(@GetAllWindows, Integer(tmp)); tmp.BeginUpdate; for i := 0 to tmp.Count - 1 do if Pos(UpperCase(SubWindowCaption), UpperCase(tmp[i])) <> 0 then AList.Add(tmp[i]); tmp.EndUpdate; finally tmp.Free; end; end; end; |
Siehe auch: www.entwickler-ecke....ewtopic.php?t=116545
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 21.08.18 06:10
galagher hat folgendes geschrieben : | Delphi-Quelltext 1:
| EnumWindows(@GetAllWindows, Integer(tmp)); | |
Wie viele Bytes groß ist denn tmp unter 64-Bit? Richtig, 8 Byte oder 64 Bit. Wenn du das nun auf die Hälfte abschneidest (Integer = 32 Bit bzw. 4 Byte), ist der Pointer auf die Liste kaputt und dementsprechend knallt es beim Zugriff.
Der zweite Parameter von EnumWindows ist nicht umsonst vom Typ NativeInt. Dann geht es vermutlich auch: Delphi-Quelltext 1:
| EnumWindows(@GetAllWindows, NativeInt(tmp)); |
Ich würde allerdings auch noch prüfen, ob das Fenster überhaupt Text enthält, sonst kann es beim GetWindowText knallen: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure GetSpecificWindowCaption(const AList: TStrings; const SubWindowCaption: string); function GetAllWindows(hWnd: HWND; const AList: TStrings): Boolean; stdcall; var captionLength: Integer; wndCaption: string; begin captionLength := GetWindowTextLength(hWnd); if captionLength > 0 then begin SetLength(wndCaption, captionLength); GetWindowText(hWnd, PChar(wndCaption), captionLength + 1); Alist.Add(wndCaption); end; result := true; end; var tmp: TStringList; i: Integer; begin if (AList <> nil) and (SubWindowCaption <> '') then begin tmp := TStringList.Create; try EnumWindows(@GetAllWindows, NativeInt(tmp)); tmp.BeginUpdate; for i := 0 to tmp.Count - 1 do if Pos(UpperCase(SubWindowCaption), UpperCase(tmp[i])) <> 0 then AList.Add(tmp[i]); tmp.EndUpdate; finally tmp.Free; end; end; end; |
Für diesen Beitrag haben gedankt: galagher
|
|
Delphi-Laie
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Di 21.08.18 15:59
Von meinem Programm " Prozesse" gibt es auch zwei 64-Bit-Versionen: Eine von Delphi XE2 und eine von Lazarus compilierte.
Es enumeriert alles mögliche. Fenster sind als Enumerationsobjekte auch darin vorhanden.
_________________ Ordnung ist das halbe Leben - und sie zu schaffen die andere Hälfte.
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Di 21.08.18 16:54
jaenicke hat folgendes geschrieben : | Wie viele Bytes groß ist denn tmp unter 64-Bit? Richtig, 8 Byte oder 64 Bit. Wenn du das nun auf die Hälfte abschneidest (Integer = 32 Bit bzw. 4 Byte), ist der Pointer auf die Liste kaputt und dementsprechend knallt es beim Zugriff. |
Das habe ich überhaupt nicht bedacht, habe es aber trotzdem bereits mit NativeInt versucht, zunächst aber erfolglos, denn:
jaenicke hat folgendes geschrieben : | Ich würde allerdings auch noch prüfen, ob das Fenster überhaupt Text enthält, sonst kann es beim GetWindowText knallen: |
Hm, mit 32-Bit ist das aber scheinbar kein Problem...
Jedenfalls klappt es jetzt!
//Edit: Naja, es klappt im dem Sinn, dass es sich kompilieren lässt. Aber es findet keine entsprechenden Fenster, zumindest die Caption der MainForm müsste es auflisten, tut es aber nicht!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Di 21.08.18 20:38
Delphi-Laie hat folgendes geschrieben : | Es enumeriert alles mögliche. Fenster sind als Enumerationsobjekte auch darin vorhanden. |
Dein WindowsEnumeration verursacht genauso einen Zugriffsfehler, und wenn ich zusätzlich Code einfüge, um die Länge der Caption zu prüfen, bleibt die Liste leer.
Ich bin ratos!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Delphi-Laie
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Di 21.08.18 21:02
galagher hat folgendes geschrieben : | Delphi-Laie hat folgendes geschrieben : | Es enumeriert alles mögliche. Fenster sind als Enumerationsobjekte auch darin vorhanden. | Dein WindowsEnumeration verursacht genauso einen Zugriffsfehler |
Aber doch wohl nicht in meinen Compilaten, sondern in Deinem?!
"Meine" Enumwindows-Funktionen sind ja auch nur in Delphiforen zusammengeklaubt worden.
Wenn es bei mir funktioniert, bei Dir aber nicht, gibt es einen sicheren, wenngleich meistens recht mühsamen, langwierigen Weg, den Fehler sicher aufzuspüren: Den funktionirenden Code "schälen", entblättern, herunterbrechen und anschließend mit dem neuen Code zu umhüllen. Alles schön schrittweise. Es gibt kaum Fehler, die nicht aufzuspüren wären, entsprechende Hartnäckigkeit vorausgesetzt.
_________________ Ordnung ist das halbe Leben - und sie zu schaffen die andere Hälfte.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Di 21.08.18 21:16
Delphi-Laie hat folgendes geschrieben : | Aber doch wohl nicht in meinen Compilaten, sondern in Deinem?! |
In meinem, und nur mit 64-Bit!
Delphi-Laie hat folgendes geschrieben : | "Meine" Enumwindows-Funktionen sind ja auch nur in Delphiforen zusammengeklaubt worden. |
Ja, so was kenne ich!
Delphi-Laie hat folgendes geschrieben : | Wenn es bei mir funktioniert, bei Dir aber nicht, gibt es einen sicheren, wenngleich meistens recht mühsamen, langwierigen Weg, den Fehler sicher aufzuspüren: Den funktionirenden Code "schälen", entblättern, herunterbrechen und anschließend mit dem neuen Code zu umhüllen. |
Es liegt definitiv an EnumWindows, das findet mit 64-Bit-Code keine Fenster mit Caption, in der der angegebene Text vorkommt. Mit 32-Bit funktioniert es aber. Das Problem ist also bereits eingegrenzt!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 04:36
Wo genau knallt es denn? Stacktrace, lokale Variablen, Assemblercode an der Fehlerstelle, Registerinhalte, ...?
Du kannst ja Screenshots machen, wenn du möchtest. In die Assembleransicht kommst du mit Strg +Alt + C oder über das Menü.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 06:39
jaenicke hat folgendes geschrieben : | Wo genau knallt es denn? Stacktrace, lokale Variablen, Assemblercode an der Fehlerstelle, Registerinhalte, ...?
Du kannst ja Screenshots machen, wenn du möchtest. In die Assembleransicht kommst du mit Strg +Alt + C oder über das Menü. |
Assemblercode nicht, das andere muss ich mir noch ansehen. Kann dann ja Screenshots machen, es ist jedenfalls eine Zugriffsverletzung!
jaenicke hat folgendes geschrieben : | Der zweite Parameter von EnumWindows ist nicht umsonst vom Typ NativeInt. |
Diese Stelle verursacht die Zugriffsverletzung nicht, sondern, wenn ich die Prüfung if captionLength > 0 nicht durchführe.
Wenn ich aber den Rat von jaenicke befolge:
jaenicke hat folgendes geschrieben : | Ich würde allerdings auch noch prüfen, ob das Fenster überhaupt Text enthält, sonst kann es beim GetWindowText knallen: |
... die Abfrage if captionLength > 0 also mache, dann läuft das Programm zwar ohne Zugrifssverletzung, findet aber keine Fenster mit entsprechender Caption, obwohl die da sind. Wohlgemerkt: Das alles nur bei 64-Bit!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 07:02
Ach so, dann schreib doch einfach mal alle Überschriften in die Liste rein unabhängig von der Bedingung bzw. schau dir die Liste im Debugger an. Werden da Fenster gefunden?
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 07:34
jaenicke hat folgendes geschrieben : | Ach so, dann schreib doch einfach mal alle Überschriften in die Liste rein unabhängig von der Bedingung |
Kann ich machen, dann wird's wohl auch funktionieren. Die Fenstercaptions sollen aber gefunden, nicht vorgegeben werden!
jaenicke hat folgendes geschrieben : | schau dir die Liste im Debugger an. Werden da Fenster gefunden? |
Mit 64-Bit-Code trennt sich jedesmal der Debugger vom Programm. Aber das ist jetzt nicht das Problem! Ist mir im Moment egal.
Vielleicht klappt ja captionLength := GetWindowTextLength(hWnd); nicht. Habe es stattdessen auch schon mit SendMessage versucht (und dabei auf die richtigen Parameter für 64-Bit-Code geachtet) - erfolglos.
Es klappt nicht, eagl, ob ich PWideChar statt PChar verwende, egal, ob mit NativeInt oder Integer. Sogar, wenn ich den Suchtext hardcode - das Fenster wird nicht gefunden. Also entweder funktioniert EnumWindows oder GetWindowTextLength oder beides nicht...
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 09:28
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 10:11
jaenicke hat folgendes geschrieben : | Nein, ich meinte das zum Debuggen.
Denn die Frage ist ja, ob die Überschriften nicht richtig ausgelesen werden oder der Vergleich schief geht. |
Ich bin jetzt nicht am Computer mit dem Projekt, aber ich werde die Liste dann noch testweise manuell befüllen, um zu sehen, ob es am Vergleich liegt.
Glaube ich aber nicht, denn die Überschriften werden nicht in die Liste geschrieben, die Liste ist leer: Wenn ich sie mit SaveToFile speichere, hat die Datei 0 Bytes.
Mein Verdacht ist, dass entweder EnumWindows oder GetWindowTextLength mit 64-Bit-Code nicht kann.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 10:19
galagher hat folgendes geschrieben : | Glaube ich aber nicht, denn die Überschriften werden nicht in die Liste geschrieben, die Liste ist leer: Wenn ich sie mit SaveToFile speichere, hat die Datei 0 Bytes. |
Die temporäre Liste?
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 16:54
jaenicke hat folgendes geschrieben : | galagher hat folgendes geschrieben : | Glaube ich aber nicht, denn die Überschriften werden nicht in die Liste geschrieben, die Liste ist leer: Wenn ich sie mit SaveToFile speichere, hat die Datei 0 Bytes. | Die temporäre Liste? |
Seltsam, es kracht schon hier bei Alist.SaveToFile:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure GetSpecificWindowCaption(const AList: TStrings; const SubWindowCaption: string); function GetAllWindows(hWnd: HWND; const AList: TStrings): Boolean; stdcall; var captionLength: Integer; wndCaption: string; begin captionLength := GetWindowTextLength(hWnd); if captionLength > 0 then begin SetLength(wndCaption, captionLength); GetWindowText(hWnd, PWideChar(wndCaption), captionLength + 1); Alist.Add(wndCaption); end; Alist.SaveToFile('1.txt'); result := true; end; |
Dann erhalte ich wieder:
Zitat: | Zugriffsverletzung bei Adresse 000000000080665D in Modul 'SynEdit.exe'. Lesen von Adresse FFFFFFFFFFFFFFFF |
Aber AList existiert doch:
Delphi-Quelltext 1: 2: 3: 4: 5:
| tmp := TStringList.Create; try EnumWindows(@GetAllWindows, NativeInt(tmp)); |
//Edit:
Das Projekt heisst zwar SynEdit, ich verwende aber kein TSynEdit! Daran kann es nicht liegen!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 19:00
Da wirst du wohl debuggen müssen welche Werte in den Variablen stecken (tmp, ...) und was dann in der Callbackfunktion ankommt usw.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 19:13
Es werden die Captions nicht mal an eine einfache String-Variable angehängt, weil enumWindows definitiv mit 64-Bit nicht funktioniert. Die Konstante AList gibt es in Funktion GetAllWindows nicht, weil EnumWindows sie nicht (richtig) mit übergibt. Wenn man mit if Assigned(AList) prüft, wird der Codeteil übersprungen. Ansonsten schlägt das Einfügen in AList fehl, weil das dort schlicht nicht existiert.
jaenicke hat folgendes geschrieben : | Da wirst du wohl debuggen müssen welche Werte in den Variablen stecken (tmp, ...) und was dann in der Callbackfunktion ankommt usw. |
Erspare ich mir! Ich habe hier -> www.swissdelphicente.../showcode.php?id=327 was gefunden und angepasst, das ohne EnumWindows auskommt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure GetSpecificWindowCaption(const AList: TStrings; const SubWindowCaption: string); var NextHandle: Hwnd; wndCaption: array[0..260] of char; begin NextHandle := GetWindow(Application.Handle, GW_HWNDFIRST); while NextHandle > 0 do begin GetWindowText(NextHandle, wndCaption, 255);
if Pos(AnsiUpperCase(SubWindowCaption), AnsiUpperCase(wndCaption)) > 0 then AList.Add(wndCaption);
NextHandle := GetWindow(NextHandle, GW_HWNDNEXT); end; end; |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19288
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 22.08.18 20:13
galagher hat folgendes geschrieben : | Es werden die Captions nicht mal an eine einfache String-Variable angehängt, weil enumWindows definitiv mit 64-Bit nicht funktioniert. Die Konstante AList gibt es in Funktion GetAllWindows nicht, weil EnumWindows sie nicht (richtig) mit übergibt. |
Bei mir funktioniert die Funktion, die ich oben gepostet habe, problemlos unter 64-Bit.
Aber wenn du es nicht brauchst, ist das natürlich noch einfacher. Kannst du da nicht einfach Screen.Forms benutzen, wenn es um deine eigene Anwendung geht? Außerdem frage ich mich wie es passieren kann, dass du selbst in deiner Anwendung nicht weißt was da für Fenster existieren.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 22.08.18 20:29
jaenicke hat folgendes geschrieben : | Bei mir funktioniert die Funktion, die ich oben gepostet habe, problemlos unter 64-Bit. |
Werde sie noch in einem separaten Programm testen. Könnte es eventuell daran liegen, dass es ursprünglich eine 32-Bit-Anwendung war, die ich jetzt zu 64-Bit kompiliere?
jaenicke hat folgendes geschrieben : | Kannst du da nicht einfach Screen.Forms benutzen, wenn es um deine eigene Anwendung geht? Außerdem frage ich mich wie es passieren kann, dass du selbst in deiner Anwendung nicht weißt was da für Fenster existieren. |
Ich möchte nicht die Captions meiner Anwendung ermitteln, sondern die Form1.Caption's anderer Instanzen meiner Anwendung!
Dann kann ich in jeder Form1.Caption aller meiner Instanzen angeben, was die aktuelle Instanz ist und wieviele Instanzen laufen, zB. steht dann bei der als 1. aufgerufenen Instanz "SynEdit (Instanz 1/1)", bei der 2. Instanz steht dann "SynEdit (Instanz 2/2)" usw. Wenn eine Instanz gestartet oder beendet wird, passe ich die Captions an.
Eine nette Spielerei, nicht mehr. Aber sie funktoniert jetzt endlich auch mit 64-Bit!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
|