![]() |
DLL Callback Pointerübergabe erwartet Variable
Hallo,
stehe hier gerade vor dem kleinen Problem das ich versuche in einer DLL eine Callback Funktion zu realisieren. Die DLL steht auch bereits nur der Aufruf der Prozedur funktioniert nicht. Bekomme immer die Meldung das eine Variable fehlen würde.
Delphi-Quellcode:
Die DLL
unit Defines;
interface type TCallBackProc = procedure(Command: Integer); stdcall; TGetName = function: Pchar; stdcall; TGetVersion = function: PChar; stdcall; TSetCallBackProc = procedure(CallBackProc: Pointer); stdcall; TGetData = function(Command: Integer): Boolean; stdcall; TInit = function: Boolean; stdcall; TStart = procedure; stdcall; TStop = procedure; stdcall; TConfigure = procedure; stdcall; implementation end.
Delphi-Quellcode:
Die Main
library TestPlugin;
uses SysUtils, Classes, Dialogs, Defines in '..\Shared\Defines.pas'; var FCallBackProc: TCallBackProc; {$E mcp} {$R *.res} // Procedure zum testen der CallBack Funktion procedure FTimerTimer(Sender: TObject); begin if Assigned(FCallBackProc) then FCallBackProc(1); end; // Name des Plugins function GetName: PChar; stdcall begin Result := 'Media Center TestPlugin'; end; // Version des Plugins function GetVersion: Pchar; stdcall begin Result := '1.0.0.0'; end; // CallBack aufruf festlegen procedure SetCallBackProc(CallBackProc: Pointer); stdcall begin @FCallBackProc := CallBackProc; end; // Befehl empfangen function GetData(Command: Integer): Boolean; stdcall begin ShowMessage(Format('Received Command: %d -> Running CallBack', [Command])); FTimerTimer(nil); end; // Initialisieren des Plugins / Hier soll auch mal das CallBack rein function Init: Boolean; stdcall begin ShowMessage('Called Init'); end; // Plugin Starten procedure Start; stdcall begin ShowMessage('Called Start'); end; // Plugin Stoppen procedure Stop; stdcall begin ShowMessage('Called Stop'); end; // Plugin konfigurieren procedure Configure; stdcall begin ShowMessage('Called Configure'); end; exports GetName, GetVersion, SetCallBackProc, GetData, Init, Start, Stop, Configure; begin end.
Delphi-Quellcode:
Was habe ich falsch gemacht? es wird doch nur ein Pointer übergeben, in der DLL scheints ja zu funktionieren...
unit Main;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, JvExStdCtrls, JvListBox, JvDialogs, Defines; type TForm1 = class(TForm) OpenDialog: TJvOpenDialog; JvListBox1: TJvListBox; Button1: TButton; Button2: TButton; Button3: TButton; procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure DLLAufruf(Command: Integer); private Lib: THandle; PluginGetName: TGetName; PluginGetVersion: TGetVersion; PluginSetCallBackProc: TSetCallBackProc; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button2Click(Sender: TObject); begin if Opendialog.Execute then begin Lib := LoadLibrary(PChar(OpenDialog.FileName)); if Lib = 0 then ShowMessage('Plugin konnte nicht geladen werden!'); @PluginGetName := GetProcAddress(Lib, 'GetName'); Self.JvListBox1.Items.Add('Name: ' + PluginGetName); @PluginGetVersion := GetProcAddress(Lib, 'GetVersion'); Self.JvListBox1.Items.Add('Version: ' + PluginGetVersion); end; end; procedure TForm1.Button3Click(Sender: TObject); begin if Lib <> 0 then begin @PluginSetCallBackProc := GetProcAddress(Lib, 'SetCallBackProc'); PluginSetCallBackProc(@DLLAufruf); // Hier kommt die Meldung Variable benötigt end; end; procedure TForm1.DLLAufruf(Command: Integer); begin ShowMessage(Format('Command von DLL: %d', [Command])); end; end. |
Re: DLL Callback Pointerübergabe erwartet Variable
Hallo!
Kannst du statt
Delphi-Quellcode:
nicht folgendes machen?
TSetCallBackProc = procedure(CallBackProc: Pointer); stdcall;
Delphi-Quellcode:
Mit untypisierten Zeigern hast du doch nur Ärger.
TSetCallBackProc = procedure(CallBackProc: TCallBackProc); stdcall;
Vielleicht scheitert's auch daran, dass TForm1.DllAufruf eine Klassenmethode ist. Schau mal ob's klappt, wenn du die Prozedur aus der Klasse herausnimmst. |
Re: DLL Callback Pointerübergabe erwartet Variable
Ganz wichtig! Immer zwischen "einfachen" Funktionen bzw. Prozeduren und Methoden (Funktionen in Klassen) unterscheiden. Methoden bestehen nicht nur aus einem Pointer wie Funktionen, sondern aus zwei (Da kommt nämlich noch "self" hinzu)
Also entweder du schreibst:
Delphi-Quellcode:
Dann aber auch
PluginSetCallBackProc(@Tform1.DLLAufruf); //erstmal für die Vollständigkeit
Delphi-Quellcode:
Oder du machst aus der Methode DLLAufruf eine Funktion, wenn es dein Konzept erlaubt.
TCallBackProc = procedure(Command: Integer) of object; stdcall; //jetzt ist es eine Methode
TSetCallBackProc = procedure(CallBackProc: TCallBackproc); stdcall; |
Re: DLL Callback Pointerübergabe erwartet Variable
Nachdem ich das TForm1 davor gesetzt hatte, hat es geklappt.
Nun stehe ich aber vor einer AV.
Delphi-Quellcode:
Er springt auch in meine Main App, so wie er es sollte, nur dort ist das Command irgendeine Zahl, aber nicht der Wert den ich übergeben habe.
// Procedure zum testen der CallBack Funktion
procedure FTimerTimer(Sender: TObject); begin if Assigned(FCallBackProc) then FCallBackProc(1); end; Danach kommt eine Zugriffsverletzung. Zitat:
Hier stellt sich dann auch die Frage, was ist besser den CallBack einfach nur so aufzurufen und sich aus der DLL dann erst den Command zu holen oder ihn eben mit zu übergeben? Es sollen ja keine Speichermanager verwendet werden. [edit]Den CallBack Teil hatte ich von hier. ![]() [/edit] |
Re: DLL Callback Pointerübergabe erwartet Variable
Was ist denn TForm1.DllAufruf eigentlich? Eine Prozedur mit der Signatur Procedure(Self: TObject; Command: integer);
So, die Dll erwartet aber, dass sie eine Prozedur mit der Signatur Procedure(Command: integer); stdcall; erhält. Zuerst einmal ist im Formular die Aufrufkonvention eine ganz andere. Die Dll schiebt den Parameter auf den Stack, aber dein Formular erwartet zwei Parameter in den Registern. Dadurch wird übrigens auch dein Stack zerschossen, da die Methode bei stdcall eigentlich aufräumen muss. Zum anderen kann, selbst wenn die Aufrufkonvention gleich ist, eigentlich nur Schrott herauskommen, da die Dll andere Parameter übergibt als die Routine erwartet. Des Weiteren musst du dich einfach mal entscheiden, ob du jetzt Methoden oder Prozeduren verwenden willst. Wenn du Methoden willst, dann musst du der Dll auch die Instanz übergeben, an der die Methode aufgerufen wird, denn ein Methodenzeiger besteht einmal aus dem Prozedurzeiger und aus Self. Also müsstest du dann Form1.Dllaufruf übergeben. |
Re: DLL Callback Pointerübergabe erwartet Variable
Delphi-Quellcode:
Dieses habe ich doch bereits benutzt, damit funktioniert es ja auch.
PluginSetCallBackProc(@Tform1.DLLAufruf); //erstmal für die Vollständigkeit
So jetzt ist die AV weg aber immernoch ein falscher Wert... setze ich wieder wo falsch an? DLL
Delphi-Quellcode:
Main
var
FCallBackProc: TCallBackProc; {$E mcp} {$R *.res} // CallBack aufruf festlegen procedure SetCallBackProc(CallBackProc: Pointer); stdcall begin @FCallBackProc := CallBackProc; end; // Befehl empfangen procedure GetData(Command: Integer); stdcall begin ShowMessage(Format('Received Command: %d -> Running CallBack', [Command])); if Assigned(FCallBackProc) then FCallBackProc(101); end;
Delphi-Quellcode:
Ich bekomme als CallBack Command nur eine 1, es sollte aber 101 sein...
type
TForm1 = class(TForm) OpenDialog: TJvOpenDialog; JvListBox1: TJvListBox; Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; JvEdit1: TJvEdit; procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); // procedure DLLAufruf(Command: Integer); procedure Button4Click(Sender: TObject); private Lib: THandle; PluginGetName: TGetName; PluginGetVersion: TGetVersion; PluginSetCallBackProc: TSetCallBackProc; PluginGetData: TGetData; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure DLLAufruf(Command: Integer); begin ShowMessage(Format('Command von DLL: %d', [Command])); end; procedure TForm1.Button2Click(Sender: TObject); begin if Opendialog.Execute then begin Lib := LoadLibrary(PChar(OpenDialog.FileName)); if Lib = 0 then ShowMessage('Plugin konnte nicht geladen werden!'); @PluginGetName := GetProcAddress(Lib, 'GetName'); Self.JvListBox1.Items.Add('Name: ' + PluginGetName); @PluginGetVersion := GetProcAddress(Lib, 'GetVersion'); Self.JvListBox1.Items.Add('Version: ' + PluginGetVersion); end; end; procedure TForm1.Button3Click(Sender: TObject); begin if Lib <> 0 then begin @PluginSetCallBackProc := GetProcAddress(Lib, 'SetCallBackProc'); PluginSetCallBackProc(@DLLAufruf); end; end; procedure TForm1.Button4Click(Sender: TObject); begin @PluginGetData := GetProcAddress(Lib, 'GetData'); PluginGetData(StrtoInt(Self.JvEdit1.Text)); end; end. |
Re: DLL Callback Pointerübergabe erwartet Variable
Du solltest in TSetCallBackProc den Parameter als TCallbackProc deklarieren (wie es schon Dani vorgeschlagen hat), dann würde nämlich ein aussagekräftiger Fehler kommen, in etwa "Incompatible types: 'Calling conventions differ'".
Zitat:
|
Re: DLL Callback Pointerübergabe erwartet Variable
Habs von Pointer auf TCallBackProc abgeändert, jedoch kommt kein Fehler und ich erhalte immernoch die 1 im CallBack...
|
Re: DLL Callback Pointerübergabe erwartet Variable
Du musst es auch in TSetCallbackProc ändern, denn daran orientiert sich ja dein Hauptprogramm.
|
Re: DLL Callback Pointerübergabe erwartet Variable
Ah ok.... Hatte da noch nen @ sitzen. nun kommt der Fehler auch.
Zitat:
mein DLLAufruf hängt ja nun auch nicht mehr direkt in der Klasse? Versteh das nun nicht ganz. Eigentlich soll es eine DLL werden die den IO-Warrior ansteuert um den IR-Receiver zu nutzen. Wenn dieser ein Signal der Fernbedienung erhällt, sollte er mittels Callback das dem Programm mitteilen. Wichtig für mich ist eben das ich das alles nicht nur auf Delphi eingrenze... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:56 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz