Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi DLL Callback Pointerübergabe erwartet Variable (https://www.delphipraxis.net/102409-dll-callback-pointeruebergabe-erwartet-variable.html)

Cyberaxx 28. Okt 2007 02:51


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:
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.
Die DLL
Delphi-Quellcode:
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.
Die Main
Delphi-Quellcode:
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.
Was habe ich falsch gemacht? es wird doch nur ein Pointer übergeben, in der DLL scheints ja zu funktionieren...

Dani 28. Okt 2007 03:42

Re: DLL Callback Pointerübergabe erwartet Variable
 
Hallo!

Kannst du statt
Delphi-Quellcode:
  TSetCallBackProc = procedure(CallBackProc: Pointer); stdcall;
nicht folgendes machen?
Delphi-Quellcode:
TSetCallBackProc = procedure(CallBackProc: TCallBackProc); stdcall;
Mit untypisierten Zeigern hast du doch nur Ärger.


Vielleicht scheitert's auch daran, dass TForm1.DllAufruf eine Klassenmethode ist. Schau mal ob's klappt, wenn du die Prozedur aus der Klasse herausnimmst.

sirius 28. Okt 2007 06:02

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:
PluginSetCallBackProc(@Tform1.DLLAufruf); //erstmal für die Vollständigkeit
Dann aber auch
Delphi-Quellcode:
TCallBackProc = procedure(Command: Integer) of object; stdcall; //jetzt ist es eine Methode
TSetCallBackProc = procedure(CallBackProc: TCallBackproc); stdcall;
Oder du machst aus der Methode DLLAufruf eine Funktion, wenn es dein Konzept erlaubt.

Cyberaxx 28. Okt 2007 11:59

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:
// Procedure zum testen der CallBack Funktion
procedure FTimerTimer(Sender: TObject);
begin
  if Assigned(FCallBackProc) then
    FCallBackProc(1);
end;
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.
Danach kommt eine Zugriffsverletzung.

Zitat:

---------------------------
Debugger Exception Notification
---------------------------
Project Testanwendung.exe raised exception class EAccessViolation with message 'Access violation at address 00000001. Read of address 00000001'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
Was habe ich da nun wieder verbockt? Wenn ich aus dem CallBack das Command ganz heruas nehme klappt es ohne Probleme.
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. http://www.delphipraxis.net/internal...t=dll+callback
[/edit]

Apollonius 28. Okt 2007 12:08

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.

Cyberaxx 28. Okt 2007 13:01

Re: DLL Callback Pointerübergabe erwartet Variable
 
Delphi-Quellcode:
PluginSetCallBackProc(@Tform1.DLLAufruf); //erstmal für die Vollständigkeit
Dieses habe ich doch bereits benutzt, damit funktioniert es ja auch.

So jetzt ist die AV weg aber immernoch ein falscher Wert... setze ich wieder wo falsch an?

DLL
Delphi-Quellcode:
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;
Main
Delphi-Quellcode:
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.
Ich bekomme als CallBack Command nur eine 1, es sollte aber 101 sein...

Apollonius 28. Okt 2007 13:12

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:

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.

Cyberaxx 28. Okt 2007 13:16

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...

Apollonius 28. Okt 2007 13:27

Re: DLL Callback Pointerübergabe erwartet Variable
 
Du musst es auch in TSetCallbackProc ändern, denn daran orientiert sich ja dein Hauptprogramm.

Cyberaxx 28. Okt 2007 13:38

Re: DLL Callback Pointerübergabe erwartet Variable
 
Ah ok.... Hatte da noch nen @ sitzen. nun kommt der Fehler auch.

Zitat:

Incompatible types: 'Calling conventions differ'
Aber warum nun der Fehler? das ist doch beides nun eine Prozedur von Command: Integer;
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...

Apollonius 28. Okt 2007 13:41

Re: DLL Callback Pointerübergabe erwartet Variable
 
:mrgreen: Genau diese Erleuchtung mit den Aufrufkonventionen wollte ich dir verschaffen. Und jetzt frag dich doch mal selbst: Welche Aufrufkonvention hat TCallbackProc? Und welche hat DllAufruf?

Cyberaxx 28. Okt 2007 13:56

Re: DLL Callback Pointerübergabe erwartet Variable
 
Für mich jetzt im Moment beide die selben, ich weiß aber auch das es falsch ist sonst würds ja gehen...

Die Prozedur in der Main hängt doch nun aber nicht mehr an der Klasse selbst oder?

Apollonius 28. Okt 2007 13:59

Re: DLL Callback Pointerübergabe erwartet Variable
 
Ja, du hast im Hauptprogramm jetzt eine echte Prozedur und keine Methode mehr.

In der Dll ist TCallbackProc doch explizit als stdcall deklariert, vermutlich weil du die Dll nicht Delphi-spezifisch machen willst. Wenn du jedoch weder stdcall noch register, pascal, cdecl oder safecall schreibst, wird automatisch register genommen. Mit anderen Worten: DllAufruf im Hauptprogramm hat die Aufrufkonvention register, die Dll will aber stdcall haben. Folglich musst du DllAufruf einfach als stdcall deklarieren.

Cyberaxx 28. Okt 2007 14:17

Re: DLL Callback Pointerübergabe erwartet Variable
 
Hey danke das wars nun klappt es. :)

So viel habe ich mit DLLs noch nicht gearbeitet das ich da die Kleinigkeiten kenne :(
Eigentlich alles dumme Fehler :(

Cyberaxx 1. Nov 2007 15:55

Re: DLL Callback Pointerübergabe erwartet Variable
 
Hallo,

ich bin es noch einmal. Da es sich irgendwie noch auf das selbe Thema bezieht, hoffe ich das ich hier noch etwas hinzufügen darf,
da es noch etwas mit der Parameterübergabe zu tun hat. Falls nicht mach ich dann nen neues Thema auf.

Das klappt alles soweit, Wenn ich allerdings versuche die DLLs einem Item vom Typ TCollectionItem hinzuzufügen, kann ich auf nichts mehr zugreifen. Mir scheint als sei in dem Fall die Speicherverwaltung hin oder?

Delphi-Quellcode:
procedure TForm1.Btn_LoadClick(Sender: TObject);
begin
  if Opendialog.Execute then begin
    Lib := LoadLibrary(PChar(OpenDialog.FileName));

    if Lib = 0 then
      ShowMessage('Plugin konnte nicht geladen werden!');

    @PluginData := GetProcAddress(Lib, 'PluginData');
    PluginData(PPlugData);

    Self.JvListBox1.Items.Add(Format('Typ: %d', [PlugData.PluginType]));
    Self.JvListBox1.Items.Add(Format('Name: %s', [PlugData.PluginName]));
    Self.JvListBox1.Items.Add(Format('Author: %s', [PlugData.PluginAuthor]));
    Self.JvListBox1.Items.Add(Format('Version: %s', [PlugData.PluginVersion]));

    Btn_Config.Enabled := PlugData.PluginCanConfig;

    if Lib <> 0 then begin
      @PluginCallBack := GetProcAddress(Lib, 'SetCallBack');
      PluginCallBack(@DLLAufruf);
      end;

    end;
end;
Wenn ich das einfach so aufrufe, gibt es keine Probleme, auch beim laden mehrerer Plugins. Alle verrichten auch ihren Dienst so wie sie es sollen. Dort habe ich aber ja keine Übersicht der Plugins.

Eigentlich das gleiche wie Oben nur das ich jetzt noch ein CollectionItem dabei nutze.

Delphi-Quellcode:
type
  TPlugData = packed record
    PluginType: Integer;
    PluginCanConfig: Boolean;
    PluginName: PChar;
    PluginAuthor: PChar;
    PluginVersion: PChar;
  end;
  TPPlugData = ^TPlugData;

[...]

procedure TForm1.Btn_ManagerClick(Sender: TObject);
  var
    I: Integer;
    MC_Plugin: TMC_Plugin;
begin
  if Opendialog.Execute then begin
    Lib := LoadLibrary(PChar(OpenDialog.FileName));

    if Lib = 0 then
      ShowMessage('Plugin konnte nicht geladen werden!');

    @PluginData := GetProcAddress(Lib, 'PluginData');
    PluginData(PPlugData); // <-- TPPlugData - Lasse ich den EIntrag weg, kommt keine AV

    if Lib <> 0 then begin
      @PluginCallBack := GetProcAddress(Lib, 'SetCallBack');
      PluginCallBack(@DLLAufruf);

      MC_Plugin := FMC_Plugins.Add;
      MC_Plugin.Name := PlugData.PluginName;
      MC_Plugin.Author := PlugData.PluginAuthor;
      MC_Plugin.Version := PlugData.PluginVersion;
      MC_Plugin.Description := '';

      Self.JvStatusBar1.Panels[0].Text := InttoStr(FMC_Plugins.Count); // AV - Kann plötzlich nicht mehr auf Komponenten zugreifen
      end;

    end;
end;
Die Collection schaut so aus...
Delphi-Quellcode:
type
  TMC_Plugin = class(TCollectionItem)
  private
    FHandle: Cardinal;
    FFilename: String;
    FName: String;
    FAuthor: String;
    FDescription: String;
    FVersion: String;
    FPluginType: Integer;
    FCanConfig: Boolean;
    FStatus: Integer;
  public
    property Handle: Cardinal read FHandle write FHandle;
    property Filename: String read FFilename write FFilename;
    property Name: string read FName write FName;
    property Author: String read FAuthor write FAuthor;
    property Description: String read FDescription write FDescription;
    property Version: String read FVersion write FVersion;
    property PluginType: Integer read FPluginType write FPluginType;
    property CanConfig: Boolean read FCanConfig write FCanConfig;
    property Status: Integer read FStatus write FStatus;
  end;

type
  TMC_Plugins = class(TCollection)
  private
    function GetPlugins(Index: Integer): TMC_Plugin;
  public
    constructor Create;
    destructor Destroy; override;
    function Add: TMC_Plugin;
    function Del(Index: Integer): Boolean;
    property Plugins[Index: Integer]: TMC_Plugin read GetPlugins;
  end;
Dem Item kann ich die Recordwerte noch hinzufügen aber danach bricht alles zusammen.
Zitat:

---------------------------
Debugger Fault Notification
---------------------------
Project D:\Develop\Delphi\Projects\MediaCenter\Testanwendu ng.exe faulted with message: 'access violation at 0x0013f771: read of address 0xd8002829'. Process Stopped. Use Step or Run to continue.
---------------------------
OK
---------------------------
Ist es weil der Record keine feste Größe hat?

Muetze1 1. Nov 2007 16:15

Re: DLL Callback Pointerübergabe erwartet Variable
 
Wieso sollte denn der Record keine feste Grösse haben? Delphi erlaubt nur feste Strukturgrössen (wie auch C/C++).

Cyberaxx 1. Nov 2007 16:19

Re: DLL Callback Pointerübergabe erwartet Variable
 
Das weiß ich ja eben nicht, ich weiß nur das sobald ich die Funktion raus nehme die mir die Daten aus der DLL holt raus lasse bekomme ich keine AV. Nur in Verbindung mit der Collection taucht er auf nachdem ich ein Item hinzugefügt habe.
Dem Item kann ich auch noch die Daten des Records zuweisen, sobald ich aber auf irgendeine andere Komponente danach zugreiffen will kommt eine Zugriffsverletzung. Habe nichtmal ansatzweise eine Vermutung woran es liegen könnte...

SirThornberry 1. Nov 2007 16:22

Re: DLL Callback Pointerübergabe erwartet Variable
 
Collection? Du arbeitest nicht zufällig mit Klassen und reischst diese von der DLL ins Hauptprogramm und umgekehrt?! hast du den Abschnitt ganz oben in der DLL gelesen der dort steht wenn man ein neues Projekt anlegt?

Cyberaxx 1. Nov 2007 16:25

Re: DLL Callback Pointerübergabe erwartet Variable
 
Ja den habe ich gelesen, hast Du denn auch meine Posts gelesen ;)

Die Collection dient nur in meiner Main App zu Verwaltung...

Apollonius 1. Nov 2007 16:28

Re: DLL Callback Pointerübergabe erwartet Variable
 
Wie sieht denn TMC_Plugins.Add aus? Wird dort wirklich ein TMC_Plugin zurückgegeben oder nur ein TCollectionItem gecastet?

Cyberaxx 1. Nov 2007 16:54

Re: DLL Callback Pointerübergabe erwartet Variable
 
Delphi-Quellcode:
function TMC_Plugins.Add: TMC_Plugin;
begin
  Result := inherited Add as TMC_Plugin;
end;
Was da nun weiß ich nicht aber ich denke mal es wird eines zurück geliefert.

Generelle Frage, ist denn der Part der bei mir die AV auslöst denn soweit in Ordnung?
Das hat mir im Moment wieder die Lust auf mein MediaCenter verdorben, das ich schon wieder an sowas kleinem scheiter...

Die gemeinsame Unit
Delphi-Quellcode:
type
  TPlugData = packed record
    PluginType: Integer;
    PluginCanConfig: Boolean;
    PluginName: PChar;
    PluginAuthor: PChar;
    PluginVersion: PChar;
  end;
  TPPlugData = ^TPlugData;

type
  TPluginData = procedure(PPlugData: TPPlugData); stdcall;
Meine Main App
Delphi-Quellcode:
[...]
Lib: THandle
PluginData: TPluginData;
[...]
procedure TForm1.Btn_LoadClick(Sender: TObject);
begin
  if Opendialog.Execute then begin
    Lib := LoadLibrary(PChar(OpenDialog.FileName));

    if Lib = 0 then
      ShowMessage('Plugin konnte nicht geladen werden!');

    @PluginData := GetProcAddress(Lib, 'PluginData');
    PluginData(@PlugData);
[...]
In der DLL
Delphi-Quellcode:
[...]
procedure PluginData(PPlugData: TPPlugData);
begin
  PPlugData^.PluginType := INIT_READ;
  PPlugData^.PluginCanConfig := True;
  PPlugData^.PluginName := 'Media Center TestPlugin';
  PPlugData^.PluginAuthor := 'dsn';
  PPlugData^.PluginVersion := '1.0.0';
end;
[...]
exports
  SetCallBack, ReceiveData, Start, Stop, Configure, PluginData;

Apollonius 1. Nov 2007 16:55

Re: DLL Callback Pointerübergabe erwartet Variable
 
Arg. Lass dir mal MC_Plugins.ItemClass.ClassName ausgeben.

[edit]Oh, ich habe gerade den as-Cast gesehen. Da hast du ItemClass wohl irgendwo schon richtig umgestellt.[/edit]

Cyberaxx 1. Nov 2007 16:59

Re: DLL Callback Pointerübergabe erwartet Variable
 
Zitat:

---------------------------
Testanwendung
---------------------------
TMC_Plugin
---------------------------
OK
---------------------------

Muetze1 1. Nov 2007 19:57

Re: DLL Callback Pointerübergabe erwartet Variable
 
Kleiner Vorschlag. Damit sparst du dir das @ und die anderen Verrenkungen und du bist typensicherer:
Delphi-Quellcode:
type
  TPlugData = packed record
    PluginType: Integer;
    PluginCanConfig: Boolean;
    PluginName: PChar;
    PluginAuthor: PChar;
    PluginVersion: PChar;
  end;

type
  TPluginData = procedure(var PlugData: TPlugData); stdcall;

Cyberaxx 1. Nov 2007 20:31

Re: DLL Callback Pointerübergabe erwartet Variable
 
Finde gerade den Post / das Forum nicht mehr...

Dazu gab es ein Beispiel Projekt wie man Records und Objekte mit DLLs nutzen kann, die dann auch C Conform sind.
Was für mich doch recht wichtig ist. :)
Daran hatte ich mich gehalten darum diese Umstände.

Wenn es aber auch auf die normale Art geht, mach ich das auch gerne so :)

Cyberaxx 1. Nov 2007 22:54

Re: DLL Callback Pointerübergabe erwartet Variable
 
Sicherlich wird jeder der diesen Post liest anfangen laut über mich zu lachen...

Nachdem ich die DLLs neu kompiliert habe, funktioniert es.
Hat denn jemand eine Ahnung wo der Unterschied liegt zwischen der normalen Lade Prozedur und der Lade Prozedur mit der Collection?

Ich glaube ich sollte die Finger von der Plugin programmierung lassen...

Cyberaxx 2. Nov 2007 00:23

Re: DLL Callback Pointerübergabe erwartet Variable
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich dachte ich kann es nicht schlimmer machen aber zack da kommt wieder nen Prob, wieder gleicher Record...

Ich habe nun versucht alles in eine eigene Klasse zu verpacken "TMCP_Manager", da es ja nun so klappt wie es soll.
Dabei kommt nun wieder der die AV und ich kann wieder nicht auf meine Komponenten zugreifen.
Was ist das für eine ....?

Tausche ich das Record gegen einen einfachen PChar als Rückgabewert aus klappt es, er hat wirklich nur Probleme mit dem Record auf das ich allerdings zugreiffen kann...

Habe mal den Source angehängt, vllt. traut sich ja jemand mal darüber zu schauen.
Es gibt die Hauptanwendung und zwei Plugins, einer ist ein reiner Testplugin und der andere nutzt den IO-Warrior.

Zu erwarten ist aber nicht viel, da es nur zum testen ist.

Wäre eigentlich toll wenn ich das so nutzen könnte wie ich es gerne würde. Da soll noch ne Menge hinter sitzen.

Muetze1 2. Nov 2007 08:07

Re: DLL Callback Pointerübergabe erwartet Variable
 
Du gibst temporäre Strings zurück. Diese sind nach verlassen der Procedure natürlich nicht mehr gültig und verlieren damit meist ihren Inhalt, da deren Speicher wieder verwendet wird.

Eine Möglichkeit: Konstanten definieren und das Plugin verweist auf diese:
Delphi-Quellcode:
// 1. Möglichkeit: const

const
  coPIName = 'IO-Warrior 24';
  coPIAuthor = 'dsn';
  coPIVersion = '0.9.0';

procedure PluginData(var PlugData: TPlugData); stdcall;
begin
  PlugData.PluginType := INIT_READ;
  PlugData.PluginName := @coPIName;    // das sind temporäre Variablen!
  PlugData.PluginAuthor := @coPIAuthor;
  PlugData.PluginVersion := @coPIVersion;
