Hallo,
Wenn mein "Event" ja in Wirklichkeit (nur) ein Pointer auf eine Instanz von TMethod ist
Ne, ein Event ist direkt das TMethod. Habe zur Veranschaulichung deine Methode um par Debug-Hilfen ergänzt:
Delphi-Quellcode:
function TForm1.IndexOfEvent(const _Event: TNotifyEvent): Integer;
var
i: Integer;
a: Integer;
E: TNotifyEvent;
b: Integer;
begin
Result := -1;
// Siehe Oben: Mein Ziel: Wenn von GENAU DIESEM Object (a.Pressed, b.Pressed),
// GENAU DIESES Event gefunden wird, dann gebe dessen Index zurück
// wird bei RegisterEvent(a.Pressed) NICHT durchlaufen, da hier FListSubscriber.Count noch 0 ist!
for i := 0 to FListSubscriber.Count - 1 do begin
a:= SizeOf(TNotifyEvent);
E:= THAL_ObserverItem(FListSubscriber[i]).Event;
b:= SizeOf(TMethod);
OutputDebugString(PChar(Format('TMethod(T.Event).Code= %p; TMethod(T.Event).Data= %p; @E= %p; Int64(@E)= %d; @@E= %p; SizeOf(TNotifyEvent)= %d; SizeOf(TMethod)= %d; @a= %p; @b= %p; @i= %p ', [TMethod(E).Code, TMethod(E).Data, @E, Int64(@E), @@E, a, b, @a, @b, @i])));
if (TMethod(THAL_ObserverItem(FListSubscriber[i]).Event).Data = TMethod(_Event).Data) and (TMethod(THAL_ObserverItem(FListSubscriber[i]).Event).Code = TMethod(_Event).Code) then
// ^-- HIER ist das Hauptproblem: Sei _Event = b.Pressed ergibt der Vergleich True, obwohl bisher nur a.Pressed in der Liste ist!
begin
Result := i;
Exit;
end;
end;
end;
Raus kommt dann das:
Code:
Debug-Ausgabe: TMethod(T.Event).Code= 004CBE40; TMethod(T.Event).Data= 028D3870; @E= 004CBE40; Int64(@E)= 5029440; @@E= 0018FE5C; SizeOf(TNotifyEvent)= 8; SizeOf(TMethod)= 8; @a= 0018FE4C; @b= 0018FE48; @i= 0018FE50 Prozess dp165785Project1.exe (10976)
Da sieht man, dass eine Variable vom Typ TNotifyEvent bereits so groß ist wie zwei Pointer. Bei dem @ und Methoden-Zeigern greift wiedermal ein wenig Compiler-Magie. Eigentlich gibt das @ die Adresse des dahinter stehenden Ausdrucks zurück. Bei @a bekommt man im obigen Beispiel die Adresse, wo die Variable a auf dem Stack liegt, zurück. Bei Methoden-Zeigern gibt das @ den Inhalt der Variable zurück. Die Adresse der Variable bekommt man erst mit einem @@ zurück. Wieso jetzt aber das einfache @ bei Methoden-Zeigern nur die Hälfte des Inhaltes wiedergibt, bleibt mir ein Rätsel.
Leider habe ich gerade kein lauffähiges Delphi 7 zur Verfügung. Denn ich bin der Meinung das der Vergleich mit dem @ da noch funktioniert hat. Vielleich sind ja andere so nett und Testen das mal mit anderen Versionen. Ich habe das mit Delphi 2007, XE und jetzt sogar mit XE2 Update 3 in 32 und 64bit getestet. Immer mit dem gleichen Ergebnis. Nur das sich bei 64bit die Größen verdoppeln. Und da liegt vermutlich auch das Problem. Laut Hilfe von XE2 gibt es unter 64bit kein 128bit großen Datentyp äquivalent zu Int64 bei 32bit, so das gar nicht beide Pointer bei dem @ zurückgegeben werden können.
Auch TControlActionLink.IsOnExecuteLinked und DelegatesEqual sehen bei XE2 so aus wie bei XE.
Einbeliebigername.