Einzelnen Beitrag anzeigen

helste

Registriert seit: 16. Jul 2009
72 Beiträge
 
Delphi 10.1 Berlin Professional
 
#7

AW: DLL Problem mit XE7

  Alt 8. Apr 2015, 16:34
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?
  Mit Zitat antworten Zitat