AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DLL Callback Merkwürdigkeiten

Ein Thema von haentschman · begonnen am 20. Nov 2016 · letzter Beitrag vom 23. Nov 2016
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#1

DLL Callback Merkwürdigkeiten

  Alt 20. Nov 2016, 14:21
Delphi-Version: 10 Seattle
Moin...

Ich habe eine DLL, mit D5 erstellt, und eine Anwendung die auf Seattle compiliert ist. Die QT Auschnitte sind zu Testwecken vereinfacht.

Was passieren soll:
1. DLL laden
2. procedure StartTransfer aufrufen
3. In der DLL: In StartTransfer den Wert "bearbeiten"
4. Als Callback zurückgeben.
5. In DoWork (Callback) die Werte anzeigen (MessageDialog)

Fehler: Die Werte die ich erwartet habe sind "verschoben" bzw. nicht vorhanden. Wo hab ich den Denkfehler?

DLL:
Delphi-Quellcode:
uses
    SysUtils, Classes, Windows,
    dbisamtb;

    procedure SetWorkCallback(CallBack: Pointer); stdcall;
    procedure StartTransfer(Path: PWideChar); stdcall;


implementation

var
    FWorkCallBack: procedure(TagName, TagValue: PWideChar) = nil;

procedure SetWorkCallback(CallBack: Pointer);
begin
    @FWorkCallBack := CallBack;
end;

procedure StartTransfer(Path: PWideChar);
begin
    if Assigned(FWorkCallBack) then begin
       FWorkCallBack('bla', Path); // hier werden die Werte gefüllt
    end;
end;
Anwendung:
Delphi-Quellcode:
procedure TConfigTransfer.LoadDLL;
begin
    FDLLHandle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0)) + conDBISAM_DLL));
    if FDLLHandle <> 0 then begin
        @FSetWorkCallBack := GetProcAddress(FDLLHandle, 'SetWorkCallback');
        if @FSetWorkCallBack <> nil then begin
            FSetWorkCallBack(@TConfigTransfer.DoWork); // Callback "registrieren"
        end;
        @FStartTransfer := GetProcAddress(FDLLHandle, 'StartTransfer');
    end;
end;

procedure TConfigTransfer.StartTransfer;
begin
    if @FStartTransfer <> nil then begin
        FStartTransfer('Blubb'); // Start
    end;
end;

procedure TConfigTransfer.DoWork(TagName, TagValue: PChar);
var
  Name: string;
  Value: string;
begin
    Name := TagName;
    Value := TagValue;
    MessageDlg(Name + ' ' + Value, mtInformation, [mbOK], 0); // siehe Bild1 (SOLL Name = 'bla', Value = 'Blubb')
end;
Miniaturansicht angehängter Grafiken
fehler.png  
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#2

AW: DLL Callback Merkwürdigkeiten

  Alt 20. Nov 2016, 14:29
Du übergibst einem Zeiger auf eine reguläre Prozedur eine Methode. Klappt es, wenn Du auch eine reguläre Prozedur daraus machst?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#3

AW: DLL Callback Merkwürdigkeiten

  Alt 20. Nov 2016, 14:30
TConfigTransfer.DoWork ist eine normale Klassen-Methode nehme ich an? Das Problem ist, dass bei solchen Methoden immer ein versteckter Self Parameter übergeben wird. Generell würde ich nicht einfach einen Pointer Parameter für den Callback verwenden, sondern einen Typedef verwenden:
Delphi-Quellcode:
type
  TMyCallback = procedure(Sender: TObject; A1, A2: PWideChar) of Object;
Des Weiteren würde ich aber auch generell keinen Methoden-Callback nehmen, da die Dll ja nichtmal weiß, welches Objekt zugeordnet ist und somit den Self Parameter nicht sinnvoll füllen kann.

Möglich wäre in deiner Anwendung die entsprechende Methode als class procedure Callback; static; anzulegen. In diesem Falle verhält sie sich wie eine normale nicht-Objektgebundene Prozedur. Sehr oft haben Callbacks und deren Register-Funktionen einen Pointer Parameter, über den der Benutzer einen selbst-definierten Kontext weiterreichen kann. In diesem Falle sähe das zum Beispiel so aus:
Delphi-Quellcode:
type
  TMyCallbackClass = class(TObject)
  public
    FIrgendwas: Integer;
  public
    class procedure Callback(Context: Pointer; A1, A2: PWideChar); static;
  end;

...

MyCallbackClassInstance := TMyCallbackClass.Create;
MyCallbackClassInstance.FIrgendwas := 42;
SetCallback(@TMyCallbackClass.Callback, MyCallbackClassInstance) // <- 2. Parameter ist dein beliebig wählbarer Kontext
Und in der Dll dann entsprechend FWorkCallback(Context, 'bla', Path) Jetzt kannst du in deiner Callback Funktion jederzeit wieder das dazugehörige Objekt ermitteln:
Delphi-Quellcode:
class procedure TMyCallbackClass.Callback(Context: Pointer; A1, A2: PWideChar);
begin
  ShowMessage(IntToStr(TMyCallbackClass(Context).FIrgendwas));
end;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl (20. Nov 2016 um 14:38 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#4

AW: DLL Callback Merkwürdigkeiten

  Alt 20. Nov 2016, 14:52
Danke...

Das Geheimnis war das:
Delphi-Quellcode:
// procedure DoWork(TagName, TagValue: PChar);
class procedure DoWork(TagName, TagValue: PChar); static;
Miniaturansicht angehängter Grafiken
fehler.png  
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#5

AW: DLL Callback Merkwürdigkeiten

  Alt 20. Nov 2016, 20:09
Und, du hast über einen typlosen Zeiger sämtliche Typprüfungen umgangen.
Wenn man das nicht nacht, dann würde einem der Compiler auch brav sagen können, dass hier etwas nicht stimmt und sogar wo der Fehler liegt.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#6

AW: DLL Callback Merkwürdigkeiten

  Alt 21. Nov 2016, 07:19
Moin...

Um diese Uhrzeit (ohne Kaffe) ist das mit dem Denken schlecht. Dann zeigt mir mal, wie es richtig geht.

Stichworte:
- nicht Typlos
- in der Klasse aber ohne class (Zugriff auf private Felder)
- ohne Context Objekt

Danke...
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

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

AW: DLL Callback Merkwürdigkeiten

  Alt 21. Nov 2016, 07:44
Statt sich mit Pointern und Methodenreferenzen herumzuärgern würde ich schlicht Interfaces benutzen. Dann übergibst du der DLL einfach nur dieses Interface und kannst dann aus der DLL dein Objekt in der Hostanwendung ganz normal über Methoden, Properties usw. ansprechen.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#8

AW: DLL Callback Merkwürdigkeiten

  Alt 21. Nov 2016, 10:18
Statt sich mit Pointern und Methodenreferenzen herumzuärgern würde ich schlicht Interfaces benutzen. Dann übergibst du der DLL einfach nur dieses Interface und kannst dann aus der DLL dein Objekt in der Hostanwendung ganz normal über Methoden, Properties usw. ansprechen.
Wäre auf jeden Fall kein schlechter Ansatz und wenn man tatsächlich auf einen Context-Parameter verzichten will auch die einzige saubere Lösung.

Zur Typsicherheit:
Delphi-Quellcode:
type
  TMyCallback = procedure(Context: Pointer; P1, P2: PWideChar); stdcall;

..

procedure SetCallback(Callback: TMyCallback; Context: Pointer); // <- TMyCallback statt Pointer
Ich persönlich bin ein wenig von C-APIs (insbesondere der WinAPI) beeinflusst, weshalb ich diese Art von Context-Parametern gewöhnt bin und sie auch recht gerne verwende. Den untypisierten Pointer-Typ kannst du an dieser Stelle auch ohne weiteres mit dem Typ deiner Klasse austauschen (nur im Programm, nicht in der Dll), wenn du dich damit sicherer fühlst.
Delphi-Quellcode:
type
  TMyCallback = procedure(Instance: TMyCallbackClass; P1, P2: PWideChar); stdcall;

..

procedure SetCallback(Callback: TMyCallback; Instance: TMyCallbackClass);
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl (21. Nov 2016 um 10:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#9

AW: DLL Callback Merkwürdigkeiten

  Alt 21. Nov 2016, 10:34
Ich persönlich bin ein wenig von C-APIs (insbesondere der WinAPI) beeinflusst, weshalb ich diese Art von Context-Parametern gewöhnt bin und sie auch recht gerne verwende. Den untypisierten Pointer-Typ kannst du an dieser Stelle auch ohne weiteres mit dem Typ deiner Klasse austauschen (nur im Programm, nicht in der Dll), wenn du dich damit sicherer fühlst.
Aber nicht bei Schnittstellen zu DLLs, zumindestens nicht mit Klassen und vorallem nicht ohne gegen die RTL (Laufzeitpackages) zu linken,
denn so klappt mit der RTTI und gemeinsamen Ressourcen garnichts, was bei Klassen aber zwingend nötig ist.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#10

AW: DLL Callback Merkwürdigkeiten

  Alt 21. Nov 2016, 11:16
Ich persönlich bin ein wenig von C-APIs (insbesondere der WinAPI) beeinflusst, weshalb ich diese Art von Context-Parametern gewöhnt bin und sie auch recht gerne verwende. Den untypisierten Pointer-Typ kannst du an dieser Stelle auch ohne weiteres mit dem Typ deiner Klasse austauschen (nur im Programm, nicht in der Dll), wenn du dich damit sicherer fühlst.
Aber nicht bei Schnittstellen zu DLLs, zumindestens nicht mit Klassen und vorallem nicht ohne gegen die RTL (Laufzeitpackages) zu linken,
denn so klappt mit der RTTI und gemeinsamen Ressourcen garnichts, was bei Klassen aber zwingend nötig ist.
Sollte doch eigentlich in jedem Falle funktionieren Innerhalb der Dll wird ja nicht mit der Klasseninstanz gearbeitet. Dort kommt sie als untypisierter Pointer rein und wird als Solcher auch wieder an die Callback Funktion übergeben. Sehe jetzt nicht, wo es da Probleme geben könnte.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 00:15 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