Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - EnumWindowsProc


HenryHux - Sa 29.01.11 20:57
Titel: EnumWindowsProc
Hey, bis jetzt habe ich immer erfolgreich mit dieser Funktion für das aufzählen von Prozessen gearbeitet.
Doch jetzt, wo ich sie in Klassen versuche aufzurufen, geht es nicht mehr wie vorher.
Hier die Funktion:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
function EnumWindowsProc(wHandle: HWND; lb: TListBox): Bool; stdcallexport;
var
  Title, ClassName: array[0..255of char;
begin
  Result := True;
  GetWindowText(wHandle, Title, 255);
  GetClassName(wHandle, ClassName, 255);
  if IsWindowVisible(wHandle) then
     lb.Items.Add(string(Title) + '-' + string(ClassName));
end;


Ohne Klassen hat der Aufruf so gut geklappt :

Delphi-Quelltext
1:
EnumWindows(@EnumWindowsProc, Integer(main.Listbox1));                    


Aber jetzt nimmt er kein @EnumWindowsProc mehr mit der Erklärung "Variable Erforderlich".
Habe vieles Probiert, aber er compiliert nicht oder kriegt Exceptions.
Habe leider keine Ahnung, was schief läuft.
Vlt weiß ja einer von euch weiter.

Lg


bummi - Sa 29.01.11 21:25

Zitat:

, wo ich sie in Klassen versuche aufzurufen


was genau meinst Du damit, unter XE zumindest funktioniert o.g.


HenryHux - Sa 29.01.11 21:30

Ich wusstes selber die ganze Zeit nicht ganz genau, nur jetzt klappt es.
Hier das hat mir geholfen : http://www.delphipraxis.net/147240-[delphi-2010]-enumwindows-mit-handle.html .
Ich habe die Funktion also aus dem KlassenForwarding genommen und nur lokal in die Prozedur gestellt, die es benötigt.
Seitdem kann ich auch den Zeiger richtig angeben.
Trotzdem habe ich keine Ahnung, wieso es vorher nicht geklappt hat :?:

Lg


Delete - Sa 29.01.11 21:38

Eine Klassenmethode hat immer noch einen unsichtbaren Self-Parameter, der ein Zeiger auf die Klasse selber ist. Wenn du die Callback jetzt als Klassenmethode implementiert hast, stimmt somit die Parameterliste nicht mehr. Und hier wäre eine Lösung: http://www.michael-puff.de/Programmierung/Artikel/CallbackMethod.shtml


HenryHux - Sa 29.01.11 21:41

Danke, wieder was neues gelernt.
Aber wie bitte soll man als Dephi-Anfänger auf sowas kommen??


Delete - Sa 29.01.11 21:53

OK, das würde ich unter Erfahrung ablegen. Kommt mit der Zeit.


jaenicke - Sa 29.01.11 22:10

Man muss aber kein Assembler dafür nutzen. Ich habe einfach einen Record als Userdata mitgegeben, der die nötigen Infos zum Handling enthielt. Zum Beispiel eben den Methodenzeiger oder was man sonst haben will.

Dann kann man einfach aus der Prozedur heraus über diese zusätzlichen Daten die Methode in der Klasse aufrufen.


HenryHux - Sa 29.01.11 22:49

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
OK, das würde ich unter Erfahrung ablegen. Kommt mit der Zeit.

Na, dann bin ich ja mal beruhigt =)
Ich denke ich kann hier nochmal ein ähnliches Problem ansprechen, ohne direkt einen neuen Thread aufzumachen.
Und zwar hängt es wieder mit Umstellungen zusammen, wenn ich etwas in Klassen stelle.
Hier das zb:

Delphi-Quelltext
1:
2:
3:
4:
5:
constructor TClass.Create;
begin
  VListBox := TListBox.Create(application);
  VListBox.Parent := Nil;  //würde hier normalerweise self eintragen, nimmt er aber nicht, nil gibt exceptions
end;

Generell, wie löst man solche Probleme am besten?
Luckie hat da ja schon eine schöne Erklärung + Link gepostet, was ich aber leider nicht 100%tig nachvollziehen kann, vorallem weil ich keine Ahnung von Assembler-Befehlen habe.


jaenicke - Sa 29.01.11 22:53

Das ist eigentlich schon wieder eine ganz andere Frage. ;-)

Parent ist die visuelle Komponente, auf der die ListBox liegt. Das kann logischwerweise nicht nil sein. Und auch keine eigene Klasse, wenn das keine visuelle Komponente ist.

Du musst also z.B. die Parentkomponente mit an deine Klasse übergeben.


bummi - Sa 29.01.11 22:55

Wenn Du TListBox benötigst kannst Du dem Contructor einen Parent mitgeben, wenn nicht nimm eine TStringList.


HenryHux - Sa 29.01.11 23:03

Ok, danke, habe einfach als TWinControl das Self übergeben beim Aufruf, so klappt es.
Habe mich hier für eine Listbox entschlossen, da ich nicht wüsste, dass eine StringList Sachen wie items.count hätte, die ich aber benötige. Deshalb halt eine dynamisch erzeugte ListBox.
Korrigiert mich aber ruhig =)

Lg


jaenicke - Sa 29.01.11 23:06

user profile iconbummi hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du TListBox benötigst kannst Du dem Contructor einen Parent mitgeben, wenn nicht nimm eine TStringList.
Nein, im Konstruktor übergibst du den Owner, das ist etwas anderes. ;-)

user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
Habe mich hier für eine Listbox entschlossen, da ich nicht wüsste, dass eine StringList Sachen wie items.count hätte, die ich aber benötige. Deshalb halt eine dynamisch erzeugte ListBox.
Aua. Eine visuelle Komponente als Datenspeicher in einer eigenen Klasse zu missbrauchen ist so ungefähr der schlimmste Programmierstil, den es gibt...

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var
  Test: TStringList;
begin
  Test := TStringList.Create;
  try
    Test.Add('a');
    ShowMessage(IntToStr(Test.Count));
    ShowMessage(Test[0]);
    ShowMessage(Test.Strings[0]);
    ShowMessage(IntToStr(Test.Strings.Count));
  finally
    Test.Free;
  end;


bummi - Sa 29.01.11 23:11

@jaenicke
da er von TClass ableitet kann er im Constructor übergeben was er will....


jaenicke - Sa 29.01.11 23:14

Ach so meinst du das, ja so meinte ich das vorher ja auch. :mrgreen: Ich hatte das falsch verstanden, ich dachte du meintest den Konstruktor von TListBox. ;-)