Autor Beitrag
toms
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1099
Erhaltene Danke: 2



BeitragVerfasst: Di 29.04.03 06:58 
Hi,

Grundlegendes Problem:

Ich möchte in einer Callback Funktion auf Methoden/Members einer Klasse
zurückgreifen.
(Dies soll später in einer Komponente geschehen)

Mein Ansatz:

Die Callback Funktion selbst als Methode derselben Klasse machen.
(Im Beispiel EnumWindowsProc)


ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
type
  TfrmMain = class(TForm)
  published
      function EnumWindowsProc(wHandle: HWND; LParm: lParam): Bool; stdcall; export;
  end;

{...}

function TfrmMain.EnumWindowsProc(wHandle: HWND; LParm: lParam): Bool; stdcall; export;
begin
  //...
end;

procedure TfrmMain.Button1Click(Sender: TObject);
var
  EnumWindowsProc: TMethod;
begin
  EnumWindowsProc.Data := Pointer(self);
  EnumWindowsProc.Code := Self.MethodAddress('EnumWindowsProc');
  if (EnumWindowsProc.Data <> nil) and  (EnumWindowsProc.Code <> nil) then
    EnumWindows(@EnumWindowsProc, 0);
end;


Problem:

Es kommt eine EAccessViolation beim Ausführen von EnumWindows.

Wer es testen möchte, hier der Code in einem Testprojekt: tinyurl.com/ajm5
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 29.04.03 09:37 
Das will ich gar nicht testen.

Grundlegendes Problem:

ausblenden Quelltext
1:
function TfrmMain.EnumWindowsProc(wHandle: HWND; LParm: lParam): Bool; stdcall; export;					

Der Compiler macht daraus:
ausblenden Quelltext
1:
function TfrmMain_EnumWindowsProc({-->}Self: TfrmMain;{<--} wHandle: HWND; LParm: lParam): Bool; stdcall; export;					

Denn Self wird als versteckter Parameter an jede Methode übergeben.

In deinem Fall würde ich das über eine "Zwischen"-Funktion lösen.
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function EnumWindowsProc(wnd: HWND; Form: TfrmMain); stdcall;
begin
  Result := Form.EnumWindowProc(wnd, 0);
end;

procedure TfrmMain.Button1Click(Sender: TObject); 
begin 
  EnumWindows(@EnumWindowsProc, {-->}Integer(Self){<--}); 
end;



Ein Wort zu export
Zitat:
The directives near, far, and export refer to calling conventions in 16-bit Windows programming. They have no effect in 32-bit applications and are maintained for backward compatibility only.

_________________
Ist Zeit wirklich Geld?
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 29.04.03 10:19 
Wie AndyB schon gesagt hat führt Delphi bei Methoden implizit immer den Self-Pointer mit (immer im ebp-Register). Davon abgesehen braucht eine CallBack-Funktion die sdtcall-Aufrufkonvetion, deine Methode hat aber die pascal-Aufrufkonvention.

2 Vorschläge:

1. Du nimmst eine Normale Funktion (keine Methode) und übergibst den Self-Pointer des aufrufenden Objekts als lParam.

2. Du schaust dir mal die beiden Delphi-Funktionen MakeObjectInstance und FreeObjectsInstance an (weiß nicht ob die in der OH beschrieben sind). Ich weiß nicht ob das mit EnumWindows funktioniert (hab sie bis jetzt nur im Zusammenhang mit SetWindowLong benutzt um die WndProc zu subclassen) könnt mir aber schon vorstellen, dass es funktioniert... (ein Beispiel für MakeObjectInstance/FreeObjectInstance im Zusammenhang mit SetWindowLong findest du in meiner TTaskbar unter www.x-spy.net/personal)

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 29.04.03 11:19 
Motzi hat folgendes geschrieben:
immer im ebp-Register

Du meintest eax


Zitat:
MakeObjectInstance und FreeObjectsInstance

