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?