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 project 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"):
oIf you compile DLLs with EurekaLog's "Lightweight DLL" profile - you don't need to alter any other options;
oIf you compile DLLs without EurekaLog at all - 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 project type must be set to "Lightweight 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's 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 "Lightweight DLL" profile; You do not need to change additional options;
be post-processed without EurekaLog; "Capture stack only for exceptions from current module" option must be turned off; Chained exceptions must be turned off;
obe post-processed by JCL (without having JclHookExcept active);
obe post-processed by madExcept (without exception tracer activation);
osupply .map/.tds files (this is only useful for IDEs without any exception tracer tool installed);
osupply PDB/DBG files;
oNon-Embarcadero DLL can be post-processed by EurekaLog based on output from 3rd party compiler;

 

 

Host application loads multiple DLLs with "Lightweight 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 project type to "VCL Forms Application". That's all.

 

Now, create a new DLL project:

 

library Project2;
 
uses
  // Added automatically
  EAppDLL, // "Lightweight DLL" profile
 
  // Added manually

  Windows,
  SysUtils,
  Classes,

  EBase;
 
{$R *.res}
 
procedure Test1;
begin
  // This is just an example! It's highly not recommended to do this.
  raise Exception.Create('Error Message');
end;
 
procedure Test2;
begin
  // Recommended way: handle exceptions, do not let them escape DLL
  try
    raise Exception.Create('Error Message');
  except
    on E: Exception do
      // Ask exception manager in host application to process this exception
      HandleException(E); // EBase unit
  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 as example (illustration). It will work correctly for our case, because DLL and exe are both compiled by exactly the same compiler. This may not work properly for a generic case. See this article for more info.

 

Second function illustrate more correct approach: we catch exceptions in the function and handle exceptions. For this example we will do very simple handling. 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 project type to "Lightweight DLL".

 

Note: EAppDLL unit will be added automatically when you set profile to "Lightweight 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

Call stack shows mixed exe/DLL lines

Notice line numbers for routine in DLL

 

Please note: while results for Test1 and Test2 looks very similar, but it is important to understand that only second example (Test2) is safe. Test1 is not safe, because exception object will cross module boundary.

 

 

See also:




Send feedback... Build date: 2023-09-11
Last edited: 2023-03-07
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