![]() |
DLL Fehler
Hallo
jetzt wirds ein bischen ausführlich: 1. eine dll: "deu.dll"
Delphi-Quellcode:
ganz simpel. Die eine Funktion soll ein Paar Infos zurückgeben, die andere soll dann nachher recht viele Strings hergeben
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; dann in meiner Host-Anwendung:
Delphi-Quellcode:
was jetzt eingetlich passieren sollte: in der retinfo sollten jetzt eingetlich die beiden Strings aus der DLL drinstehen. Tun sie aber nicht.
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; Aus irgendeinem Grund wird in diese Schlaufe verlinkt und damit die DLL wieder geunloaded:
Delphi-Quellcode:
Warum ist das so?
if(@Dllinfo = nil) or (@Dlllanguage = nil)then
begin FreeLibrary(MyDll); MyDll := 0; end Weiß jemand Rat? Danke TO [edit=Admin]Delphi-Tags eingefügt. Mfg. Daniel[/edit] |
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; |
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:
@sakura: Das export Symbol ist veraltet und nur noch zur Kompatiblität zu älterem Code vorhanden. Es hat keine Bedeutung mehr im 32Bit Zeitalter.
procedure info(var AInfo: TInfo); stdcall;
Was am obigen Code fehlt ist der exports Abschnitt:
Delphi-Quellcode:
library xyz;
... exports info, language; end. |
Der exports teil fehlt bei mir aber nicht!
|
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:
die andere Procedure ist gleichgeblieben.
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. Und nochwas: Das Array ist im Programm nachher leer. Vielleicht habt ihr doch recht. Aber was für andere Möglichkeiten gibt es denn? |
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: |
ich meine den record :oops:
|
Ich habe den Fehler gefunden. In deinem Host-Programm hast du das stdcall; vergessen:
Delphi-Quellcode:
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:
TDllLanguage = function: TLanguage; stdcall;
TDllInfo = function: TInfo; stdcall;
Code:
Was natürlich auch für deine Host-Anwendung anwendbar wäre:
void WINAPI info(TInfo* re);
Delphi-Quellcode:
TDllInfo = procedure(var re: TInfo); stdcall;
// ist bei stdcall identisch mit TDllInfo = function: TInfo; stdcall; |
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? |
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 23:49 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