end;
Andere Möglichkeit: der Aufrufer besorgt vor dem Aufruf Speicher und übergibt diesen an die DLL. Sprich: Der Aufrufer muss (z.B. 41 Bytes) an Speicherplatz reservieren und gibt die Zeiger auf diesen Speicherplatz an vor dem Aufruf. Die DLL kopiert dann die Zeichenketten entsprechend in den zur Verfügung gestellten Speicher.

Delphi-Quellcode:
// 2. Möglichkeit: caller stellt Speicherplatz in den PChar's zur Verfügung
//                  und du füllst den entsprechend

procedure PluginData(var PlugData: TPlugData); stdcall;
begin
  PlugData.PluginType := INIT_READ;
  StrPLCopy(PlugData.PluginName, coPIName, 40); // 40 = bytes die der Aufrufer zur Verfügung stellt
  StrPLCopy(PlugData.PluginAuthor, coPIAuthor, 40); // 40 = bytes die der Aufrufer zur Verfügung stellt
  StrPLCopy(PlugData.PluginVersion, coPIVersion, 40); // 40 = bytes die der Aufrufer zur Verfügung stellt
end;
Und da die bösen Pufferüberlaufe auch in Delphi entstehen können, nutzen wir eine Funktion um dies zu verhindern.

Cyberaxx 2. Nov 2007 09:56

Re: DLL Callback Pointerübergabe erwartet Variable
 
Ja das klingt logisch aber warum funktioniert es dann wenn ich es so laufen lasse immer?

Ich dachte das hätte ich ja "gelößt" indem ich ja direkt von der Main App in das Record schreiben lasse, ich übergebe doch den Pointer auf den Record? Dieser sollte doch noch erhalten sein, da er aus der Main App kommt oder irre ich mich da?

Wie würde es zudem aussehen wenn ich den Record als Result einer Funktion zurück gebe, macht das nen Unterschied?

Muetze1 2. Nov 2007 10:27

Re: DLL Callback Pointerübergabe erwartet Variable
 
Zitat:

Zitat von Cyberaxx
Ja das klingt logisch aber warum funktioniert es dann wenn ich es so laufen lasse immer?

Zufall, weil der temporäre Speicher noch nicht überschrieben wurde?

Zitat:

Zitat von Cyberaxx
Ich dachte das hätte ich ja "gelößt" indem ich ja direkt von der Main App in das Record schreiben lasse, ich übergebe doch den Pointer auf den Record?

Der Record ist nicht das Problem (der Var-Typ sorgt auch dafür, dass es ein Pointer ist, von daher bevorzuge ich die var Methode) - aber die PChars in den Record sind das Problem. Das sind Zeiger auf die Zeichenketten. Und diese müssen irgendwo alloziiert werden.

Zitat:

Zitat von Cyberaxx
Dieser sollte doch noch erhalten sein, da er aus der Main App kommt oder irre ich mich da?

Die PChars sind nur Zeiger und im Idealfall nil.

Zitat:

Zitat von Cyberaxx
Wie würde es zudem aussehen wenn ich den Record als Result einer Funktion zurück gebe, macht das nen Unterschied?

Dort würde dann die DLL den Speicher für den Record alloziieren und die App freigeben. Das wären dann auch wieder zwei unterschiedliche Speichermanager. Aber auch diese Lösung löst nicht das Hauptproblem mit den PChar's.

Cyberaxx 2. Nov 2007 10:47

Re: DLL Callback Pointerübergabe erwartet Variable
 
Gibt es auch noch weitere Möglichkeiten, z.B. Array [0..255] of Char um es was einfacher zu gestalten?
Falls nicht werd ich es anpassen.

Delphi-Quellcode:
StrPLCopy(PlugData.PluginName, coPIName, 40); // 40 = bytes die der Aufrufer zur Verfügung stellt
Geht hierbeit auch die Funktion?

Delphi-Quellcode:
StrPLCopy(PlugData.PluginName, coPIName, Sizeof(coPIName));

Cyberaxx 2. Nov 2007 11:25

Re: DLL Callback Pointerübergabe erwartet Variable
 
Ich habe einfach mal alle PChars raus genommen und nur den Integer und das Boolean Feld drin gelassen, kompiliert aber selbst dabei kommt meine AV :(

[edit]Beim einfügen des gleichen mal als Funktion ist mir was aufgefallen, wenn man sich die DLL mal genau anschaut, sieht man das dort das stdcall bei der Prozedur fehlt... Das war gestern wohl einfach zu spät für mich :( Dann muss ich nur noch die PChars besser ersetzen.[/edit]

Muetze1 2. Nov 2007 14:16

Re: DLL Callback Pointerübergabe erwartet Variable
 
Zitat:

Zitat von Cyberaxx
[edit]Beim einfügen des gleichen mal als Funktion ist mir was aufgefallen, wenn man sich die DLL mal genau anschaut, sieht man das dort das stdcall bei der Prozedur fehlt... Das war gestern wohl einfach zu spät für mich :( Dann muss ich nur noch die PChars besser ersetzen.[/edit]

Das habe ich bei dem Code ergänzt - aber nachher beim Post vergessen zu erwähnen. Ich hatte mehrere Dinge geändert und es lief ohne Probleme.

Cyberaxx 2. Nov 2007 14:20

Re: DLL Callback Pointerübergabe erwartet Variable
 
Na dann her mit den sonstigen Änderungen oder betreffen die nur mein PChar Problem?

Muetze1 2. Nov 2007 15:35

Re: DLL Callback Pointerübergabe erwartet Variable
 
Nur das PChar Problem.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:42 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