Autor Beitrag
HenryHux
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: So 25.09.11 22:22 
Hey,

habe fast schon ein schlechtes Gewissen, immerhin schon der 4te Thread an diesem Wochenende :D
Nunja, ich denke dass die Frage auch andere interessieren könnte.
Und zwar geht es um die Windows Funktion EnumWindows.
Unter 32Bit so lauffähig (Listet Captions aller gefunden Handles) :
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//Aufruf
EnumWindows(@EnumWindowsProc, integer(StrList));

//CallBack Function
  function EnumWindowsProc(wHandle: HWND; lb: TStringList): Bool; stdcallexport;
  var
    caption: array[0..256of Char;
  begin
    if GetWindowText(wHandle, Caption, SizeOf(Caption)-1) <> 0 then begin
      Lb.Add(Caption);
    end;
    result :=True;
  end;


Jetzt ändert sich mit 64-Bit ja einiges an Pointergrößen usw.
Habe einiges ausprobiert, weiß aber nicht wo hier der Fehler liegt.
Falls es die Windows Funktion an sich ist, gibt es Alternativen?

lg


Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am So 25.09.2011 um 22:29
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 25.09.11 23:05 
Mein Programm mit dem einfallslosen Namen "Prozesse" (auch in diesem Forum zu finden) beinhaltet 3 Schnappschüsse (Prozesse, Module, Threads) und auch drei Windowenumerationen (Enumwindows, Enumthreadwindows und Enumchildwindows), und es gibt es neben 32 Bit auch in zwei 64-Bit-Versionen: Eine mit Lazarus und - nun endlich - auch eine mit Delphi zu 64 Bit (mit XE2) compilierte.

Nur soviel: Ich hatte keinerlei Probleme mit dem Enumwindows! Eigentlich hatte ich überhaupt keine grundsätzlichen Funktionsproblme, einmal mit 32 und einmal mit 64 Bit zu compilieren, weder beim Compilieren selbst noch beim Laufenlassen der Compilate.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 25.09.11 23:07 
user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
//Aufruf
EnumWindows(@EnumWindowsProc, integer(StrList));
Integer = 32 Bit
Pointer = 64 Bit
--> casten dazwischen = böse

Dafür gibt es NativeInt, das immer die gleiche Größe wie ein Pointer hat.

Für diesen Beitrag haben gedankt: BenBE
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Mo 26.09.11 17:54 
Nach mindestens einer frustrierender Stunde ist mir etwas aufgefallen.
Kann mir mal jemand erklären was das für einen Unterschied macht ob ich EnumWindows im Thread aufrufe oder nicht?
Kann man an dem Beispiel gut erkennen :
1. 32-Bit klappen beide Varianten.
2. 64-Bit klappt nur außerhalb des Threades.

Beschreibung (rar, 87.67 KB)

lg
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 26.09.11 18:17 
Das dürfte eigentlich gar nicht richtig aus dem Thread heraus klappen, denn du greifst unsynchronisiert auf Form1.Memo1 zu...
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Mo 26.09.11 18:26 
Wie gesagt, es ist ein schnelles Beispiel gewesen.
Dann ersetzt euch die Memo Anweisung mit einer MessageBox.
Der Punkt ist immernoch, dass das EnumWindows aus dem Thread heraus nicht klappt.
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 13.05.12 10:45 
Hallo HenryHux, ist zwar schon eine Weile her, aber trotzdem - ich habe etwas entdeckt, was ich selbst noch nicht fassen kann (sowohl das, was ich entdeckte als auch, daß ich es entdeckte):

Wenn die Enumerationen (egal, ob EnumWindows, EnumThreadWindows oder EnumChildWindows, es trifft für alle 3 Enumerationsarten zu) nicht klappen, dann die von der Enumeration aufgerufene Funktion (mit @) aus der Funktion, in der sie eingebettetet ist, herauslösen und übergeordnet anordnen - zur Not eben global. Dann funktioniert es auch mit den 64-Bit-Compilaten von XE2. Keine Ahnung, was da wieder rumgemacht wurde, es funktionerte nach meinem Wissen mit allen Delphis zuvor und mit allen 32-Bit-Compilaten, wenn man die aufgerufene Funktion möglichst tief lokal einbettet - sogar mit den 32-Bit-Compilaten von XE2. Vermutlich sind bei XE2 intern für 32 und 64 Bit zwei verschiedene Compiler am Wirken.

Und, jaenicke, was meinst Du dazu?
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: So 13.05.12 11:10 
Hey,

danke für die Antwort.
Bin an meinem Projekt, in dem ich das Problem hatte, im Moment nicht mehr am arbeiten, habe mir aber mal deinen Post dort notiert, falls ich wieder anfangen sollte.

Vielen Dank,

lg
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 13.05.12 11:15 
Hier im Anhang eine Demonstration dieses XE2-(Fehl-?)Verhaltens anhand des EnumWindows (wie gesagt, EnumChildWindows und EnumThreadWindows zeigen es auch).

Zur Not kann man statt des Pointeraufrufes der Funktion auch eine Liste füllen, wie es mir unter bugs.freepascal.org/view.php?id=16442 gezeigt wurde - das mußte ich für Lazarus, das diese Pointeraufrufe anscheinend nicht unterstützt, verwenden, funktionert dort aber für 32- und 64-Bit-Compilate gleichermaßen, und auch bei Delphi-Compilate.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 13.05.12 11:30 
Unter 32-Bit funktionierte es rein zufällig. Bei eingebetteten Prozeduren wird bei Zugriffen auf die äußere Funktion bzw. auf das Objekt die entsprechende Referenz benötigt und bei einem Aufruf mitgeliefert.
Inkonsistenterweise passiert das aber (wie ein kurzer Block in den Assemblercode zeigt) nur, wenn aus der inneren Funktion auch auf die äußere zugegriffen wird. Deshalb funktioniert es, wenn das nicht passiert, da Windows logischerweise diesen Parameter ebenfalls nicht mitgibt.

Sobald man aus der inneren Funktion auf die äußere zugreift, funktioniert es daher auch unter 32-Bit vor XE2 nicht.

Unter 64-Bit gibt es nun nur noch eine Aufrufkonvention und das Aufrufmodell ist strikter. Es müssen nun auf jeden Fall der Stack und der Exception Frame usw. intakt bleiben. (Um das sicherzustellen wurden auch mit Assembler gemischte Funktionen bei 64 Bit gestrichen.)
Im Zuge dieser Umstellung wurde dann offenbar auch das Verhalten an dieser Stelle glattgezogen, so dass immer das gleiche passiert, egal was innerhalb der Funktion passiert.

Heißt:
Eigentlich war es unter 32-Bit vorher falsch oder zumindest inkonsistent, dass es mit eingebetteten Funktionen funktioniert hat. Unter Delphi XE2 funktioniert es weder unter 32-Bit noch unter 64-Bit.

Für diesen Beitrag haben gedankt: BenBE, Delphi-Laie
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 13.05.12 15:16 
Daß Du um eine Antwort und Erklärung nicht verlegen wärest, war ich mir sicher, aber es ist doch ein ganz kleines bißchen schade, daß ich es nicht einmal damit schaffte, Dich zu beeindrucken.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Unter Delphi XE2 funktioniert es weder unter 32-Bit noch unter 64-Bit.


Der mitgelieferte Anhang meinen Beitrag zuvor spricht beim (mit XE2 generiertem!) 32-Bit-Compilat etwas anderes.

Dank und Gruß!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 13.05.12 15:30 
Schau dir einmal an was du da bei 32-Bit als "Handles" ausgibst. ;-)
Sprich versuch dazu einmal die Klassennamen zu ermitteln und schau dir dann SysErrorMessage(GetLastError) an (-->"Ungültiges Fensterhandle").

Dass an der Stelle Zahlen stehen, habe ich nie bestritten, es sind nur leider nicht die Fensterhandles. :zwinker:

Für diesen Beitrag haben gedankt: BenBE
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 13.05.12 16:30 
Das läßt mir natürlich keine Ruhe....

Bei der ersten Ausgabe erhalte ich den Fehler Nr. 0, ab der zweiten den mit der Nr. 5 ->"Zugriff verweigert", auch wenn ich das Programm als Administrator starte.

Und das Phänomen zeigt sich bei 32 Bit sowohl bei "lokaler" als auch bei "globaler" Fensterenumeration. Bei 64 Bit zeigt es sich genauso bei globaler Fensterenumeration, bei lokaler - nicht verwunderlich - kommt "Ungültiges Fensterhandle".

Was mich auch stutzig macht: Es wird immer ein Klassenname ausgegeben, dabei können doch längst nicht alle Zahlen mit einem belegt sein -> bei falschen Klassennamen müßte eine Leerausgabe doch dann weit wahrscheinlicher und häufiger erfolgen.

Siehe / sehet den Anhang.

Auch mein Programm "Prozesse" als 32-Bit-Compilat ermittelt anhand der Fensterhandles offensichtlich die korrekte Anzahl der Childwindows, also müssen die Handles doch stimmen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 13.05.12 16:53 
Da fehlt eine Zeile vor dem Aufruf von GetClassName:
ausblenden Delphi-Quelltext
1:
SetLastError(0);					
Du bekommst sonst evtl. (wie hier) einen Fehlercode, der vorher schon gesetzt war.

Für diesen Beitrag haben gedankt: BenBE, Delphi-Laie
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 13.05.12 17:26 
Daß man den Fehlercode zurücksetzen kann / muß, wußte / kannte ich noch gar nicht, danke!

Woher mag dann bloß dieser elende Fehlercode 5 stammen? :gruebel:

Diese Lasterroreinnullung in beide per Pointer aufgerufenen Prozeduren vor GetClassName gesetzt, ist alles mit 32 Bit und bei der globalen Procedur mit 64 Bit in Ordnung -> "Der Vorgang wurde erfolgreich ausgeführt". Also nichts da mit "Unter Delphi XE2 funktioniert es weder unter 32-Bit noch unter 64-Bit." (das sehe ich also weiterhin nicht bestätigt). Außerdem schriebst Du auch "Sobald man aus der inneren Funktion auf die äußere zugreift, funktioniert es daher auch unter 32-Bit vor XE2 nicht.". Also, eben mal mit Delphi 3 den gleichen Code ausprobiert, und es funktioniert sowohl mit lokaler als auch mit globaler Funktion (bei globaler wird ja aus der inneren auf die äußere zugegriffen). Könnte noch hier auch noch hochladen, ist aber eigentlich zu simpel, als daß man es selbst nicht mal auf die Schnelle hingekäme.

Vielleicht verstehe ich Dich falsch. Wir müssen das auch nicht weiter ausdiskutieren. Für mich bzw. bei mir funktionert alles bis auf die lokale Enumerationsfunktion im 64-Bit-Compilat, nicht nur "anscheinend", sondern auch anhand der "Fehler"meldungen, die genaugenommen dann ja gar keine sind.


Zuletzt bearbeitet von Delphi-Laie am So 13.05.12 21:05, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: jaenicke
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 13.05.12 19:19 
Stimmt, unter 32 Bit XE2 sieht es nur im Debugger falsch aus. Und wenn man die Optimierung deaktiviert, geht das Auswerten von aktuellen Variablen gar nicht mehr richtig.
Und zu 64 Bit ist ja alles erklärt warum es da anders / korrekt läuft.