AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Übergabe von Listen an DLL ohne Kopie zu erstellen.

Übergabe von Listen an DLL ohne Kopie zu erstellen.

Ein Thema von Ookami · begonnen am 2. Jan 2012 · letzter Beitrag vom 2. Jan 2012
Antwort Antwort
Benutzerbild von Ookami
Ookami

Registriert seit: 20. Nov 2009
Ort: Baden Württemberg
77 Beiträge
 
Delphi 2009 Architect
 
#1

Übergabe von Listen an DLL ohne Kopie zu erstellen.

  Alt 2. Jan 2012, 16:25
Hallo Kollegen,


Mein Problem ist wie folgt:

Ich möchte Listen oder Inhalte von Komponenten an eine DLL übergeben. Soweit kein Problem, das funktioniert problemlos!
Im Moment stehe ich total auf dem Schlauch. Ich weiß zwar, wie ich das in C# machen muss, kann das aber irgendwie nicht auf Delphi übertragen.
Ich bin mir sicher, dass dies möglich ist (auch in Delphi) aber ich bekomm es nicht auf die Reihe.
Hoffentlich drücke ich mich verständlich aus.
Bei der Vorgehensweise die ich nun anstrebe, möchte ich aber innerhalb der DLL nicht mit einer Kopie arbeiten sondern mit dem Original.
D.h. wenn ich die Liste/Komponente oder den Record oder was auch immer in der DLL berarbeite, möchte ich, dass das Ergebnis direkt in der Applikation sichtbar ist.
Damit müsste ich dann nicht immer den lästigen Abgleich der Daten händisch vornehmen.


Habt ihr irgendwelche Vorschläge, vielleicht auch mit einem kleinen Code-Schnipsel zum besseren Verständnis?

ich sage schon mal vorab Danke.
und by the way, euch allen ein gutes neues Jahr
Wolfgang
Grüße und Danke
Wolfgang
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#2

AW: Übergabe von Listen an DLL ohne Kopie zu erstellen.

  Alt 2. Jan 2012, 16:41
Also ich hab das ganze über ne Klasse gelöst, die den Zugriff auf die Liste über interfaces kapselt. Um möglichst kompatibel mit verschiedenen Datentypen zu sein hab ich mir zuerst nen record definiert:

Delphi-Quellcode:
  PDataModuleItem = ^TDataModuleItem;
  TDataModuleItem = packed record
    Key : Pointer;
    Value : Pointer;
    datatype: word;
    Size : integer;
  end;
Dann baust du dir nen interface, das du an die DLL übergibst und den Zugriff auf die Listenelemente bereitstellt:

Delphi-Quellcode:
  IDataModule = interface(IEnumerator)
  ['{57AF81B3-B7A8-4B33-8174-C2DBA70DAC97}']
    function GetLinked: boolean; stdcall;
    procedure GetLink(out Link); stdcall;
    procedure SetLink(const ALink: IInterface); stdcall;
    procedure RemoveLink; stdcall;
    function GetValueCount: integer; stdcall;
    function GetValue(index: integer): Pointer; stdcall; // liefert PDataModuleItem zurück
    procedure SetValue(index: integer; Value: Pointer); stdcall;
    procedure DeleteValue(index: integer); overload; stdcall;
    procedure DeleteValue(Key: PChar); overload; stdcall;
    function HasValue(Key: PChar): boolean; stdcall;
    procedure SetCharValue(AKey: PChar; AValue: PChar); stdcall;
    function GetCharValue(AKey: PChar): PChar; stdcall;
    procedure SetFloatValue(AKey: PChar; AValue: real); stdcall;
    function GetFloatValue(AKey: PChar): real; stdcall;
    procedure SetIntValue(AKey: PChar; AValue: Int64); stdcall;
    function GetIntValue(AKey: PChar): Int64; stdcall;
    procedure SetBoolValue(AKey: PChar; AValue: boolean); stdcall;
    function GetBoolValue(AKey: PChar): boolean; stdcall;

    property ValueCount: integer read GetValueCount;
    property Linked: boolean read GetLinked;
  end;
Das interface kann gleich noch nen interface besitzen, dass als Link fungiert und dem Besitzer mitteilt ob sich was geändert hat

Jetzt musst du dir nur noch ne Klasse definieren, die dieses Interface implementiert und schon kannst du das in die DLL rüberschicken bei Bedarf. Als Auszug könnte das so aussehen

Delphi-Quellcode:

function TCustomDataModule.GetCharValue(AKey: PChar): PChar;
var index: integer;
begin
  result := nil;
  index := IndexOf(AKey);
  with FList.LockList do
    try
      if (index > -1) and
         (PDataModuleItem(Items[index])^.datatype = STR_DATA) then
          result := PChar(PDataModuleItem(Items[index])^.Value);
    finally
      FList.UnlockList;
    end;
end;

procedure TCustomDataModule.SetCharValue(AKey: PChar; AValue: PChar);
var Buffer: PDataModuleItem;
begin
  Buffer := nil;
// if IndexOf(AKey) > -1 then
    try
      Buffer := NewDataModuleItem(STR_DATA);
      Buffer^.Key := CopyPChar(AKey);
      Buffer^.Value:= CopyPChar(AValue);
      SetValue(IndexOf(AKey),Buffer);
    finally
      DisposeDataModuleItem(Buffer);
    end;
end;

procedure TCustomDataModule.SetValue(index: integer; Value: Pointer);
var Buffer: PDataModuleItem;
begin
  Buffer := nil;
  if (index > -1) and (index < ValueCount) then
    with FList.LockList do
      try
        Buffer := Items[index];
      finally
        FList.UnlockList;
      end;
  if Assigned(Buffer) then
  begin
    LinkNotification(Buffer^.Key, Buffer^.datatype, lnsChanging);
    DisposeDataModuleItem(Buffer);
  end;
  Buffer := CopyDataModuleItem(PDataModuleItem(Value));

  if Assigned(Buffer) then
    with FList.LockList do
      try
        if (index > -1) and (index < Count) then
          Items[index] := Buffer
        else
          Add(Buffer);
        LinkNotification(Buffer^.Key, Buffer^.datatype, lnsChanged);
      finally
        FList.UnlockList;
      end;
end;
FList is ne ThreadList, damit bist du auch noch Threadsafe, LinkNotification ist ne Methode des Datenmoduls, die bei Bedarf dem Link mitteilt dass sich was geändert hat

Ach und ebenso gesundes neues

Edit\\ CopyDataModuleItem kopiert das record, wobei du dann je nach pItem^.datatype die Werte sinnvoll kopieren solltest

Geändert von snook ( 2. Jan 2012 um 16:46 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Ookami
Ookami

Registriert seit: 20. Nov 2009
Ort: Baden Württemberg
77 Beiträge
 
Delphi 2009 Architect
 
#3

AW: Übergabe von Listen an DLL ohne Kopie zu erstellen.

  Alt 2. Jan 2012, 17:46
Hi Sebastian,

erst mal Danke.
Dein Beitrag ist riesig, will sagen ich bin erschlagen.
Ich hatte da irgendwie auf etwas einfacheres gehofft. in C# gibt es da einfache Zuweisungen, die meist über einen Einzeiler zuzuweisen sind.
Da war ich eben in der Hoffnung, dass man das irgenwie über xxx.Assign (yyy) oder so machen könnte.

Da muss ich mich erst mal durchwursteln.

Aber nochmal Danke
Wolfgang
Grüße und Danke
Wolfgang
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#4

AW: Übergabe von Listen an DLL ohne Kopie zu erstellen.

  Alt 2. Jan 2012, 18:02
Hmm das ist nciht ganz so einfach in Delphi, da jede DLL für sich erstmal ihren eigenen Speichermanager, VCL... mitbringt. Das heisst wenn du ne Klasse in eine DLL rüberschieben willst, dann sieht die compilierte Klasse in der DLL mitunter ganz anders aus als im Hauptprogramm. Wenn du dann in die DLL eine Referenz auf ein Objekt aus dem Hauptprogramm übergibst, können schon einfache Aufrufe krachen. Daher in solchen Fällen immer interfaces benutzen.
Das gleiche gilt dann bei strings, die besitzen ne interne Referenzzählung, die du völlig über den Haufen wirfst, wenn du einen string in eine DLL übergibst, daher nehme ich PChars. Es gibt allerdings auch Ausnahmen. Da müsstes du mal nach Runtimepackages suchen, gegebenenfalls hilft dir auch ein anderer Speichermanager, wie zum Beispiel FastMM4

im einfachsten Fall, bei dem in der DLL weisst von welchem Datentyp die Einträge in der Liste sind, kannst du dir einfach ne Wrapper klasse bauen, der du im Create die Liste übergibst. Wenn diese Wrapperklasse nun ein interface unterstützt, mit dem du auf die die Elemente der Liste zugreifen kannst, dann geht das auch so.

also in etwa:

Delphi-Quellcode:
PMyRecord = ^TMyRecord;
TMyRecord = packed record
  A: integer;
  B: boolean;
end;

IMyRecordWrapper = interface(IUnknown)
  procedure SetValue(AIndex: integer; ANewRecord: PMyRecord); stdcall;
  function GetValue(AIndex: integer): PMyRecord; stdcall;
end;

TWrapMyRecordList = class(TInterfacedObject, IMyRecordWrapper)
private
  FMyList: TList;
public
  constructor Create(AWrappedList: TList); reintroduce; virtual;
  procedure SetValue(AIndex: integer; ANewRecord: PMyRecord); stdcall;
  function GetValue(AIndex: integer): PMyRecord; stdcall;
end;
EDIT\\ da kannst du dann im GetValue/SetValue auch gleich bei Änderungen die Anzeige updaten oder ähnliches...
EDIT EDIT\\ und sry falls ich dich erschlagen hab, dachte mir wenn du sowas machen willst, dann hilft es dir vielleicht das ganze gleich so allgemein wie möglich zu halten, so dass du das später auch mal anderer Stelle verwenden kannst

Geändert von snook ( 2. Jan 2012 um 18:07 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Ookami
Ookami

Registriert seit: 20. Nov 2009
Ort: Baden Württemberg
77 Beiträge
 
Delphi 2009 Architect
 
#5

AW: Übergabe von Listen an DLL ohne Kopie zu erstellen.

  Alt 2. Jan 2012, 19:31
Thx,

Hmm das ist nciht ganz so einfach in Delphi, da jede DLL für sich erstmal ihren eigenen Speichermanager, VCL... mitbringt. ...
Die Problematik ist mir bekannt. Daher knallt es auch regelmäßig, wenn man z.B. einen Typ TFont direkt an eine DLL übergeben will.
Wie gesagt, was mein Problem anbelangt bin ich da von C# verwöhnt und du weißt ja, wie das so ist, da kennt man was in der einen Sprache und versucht dann immer wieder verzweifelt ein Gutes aus der einen Sprache in einer anderen auch anzuwenden.
Wenn mir Delphi aufgrund seiner Struktur nicht so ans Herz gewachsen wäre...

Daher werde ich mich in den kommenden Tagen durch deine Snippets wühlen. Erklärt hast du ja gut, daher nochmal Danke.

Bin aber weiterhin immer Dankbar für weitere Tipps in der Richtung. Könnte ja auch für andere interessant sein.

Grüße
Wolfgang
Grüße und Danke
Wolfgang
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 09:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf