AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Plugins: Datenaustausch zwischen DLL und Hauptprogramm
Thema durchsuchen
Ansicht
Themen-Optionen

Plugins: Datenaustausch zwischen DLL und Hauptprogramm

Ein Thema von alleinherrscher · begonnen am 21. Okt 2009 · letzter Beitrag vom 27. Nov 2009
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#1

Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 00:19
Hi, ich versuche mich gerade in das doch ziemlich spannende Gebiet der DLLs einzuarbeiten, da ich darüber nachdenke, für mein kleines Netzwerkprogramm eine Plugin Schnittstelle zu schaffen. Allerdings bin ich bis jetzt ganz gut ohne DLL programmierung zurecht gekommen - ich bin also DLL-Anfänger (bitte Rücksicht nehmen! )

Ich habe ein bisschen im Forum rumgesucht und bin auf Luckies Plugin Demo gestoßen, die ja schonmal eine sehr gute Einführung liefert.

Ich stelle mir dabei vor, dass man kleine Programme, wie z.B. ein Whiteboard (-> man zeichnet eine Grafik und diese wird dann auf allen Netzwerkrechnern angezeigt), in einer DLL verpackt und mein Netzwerktool quasi die Netzwerkkommunikation leistet.

Warum so kompliziert und die Netzwerkkommunikation nicht direkt in das kleine Programm integrieren? - Weil ich eben alles in einem Programm bündeln möchte und in dem Netzwerktool schon eine recht leistungsstarke Netzwerkkommunikation eingebaut habe.

Um größere Datenmengen zu handeln benutzt mein Netzwerkprogramm Memorystreams und da dachte ich mir, es wäre sinnvoll, auch die Kommunikation zwischen Hauptprogramm und DLL über diesen Datentyp laufen zu lassen.

Jetzt meine Frage:

1. Ist es technisch überhaupt möglich, diesen Datentyp zwischen DLL und Hauptprogramm auszutauschen, da ja ein memorystream im Endeffekt ein reservierter Speicherbereich ist, der einem bestimmten Prozess gehört? Kommt an dieser Stelle evtl. ShareMEM zum Einsatz - ich hab gelesen, das soll ziemlich langsam sein?

2. Ist es möglich (z.B. wenn man sich ein Event definiert) aus der Dll eine procedure im Hauptprogramm aufzurufen -> Irgendwie muss das Hauptprogramm ja anfangen, die erhaltenen Daten abzuschicken...

Vielen Dank dass ihr mir unwissenden Person helft,

Euer Michael
„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 01:31
Objekte (Klassen) mit DLLs zu Teilen ist so nicht möglich, da jeder seine eigene RTTI hat.

Also die Klassen/Typen sind nicht direkt Kompatibel, selbst wenn sie gleich definiert sind.

Und dann hat standardmäßig auch noch jeder seine eigene Speicherverwaltung, welche ebenfalls nicht miteinander arbeitet,

http://www.delphipraxis.net/internal...t.php?t=166651
http://www.delphipraxis.net/internal...t.php?t=162452
http://www.delphipraxis.net/internal...t.php?t=161358


Wo das alles gehn würde, das wären BPLs.


Ansonsten: statt Klassen verwendet man hier Interfaces
allerdings bleibt hier immernoch ein kleines Problem mit deinem Speicher.

Aber da könntest du dir den Stream ebenfalls als Interface erstellen,
welchem dann beim Auslesen ein Speicherblock vom jeweiligen Modul (DLL/EXE), bzw. von dessen Speicherverwaltung gegeben wird, wo er die Daten reinkopiert, welches bei vielen Streams allerdings eh oftmals schon so gemacht wird.


Man könnte (wenn es unbedingt nötig ist) den Stream so erstellen, daß er sich Speicher direkt von Windows (VirtualAlloc, MMF und Co.) besorgt und diesen Speicher kann man dann auch ganz leicht üerall in der ganzen Anwendung verwenden und komplett weiterreichen.



Und zu 2.
Ja, das mit den Callbackprozeduren kannst du hier auch ganz einfach lösen ... das geht genauso, wie sonst auch.
Entweder als normale Prozedur und hier dürfte sogar Methoden möglich sein, so wie du es von der VCL (z.B. Button.OnClick) kennst.
Aber in Bezug darauf, daß man hier DLLs auch mit anderen Sprachenn (nicht immer nur Delphi) erstellen kann,

wäre es praktisch, wenn du Interfaces und als Callback einfach Prozeduren via StdCall verwendest.
Oder du gibst beim Start der DLL, bzw. beim Erstellen (Createn) des PlugIns selber wiederum ein Callback-Interface an.

Dieses Callback-Interface kapselt dann einfach alle Befehle, welche das Plugin in der Hauptanwendung aufrufen kann.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#3

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 11:39
Hey, vielen Dank!

Ich habe auch noch das hier gefunden und werde mich da erstmal durcharbeiten...

http://www.delphipraxis.net/internal...ect.php?t=4203

Viele Grüße,
Michael
„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 11:52
Zu deinem TMemoryStream gibt es ja auch IStream. Ist quasi schon alles vorbereitet, wie bei Biolek
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#5

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 12:07
Zitat von sirius:
Zu deinem TMemoryStream gibt es ja auch IStream. Ist quasi schon alles vorbereitet, wie bei Biolek
Hmmmm, das ist ja Klasse! *Wasser im Mund zusammenläuft* Jetzt noch einen guten Wein dazu....hmmmmm!

Das werd ich direkt mal probieren! Melde mich, sobald die erste Probleme auftauchen!! Vielen Dank, ich glaube du hast mir viel arbeit erspart... (jetzt muss ich nur noch komplett dahinter steigen
„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 13:24
IHost = interface; alle Funktionen/Ereignisse, welcher ein Plugin im Hauptprogramm aufrufen muß

THost = class(TObject, IHost); das interne Objekt der Anwendung

IPlugin = interface; die Schnittstelle zum Plugin, welche jedes Plugin implementiert
hier sind die Funktionen drinnen, welche die Anwendung im Plugin aufrufen muß/kann

TPlugin = class(TObject, IPlugin); das interne Objekt des Plugins

Delphi-Quellcode:
function GetPlugin(Host: IHost): IPlugin; StdCall;
begin
  Result := TPlugin.Create(Host);
end;
das wäre dann z.B. 'ne Funktion, welche die Plugin-DLL exportiert, womit die Anwendung ihr Callback-Interface mitteilt und als Ergebnis das Interface zum Plugin bekommt.

Die Objekte bleiben in ihrem jeweiligem Bereich und der Andere (EXE/DLL) bekommt immer nur das Interface


für den Stream
entweder TStreamAdapter, welcher irgendeinen Nachfahren von TStream kapseln kann (also auch TMemoryStream)

oder du leitest die TMemoryStream ab und implementierst selber das Interface

Delphi-Quellcode:
type
  IDelphiStream = interface['{65805750-623E-4719-AD79-A30FF6FCA3CA}']
    procedure SetSize(NewSize: Longint);
    function Write(const Buffer; Count: Longint): Longint;
    function Read(var Buffer; Count: Longint): Longint;
    function Seek(Offset: Longint; Origin: Word): Longint;
    procedure Clear;
    //procedure LoadFromStream(Stream: IDelphiStream);
    //procedure SaveToStream(Stream: IDelphiStream);
    //procedure LoadFromFile(const FileName: WideString);
    //procedure SaveToFile(const FileName: WideString);
    property Position: Int64 read GetPosition write SetPosition;
    property Size: Int64 read GetSize write SetSize64;
  end;
  TInterfacedMemoryStream = class(TMemoryStream, IDelphiStream);
nur die auskommentierten Methoden müßte man notfalls in TInterfacedMemoryStream noch implementieren, da sie vom "Original" abweichen.
> IDelphiStream ist klar, da man hier ja nicht kein TStream verwenden kann
> warum nicht IStream ... dessen definition weicht sehr stark von TStream ab (IStream = Windows und TStream = Borland/Delphi)
> WideString ist der einzige StringTyp, welchen man ohne Einschränkung über Modulgrenzen (EXE-DLL) hinweg nutzen kann (abgesehn von PChar, aber da muß man auch aufpassen und es geht nicht alles)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#7

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 14:58
Okay, danke! Ich denke, ich hab es soweit verstanden. Was schonmal läuft: Ich kann Plugins laden und gegenseitig Procedures aufrufen. Bin jetzt gerade dabei, den IDelphiStream zu implementieren. Müssen dabei nicht auch die Funktionen "GetPosition", "SetPosition", "GetSize" und "SetSize64" im Interface angegeben werden?

[edit] Ansonsten kennt er die in der Interface-Unit nicht: "[Fehler] InterfaceDefinition.pas(21): E2168 Feld- oder Methodenbezeichner erwartet" [//edit]
„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 15:28
die dort schon eingetragenen Funktionen sind schon im MemoryStream vorhanden,
aber ich glaub du hast Recht, da diese Getter/Setter ja als Private nicht zur Verfügung stehn

aber du brauchst ja auch nur das implementieren, welches man am Ende auch benutzt
(hab hier einfach mal "alle" nötigen Standardfunktionen kopiert)


nja, schön wäre es, wenn man von 2 Objekten erben könne
TMemoryStream und TInterfacedObject, dann brächte man nur noch diese Drei implementieren
Delphi-Quellcode:
function GetPosition: Int64;
procedure SetPosition(const Pos: Int64);
procedure SetSize64(const NewSize: Int64);

jetzt könnte man also von TInterfacedObject erben und hätte die Interfaceverwaltung, muß dann aber den "echten" TMemoryStream mit einbauen und an diesen alles weiterleiten, also alle Stream-Funktionen neu implementieren/umleiten

oder eben so (vom Stream erben und "nur" noch das Basis-Interface reinbauen)
> die Funktionen von IInterface muß jedes Interface bereitstellen, da sie zur Verwaltung gehören

Delphi-Quellcode:
type
  IDelphiStream = interface
    ['{65805750-623E-4719-AD79-A30FF6FCA3CA}']
    {private}
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
    function GetSize: Int64;
    {public}
    procedure SetSize(NewSize: Longint);
    function Write(const Buffer; Count: Longint): Longint;
    function Read(var Buffer; Count: Longint): Longint;
    function Seek(Offset: Longint; Origin: Word): Longint;
    procedure Clear;
    //procedure LoadFromStream(Stream: IStream);
    //procedure SaveToStream(Stream: IStream);
    //procedure LoadFromFile(const FileName: WideString);
    //procedure SaveToFile(const FileName: WideString);
    property Position: Int64 read GetPosition write SetPosition;
    property Size: Int64 read GetSize write SetSize64;
  end;

  TInterfacedMemoryStream = class(TMemoryStream, IDelphiStream, IInterface)
  private
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
  protected
    FRefCount: Integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    class function NewInstance: TObject; override;
    property RefCount: Integer read FRefCount;
  end;

function TInterfacedMemoryStream.GetPosition: Int64;
begin
  Result := inherited Position;
end;

procedure TInterfacedMemoryStream.SetPosition(const Pos: Int64);
begin
  inherited Position := Pos;
end;

procedure TInterfacedMemoryStream.SetSize64(const NewSize: Int64);
begin
  inherited Size := NewSize;
end;

function TInterfacedMemoryStream.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TInterfacedMemoryStream._AddRef: Integer;
begin
  Result := InterlockedIncrement(FRefCount);
end;

function TInterfacedMemoryStream._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;

procedure TInterfacedMemoryStream.AfterConstruction;
begin
  InterlockedDecrement(FRefCount);
end;

procedure TInterfacedMemoryStream.BeforeDestruction;
begin
  if RefCount <> 0 then
    System.Error(reInvalidPtr);
end;

class function TInterfacedMemoryStream.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  TInterfacedMemoryStream(Result).FRefCount := 1;
end;
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  Stream: IDelphiStream;
begin
  Stream := TInterfacedMemoryStream.Create;
end;
wegen dem AfterConstruction und BeforeDestruction nicht wundern, das ist nur dafür da, damit das Objekt/Interface nicht mitten im Create wieder freigegeben wird, da durt durch ein paar "Problemchen" der Referenzzähler kurz auf 0 runterkommen kann (z.B. wenn man das erstellte Objekt/Interface an eine Objektvariable übergibt gibt und nicht SOFORT an eine Interfacevariable)


da es leider kein Private bei Interfaces gibt:
der Trick ist mir mal eingefallen ... so sind über IDelphiStreamIntern die "privaten"/internen Definitionen nicht sichtbar ... tauchen also auch nicht in der Autovervolständigung auf
Delphi-Quellcode:
type
  IDelphiStreamIntern = interface
    {private}
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
    function GetSize: Int64;
  end;
  IDelphiStream = interface(IDelphiStreamIntern)
    ['{65805750-623E-4719-AD79-A30FF6FCA3CA}']
    procedure SetSize(NewSize: Longint);
    function Write(const Buffer; Count: Longint): Longint;
    function Read(var Buffer; Count: Longint): Longint;
    function Seek(Offset: Longint; Origin: Word): Longint;
    procedure Clear;
    //procedure LoadFromStream(Stream: IStream);
    //procedure SaveToStream(Stream: IStream);
    //procedure LoadFromFile(const FileName: WideString);
    //procedure SaveToFile(const FileName: WideString);
    property Position: Int64 read GetPosition write SetPosition;
    property Size: Int64 read GetSize write SetSize64;
  end;
(das ist soein Trick, welchen ich im Zusammenhang mit meinen XML-Klassen mal gelernt hatte)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#9

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 16:12
Herzlichen Dank - komplett Verstanden aber da wäre ich nie selber drauf gekommen. Interfaces sind nützlicher als gedacht! Ich habe zum test mal folgendes programmiert:


Delphi-Quellcode:
//Hauptanwendung schickt ein Bild in einem Memorystream an DLL:
procedure TForm1.Button1Click(Sender: TObject);
var app:tapp;
    astream:TInterfacedMemoryStream;
begin

  app:=tapp.create;
  StartPlugin('P_DLL.dll',app); //Sucht Procedur "LoadPlugin" in der DLL und übergibt den Zeiger auf APP an das Plugin.
                                //Der Zeiger auf TPlugin wird in PluginList gespeichert.

  showmessage('GetName: '+PluginList[0].Getname); //Funktioniert einwandfrei

  astream:=TInterfacedMemoryStream.Create;
  astream.LoadFromFile('C:\Autumn Leaves.jpg');

  PluginList[0].ReceiveStream(astream);

end;
Delphi-Quellcode:
//DLL erhält Stream korrekt und schickt ihn direkt mal wieder zurück an Hauptanwendung (einfach nur als Test der "Durchgängigkeit"):
procedure TPlugin.ReceiveStream(aStream: IDelphiStream); stdcall;
  begin
    App.AddStream(astream);

  end;
Delphi-Quellcode:
//Hauptanwendung erhält Stream wieder zurück:
procedure TApp.AddStream(aStream: IDelphiStream); stdcall;
begin
 TInterfacedMemoryStream(astream).position:=0;
 TInterfacedMemoryStream(astream).SaveToFile('C:\test2.jpg');
end;
Allerdings wird bei "TInterfacedMemoryStream(astream).position:=0; " eine Access Violation hervorgerufen, die ich noch nicht verstehe.
Hast du da evtl noch eine Idee?

„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: Plugins: Datenaustausch zwischen DLL und Hauptprogramm

  Alt 21. Okt 2009, 16:20
wie gesagt, es ist ein Interface und das ist was "ganz" anderes, wie ein Objekt.

man kommt auch nicht so leicht auf das Objekt zurück (eigentlich garnicht), da nach außen egal ist, was hinter dem Interface steckt ... es ist halt nur eine Schnittstelle zu irgendwas anderem.

Delphi-Quellcode:
procedure TApp.AddStream(aStream: IDelphiStream); stdcall;
begin
  astream.position:=0;
  astream.SaveToFile('C:\test2.jpg');
end;
hier also die Funktionen vom Interface nutzen
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 07:11 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