Hallo,
ich bekomme Events von einer Telefonanlage. Während die Event-Handler laufen, dürfen keine weiteren Windows-Messages verarbeitet werden, damit sich die Events von der Telefonanlage nicht gegenseitig überholen. Nun kann es natürlich vorkommen, dass ich beispielsweise aufgrund eines Telefonanlagenevents eine Meldung mit ShowMessage ausgeben möchte. Dabei werden Messages verarbeitet (Anzeige eines modalen Fensters).
Mechanismus, der das Problem löst: Ich verschicke mit PostMessage eine Windows-Message, sobald diese ankommt, rufe ich ShowMessage auf (oder was immer ich tun möchte). Diesen Mechanismus möchte ich natürlich mit möglichst frei definierbaren Methoden verwenden, was die Signatur betrifft. Deshalb möchte ich mit Generics arbeiten. Mein Entwurf:
Delphi-Quellcode:
type
TAsync = class
public
type
TAsyncProc = reference to procedure;
TAsyncProc1<T1> = reference to procedure(P1: T1);
class procedure Call(Proc: TAsyncProc); overload;
class procedure Call<T1>(Proc: TAsyncProc1<T1>; P1: T1); overload;
private
const
WM_ASYNCCALLINVOKE = WM_USER + $4df8;
type
TAsyncProcRec = record
Proc: TAsyncProc;
end;
TAsyncProcRec1<T1> = record
Proc: TAsyncProc1<T1>;
P1: T1;
end;
class function AsyncCallInvoke(var m: TMessage): Boolean;
end;
...
implementation
...
class procedure TAsync.Call(Proc: TAsyncProc);
var
AsyncProcRec: ^TAsyncProcRec;
begin
MessageDistributor.RegisterMessageHandlerMethod(TAsync.AsyncCallInvoke);
New(AsyncProcRec);
AsyncProcRec^.Proc := Proc;
PostMessage(MessageDistributor.Handle, WM_ASYNCCALLINVOKE,
0, Integer(AsyncProcRec));
end;
class procedure TAsync.Call<T1>(Proc: TAsyncProc1<T1>; P1: T1);
var
AsyncProcRec1: ^TAsyncProcRec1<T1>;
begin
MessageDistributor.RegisterMessageHandlerMethod(TAsync.AsyncCallInvoke);
New(AsyncProcRec1);
AsyncProcRec1^.Proc := Proc;
AsyncProcRec1^.P1 := P1;
PostMessage(MessageDistributor.Handle, WM_ASYNCCALLINVOKE,
1, Integer(AsyncProcRec1));
end;
class function TAsync.AsyncCallInvoke(var m: TMessage): Boolean;
var
AsyncProcRec: ^TAsyncProcRec;
Proc: TAsyncProc;
AsyncProcRec1: ^TAsyncProcRec1<T1>; // Hier fehlt nun die Typinformation
Proc1: TAsyncProc1<T1>;
begin
case m.Msg of
WM_ASYNCCALLINVOKE:
begin
Result := True;
case m.WParam of
0:
begin
AsyncProcRec := Pointer(m.LParam);
try
Proc := AsyncProcRec^.Proc;
Proc;
finally
Dispose(AsyncProcRec);
end;
end;
1:
begin
AsyncProcRec1 := Pointer(m.LParam);
try
Proc1 := AsyncProcRec1^.Proc;
Proc1(AsyncProcRec1^.P1); // um lediglich diesen Aufruf zu machen
finally
Dispose(AsyncProcRec1);
end;
end;
end;
end;
else
Result := False;
end;
end;
Das Problem ist nun, dass an der markierten Stelle (also beim Empfangen der Windows-Message) keine Typinformationen für den generischen Typ mehr habe. Die erste überladene Version von Call läuft dagegen wie gewünscht (wenn ich die zweite Version auskommentiere).
Gibt es eine Möglichkeit, die generischen Typinfos irgendwie zwischenzuspeichern und später weiterzuverwenden?
RTTI könnte ein Ansatz sein, deckt aber nicht alle möglichen Typen ab (z.B. Records), wenn ich mich auf die Schnelle richtig informiert habe.
"Seit er seinen neuen Computer hat, löst er alle seine Probleme, die er vorher nicht hatte."