Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Mit DLLs arbeiten (https://www.delphipraxis.net/106502-mit-dlls-arbeiten.html)

Christian18 11. Jan 2008 19:52


Mit DLLs arbeiten
 
Hallo,

ich habe eine Funktion programmiert, die mir einen bestimmten String zusammen baut. Diese Funktion möchte ich in eine DLL auslagern. Ich habe irgendwie gehört, dass es nicht funktionieren soll. Ich habe auch schon vor einiger zeit mal was probiert und das hat auch nicht funktioniert. Ist es überhaupt möglich mit Dlls String übergeben zu lassen?

so baue ich meine DLLs immer aus:

Delphi-Quellcode:
library Project1;

{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muß die
  erste Unit im Uses-Anweisungsteil des Interface-Abschnitts Ihrer
  Unit sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die
  String-Parameter oder Funktionsergebnisse übergeben. Dies gilt für
  alle Strings die an und von Ihrer DLL übergeben werden --  selbst
  für diese, die in Records oder Klassen verschachtelt sind. ShareMem
  ist die Schnittstellen-Unit zur DELPHIMM.DLL, welche Sie mit Ihrer
  DLL weitergeben müssen. Um die Verwendung von DELPHIMM.DLL zu
  vermeiden, übergeben Sie String-Parameter unter Verwendung von
  PChar- oder ShortString-Parametern. } 

uses
  SysUtils,
  Classes;

function Rechne(a, b : Integer) : Integer;
begin
  Result:=a + b;
end;

exports
      Rechne name 'Rechne';

begin
end.
Importiert wird im Programm mit folgender Definition:
Delphi-Quellcode:
Rechne(a, b : Integer) : Integer; external 'Project1' name 'Rechne';

SirThornberry 11. Jan 2008 19:53

Re: Mit DLLs arbeiten
 
du hast die Lösung doch bereits selbst gepostet :wink: Lese dir mal den Text zwischen "library Project1;" und "uses" durch!!

[Edit]Es ist schicker hinter Externale den vollständigen Dateinamen zu schreiben ('Project1.dll' anstelle von 'Project1').
Und die explize Angabe von Name kannst du auch weglassen wenn die Funktion genau so heißt wie in der DLL.

Delphi-Quellcode:
Rechne(a, b : Integer) : Integer; external 'Project1.dll';
oder
Delphi-Quellcode:
Irgendwas(a, b : Integer) : Integer; external 'Project1.dll' name 'Rechne';

DeddyH 11. Jan 2008 19:56

Re: Mit DLLs arbeiten
 
Der Kommentar ist anscheinend nicht auffällig genug :D

Christian18 11. Jan 2008 20:07

Re: Mit DLLs arbeiten
 
Hallo,

ich glaube ich stehe gerade ein bisschen auf dem schlauch. Irgendwie verstehe ich den komentar nicht. kann mir das jemand nochmal verständlich erklären? Ich würde mich freuen.

MFg Christian18

DeddyH 11. Jan 2008 20:09

Re: Mit DLLs arbeiten
 
Delphi-Quellcode:
{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muß die
  erste Unit im Uses-Anweisungsteil des Interface-Abschnitts Ihrer
  Unit sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die
  String-Parameter oder Funktionsergebnisse übergeben. Dies gilt für
  alle Strings die an und von Ihrer DLL übergeben werden --  selbst
  für diese, die in Records oder Klassen verschachtelt sind. ShareMem
  ist die Schnittstellen-Unit zur DELPHIMM.DLL, welche Sie mit Ihrer
  DLL weitergeben müssen. Um die Verwendung von DELPHIMM.DLL zu
  vermeiden, übergeben Sie String-Parameter unter Verwendung von
  PChar- oder ShortString-Parametern. }
Der ist gemeint.

Christian18 11. Jan 2008 20:16

Re: Mit DLLs arbeiten
 
den kommentar meine ich jairgendwie verstehe ich den nicht.

DeddyH 11. Jan 2008 20:18

Re: Mit DLLs arbeiten
 
Wenn Du Strings an die DLL übergeben willst oder die DLL selbst Strings zurückgeben soll, musst Du ShareMem einbinden, und zwar als erste Unit (sowohl in der DLL als auch in der Anwendung). Der einfachere Weg ist allerdings, keine Strings zu übergeben, sondern PChars.

[edit] Nachtrag: wenn Du nicht auf Strings verzichten willst und den Weg über ShareMem gehst, musst Du zusätzlich zur Anwendung und der DLL noch die DELPHIMM.DLL an den Endkunden weitergeben, sonst nützt Dir ShareMem nichts. [/edit]

mkinzler 11. Jan 2008 20:26

Re: Mit DLLs arbeiten
 
Zitat:

wenn Du nicht auf Strings verzichten willst und den Weg über ShareMem gehst, musst Du zusätzlich zur Anwendung und der DLL noch die DELPHIMM.DLL an den Endkunden weitergeben, sonst nützt Dir ShareMem nichts.
Oder einen anderen Speichermanager wie z.B. FastMem verwenden, der das überflüssig macht

DeddyH 11. Jan 2008 20:29

Re: Mit DLLs arbeiten
 
Auf die Erwähnung alternativer Speichermanager hatte ich bewusst verzichtet, um die Verwirrung nicht noch größer zu machen ;)

dor557 11. Jan 2008 21:07

Re: Mit DLLs arbeiten
 
Ich verzichte auf Strings denn Pchar's sind nichts anderes und umwandeln ist einfach und die Speicherauslastung in der DLL und der anwendung ist auch gleiner.

Sollte man auf diese ShareMem dll nicht verzichten wird das Projekt unnötig in die Grösse gezogen.

Gruss Sascha

DeddyH 11. Jan 2008 21:12

Re: Mit DLLs arbeiten
 
Ich bin auch bereits vor Jahren dazu übergegangen, im Zusammenhang mit DLLs PChars zu verwenden. Ist ja nicht mehr so ein Akt mit dem Typecasting wie noch zu Win16-Zeiten.

SirThornberry 11. Jan 2008 21:20

Re: Mit DLLs arbeiten
 
Wenn man viel mit WinApi-Funktionen gearbeitet hat ist man die Arbeit mit PChars gewohnt so das man auch nicht casten muss sondern einfach nur mit Speicheradressen rum hantiert. Wenn man sich dran gewöhnt hat genießt man voller Freunden die Geschwindigkeitsvorteile.

[Edit]Editiert weil es den Text nicht angezeigt hat *grübel*grummel*[/Edit]

DeddyH 11. Jan 2008 21:21

Re: Mit DLLs arbeiten
 
@Jens: wie bitte?

DeddyH 11. Jan 2008 21:55

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von SirThornberry
Wenn man viel mit WinApi-Funktionen gearbeitet hat...

Und auch wenn nicht, ist es ja kein Thema, so etwas zu schreiben:
Delphi-Quellcode:
Bla := Funktion_aus_DLL(PChar(String_aus_Anwendung));
Die Zeiten von StrPas, StrCopy und Konsorten sind ja Gott sei Dank vorbei.

DMW 11. Jan 2008 22:06

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von mkinzler
Oder einen anderen Speichermanager wie z.B. FastMem verwenden, der das überflüssig macht

Sicher? IIRC ist der Grund dafür, daß Strings referenzgezählt sind und deshalb möglicherweise von der DLL alloziert, aber von der Anwendung freigegeben werden könnten (oder natürlich umgekehrt), weshalb beide denselben Speichermanager benutzen müssen - was aber eigentlich doch nur mit einer zusätzlichen DLL geht.

Christian18 12. Jan 2008 12:33

Re: Mit DLLs arbeiten
 
Hallo,

ihr redet die ganze zeit von Pchar und so, hat jemand vieleicht mal ein kleines beispiel, wie sowas aussieht?

MFG Christian18

STS301 12. Jan 2008 12:35

Re: Mit DLLs arbeiten
 
Delphi-Quellcode:
implementation
type TSummenFunktion = function(zahl1, zahl2: integer): integer; stdcall;

function addieren(zahl1, zahl2: integer): integer;
var SummenFunktion: TSummenFunktion;
    Handle: THandle;
begin

Handle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'rechenpro.dll'));

if Handle <> 0 then begin
    @SummenFunktion := GetProcAddress(Handle, 'addiere');
    if @SummenFunktion <> nil then begin
      result:=SummenFunktion(zahl1, zahl2);
    end;
FreeLibrary(Handle);
vielleicht hilft dir da etwas

Elvis 12. Jan 2008 13:09

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von DMW
Zitat:

Zitat von mkinzler
Oder einen anderen Speichermanager wie z.B. FastMem verwenden, der das überflüssig macht

Sicher? IIRC ist der Grund dafür, daß Strings referenzgezählt sind und deshalb möglicherweise von der DLL alloziert, aber von der Anwendung freigegeben werden könnten (oder natürlich umgekehrt), weshalb beide denselben Speichermanager benutzen müssen - was aber eigentlich doch nur mit einer zusätzlichen DLL geht.

Wenn du in DLL und Echse FastMM benutzt dann gates auch ohne extra DLL.

Außerdem mein üblicher Hinweis bei dem Thema: WideString lässt sich ohne Tricksereien zwischen Echse und DLL (und auch anderen Sprachen, weil normaler OleString aka BSTR)

PChar zu verwenden, ohne eine Kopie des Strings zu übergeben ist ein wenig heikel.
Da Stringinstanzen in Delphi auf mehrere Referenzen verteilt sein könnten, könnten so aus Versehen auch andere Variablen/Felder mit dem ehemals gleichen Wert mitgeändert werden.
Nicht zu vergessen, dass das schnell sehr, sehr hässlicher Code wird... :?

DeddyH 12. Jan 2008 13:20

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von Christian18
Hallo,

ihr redet die ganze zeit von Pchar und so, hat jemand vieleicht mal ein kleines beispiel, wie sowas aussieht?

MFG Christian18

Jepp, biddeschön. Die DLL (HauptUnit):
Delphi-Quellcode:
library TestDLL;

{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muss sich in der
  ersten Unit der unit-Klausel der Bibliothek und des Projekts befinden (Projekt-
  Quelltext anzeigen), falls die DLL Prozeduren oder Funktionen exportiert, die
  Strings als Parameter oder Funktionsergebnisse übergeben. Das gilt für alle
  Strings, die von oder an die DLL übergeben werden -- sogar für diejenigen, die
  sich in Records und Klassen befinden. Sharemem ist die Schnittstellen-Unit zur
  Verwaltungs-DLL für gemeinsame Speicherzugriffe, BORLNDMM.DLL.
  Um die Verwendung von BORLNDMM.DLL zu vermeiden, können Sie String-
  Informationen als PChar- oder ShortString-Parameter übergeben. }
 
uses
  DLLUnit in 'DLLUnit.pas';

exports Meldung;

begin
end.
DLLUnit:
Delphi-Quellcode:
unit DLLUnit;

interface

uses Windows;

function Meldung(sMeldung: PChar): DWORD;stdcall;

implementation

function Meldung(sMeldung: PChar): DWORD;stdcall;
begin
  Result := MessageBox(0,sMeldung,nil,0);
end;

end.
Und die Hauptunit des aufrufenden Programms:
Delphi-Quellcode:
unit AppUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function Meldung(sMeldung: PChar): DWORD;stdcall;external 'TestDLL.dll';


procedure TForm1.FormCreate(Sender: TObject);
begin
  Meldung('Huhu');
end;

end.

Henry 7. Mär 2008 16:40

Re: Mit DLLs arbeiten
 
Hallo,

ich habe auch noch einmal eine Frage zu Strings und DLLs.

Kann ich innerhalb der DLL mit Strings arbeiten ohne das ich einen Speichermanager verwenden zu müssen?
Also zumindest wenn ich bei den exportierten Funktionen und Proceduren keinen String übergebe, sondern einen PChar.

Danke schon einmal für die Antwort.

Luckie 8. Mär 2008 00:18

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von dor557
Ich verzichte auf Strings denn Pchar's sind nichts anderes

Autsch. Ein String ist ein Zeiger auf eine Zeichenkette. Ein PChar ist ein Zeiger auf ein Charakter-Array. Das sind zwei absolut unterschiedliche Dinge.

Zitat:

und umwandeln ist einfach
Aber nur dank der Compiler Magic.

Zitat:

und die Speicherauslastung in der DLL und der anwendung ist auch gleiner.
Kann man so generell nicht sagen. Eher umgekehrt, da Strings nur kopiert werden im Speicher, wenn es nötig ist, ansonsten wird immer nur eine Referenz auf den original String gesetzt.

Zitat:

Sollte man auf diese ShareMem dll nicht verzichten wird das Projekt unnötig in die Grösse gezogen.
Das wäre für mich weniger das Problem. Man muss ben nur daran denken, die ShareMem.dll mit auszuliefern.

@DeddyH: das war ein trivial Beispiel. Interesannt wird es aber erst, wenn die DLL Zeichenketten zurückgeben soll. Wie das geht, siehe hier: http://www.michael-puff.de/Artikel/2...String_DLL.php

@Henry: Innerhalb der DLL kannst du machen, was du willst. Du musst eben nur dann aufpassen, wenn du die Grenzen der Speichermanager (Programm, DLL) überschreiten willst.

Zum Verständnis wie das mit den Speichermanager funktioniert, siehe hier: http://www.michael-puff.de/Artikel/2...ingsAusDLL.php

thabaker 8. Mär 2008 01:27

Re: Mit DLLs arbeiten
 
Zitat:

Außerdem mein üblicher Hinweis bei dem Thema: WideString lässt sich ohne Tricksereien zwischen Echse und DLL (und auch anderen Sprachen, weil normaler OleString aka BSTR)
ist das tatsächlich so? das wäre ja toll, weil widestrings eh immer mehr Verbreitung finden.

Henry 8. Mär 2008 11:13

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von Luckie
@Henry: Innerhalb der DLL kannst du machen, was du willst. Du musst eben nur dann aufpassen, wenn du die Grenzen der Speichermanager (Programm, DLL) überschreiten willst.

OK. Dann könnte ja mein neuer Ansatz klappen, ich werde dann bei der Übergabe von und zur DLL mit PChar arbeiten.
Mal schauen ob es klappt.

Danke erst einmal für die Hilfe.

Elvis 8. Mär 2008 13:26

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von thabaker
Zitat:

Außerdem mein üblicher Hinweis bei dem Thema: WideString lässt sich ohne Tricksereien zwischen Echse und DLL (und auch anderen Sprachen, weil normaler OleString aka BSTR)
ist das tatsächlich so? das wäre ja toll, weil widestrings eh immer mehr Verbreitung finden.

Ja klar.
WideString ist etwas langsamer als AnsiString, da es kein nativer Delphi typ ist (keine Referenzzählung, und auch noch Unicode...).
Sollte aber nicht viel ausmachen. PChars sind nicht nur heikel, weil man vergessen könnte den String vorher explizit zu kopieren, sie machen deine Anwendung auch viel anfälliger für Buffer overflows.
Egal ob unbeabsichtigt, oder als Sicherheitslücke, die andere gezielt ausnutzen könnten...
Und wie gesagt, der Code, der mit PCHars arbeitet ist einfach nur hässlich.

PChars innerhalb von optimierten Funktionen zu nehmen um Kopiererei zu sparen ist eine Sache (und das macht auch Sinn!), aber sich sinnlos auf diese mittelalterliche Art unnötige Bufferflows oder Umwege anzutun kann ich nicht ganz nachvollziehen...
Wenn du weißt, dass die DLL von dir kommt, dann wären auch AnsiString und FastMM ein schöne Lösung.

Henry 8. Mär 2008 15:26

Re: Mit DLLs arbeiten
 
Hallo Robert,

in meinem Fall wäre ich mir sicher das Die DLL von mier kommt ;-)
Ich hätte auch prinzipiell kein Problem damit die BORLNDMM.DLL mit meinem Programm auszuliefern.
Ich konnte bisher allerdings noch nirgendwo finden wo diese Datei hin muss, damit es funktioniert.
Reicht es wenn sie im Programmverzeichnis liegt? So lange es dort liegen kann wäre das auch eine Option für mich.
Ich installiere nämlich ungern Dateien in das Systemverzeichnis von jemand anderem.

Ein Weiteres Problem ist, wo ausser in der DLL muss ich noch die Unit ShareMem (als erstes) einbinden?
Reicht es in der Unit im Programm wo ich die Funktionen importiere, oder auch in allen Units wo ich dann die importierten Funktionen aufrufe?

Elvis 8. Mär 2008 15:49

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von Henry
Hallo Robert,
in meinem Fall wäre ich mir sicher das Die DLL von mier kommt ;-)

Na dann nimm gleich String.
Oder explizit AnsiString, falls du Angst vor binären Inkompatibilitäten mit der nächsten Delphiversion hast. Da dort "String" auf einen UTF16-basierten String zeigen wird.

Zitat:

Ich hätte auch prinzipiell kein Problem damit die BORLNDMM.DLL mit meinem Programm auszuliefern.
...
Ein Weiteres Problem ist, wo ausser in der DLL muss ich noch die Unit ShareMem (als erstes) einbinden?
Reicht es in der Unit im Programm wo ich die Funktionen importiere, oder auch in allen Units wo ich dann die importierten Funktionen aufrufe?
Das ist (fast) alles ein furchtbares Relikt der Vergangenheit.
Ziehe dir FastMM und packe den als erste Unit in die Uses clause von allen .DPRs.
WideString ist aber trotzdem nicht aus dem Rennen und würde von dir gar nix spezielles erfordern...

Henry 8. Mär 2008 16:09

Re: Mit DLLs arbeiten
 
Hallo,

mein Problem ist hauptsächlich, dass ich nicht nur Strings einzeln übergeben möchte.
Ich hatte schon einmal im DelphiForum einen Beitrag zu meinem eigentlichen Problem gestartet und bin immer noch am tüfteln, da es nicht klappt.

Ich möchte nämlich komponenten an die DLL übvergeben (z.B. StringGrid) Siehe: Beitrag im DF

Und dann habe ich hier das Thema gefunden und dachte, frege ich hier mal nach dem Umgang mit dem Speichermanager.
Es kann natürlich auch sein das ich da noch ein ganz anderes Problem habe.
Kannst es Dir ja mal anschauen, vieleicht hast Du ja eine Idee für mich.

Nach FastMM werde ich mal schauen, oder hast du ne Quelle parat?

Danke

Elvis 8. Mär 2008 16:22

Re: Mit DLLs arbeiten
 
Zitat:

Zitat von Henry
Ich möchte nämlich komponenten an die DLL übvergeben (z.B. StringGrid)

Das mag jetzt überraschend kommen, aber Objekte and die DLL zu übergeben hat (fast) gar nichts mit dem Speichermanager zu tun.
Damit das geht müssen alle Packages, die für die Komponenten benötigt werden als Laufzeit-Packages von DLL und Echse referenziert werden.
Das heißt, du musst mindestens die RTL, VCL mitliefern und als Laufzeit Packages angeben. (Unter "Packages" in den Projektoptionen)
Das ist die einzige Möglichkeit, damit TStringGrid in der DLL das gleiche wie TStringGrid in der Echse ist.

Eine andere Möglichkeit wäre es, wenn du dein StringGrid in ein Interface mit den Methoden verpackst, die du benötigst.
Dann bräuchtest du in der DLL nur das Interface benutzen, ohne den Rattenschwanz an Packages mit schleppen zu müssen. (Du kannst hier nach Hier im Forum suchenDLL und Interfaces suchen)

Packages sind eigentlich ein sehr furchtbares Format für eine Bibliothek, da sie immer nur mit einer ganz speziellen Version des Compilers laufen. Du kannst mit Packages nicht die DLL mit Delphi 7 und die Echse mit 7.1 kompilieren.

Henry 8. Mär 2008 16:34

Re: Mit DLLs arbeiten
 
Ohje, da habe ich mir ja was einfallen lassen.
Ich werde deinem Suchtip mal folgen und schauen ob ich das dann hinbekomme.
Hört sich für mich erst mal kompliziert an. Aber mit diesen Packages werde ich dann mal die Finger von lassen, ohne wäre mir auch lieber.

Danke Dir erst einmla für die Hilfe.
Wenn ich noch fragen dazu habe werde ich mich entweder in einem neuen Beitrag oder per PM melden, denn ich denke das passt dann nicht mehr hier zum Thema ;-)


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