views:

357

answers:

4

What is the right way to handle exceptions thrown from inside a DLL in Delphi?

Something like this

on E : ESomeException do ...

or

if (E is ESomeException) then ...

fails, because of the separate type registries of the DLL and the main application.

+4  A: 

The safest way is to not allow exceptions to "escape" from the DLL in the first place.

But if you have no control over the source of DLL and are therefore unable to ensure this, you can still test the exception class name:

if SameText(E.ClassName, 'ESomeException') then ...
Deltics
That's what I use as a workaround for now. Unfortunately it does not allow for catching parent exception classes. What is the right way to do error handling in a DLL? Error Codes?
Smasher
+2  A: 

If you use runtime packages (at least rtlxx.bpl) for both your application and your dll, then both have the same type and it will work. Of course this limits the use of your dll to Delphi/BCB only.

Another solution is not using exceptions at all like Deltics suggest. Return error codes.

Or use COM. Then you can have exceptions and not limit your dll to Delphi only.

Lars Truijens
Thanks! Unfortunately runtime packages are not an option for us. And COM seems like too much overkill to me. What's wrong with exceptions in this case exactly (apart from the fact that the dynamic type check does not work)?
Smasher
....To that specific version of BCB/Delphi only. (D2006/D2007 excepted maybe)
Marco van de Voort
Why are runtime packages not an option? With SimpleShareMem you are already tied to a specific Delphi/BCB version. And just using rtl70.bpl as a runtime package just gives you 1 extra dll to be distributed.
Lars Truijens
A: 

This workaround seems to do it for me:

 function ExceptionMatch (Exc : Exception; ExcClass : TClass) : Boolean;

 var
    CurrClass           : TClass;

  begin
  CurrClass := Exc.ClassType;
  while (CurrClass <> nil) do
    begin
    if SameText (CurrClass.ClassName, ExcClass.ClassName) then
      Exit (True);
    CurrClass := CurrClass.ClassParent;
    end;
  Result := False;
  end;

I'm prepared for you to destroy this :)

What is wrong with this approach? What is potentially dangerous?

Smasher
Memory management, RTL versioning, classes that don't exist on both sides of the bounary. And that is only the beginning of your nightmare...
Jeroen Pluimers
I'm using `SimpleShareMem`, so memory management is not a problem here. I don't understand your other points.
Smasher
BTW: you downvote this and updvote Deltics (good) answer? I use the same approach as he suggests for the case that I can't influence the DLL itself.
Smasher
+3  A: 

For pure DLL's exceptions are not allowed to cross the DLL boundary (like Deltics mentions).
No matter what language.

You get all sorts of trouble there, especially because you don't know which language, RTL, memory manager, etc, is on each side of the boundary.

So you are back tot the classic error handling paradigm:

In stead of DLL's, you could use use BPL packages (as Lars suggested): there you know that both sides will use the same RTL and memory manager.

Both packages and BPL usually give you a versioning nightmare anyway (too many degrees of freedom).

A more rigorous solution is to go for a monolithic executable; this solves both problems:

  • much easier versioning
  • guaranteed only one RTL and memory manager

--jeroen

PS: I've made this an additional answer because that allows me for easier pasting of links.

Jeroen Pluimers