Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi DLL Fehler (https://www.delphipraxis.net/1525-dll-fehler.html)

theomega 5. Dez 2002 15:51


DLL Fehler
 
Hallo
jetzt wirds ein bischen ausführlich:

1. eine dll: "deu.dll"

Delphi-Quellcode:
library DEU;

uses
  SysUtils,
  Classes;

{$R *.res}


type TInfo=record
author:shortstring;
name:shortstring;
end;

function info:TInfo;stdcall;

var re:tInfo;
begin;
re.author := 'Dominik Bruhn';
re.name := 'German / Deutsch';

result := re;
end;
//=================================================


type TLanguage=record
opentermset:shortstring;
newtermset:shortstring;
end;

function language:TLanguage; stdcall;
var re:TLanguage;
begin;
re.opentermset := 'Termset öffnen';
re.newtermset := 'Neues Termset';

result := re;
end;



begin

end.
export
language,
info;
ganz simpel. Die eine Funktion soll ein Paar Infos zurückgeben, die andere soll dann nachher recht viele Strings hergeben

dann in meiner Host-Anwendung:
Delphi-Quellcode:
unit functions;

interface

uses ComCtrls,inifiles,SysUtils,Classes,Dialogs,XMLDoc,XMLIntf,Graphics,Controls,Math,Types,windows;

type TInfo=record
author:shortstring;
name:shortstring;
end;

type TLanguage=record
opentermset:shortstring;
newtermset:shortstring;
end;

type
TDlllanguage=function: TLanguage;
TDllinfo=function :TInfo;

procedure loadlanguage(lang:string);
implementation

procedure loadlanguage(lang:string);
var
  mydll : dword;
  Dllinfo : TDLLinfo;
  Dlllanguage: TDlllanguage;

  retinfo:TInfo;
begin;
mydll :=0;
mydll := LoadLibrary(pchar(lang+'.dll');

if(mydll <> 0) then
  begin
  Dllinfo := GetProcAddress(mydll,'info');
  Dlllanguage := GetProcAddress(mydll,'language');

  if(@Dllinfo = nil) or (@Dlllanguage = nil)then
       begin
          FreeLibrary(MyDll);
          MyDll := 0;
  end
end;

if(not (@Dllinfo = nil)) and (MyDll <> 0) then begin;
retinfo := Dllinfo;
end;

if(MyDll <> 0) then
  FreeLibrary(MyDll);
end;
was jetzt eingetlich passieren sollte: in der retinfo sollten jetzt eingetlich die beiden Strings aus der DLL drinstehen. Tun sie aber nicht.

Aus irgendeinem Grund wird in diese Schlaufe verlinkt und damit die DLL wieder geunloaded:
Delphi-Quellcode:
  if(@Dllinfo = nil) or (@Dlllanguage = nil)then
       begin
          FreeLibrary(MyDll);
          MyDll := 0;
  end
Warum ist das so?
Weiß jemand Rat?

Danke

TO


[edit=Admin]Delphi-Tags eingefügt. Mfg. Daniel[/edit]

sakura 5. Dez 2002 16:00

Funktioniert es, wenn Du Deine DLL Deklariationen wie folgt anpasst?

Code:
library DEU;

uses
  SysUtils,
  Classes;

{$R *.res} 


type TInfo=record
author:shortstring;
name:shortstring;
end;

function info:TInfo;stdcall; [color=#ee0000][b]exports;[/b][/color]

var re:tInfo;
begin;
re.author := 'Dominik Bruhn';
re.name := 'German / Deutsch';

result := re;
end;
//=================================================


type TLanguage=record
opentermset:shortstring;
newtermset:shortstring;
end;

function language:TLanguage; stdcall; [color=#ee0000][b]exports;[/b][/color]
var re:TLanguage;
begin;
re.opentermset := 'Termset öffnen';
re.newtermset := 'Neues Termset';

result := re;
end;



begin

end.
export
language,
info;

jbg 5. Dez 2002 17:00

Den Record als Result zurückzuliefern ist sehr gewagt. Ein C++/VB Programm kann damit überhaupt nichts anfangen und wird den Speicher auch nicht freigeben, bzw. ihn, da er nicht von selbigem reserviert wurde überschreiben. Ich kenne auch keine WinAPI die einen Record so zurückkliefert.

Eine bessere Deklaration wäre (WinAPI konform):
Delphi-Quellcode:
procedure info(var AInfo: TInfo); stdcall;
@sakura: Das export Symbol ist veraltet und nur noch zur Kompatiblität zu älterem Code vorhanden. Es hat keine Bedeutung mehr im 32Bit Zeitalter.


Was am obigen Code fehlt ist der exports Abschnitt:
Delphi-Quellcode:
library xyz;
...
exports
  info,
  language;

end.

theomega 5. Dez 2002 18:45

Der exports teil fehlt bei mir aber nicht!

theomega 5. Dez 2002 18:56

doch tut er :oops: :oops:

jetzt taucht das nächste Problem auf: Wenn ich alle Debug-Showmessages raus mache, dann passiert garnix. Wenn ich die DLL lösche, dann läuft das Programm wieder. Und wenn ich eine showmessage in die Procedure einbau, wird die auch angezeigt, allerdings ist das Programm dannach wieder weg.

hier nocheinmal der neue DLL-Code:
Code:
library DEU;

uses
  SysUtils,
  Classes;

{$R *.res}


type TInfo=record
author:shortstring;
name:shortstring;
end;

function info:TInfo;stdcall;

var re:tInfo;
begin;
re.author := 'Dominik Bruhn';
re.name := 'German / Deutsch';

result := re;
end;
//=================================================


type TLanguage=record
opentermset:shortstring;
newtermset:shortstring;
end;

function language:TLanguage; stdcall;
var re:TLanguage;
begin;
re.opentermset := 'Termset öffnen';
re.newtermset := 'Neues Termset';

result := re;
end;

exports
language,
info;

begin

end.
die andere Procedure ist gleichgeblieben.

Und nochwas: Das Array ist im Programm nachher leer. Vielleicht habt ihr doch recht. Aber was für andere Möglichkeiten gibt es denn?

jbg 5. Dez 2002 19:04

Welches array?

Den Strichpunkt nach begin kannst du dir sparen. Da kommt keiner hin. Aber das ist deine Sache ob du ihn schreibst oder nicht, da er wahrscheinlich schon automatisch da hinkommt :mrgreen:

theomega 5. Dez 2002 19:09

ich meine den record :oops:

jbg 5. Dez 2002 19:28

Ich habe den Fehler gefunden. In deinem Host-Programm hast du das stdcall; vergessen:
Delphi-Quellcode:
  TDllLanguage = function: TLanguage; stdcall;
  TDllInfo = function: TInfo; stdcall;
Aber das mit dem Result := re ist trotzdem etwas wage. Es funktioniert nur, da Delphi mitdenkt (zumindest bei Records) und bei als stdcall deklarieren Funktionen die Adresse der Variable, die das Ergebnis aufnehmen soll, als 1. Parameter übergibt. So würde deine Funktion für ein C/C++ Programm so aussehen:
Code:
void WINAPI info(TInfo* re);
Was natürlich auch für deine Host-Anwendung anwendbar wäre:
Delphi-Quellcode:
TDllInfo = procedure(var re: TInfo); stdcall;
// ist bei stdcall identisch mit
TDllInfo = function: TInfo; stdcall;

theomega 5. Dez 2002 20:11

Funzt jetzt
aber nocheinmal wegen dem Record. Ich versuche damit meine Anwendung mehrsprachig zu gestalten. Gibt es da andere Möglichkeiten, außerdem (bescheuterten) Sprachtool von Delphi?

Christian Seehase 5. Dez 2002 20:43

Moin The Omega,

der Möglichkeiten gibt's da wohl ein paar mehr.
(Das Tool von Borland kenne ich nicht)

Du könntest Dir z.B. Resourcen DLL's bauen, entsprechend benannt werden müssen, und die die jeweiligen lokalisierten Strings als Stringresourcen enthalten. Schlüsselwort: resourcestring.
Ein Beispiel dafür, auch wenn's nicht als DLL sondern als Unit gemacht ist, gibt's in der consts.pas in den VCL Sourcen.

Eine andere Möglichkeit, die es auch anderen ermöglicht Dein Programm zu "übersetzten" wäre eine schlichte Textdatei, ähnlich einer INI.
Dazu könntest Du Dir als Beispiel mal Inno Setup ansehen. Da sind ja viele Leute dabei das Programm zu lokalisieren.

Was die Längen der Strings angeht müsstest Du natürlich in letzterem Falle besonders aufpassen.
Ausserdem wäre es dann vielleicht noch ganz sinnvoll, wenn Du Dir Gedanken über Unicode Unterstützung machen würdest. Nicht alle Sprachen kommen schliesslich mit dem ANSI Zeichensatz aus.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:48 Uhr.
Seite 1 von 2  1 2      

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