AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Interface zu dynamischer DLL mit Callback
Thema durchsuchen
Ansicht
Themen-Optionen

Interface zu dynamischer DLL mit Callback

Ein Thema von norwegen60 · begonnen am 4. Jul 2021 · letzter Beitrag vom 5. Jul 2021
Antwort Antwort
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#1

Interface zu dynamischer DLL mit Callback

  Alt 4. Jul 2021, 15:48
Hallo,

ich möchte ein Callback zusammen mit einer dynamisch geladenen DLL behandeln und habe folgenden Test-Code
Delphi-Quellcode:
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.
Weise ich im Init-Part MyCallbackProc(ShowDLLMessageExt); zu, funktioniert das Ganze einwandfrei.
Möchte ich aber alles innerhalb der Klasse behandeln und weise MyCallbackProc(ShowDLLMessage); zu, bekomme ich die Meldung "Inkompatible Typen: Reguläre Procedure und Methodenzeiger"
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
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.942 Beiträge
 
Delphi 12 Athens
 
#2

AW: Interface zu dynamischer DLL mit Callback

  Alt 4. Jul 2021, 18:00
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
  Mit Zitat antworten Zitat
brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#3

AW: Interface zu dynamischer DLL mit Callback

  Alt 4. Jul 2021, 18:22
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)
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#4

AW: Interface zu dynamischer DLL mit Callback

  Alt 4. Jul 2021, 20:37
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:
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;
Hätte jetzt erhofft, dass es mit MyCallbackProc(self, ShowDLLMessage); aber dem ist nicht so.

Standardmässig verwende ich eigentlich Widestring
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.582 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Interface zu dynamischer DLL mit Callback

  Alt 4. Jul 2021, 23:20
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.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#6

AW: Interface zu dynamischer DLL mit Callback

  Alt 5. Jul 2021, 14:12
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.
Ich habe schon mal eine Klasse an eine DLL übergeben, auch wenn hier im Forum davor vielfach gewarnt wird. Läuft aber zuverlässig so lange man sicher stellt, dass bei einer Änderung der Klasse beide Seiten kompiliert werden.

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?
  Mit Zitat antworten Zitat
Incocnito

Registriert seit: 28. Nov 2016
223 Beiträge
 
#7

AW: Interface zu dynamischer DLL mit Callback

  Alt 5. Jul 2021, 16:39
Nur, wenn du "CallbackProc" in der "Callback.dll" ändern kannst,
da wie die anderen versucht haben zu erklären
procedure ShowDLLMessageExt(sMsg: string); stdcall;
etwas anderes ist als
procedure TintDll.ShowDLLMessage(sMsg: String);
sowie (um das mal zu verdeutlichen)
procedure TintDll.ShowDLLMessage(sMsg: String);
etwas anderes ist als
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
TCallbackProcedure = procedure(Msg: string); stdcall;
ist.
TintDll.ShowDLLMessage ist aber vom Typ
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
  Mit Zitat antworten Zitat
brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#8

AW: Interface zu dynamischer DLL mit Callback

  Alt 5. Jul 2021, 18:53
Delphi-Quellcode:
  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)
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:

Delphi-Quellcode:
procedure ShowDLLMessageExt(obj: TObject; sMsg: widestring); stdcall;
begin
  TintDll(obj).OnMyMsg(sMsg);
end;
oder du nimmst ein TMyMsgEvent und übergibst beim Callback dieses (sollte hoffentlich funktionieren).

Geändert von brechi ( 5. Jul 2021 um 18:56 Uhr)
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#9

AW: Interface zu dynamischer DLL mit Callback

  Alt 5. Jul 2021, 21:11
Danke für die genaue Erklärung. Vor allem der Hinweis
Zitat:
// TCallbackProcedure != TMyMsgEvent
// ein "of object" fuegt einen (nicht sichtbaren) 1. neuen Parameter ein
hat mir sehr geholfe.
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
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:27 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