Interface zu dynamischer DLL mit Callback
Hallo,
ich möchte ein Callback zusammen mit einer dynamisch geladenen DLL behandeln und habe folgenden Test-Code
Delphi-Quellcode:
Weise ich im Init-Part
unit u_IntDll;
interface uses Winapi.Windows; type TCallbackProcedure = procedure(Msg: string); stdcall; TSetCallbackProc = procedure(ACallbackProc: TCallbackProcedure); stdcall; TEnableDllTimer = procedure(AEnabled: boolean); stdcall; TMyMsgEvent = procedure(Msg: string) of object; TintDll = class private FDLLHandle: THandle; FOnMyMsg: TMyMsgEvent; MyCallbackProc: TSetCallbackProc; MyEnableDllTimer: TEnableDllTimer; procedure ShowDLLMessage(sMsg:String); stdcall; public constructor Create; destructor Destroy; override; property OnMyMsg: TMyMsgEvent read FOnMyMsg write FOnMyMsg; procedure Init; procedure EnableDllTimer(bValue: boolean); end; procedure ShowDLLMessageExt(sMsg: string); stdcall; var intDll: TintDll; implementation procedure ShowDLLMessageExt(sMsg: string); stdcall; begin if assigned(intDll.OnMyMsg) then intDll.OnMyMsg(sMsg); end; { TintDll } constructor TintDll.Create; begin end; destructor TintDll.Destroy; begin FreeLibrary(FDLLHandle); inherited; end; procedure TintDll.EnableDllTimer(bValue: boolean); begin MyEnableDllTimer(bValue); end; procedure TintDll.Init; begin FDLLHandle := LoadLibrary('Callback.dll'); if FDLLHandle <> 0 then begin @MyEnableDllTimer := GetProcAddress(FDLLHandle, 'EnableDllTimer'); @MyCallbackProc := GetProcAddress(FDLLHandle, 'CallbackProc'); MyCallbackProc(ShowDLLMessageExt); end; end; procedure TintDll.ShowDLLMessage(sMsg: String); begin if assigned(intDll.OnMyMsg) then intDll.OnMyMsg(sMsg); end; end.
Delphi-Quellcode:
zu, funktioniert das Ganze einwandfrei.
MyCallbackProc(ShowDLLMessageExt);
Möchte ich aber alles innerhalb der Klasse behandeln und weise
Delphi-Quellcode:
zu, bekomme ich die Meldung "Inkompatible Typen: Reguläre Procedure und Methodenzeiger"
MyCallbackProc(ShowDLLMessage);
Mir ist nicht ganz klar, was der Unterschied zwischen dem Handling von ShowDLLMessageExt und ShowDLLMessage ist. Was muss ich machen, dass ich auch den Callback innnerhalb der Klasse behandeln kann? Grüße Gerd |
AW: Interface zu dynamischer DLL mit Callback
Dein Problem ist, dass eine Prozedur und eine Methode trotz gleichem Schlüsselwort
und ähnlicher Semantik doch technisch unterschiedlich sind. Warum? Bei einer normalen Prozedur Referenz gibt es einen Zeiger. Den auf den Startpunkt des Codes der Prozedur im Speicher. Bei einer Methode gibt es zwei Zeiger: Den auf den Startpunkt des Codes der Methode im Speicher und einen auf die Objektinstanz zu der die Methode gehört, damit man von dort aus auch an die Daten des Objektes ran kommt. Grüße TurboMagic |
AW: Interface zu dynamischer DLL mit Callback
Du musst das Objekt auch übergeben (vereinfacht) und nimm keinen string:
Delphi-Quellcode:
TCallbackProcedure = procedure(obj: Tobject; Msg: widestring); stdcall;
procedure ShowDLLMessageExt(obj: TObject; sMsg: widestring); stdcall; begin TintDll(obj).OnMyMsg(sMsg); end; ... MyCallbackProc(self, @ShowDLLMessageExt) |
AW: Interface zu dynamischer DLL mit Callback
Das grundsätzliche Problem habe ich verstanden. Ich weiß aber immer noch nicht wie ich es lösen kann. Die Zuweisung auf ShowDLLMessageExt funktioniert jetzt schon korrekt. Ich suche, wie ich auf das klasseneigene ShowDLLMessage verweisen kann.
Delphi-Quellcode:
Hätte jetzt erhofft, dass es mit
procedure TintDll.Init;
begin FDLLHandle := LoadLibrary('Callback.dll'); if FDLLHandle <> 0 then begin @MyEnableDllTimer := GetProcAddress(FDLLHandle, 'EnableDllTimer'); @MyCallbackProc := GetProcAddress(FDLLHandle, 'CallbackProc'); MyCallbackProc(ShowDLLMessage); end; end; procedure TintDll.ShowDLLMessage(sMsg: String); begin if assigned(intDll.OnMyMsg) then intDll.OnMyMsg(sMsg); end;
Delphi-Quellcode:
aber dem ist nicht so.
MyCallbackProc(self, ShowDLLMessage);
Standardmässig verwende ich eigentlich Widestring |
AW: Interface zu dynamischer DLL mit Callback
Wenn du beide Seiten frei gestalten kannst, kannst du auch schlicht mit Interfaces arbeiten. Wenn du an die DLL z.B. ein Interface IUserDialog übergibst, kann dieses die Prozedur ShowDLLMessage enthalten. Dann kannst du die einfach und ohne Tricks aus der DLL aufrufen.
|
AW: Interface zu dynamischer DLL mit Callback
Zitat:
Mit Interfaces habe ich noch nie gearbeitet. Müsste schauen wie groß der Umstellungsaufwand ist. Wenn ich an mein Projekt mit der Klasse denke, da waren die Vereinfachungen enorm. Trotzdem die Frage: Gibt es eine Möglichkeit MyCallbackProc mit der klasseneigenen Procedure zu verbinden? |
AW: Interface zu dynamischer DLL mit Callback
Nur, wenn du "CallbackProc" in der "Callback.dll" ändern kannst,
da wie die anderen versucht haben zu erklären
Delphi-Quellcode:
procedure ShowDLLMessageExt(sMsg: string); stdcall;
etwas anderes ist als
Delphi-Quellcode:
procedure TintDll.ShowDLLMessage(sMsg: String);
sowie (um das mal zu verdeutlichen)
Delphi-Quellcode:
procedure TintDll.ShowDLLMessage(sMsg: String);
etwas anderes ist als
Delphi-Quellcode:
procedure TintDll.ShowDLLMessage2(iWert: Integer);
Hier kommt es nicht auf den Namen an, sondern auf die Parameter und auf den Aufruf-Typ. Es wird definiert, dass CallbackProc vom Typ
Delphi-Quellcode:
TCallbackProcedure = procedure(Msg: string); stdcall;
ist. TintDll.ShowDLLMessage ist aber vom Typ
Delphi-Quellcode:
TCallbackProcedure2 = procedure(Msg: string) of object; stdcall;
(ich weiß nur nicht, ob "of object" und "stdcall" zusammen funktionieren und überhaubt bei DLL-Proceduren als Parameter verwendet werden können) Es geht mir nur darum zu zeigen, wie sich der Typ unterscheidet. Ich hoffe das hilft beim Verständnis. LG Incocnito |
AW: Interface zu dynamischer DLL mit Callback
Delphi-Quellcode:
Entweder du nimmst ein "TMyMsgEvent2" und übergibst zusätzlich das "self" als Parameter an die DLL. Die Dll muss das Objekt zwischenspeichern und beim Aufruf ebenfalls übergeben. Du benoetigst dann eine Funktion ShowDLLMessageExt (keine Methode). Innerhalb dieser kannst du das Objekt dann casten und die Methode aufrufen. Dann sparst du dir die globale Variable:
TCallbackProcedure = procedure(Msg: string); stdcall;
TMyMsgEvent = procedure(Msg: string) of object; // TCallbackProcedure != TMyMsgEvent // ein "of object" fuegt einen (nicht sichtbaren) 1. neuen Parameter ein // Technisch ist demnach das TMyMsgEvent ein // TMyMsgEvent2 = procedure(Sender: TObject; Msg: string) // diese sind nicht kompatibel (daher die Fehlermeldung)
Delphi-Quellcode:
oder du nimmst ein TMyMsgEvent und übergibst beim Callback dieses (sollte hoffentlich funktionieren).
procedure ShowDLLMessageExt(obj: TObject; sMsg: widestring); stdcall;
begin TintDll(obj).OnMyMsg(sMsg); end; |
AW: Interface zu dynamischer DLL mit Callback
Danke für die genaue Erklärung. Vor allem der Hinweis
Zitat:
In dem Fall erscheint mir die bestehende Lösung als am Einfachsten da ich nur auf der Exe-Seite handeln muss. Ich probier aber um des Verständnis Willen auch mal die angedachten Ansätze |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz