![]() |
DLL Problem mit XE7
Hallo,
ich stehe gerade vor einem Problem, wo ich nicht mehr weiter weiß. Ich habe einige Programmteile in einer DLL. Der Hintergrund ist der, dass ich neue Programmteile in Delphi XE (derzeit XE7) programmiere, aber das Hauptprogramm immer noch mit Delphi 2007 warten muss. Geht einfach nicht, das alles mit vertretbarem Aufwand umzustellen. Das Problem ist nun, dass Routinen in meiner DLL, die immer funktioniert haben, plötzlich nicht mehr laufen. Wenn ich die DLL mit Delphi XE5 kompiliere, funktioniert alles einwandfrei. Kompiliere ich sie mit XE7, gibt es Probleme. Ein Problem ist, dass einige Proceduren zwar machen was sie sollen, dann beim Beenden des Hauptprogrammes aber ein Runtimeerror 207 generiert wird oder das Hauptprogramm einfach nicht mehr freigegeben wird. Das läuft dann mit ca. 25% Prozessorleistung weiter (im Taskmanager sichtbar). Ich habe nun ein kleines Testprogramm geschrieben, welches eine der problematischen Proceduren aufruft. Da passiert es nun schon, dass das Programm kommentarlos beendet wird, sobald ich die Procedure aus der DLL lade. Wird die DLL mit Delphi XE5 kompiliert, funktioniert alles. Kompiliere ich mit XE7 gibt es das Problem. Das besteht übrigens auch, wenn das rufende Programm mit XE7 kompiliert wird. Liegt also nicht an Delphi 2007. Ich weiß nun echt nicht mehr weiter. Woran kann das unterschiedliche Verhalten beim Kompilieren bzw. Linken der DLL zwischen XE5 und XE7 liegen? Habe ich da im XE7 irgendwas nicht richtig eingestellt? Ich hoffe es kann mir wer helfen. Hänge nun schon seit 3 Tagen mit diesem Problem rum. LG Helmut |
AW: DLL Problem mit XE7
Die Frage ist voallem erstmal was ausgelagert wurde, bzw. wie die Prozeduren/Interfaces asussehen.
Was für Typen haben denn die Parameter und welche Aufrufkonvention wird benutzt? |
AW: DLL Problem mit XE7
Das ist etwas schwierig auf einen Nenner zu bringen.
Ich habe ganze Eingabemasken inklusive Datenbankzugriff, die problemlos funktionieren. Dann gibt es wieder welche, die das Problem verursachen. Bei einer Maske musste ich z.B. TFileSaveDialog durch TSaveDialog ersetzen, damit sie funktioniert. Die selbe DLL mit TFileSaveDialog mit Delphi XE5 kompiliert macht kein Problem. In der DLL kann das z.B. so aussehen:
Code:
im rufenden Programm kommt dann z.B. folgendes:
procedure edit_test; stdcall;
begin ..... end;
Code:
var
edit_test : procedure; stdcall; testdll : HMODULE; procedure TForm1.Button1Click(Sender: TObject); // DLL laden begin testdll := LoadLibrary('testdll.dll'); if testdll <> 0 then begin @edit_test := GetProcAddress(testdll, 'edit_test'); end; end; procedure TForm1.Button2Click(Sender: TObject); // Routine aufrufen begin edit_test; end; procedure TForm1.Button3Click(Sender: TObject); // DLL freigeben begin FreeLibrary(LHnd); edit_test := nil; end; Ich habe das zum Testen bewusst auf 3 Schalter gelegt. Beim Drücken von Button1 wird das Programm jedoch schon kommentarlos beendet. Ich werde versuchen ein komplettes Programm samt kompletter DLL zu erstellen, welches möglichst einfach gehalten ist, aber das Problem bringt. Ich hoffe das gelingt. Ich weiß, so wird es schwierig. Warum kompiliert XE5 die DLL so, dass sie funktioniert und XE7 macht Mist? Das ist mal die Hauptfrage, die mich beschäftigt. |
AW: DLL Problem mit XE7
Es sind immer die ganz kleinen Fehler, die einen Stunden/Tagelang beschäftigen.
Gehe mal gedanklich einen Schritt zurück. Ist es vielleicht irgendetwas banales? Bspw: Mit XE5 erstellst du eine 32-Bit-DLL und mit XE7 unabsichtlich eine 64-Bit-DLL? |
AW: DLL Problem mit XE7
Ja, vielleicht ist es was banales, aber 64bit DLL ist es definitiv nicht.
|
AW: DLL Problem mit XE7
Zitat:
Übergibst Du ggf. Strings? |
AW: DLL Problem mit XE7
Ich konnte jetzt ein Szenarium erstellen, welches den Fehler bringt.
Das Ergebnis ist merkwürdig. So sieht die DLL aus:
Code:
library testdll;
uses System.SysUtils, System.Classes, Winapi.Windows, dlltestunit in 'dlltestunit.pas' {Form1}; {$R *.res} function edittest : HWND; stdcall; begin result := edit_test; end; exports edittest; begin end. In der dlltestunit habe ich ein Formular, auf welches ich Datenbankkomponenten von IBDAC platziert habe. Dazu noch eine TFileSaveDialog Komponente. Dann noch 3 Schalter, welche unterschiedliche Aktionen ausführen. Der Source sieht dann so aus:
Code:
unit dlltestunit;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Data.DB, MemDS, DBAccess, IBC; type TForm1 = class(TForm) FileSaveDialog1: TFileSaveDialog; Button1: TButton; Label1: TLabel; IBCConnection1: TIBCConnection; IBCTransaction1: TIBCTransaction; IBCQuery1: TIBCQuery; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormShow(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; function edit_test : HWND; implementation {$R *.dfm} function edit_test : HWND; var Form1: TForm1; begin result := 0; Form1 := TForm1.Create (nil); if assigned (Form1) then begin result := Form1.Handle; Form1.Show; end; end; procedure TForm1.Button1Click(Sender: TObject); begin IBCQuery1.Open; if not IBCQuery1.Eof then Label1.Caption := IBCQuery1.FieldByName('testfield').AsString;; IBCQuery1.Close; end; procedure TForm1.Button2Click(Sender: TObject); begin if FileSaveDialog1.Execute then Label1.Caption := FileSaveDialog1.FileName; end; procedure TForm1.Button3Click(Sender: TObject); begin if FileSaveDialog1.Execute then begin Label1.Caption := FileSaveDialog1.FileName; IBCQuery1.Open; if not IBCQuery1.Eof then Label1.Caption := Label1.Caption + ' - ' + IBCQuery1.FieldByName('testfield').AsString;; IBCQuery1.Close; end; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; procedure TForm1.FormShow(Sender: TObject); begin IBCQuery1.SQL.Text := 'Select testfield from testtable'; end; end. Im Rufenden Programm habe ich ebenfalls eine kleine Maske gemacht, auf der sich 3 Schalter befinden. Die clicke ich dann der Reihe nach an, wodurch zuerst die DLL initiailsiert wird, dann die Funktion aufgerufen wird (maske der DLL wird angezeigt und da wird dann einer der 3 Schalter gedrückt). Anschließend wird die Maske der DLL geschlossen und im rufenden Programm der 3 Button gedrückt um die DLL wieder frei zu geben. Dann wird das Programm beendet. Hier nun noch das rufende Programm (bzw. die Unit mit dem Form).
Code:
Ich hoffe, das ist soweit verständlich.
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Menus, StdCtrls; type Tmain = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } h : HWND; testdll : HMODULE; edittest : function : HWND; stdcall; end; var main: Tmain; implementation {$R *.dfm} procedure Tmain.Button1Click(Sender: TObject); begin testdll := LoadLibrary('testdll.dll'); if testdll <> 0 then begin @edittest := GetProcAddress(testdll, 'edittest'); end; end; procedure Tmain.Button2Click(Sender: TObject); begin if h = 0 then h := edittest else ShowWindow(h, SW_SHOWNORMAL); end; procedure Tmain.Button3Click(Sender: TObject); begin FreeLibrary(LHnd); edittest := nil; end; end. Ich beobachte nun folgendes: Drückt man in der aufgerufenen Maske (die aus Unit dlltestunit, also aus der aufgerufenen DLL Funktion) jeweils einen Button und beendet dann, dann passiert folgendes. Bei Button1 und Button2 läuft alles völlig normal ab. bei Button3 jedoch, läuft auch alles normal bis zum beenden des Hauptprogrammes. Das bleibt dann nämlich hängen und muss in der IDE durch den Programm abbrechen Button beendet werden. Startet man es außerhalb der IDE muss man den Taskmanager bemühen. Es sieht also so aus: Ein Datenbankaufruf alleine macht nichts. FileSaveDialog1.Execute alleine macht ebenfalls nichts. Beides zusammen bringt Probleme. Das ist nur eines von vielen Beispielen, wo das Problem auftritt. Einfaches Weglassen von FileSaveDialog1.Execute bringt mich also nicht weiter. In anderen Modulen ist es wieder ganz was anderes. Jemand eine Idee? |
AW: DLL Problem mit XE7
Zitat:
In meiner realen Anwendung übergebe ich auch Strings, aber nicht direkt, sondern in einem Datenkonstrukt. Sieht dann z.B. so aus:
Code:
Übergeben wird dann ein Pointer.
tparameter = record
stringvar1, stringvar2 : pwidechar; intvalue1, intvalue2 : integer; end; pparameter = ^tparameter; var parameter : tparameter; In der DLL sieht das dann so aus:
Code:
Und aufgerufen wird es so:
function edittest (par : pparameter) : HWND; stdcall;
begin ..... end;
Code:
Das funktioniert einwandfrei.
function edittest (par : pparameter) : HWND; stdcall; external 'testlib.dll';
procedure testaufruf; var par : tparameter; begin par.stringvar1 := 'aaa'; par.stringvar2 := 'bbb'; par.intvalue1 := 1; par.intvalue1 := 2; edittest (@par); end; Verwende ich z.B. um Parameter für die Datenbank zu übergeben. |
AW: DLL Problem mit XE7
Delphi-Quellcode:
Mir fällt auf das du hier LHnd freigibst, dieses aber nirgendwo deklariert ist. Müsste das nicht eher
FreeLibrary(LHnd);
Delphi-Quellcode:
lauten?
FreeLibrary(testdll);
|
AW: DLL Problem mit XE7
FreeLibrary ... siehe mein Vorredner.
Versuch mal
Delphi-Quellcode:
und wenn die DLL Strings rausgibt, dann hoffe ich die werden nicht bei Prozedurende freigegeben.
tparameter = packed record
Die VCL in einer DLL ist aber keine sonderlich gute Idee und kann natülich auch manchmal Probleme bereiten (außer vielleicht in einem eigenem Thread laufend), denn wenn man z.B. mal in TApplication.ProcessMessage reinsieht, dann erkennt man, daß dann Einiges an Funktionalität fehlt, bzw. Schief laufen kann, wenn die Messages nicht im eigenem Modul verarbeitet werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 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