Diese Funktionen reservieren Speicher und geben diesen erst wieder am Programmende frei. Aber wen das nicht stört, bzw. wer diese beiden Funktionen nicht bis zum Exzess einsetzt, der wird gerade mal 4kb verlieren. Es sei nur gesagt, dass alle 313 MakeObjectInstance Aufrufe neue 4kb reserviert werden, die nicht mit FreeObjectInstance freigegeben werden.

_________________
Ist Zeit wirklich Geld?
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 29.04.03 11:52 
AndyB hat folgendes geschrieben:
Motzi hat folgendes geschrieben:
immer im ebp-Register

Du meintest eax

Nein, ich meinte ebp! Ich bin zwar auch der Meinung, dass es früher mal eax war (und hab bis vor kurzem auch geglaubt es wäre immer noch si), aber ich hab mir nach einem Hinweis die Situation in Delphi6 angeschaut und wie es scheint ist es jetzt ebp..!

Zitat:
Zitat:
MakeObjectInstance und FreeObjectsInstance

Diese Funktionen reservieren Speicher und geben diesen erst wieder am Programmende frei. Aber wen das nicht stört, bzw. wer diese beiden Funktionen nicht bis zum Exzess einsetzt, der wird gerade mal 4kb verlieren. Es sei nur gesagt, dass alle 313 MakeObjectInstance Aufrufe neue 4kb reserviert werden, die nicht mit FreeObjectInstance freigegeben werden.

Ich weiß... aber auf der Borland-Homepage gibt es einen Artikel für eine "Ersatz-Implementierung" von Make/FreeObjectInstace die dieses Problem nicht mehr haben.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 29.04.03 12:35 
Motzi hat folgendes geschrieben:
aber ich hab mir nach einem Hinweis die Situation in Delphi6 angeschaut und wie es scheint ist es jetzt ebp..!

Und ich habe es vor meinem Posten noch einmal angeschaut und es ist definitiv eax.
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.FormCreate(Sender: TObject);
begin
  NormProc; // normale Prozedur um den Register-Cache zu umgehen
end;

procedure NormProc;
begin
  Form1.SelfTest;
end;

procedure TForm1.SelfTest;
begin
  ShowMessage('Hier bin ich.');
end;

Das wird zu
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
PROC TForm1.FormCreate:
asm
  CALL NormProc
end;

PROC NormProc:
asm
  MOV EAX, [Form1]
  CALL TForm1.SelfTest
end;



Zudem aus der Online Hilfe (register ist die Standardaufrufkonvention):
Zitat:
Bei der Konvention register verhält sich der Parameter Self, als ob er vor allen anderen Parametern deklariert worden wäre. Er wird somit immer im Register EAX übergeben.

Bei der Konvention pascal verhält sich der Parameter Self, als ob er nach allen anderen Parametern (einschließlich dem zusätzlichen var-Parameter für das Funktionsergebnis) deklariert worden wäre. Er wird somit als letzter Parameter übergeben und hat von allen Parametern die niedrigste Adresse.

Bei den Konventionen cdecl, stdcall und safecall verhält sich der Parameter Self, als ob er vor allen anderen Parametern, aber nach dem zusätzlichen var-Parameter für das Funktionsergebnis deklariert worden wäre. Er wird daher als letzter Parameter, aber vor dem zusätzlichen var
-Parameter (falls vorhanden) übergeben.





Zitat:
aber auf der Borland-Homepage gibt es einen Artikel für eine "Ersatz-Implementierung" von Make/FreeObjectInstace die dieses Problem nicht mehr haben.

Der läuft auch bei mir, obwohl ich für AllocateHWnd/DeallocateHWnd eine eigene Funktion geschrieben habe, die die PROPs des Fensters für die Klasse misbraucht und ein MakeObjectInstance damit nicht nötig ist.

_________________
Ist Zeit wirklich Geld?
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 29.04.03 18:58 
Hast recht.. hatte wie ich gepostet hab weder Delphi noch OH zur Verfügung.. bin jetzt zu Hause und habs selber nochmal ausprobiert. Es ist eax.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!