Root > Advanced topics > Using EurekaLog in DLL > Using exception tracer tool in DLLs > Single instance of exception tracer

Single instance of exception tracer

Previous pageReturn to chapter overviewNext page   

This case require you to enable exception tracer for host application. You should do this in the same way as you do it for typical application without any DLLs. For example, if you have VCL Forms application as the host - then you need to enable EurekaLog for host application and set application type to "VCL Forms Application". This will add EurekaLog code and data into final .exe file. It would also set hook for Forms.TApplication.HandleException method, which will allow to automatically handle exceptions without writing any code.

 

Now, the host has exception tracer. The host must be configured with different settings depending on your API design:

If your API follows the best practice ("never let exception escape DLL") - you don't need to alter any other options;
If your API does not follow the best practice ("never let exception escape DLL") - you have to disable "Capture stack only for exceptions from current module" and chained exceptions support options as explained here.

 

Each DLL must also has EurekaLog enabled and application type must be set to "DLL". Such settings will inject debug information into DLL, but will not include exception tracer code. Rather DLL will ask host application for information. Please note that majority of EurekaLog settings will be ignored for DLL, since there will be no EurekaLog code in your DLL.

 

Note: it's not strictly necessary to enable EurekaLog for DLLs in this example. You can just supply debug information and keep EurekaLog off. For example, DLLs can:

be post-processed by EurekaLog with "DLL" profile;
be post-processed by JCL (without having JclHookExcept active);
be post-processed by madExcept (without exception tracer activation);
supply .map/.tds files (this is only useful for IDEs without any exception tracer tool installed);
supply PDB/DBG files;
Non-Embarcadero DLL can be post-processed by EurekaLog based on output from 3rd party compiler;

 

 

Host application loads multiple DLLs with "DLL" profile

 

Let's see this on practice. Create a new VCL application and place buttons to invoke functions from DLL.

 

...
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    FDLL: HMODULE;
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  FDLL := LoadLibrary('Project2.dll');
  Win32Check(FDLL <> 0);
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeLibrary(FDLL);
  FDLL := 0;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  raise Exception.Create('Error Message');
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  P: procedure;
begin
  P := GetProcAddress(FDLL, 'Test1');
  Win32Check(Assigned(P));
  P;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
var
  P: procedure;
begin
  P := GetProcAddress(FDLL, 'Test2');
  Win32Check(Assigned(P));
  P;
end;
 
...

 

Code is pretty simple: we load DLL on form's creating and unload it when form is gone. There are 3 buttons on the form to invoke different testing routines. First button raises exception in application itself. The 2nd and 3rd buttons raise exceptions in DLL.

 

Don't forget to enable EurekaLog for host and set application type to "VCL Forms Application". That's all.

 

Now, create a new DLL project:

 

library Project2;
 
uses
  // Added automatically
  EAppDLL, // "DLL" profile
 
  // Added manually
  Windows,
  SysUtils,
  Classes;
 
{$R *.res}
 
procedure Test1;
begin
  // This is just example! It's highly not recommended to do this.
  raise Exception.Create('Error Message');
end;
 
procedure Test2;
var
  Msg: String;
begin
  // Recommended way: handle exceptions, do not let them escape DLL
  try
    raise Exception.Create('Error Message');
  except
    on E: Exception do
    begin
      Msg := E.ToString + sLineBreak + E.StackTrace;
      MessageBox(0, PChar(Msg), 'Error', MB_OK or MB_ICONSTOP);
    end;
  end;
end;
 
exports
  Test1, 
  Test2;
 
end.

 

This simple DLL exports 2 functions to test exceptions. First function raises exception and lets it escape DLL, so it will be catched by caller. In our test example caller would be the host application. Such approach is not recommended - as it's already explained above: you should never let exceptions escape DLL. This is done only for example (illustration). It will work correctly for our case, because DLL and exe are both compiled by the same compiler. This will not work properly for generic case. So, it's only suitable for testing.

 

Note: if you want to raise exception in DLL and catch it by the caller - then do not use DLLs. Use packages instead. Using packages will guarantee compatible compiler for host and DLL (package). It's also generally less problematic with all cross-modules communications.

 

Second function illustrate more correct approach: we catch exceptions in function and handle them somehow. For this example we will do very simple handling: just display error message with stack trace. More proper approach was discussed above: you should use some kind of error indication (such as boolean flag, HRESULT, etc.) to indicate failure condition to the caller.

 

Now, enable EurekaLog for this DLL and set application type to "DLL".

 

Note: EAppDLL unit will be added automatically when you set profile to "DLL". This unit contains default callbacks into host to ask for exception's info and handling. You may use your own custom callbacks instead.

 

Compile both host and DLL project, run host application.

 

Hit buttons 1-3.

 

 

Typical exception in host application

Call stack shows only items for exe

 

 

Exception escaped DLL

Call stack shows mixed exe/DLL lines

Notice line numbers for routine in DLL

 

 

Exception did not escape DLL, it was handled by DLL by displaying error message

(screenshot was cut to save space)

Call stack shows mixed exe/DLL lines

Notice line numbers for routine in DLL

 

Please note that last case was a simple example of trivial exception handling in DLL. You may be not satisfied with looks of error dialog. You may want not just "error message", but complete bug report. To do this - you need to replace the call to MessageBox with a call to exception manager. Normally, it would be ExceptionManager.Handle. However, there is no exception manager in our DLL. We'll show how to do this in the "Working with frameworks and exception tracers in DLLs" article or "Creating bug reports for DLL exceptions" article).

 

 

See also:




Send feedback... Build date: 2018-11-26
Last edited: 2018-06-14
PRIVACY STATEMENT
The documentation team uses the feedback submitted to improve the EurekaLog documentation. We do not use your e-mail address for any other purpose. We will remove your e-mail address from our system after the issue you are reporting has been resolved. While we are working to resolve this issue, we may send you an e-mail message to request more information about your feedback. After the issues have been addressed, we may send you an email message to let you know that your feedback has been addressed.


Permanent link to this article: https://www.eurekalog.com/help/eurekalog/dll_single_instance.php