Wednesday, March 18, 2009

Why i can't capture exceptions from Dlls?

A very common topic in newsgroups is Dll Exception handling. If your dll raises an exception, the exception handler in the host app should not be able to recognize the class of the exception it trapped. That's because the host application doesn't recognizes the exception class raised by the dll.

The recommended aproach is to capture any exception within the Dll and create functions that return values of success or failure, then the host application can evaluate such results and raise an exception.

This is an example produces different results when compiled with Delphi or FreePascal, you shouldn't do this:

library failedlib;

uses
SysUtils;


function divide(a, b: integer): Boolean; cdecl;
begin
if b = 0 then
raise Exception.Create('Can''t divide by zero');
Result := True;

end;

exports
divide;

end.

program sample;

{$APPTYPE CONSOLE}

type
TDivide = function (a, b: integer): Boolean; cdecl;


var
FuncDivide: TDivide;
lHandle: Cardinal;

begin
lHandle := LoadLibrary('failedlib.dll');
if lHanlde <> 0 then

begin
FuncDivide = GetProcAddress(lHandle, 'divide');
if pointer(@FuncDivide) <> nil then
begin

try
if FuncDivide(10, 0) then
writeln('Success!');
except

writeln('Failure!');
end;
end;
UnloadLibrary(lHandle);
end;
end.


The correct method is this:

library correctlib;

uses
SysUtils;


function divide(a, b: integer): Boolean; cdecl;
var
c: Integer;
begin
(* Catch any exception before return *)
try

c := a div b;
Result := True;
except
Result := False;
end;
end;

exports
divide;


end.

program sample;

{$APPTYPE CONSOLE}

type
TDivide = function (a, b: integer): Boolean; cdecl;


var
FuncDivide: TDivide;
lHandle: Cardinal;

begin
lHandle := LoadLibrary('correctlib.dll');
if lHanlde <> 0 then

begin
FuncDivide = GetProcAddress(lHandle, 'divide');
if pointer(@FuncDivide) <> nil then
begin

if FuncDivide(10, 0) then
writeln('Success!')
else
(* The exception is raised in the host app, not in the DLL *)

raise 'Failure!';
end;
UnloadLibrary(lHandle);
end;
end.

No comments: