Piotr Olszewski
Piotr Olszewski

Reputation: 1

Delphi FreeLibrary hangs after procedure from dll raise exeception

I have a problem with dll that contains procedure with Firebird TIBScript.

uses
  System.SysUtils,
  System.Classes,
  DLLMainData in 'DLLMainData.pas' {DataModule2: TDataModule};

{$R *.res}

Procedure RunScript();stdcall;
begin
   TDataModule2.RunScriptProc;
end;

exports
  RunScript;

begin
end.

dll procedure

class function TDataModule2.RunScriptProc: boolean;
begin
  with self.Create(nil) do
  begin
    try
      IBDatabase1.Open;
      IBScript1.ExecuteScript;
    finally
      IBDatabase1.Close;
      Free;
    end;
  end;
end;

Now I call this procedure from an exe as follows:

procedure TForm2.Button1Click(Sender: TObject); 
var
  Handle: Integer;    
  LibraryProc :procedure();stdcall;
begin
   Handle := LoadLibrary('dllka.dll');
   if Handle <> 0 then
   begin
     try
       LibraryProc := GetProcAddress(Handle,'RunScript');
       if @LibraryProc = nil then
         raise Exception.Create('erorr')
       else
         LibraryProc();
     finally
       Showmessage('Before free library');
       FreeLibrary(Handle);
       Handle := 0;
       LibraryProc := nil
     end
   end;
   Showmessage('ok');
end;

When TIBScript raise exception while executing (problem with sql etc.) in main App (witch this procedrue is calling from) hangs on FreeLibrary(). When Script was executed without problems everything works fine. I create small example because i thought that problem was with passing params to library but it is not.

Appreciate any assistance. I am using Delphi XE2. Thanks

Upvotes: 0

Views: 3096

Answers (2)

Kevin S. Miller
Kevin S. Miller

Reputation: 962

@David Heffemen is correct. You cannot throw an exception from a DLL, but you can exit with an ExitCode if your intention is to exit the DLL when Delphi catches an exception.

I inherited code that was raising an exception when the DLL could not load, but was just hanging when the DLL could not be found. I solved it checking that the file exists and the handle was assigned, setting ExitCode to 1, and exiting. It produced a nice exception in my C# when I called an exported function:

procedure LoadMyDll();
  begin
    if (FileExists(MY_DLL_NAME)) then
      _hMy32Dll := LoadLibrary(PChar(MY_DLL_NAME));
    if (_hMy32Dll = 0) then
      begin
        System.ExitCode:=1;
        exit;
      end;
  end;

The Exception message in C# was:

System.DllNotFoundException: Unable to load DLL 'C:\src\MyDLL\Delphi\Win32\Debug\MyDLL.dll': A dynamic link library (DLL) initialization routine failed. (Exception from HRESULT: 0x8007045A)
   at MyDLLTest.Program.Min(Int32 x, Int32 y)
   at MyDLLTest.Program.Main(String[] args) in C:\src\MyDLL\CSharp\MyDLLTest\MyDLLTest\Program.cs:line 23

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 612964

A DLL is contracted not to throw exceptions out of exported functions. Your DLL breaks this contract.

Fix the problem by handling all exceptions in any exported function. Convert those exceptions into, for instance, an error code return value. This is one of the few times that it is reasonable to use an indiscriminate catch-all exception handler.

Your exported function would look like this:

function RunScript: Integer; stdcall;
begin
  Try
    TDataModule2.RunScriptProc;
    Result := ERROR_CODE_SUCCESS;
  Except
    Result := ...; // your code to convert exception to error code goes here
  End;
end;

Upvotes: 4

Related Questions