Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   DLL Problem mit XE7 (https://www.delphipraxis.net/184595-dll-problem-mit-xe7.html)

helste 8. Apr 2015 15:22

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

himitsu 8. Apr 2015 15:30

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?

helste 8. Apr 2015 15:50

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:
procedure edit_test; stdcall;

begin
.....
end;
im rufenden Programm kommt dann z.B. folgendes:
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.

TiGü 8. Apr 2015 16:00

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?

helste 8. Apr 2015 16:07

AW: DLL Problem mit XE7
 
Ja, vielleicht ist es was banales, aber 64bit DLL ist es definitiv nicht.

Mavarik 8. Apr 2015 16:28

AW: DLL Problem mit XE7
 
Zitat:

Zitat von helste (Beitrag 1296746)
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.

Genau so mache ich es - aus den gleichen Gründen - auch!

Übergibst Du ggf. Strings?

helste 8. Apr 2015 16:34

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:
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 hoffe, das ist soweit verständlich.

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?

helste 8. Apr 2015 16:45

AW: DLL Problem mit XE7
 
Zitat:

Zitat von Mavarik (Beitrag 1296764)
Übergibst Du ggf. Strings?

Nein, in dem Beispiel nicht.

In meiner realen Anwendung übergebe ich auch Strings, aber nicht direkt, sondern in einem Datenkonstrukt.
Sieht dann z.B. so aus:
Code:
tparameter = record
              stringvar1,
              stringvar2  : pwidechar;
              intvalue1,
              intvalue2   : integer;
           end;
pparameter = ^tparameter;

var
   parameter : tparameter;
Übergeben wird dann ein Pointer.
In der DLL sieht das dann so aus:

Code:
function edittest (par : pparameter) : HWND; stdcall;

begin
.....
end;
Und aufgerufen wird es so:

Code:
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;
Das funktioniert einwandfrei.
Verwende ich z.B. um Parameter für die Datenbank zu übergeben.

ringli 8. Apr 2015 16:53

AW: DLL Problem mit XE7
 
Delphi-Quellcode:
FreeLibrary(LHnd);
Mir fällt auf das du hier LHnd freigibst, dieses aber nirgendwo deklariert ist. Müsste das nicht eher
Delphi-Quellcode:
FreeLibrary(testdll);
lauten?

himitsu 8. Apr 2015 16:58

AW: DLL Problem mit XE7
 
FreeLibrary ... siehe mein Vorredner.



Versuch mal
Delphi-Quellcode:
tparameter = packed record
und wenn die DLL Strings rausgibt, dann hoffe ich die werden nicht bei Prozedurende freigegeben.

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.

helste 8. Apr 2015 17:13

AW: DLL Problem mit XE7
 
Ja, freelibrary war ein Copy and paste Fehler.

In meiner realen Anwendung verwende ich das gar nicht, weil ich da die DLL statisch eingebunden habe. Hat einfach weniger Probleme geliefert.

In meinem Beispielprogramm habe ich nun freelibrary korrigiert. Merkwürdigerweise liefert nun auch Button1 in der Maske der dll DAS Problem. Also sobald eine Datenbankfunktion ausgeführt wird, bekomme ich Probleme beim Freigeben der DLL.
Das Programm hängt dann einfach beim Betätigen von Button3 im rufenden Programm.

Was VCL anbelangt, so muss ich das leider machen. Ich bin gerade dabei ein Programm mit hundertausenden Programmzeilen umzubauen. Da wird eine Maske nach der anderen und ein Modul nach dem anderen auf die neue Benutzeroberfläche gebracht. Das geht leider nur über die DLL.

Hat bisher auch noch kein Problem gegeben, bis ich jetzt auf XE 7 umgestiegen bin.

Ich habe jetzt aber einen anderen Verdacht. Nachdem das immer im Zusammenhang mit den IBDAC Komponenten auftritt, kann da natürlich auch die Ursache liegen. Ich musste da auf die neueste Version updaten, um sie für XE7 nutzen zu können.
In delphi XE5 habe ich noch die alte Version der IBDAC. Ob da nicht auch mit Delphi XE5 das Problem auftritt. Ich trau mich aber nicht da ein Update zu machen, weil ich sonst keine Chance mehr habe die DLL neu zu kompilieren, wenn das Problem da auch auftritt.

Werde aber mal mit Devart Kontakt aufnehmen. Mal sehen, ob die eine Erklährung haben.

Vorher versuche ich noch eine Routine zu erstellen, wo keine VCL benutzt wird, sondern nur ein reiner Datenbankaufruf geschieht. Mal sehen, ob da das Problem auch auftritt.

Echt doof so was. Da macht man nur ein Update auf die aktuellsten Versionen und schon sitzt man in der Sch....

helste 8. Apr 2015 17:33

AW: DLL Problem mit XE7
 
Hab's gerade mal ausprobiert. Liegt irgendwo bei IBDAC.
Habe eine Procedure geschrieben, die eine Datenbankverbindung erstellt, einen Datenbankaufruf macht und den Inhalt eines Feldwertes in eine Stringliste stellt und diese dann in eine Textdatei schreibt. Läuft alles planmäßig ab, aber beim Freigeben der DLL hängt die Anwendung dann.
Ob das nun an Delphi XE7 hängt oder an der aktuellsten Version von IBDAC weiß ich aber nicht. Eventuell mach ich noch mal Delphi XE5 mit neuester IBDAC auf einen Testrechner drauf.

Werde jetzt mal bei Devart nachfragen, möchte mich aber bei allen bedanken, die sich hier eingebracht haben. Danke Jungs.

EWeiss 8. Apr 2015 17:39

AW: DLL Problem mit XE7
 
Irgendwie eine Verbindung zum ComObjekt ?
Hatte auch letztlich ein Problem mit dem freigeben einer DLL die meine Anwendung zum hängen brachte.
Wenn ich CoUninitialize aufgerufen habe bevor die DLL freigegeben wurde hat sich mein Programm aufgehängt.

CoUninitialize nach dem freigeben der DLL hat das Problem beseitigt.

Kann nicht sehen ob deine Datenbank irgendeine Anbindung zu Com hat.
Wenn nicht dann vergess meinen Beitrag einfach.

gruss

helste 8. Apr 2015 18:24

AW: DLL Problem mit XE7
 
Hat damit nichts zu tun. Aber trotzdem Danke.

Habe mal ein kleines Testprogramm an Devart geschickt. Lässt sich zum Glück jetzt wunderbar reproduzieren.
Hoffentlich antworten die rasch.

BadenPower 8. Apr 2015 21:15

AW: DLL Problem mit XE7
 
Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject); // DLL freigeben
begin
  FreeLibrary(LHnd);
  edit_test := nil; // diese Zeile
end;
Ist es möglich, dass die markierte Zeile eventuell den Fehler auslöst?

helste 9. Apr 2015 06:36

AW: DLL Problem mit XE7
 
Nein, diese Zeile ist es sicher nicht.

helste 9. Apr 2015 06:52

AW: DLL Problem mit XE7
 
Ich habe gerade mal eben bei meinem einfachen Beispiel die DLL mit Delphi2007 kompiliert. Da habe ich ebenfalls die aktuellste Version von IBDAC in Verwendung. Ist also alles komplett gleich, mit Ausnahme der Delphi Version (und damit verbunden möglicherweise irgendeiner Einstellung bei den Optionen).
Mit dieser DLL funktioniert es sowohl wenn ich das Hauptprogramm mit Delphi 2007, als auch wenn ich es mit Delphi XE7 kompiliere.

Es ist also definitv so, das Delphi XE7 meine DLL irgendwie "verhunzt".

Werde mal den Support von Embarcadero bemühen.

helste 9. Apr 2015 09:27

AW: DLL Problem mit XE7
 
Heute kam Antwort von Devart. Sie haben das in der aktuellen Version (4 Tage, nachdem ich die aktuellste Version installiert hatte) behoben.
Ich bin sehr froh, dass ich mir nun ersparen kann wieder auf eine ältere Delphi Version zu gehen oder alle Datenbankroutinen umzuprogrammieren.

uligerhardt 9. Apr 2015 09:37

AW: DLL Problem mit XE7
 
Zitat:

Zitat von helste (Beitrag 1296865)
Heute kam Antwort von Devart. Sie haben das in der aktuellen Version (4 Tage, nachdem ich die aktuellste Version installiert hatte) behoben.

Und was musst du für den Hotfix zahlen? <gd&r>

helste 9. Apr 2015 10:35

AW: DLL Problem mit XE7
 
Kostet nichts. Ich habe ja erst unlängst ein Update gekauft und da habe ich dann für die nächsten Updates nichts zu zahlen. Ich weiß nicht sicher, aber das geht wohl ein Jahr bzw. einen bestimmten Versionssprung.

uligerhardt 9. Apr 2015 10:40

AW: DLL Problem mit XE7
 
Zitat:

Zitat von helste (Beitrag 1296882)
Kostet nichts. Ich habe ja erst unlängst ein Update gekauft und da habe ich dann für die nächsten Updates nichts zu zahlen.

Sollte eine Stichelei in Richtung Embarcadero sein - bei denen ist das ja neuerdings nicht mehr so. :mrgreen:

helste 9. Apr 2015 11:08

AW: DLL Problem mit XE7
 
Ah, ok. Ja, die sind da etwas merkwürdig geworden, um es mal vorsichtig auszudrücken.

Ich werde mir Updates von Delphi in Zukunft ohnehin sparen. In XE7 ist absolut nichts drinnen, was sich für mich im Vergleich zu XE5 lohnt. Nachdem ich ausschließlich Windows VCL programmiere, bringt mir das nichts. Ich habe mir eigentlich mehr Stabilität der IDE erwartet, aber das ist offenbar schlechter geworden.
Firemonkey war auch mal eine Hoffnung, aber diesbezüglich bin ich völlig desillusioniert. Ich habe mittlerweile alle meine Firemonkeyprojekte auf VCL umgeschrieben. Waren zum Glück nicht viele und auch nicht so große und ich brauche sie auch nur für Windows.

Ich denke mal, dass ich wohl mit Delphi XE7 in Pension gehen werden :lol:


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:21 Uhr.

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