Delphi XE3 Starter Essentials available for download

My Delphi XE3 Starter Essentials ebook (PDF) has just been made available for download for all registered Delphi Starter developers at http://cc.embarcadero.com/item/28214 This is the first of my XE3 ebooks, shortly followed by titles like Delphi XE3 Development Essentials, Delphi XE3 DataSnap Development, Delphi XE3 XML, SOAP & Web Services Development.
Read More

Customizing EurekaLog

EurekaLog 7 offers many ways for customizing behaviour and visual appearance (error dialogs).

Important Note: please see most recent version of this documentation here.

You can use one or more of the following methods (all methods are listed starting with most high-level/easy-to-use to low-level/hard-to-use):

  1. EurekaLog options:
    1. Static options
    2. Dynamic options:
      1. Variables
      2. Filters
  2. Coding:
    1. Changing options at run-time
    2. Custom attributes
    3. Events
    4. Subclassing
    5. Low-level handlers
    6. Modifying code of EurekaLog itself

Important Note: please see most recent version of this documentation here.

EurekaLog options

EurekaLog options is the most simple way to affect on EurekaLog. They were specifically designed for that purpose. Most customizations can be done by using options.

Static options

EurekaLog stores per-project configuration in options file for your project (it’s .dproj/.cbproj for new Delphi/C++ Builder versions). Each time you build your project with EurekaLog – these options are inserted into final .exe file (or DLL). Then EurekaLog’s code can use these options at run-time.

Therefore, you can set options during design-time – and they will be accounted when application is run. In other words, EurekaLog project options works exactly as standard project options dialog.

To view/edit options – you must first open a project in your IDE. Then you should use “Project”/”EurekaLog options” menu command:

Opening EurekaLog options dialog for current project

(You can also invoke this command if you don’t have opened project, but then you’ll edit default options for each new project).

The dialog itself is similar to project options dialog from Delphi/C++ Builder:

EurekaLog project options dialog
(click to enlarge/zoom in)

You can see options categories on the left part (TreeView). Click on any category or sub-category to view and/or change options inside this category.

With this dialog you may change EurekaLog behaviour – to save bug report to disk or not, and where to save it, and what will be inside bug report, and should it be sent to you (as developer), and many other things.

Options are preset to fulfil common needs of developers. As you may guees, not always these “common needs” is what you specifically need in your own project. So we suggest you just to walk through options dialog to get yourself familiar with available options and alter them as you need. Each options has a detailed description in our help system. Yes, F1 works, if you’ve installed local help files during installation of EurekaLog (which is by default). But you may always visit our online help. Moreover, each option has short explanation in the hint. Just hover option’s control with mouse cursor and wait a little:

Popup hint with explanation of the option under the mouse cursor
(click image to enlarge/zoom in)

Conclusion:

  • + easy to use, no coding is necessary
  • options are static (i.e. set at design time)

Dynamic options

There are two additional features to mitigate “static” negative effect of options (see above).

Variables

Environment variables are a set of dynamic named values that can affect the way running processes will behave on a computer. They can be said in some sense to create the operating environment in which a process runs. For example, an environment variable with a standard name can store the location that a particular computer system uses to store temporary files – this may vary from one computer system to another. A process which invokes the environment variable by (standard) name can be sure that it is storing temporary information in a directory that exists and is expected to have sufficient space.

You can use environment variables in any text values in your project settings. You can insert variable by using “Variables” window. Variable is inserted as special tag. When you run your application at run-time, any variable value will be replaced with actual value, which is calculated at run-time.

For example, if you set your folder for saving bug-report to “%APPDATA%\MyBugReports” then your bug reports will be saved to C:\Users\UserName\AppData\Roaming\MyBugReports\ or C:\Documents and Settings\UserName\Application Data\MyBugReports – depending on real value of %APPDATA% variable at run-time.

Note: variables names are case-insensitive.

When you’re in your EurekaLog project options (see above), you can click on “Variables” button at dialog’s bottom:

“Variables” button in EurekaLog project options
(click to enlarge/zoom in)

Click on this button and you will see such window:

“Variables” dialog

“Copy” button will close the window with copying selected variable into clipboard. Alternatively: you can just double-click on variable in the list.
“Close” button will close the window without any action.

Suggested action’s sequence:

  • Open “Variables” window.
  • Select variable that you want to use.
  • Click “Copy” (or double-click variable). Dialog will be closed.
  • Paste variable name from clipboard (Ctrl + V or Shift + Ins) to target setting’s edit box.

Note: this dialog suggests you only build-in special pseudo-variables (those with names started with “_”) and commonly used variables. However, you can use any environment variable (even if it’s not listed in this dialog).
Note: you can also use relative file paths. For example, any path which starts with . (dot) will be relative to your current executable (regardless of actual current folder, which may be changed, say, by system open dialog). For example, “.\BugReport.el” means file in the same folder as your executable.

See more:

So, while variables is an easy way to add some dynamic behaviour to EurekaLog options, their powers are limited. There may be no variable for your specific need or it may be not applicable to desired options (such as checked/unchecked option kind).

Filters

Exception filter is a filter which can alter EurekaLog’s behavior based on some properties of exception. It is a easy way to customize EurekaLog on per-exception basis without writing code.

Usually exceptions are identified by exception’s class name (such as ‘Exception’, ‘EAccessViolation’, ‘EStreamReadError’, etc.). You can also identify exception by source location. And you can identify exception by its type (handled or unhandled). Once exception is identified – you can change handler for it (none, RTL or EurekaLog), dialog class (to any of existing dialog classes), override error message or set action (restart or terminate). Remember, that you can also use environment variables.

Exception filters are applied before processing exception. Filters are applied in order from top to bottom. First matched filter is applied.

Example of 3 exceptions filters added to options

Most typical usage for exceptions filters include:

  • Completely ignore particular exception type. This is useful for such exceptions as EAbort. You may use similar exception types in your code, so now you can use exception filters feature to completely hide such exceptions. Set handler to “none”. No error dialog will be shown. No bug report will be created.
  • Excluding certain exceptions from EurekaLog’s processing. For example, when disk free space is low and you try to create or write a file – an exception about insufficient disk space will be raised. You usually want this exception to be shown as error to the end user (so he/she can free some disk space and retry the operation), rather than generating bug report (and optionally sending it to you). That’s because this exception is not a bug in your code, there is nothing to fix. So you may create filter for such exceptions (they are called “expected” exceptions). Set handler to RTL, and this exception will be handled as usual (by showing error message), but no EurekaLog work will be done for it (no EurekaLog error dialog, no bug reports, etc.).
  • Some exceptions (such as access violation) are low-level. Their message contains some technical information, but it’s completely useless for most users (which are not programmers). Seeing such “cryptic” error messages may be confusing (“gosh, what should I do with it? Is it even a error? Or it asks me something that I don’t understand?”), so it may be useful to hide them. It’s better to show more user-friendly message like “Sorry, there was a error in application. Please, let us know about this problem and restart application.” Such message is far more descriptive. It explains what happenned (an error) and what to do (report to developers and restart application). You may create exception filters for such exceptions, set handler to “EurekaLog” and override a error message. You may additionally enable termination/restart features for these exceptions. Note: message override affects only error message in visual dialogs. Bug reports always contain information about original exception (with original error message).

There may be other use for exception filters (just use your imagination). But the above are the most popular ones.

Note: exceptions filter can also be created from code (see below).

Coding

While the above methods do not require writing code and provide some degree of dynamic changes at run-time, they are still limited and not suitable for custom, not common cases. So, when you have specific need that can’t be satisfied by the above – then you’ll have to write some code.

Changing options at run-time

One of the simplest customizations is changing EurekaLog options from the code. ExceptionLog7 unit declares global function CurrentEurekaLogOptions. This function returns TEurekaModuleOptions class (which is declared in EClasses unit), which contains properties corresponding to EurekaLog’s options. I.e. almost each property (that you can change in EurekaLog project options dialog) is presented as property in TEurekaModuleOptions class. For example, you may write a program which is able to work either as Win32 service or as GUI front end – depending on the way it was launched. You probably want to have differnt bug reports for each of this mode. And Win32 service can’t have visual error dialogs. Obviosly, this can’t be solved by setting options at design-time, since trigger event happens at run-time. So, you setup common options at design time and write such code, which sets the differences:

uses
  ETypes, EClasses, ExceptionLog7;

...

initialization

  if IsWin32Service then
  begin
    CurrentEurekaLogOptions.OutputPath := '%APPDATA%\MySoftware\Win32Service\';
    CurrentEurekaLogOptions.ExceptionDialogType := edtService;
  end
  else
  begin
    CurrentEurekaLogOptions.OutputPath := '%APPDATA%\MySoftware\GUIFrontEnd\';
    CurrentEurekaLogOptions.ExceptionDialogType := edtMSClassic;
  end;

end.

Note: some options (such as build options) affects compilation stage. Thus, they can’t be changed at run-time when file was already compiled.
Note: some options (such as leaks control) requires special rules for setting up. That’s why they are controled with other means, not with options class. However, 90% of options can be freely changed via this class.
Note: needless to say that you may use environment variables and exception filters from code too. You can alter exception filters via CurrentEurekaLogOptions.ExceptionsFilters property.

CurrentEurekaLogOptions is a global function which contains default options for your application in run-time. It affects all exceptions and all threads. Typically, you alter these options at startup (either in initialization section of some unit or in begin/end of .dpr file).

Often there is need to alter option only for some exceptions. EurekaLog provides additional feature for this: events and event hanlders.

Custom attributes

New Delphi and C++ Builder IDEs offer extented RTTI with support of custom attributes. EurekaLog is able to use custom attributes to alter behaviour for exception types. This is similar to exception filters. Using exception filters is simple, but sometimes it’s not very convenient. So, instead you can define EurekaLog behaviour right when you declare exception classes (this code will be ignored if there is no EurekaLog installed).

Custom attributes are declared in EClasses unit. The following attributes are declared:

type
  EurekaLogHandler = class(TCustomAttribute)
  strict private
    FHandler: TFilterHandlerType;
  public
    constructor Create(Value: TFilterHandlerType);
    property Handler: TFilterHandlerType read FHandler;
  end;

  EurekaLogMessage = class(TCustomAttribute)
  strict private
    FMessage: String;
  public
    constructor Create(Value: String);
    property Message: String read FMessage;
  end;

  EurekaLogAction = class(TCustomAttribute)
  strict private
    FAction: TFilterActionType;
  public
    constructor Create(Value: TFilterActionType);
    property Action: TFilterActionType read FAction;
  end;

  EurekaLogDialog = class(TCustomAttribute)
  strict private
    FDialog: TExceptionDialogType;
  public
    constructor Create(Value: TExceptionDialogType);
    property Dialog: TExceptionDialogType read FDialog;
  end;

Here is a sample on how to use them:

type
  // ETestException will be ignored by EurekaLog and it always will be handled by your application
  [EurekaLogHandler(fhtRTL)]
  ETestException = class(Exception);

  // Exception message will be replaced
  [EurekaLogMessage('Sorry, there was an error.')]
  ECustomMessage = class(Exception);

  // Switch dialog to EurekaLog-Detailed style 
  [EurekaLogDialog(edtEurekaLogDetailed)]
  EDialogException = class(Exception);

You get the idea – when you declare exception type, you can add attributes to it. Each attribute will modify EurekaLog behaviour for exceptions of this class only. This works the same as exception filters (actually, internally custom attributes just creates new filter rule).

To learn more about custom attributes – visit RAD Studio help.

Events

EurekaLog’s event is similar to standard Delphi/C++ Builder events, such as OnClick for TButton. Event handler is callback procedure or method, which you regiter for some event. EurekaLog will call your event handler (i.e. your code) each time this event occurs. There are many events available. Most commonly used are OnExceptionNotify and OnExceptionAction.

Note: each event handler is declared as both method or procedure. You can use either option, there is no difference between method and procedure, so you can use whatever you want.

There are two ways of registering your code as event handler. The most simple way is to use TEurekaLogV7 component. This component is similar to standard TApplicationEvents component. Just drop it on the form and assign handlers by using “Events” page in Object Inspector:

TEurekaLogV7 component on the form and one event hanlder assigned

While this is very simple way, you should be awared that your event handlers will be registered as long as host form lives. Thus, your event handler will not be invoked for events during initialization/finalization of your application. For this reason:

  • While there is no limitation on TEurekaLogV7 components in one application and no restrictions on the form (it can be main form and any child/auxilary form), we recommend to use main form as host for TEurekaLogV7 component whenever possible.
  • We recommend using component only for such events that depends on your host form. For example, event hanlder may add currently opened document to bug report. Such event handler is best registered with component. We don’t recommend using component for more generic event handlers. Use code registration (see below).

Note: registering event handler via component will create/use event handler as method of the object (i.e. form), not as callback procedure.

Second method to register event handler is to call RegisterEventName function, where Name is a name of event. For example, you may use such code:

unit Unit1;

interface

...

implmenetation

uses
  EEvents;

// Some your routine to add a message to application log
procedure AddToLog(const AMessage: String);
begin
  ...
end;

// Your handler for OnExceptionNotify event
procedure MyHandler(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean; var ACallNextHandler: Boolean);
begin
  if AExceptionInfo.ExceptionClass = 'EMyException' then
  begin
    AddToLog(AExceptionInfo.CallStack.ToString);
    AHandle := False;
  end;
end;

initialization
  
  RegisterEventExceptionNotify(nil, MyHandler);

end.

This sample event handler will log call stack of each exception of EMyException type, and it will disable EurekaLog’s processing for these exceptions.

As you can see – you need to write all code by yourself (i.e. handler registration and procedure header/prototype). All events are declared in EEvents unit.

Note: you may unregister registered event handler by using UnregisterEventName function, but it’s not required.

That’s almost all for events and event hanlders, but we must discuss one more important thing. Once exception is raised, EurekaLog options are captured from CurrentEurekaLogOptions function. Each exception is accompanied by TEurekaExceptionInfo class, which contains property and options for each exception. Further changes in CurrentEurekaLogOptions will not affect already raised exceptions. Threfore, your changes of CurrentEurekaLogOptions inside any event handler for exceptions will have no effect for current exception. It will affect only future exceptions. To change options of current exceptions – use Options property of TEurekaExceptionInfo class. For example:

unit Unit1;

interface

...

implmenetation

uses
  EEvents;

// Your handler for OnExceptionNotify event
procedure MyHandler(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; var AHandle: Boolean; var ACallNextHandler: Boolean);
begin
  // The same as exception filter for EMyException which changes dialog to "EurekaLog" style
  if AExceptionInfo.ExceptionClass = 'EMyException' then
    AExceptionInfo.Options.ExceptionDialogType := edtEurekaLog;
end;

initialization
  
  RegisterEventExceptionNotify(nil, MyHandler);

end.

The similar concern is applied for many other objects in EurekaLog. Such as dialogs, send engines, log report builders, call stack classes, etc. They all have Options property, which is captured from their “parent” or CurrentEurekaLogOptions if there is no “parent”.

To summarize:

  • Event hanlders offer you unlimited ability for customizing EurekaLog, but only within certain points of interest (i.e. events). You can’t alter whole processing logic by using only event handlers.

Subclassing

When event handlers are not enough, you need to override parts of EurekaLog’s code to fulfil your needs. For example, if you want to alter icon in error dialogs or replace dialog as whole, if you want to change processing (exchange order of saving bug report and sending it), etc. or if you want to extend EurekaLog (like add new dialog or new send method) – then you can’t use event handlers, because there is no event for that. But what you can do is to replace or extend EurekaLog’s code with your own.

High level code of EurekaLog is done as classes. Therefore, if you need to alter minor point in EurekaLog (adjust it a little), then you may create your own class as child class to standard EurekaLog class, override some virtual method, write your own bevahior code, call inherited method to get standard behaviour, and so on. I.e. the usual things that you may do with tree of classes. Or you may write your own class completely from scratch (inheriting from base abstract class).

Note: please note that (unlike events) EurekaLog classes are constantly evolving. There are new methods and features introduced as time passes. Therefore your code that uses subclassing may need to be adjusted for new EurekaLog versions.

For that reason classes are described much less in documentation than other methods. Because they are used much rarely and changes more often. To study what you can do with classes you will have to read interface sections of units with declaration of classes. There you can see class inheritance, interesting methods to override, etc. You can do this even in EurekaLog’s editions without full source code. We provide headers for your reference.

The common rule is: if class can be only one (like log builder class), then class type is registered via global class variable. All you have to do is to write your own class and assign it to variable during initialization. Otherwise, if there may be various classes (like dialogs or send engines), then you have to create your own class, register it in global list via various RegisterSomething functions (they are declared in the same place as base abstract classes), and switch EurekaLog to use your class via options.

Let’s see some code examples to make things clear.

Example #1: replacing dialog icon.
EurekaLog offers you feature to use generic error icon or icon of your application for error dialogs. However, you may want to use some other icon for that. There is no such feature in EurekaLog, but you can easily fix that with such code:

unit Unit1;
 
interface
 
// ...
 
implementation
 
uses
  EBase, ECore, EModules, EListView, EDialog, EDialogWinAPIMSClassic;
 
{$R *.dfm}
 
// To test our customization code
procedure TForm1.Button1Click(Sender: TObject);
begin
  raise Exception.Create('Error Message');
end;
 
type
  // Our child class - inheriting from standard TMSClassicDialog 
  TMSClassicDialogCustom = class(TMSClassicDialog)
  private
    FCustomIcon: HBITMAP; // our new icon
  protected 
    // Init/done:
    procedure WindowInit; override;
    procedure WindowDone; override;
    // Replacing icon drawing:
    function Paint(const ADC: HDC; const ARect: TRect): Integer; override;
  end;
 
{ TMSClassicDialogCustom }
 
procedure TMSClassicDialogCustom.WindowInit;
var
  Ico: HIcon;
begin
  inherited;
 
  Ico := LoadIcon(HInstance, 'CUSTOMICON');
  FCustomIcon := IcoToBmp(Ico, GetStockObject(WHITE_BRUSH), 32, 32);
end;
 
function TMSClassicDialogCustom.Paint(const ADC: HDC; const ARect: TRect): Integer;
begin
  Result := inherited;
  DrawBmp(ADC, FCustomIcon, MonitorLeft, MonitorTop, 32, 32);
end;
 
procedure TMSClassicDialogCustom.WindowDone;
begin
  DeleteObject(FCustomIcon);
  inherited;
end;
 
initialization

  if IsEurekaLogInstalled then
  begin
    // You have to register dialog before using it:
    RegisterDialogClass(TMSClassicDialogCustom);
    // Once registered - now you can use it in options:
    CurrentEurekaLogOptions.ExceptionDialogType := TMSClassicDialogCustom.ClassName;
  end;

end.

Obviosly, this code replaces icon for one particular dialog type (MS Classic style). If you want to alter icon for several classes, then you have to write more your own child classes.

Example #2: replacing content of bug reports.
Recently we got a request from a customer. They use their own system to collect and sort bug reports generated by EurekaLog. Previosly they worked with EurekaLog 6, but then upgraded to EurekaLog 7. Bug reports from EurekaLog 7 has slightly different structure than reports from EurekaLog 6 (new fields and columns). Therefore, new format of bug report file breaks their old code. Of course, they can update/improve their code or… switch EurekaLog to produce bug reports in old format. This can also be useful if you’re migrating to EurekaLog from other exception tracers solutions (such as JCLDebug/JCLHookExcept, madExcept or Exception Magic). You can force EurekaLog to generate bug report in the format of your previous solution, so you won’t have to re-write other code. Obviosly, there is no such build-in feature in EurekaLog.

Here is a simple code that creates bug report in format of EurekaLog 6:

uses
  EConsts, ETypes, EClasses, ECallStack, EException, EEvents, ELogBuilder;
 
type
  // EurekaLog 6 format will be altered from default EurekaLog 7 format,
  // that's why we inherit from EurekaLog 7 builder class and 
  // replace only some methods
  TEurekaLog6Builder = class(TLogBuilder)
  public
    function CreateGeneralText: String; override;
    function CreateCallStackText: String; override;
  end;
 
{ TEurekaLog6Builder }
 
// Replace header of the bug report (to change "7" to "6" in header)
function TEurekaLog6Builder.CreateGeneralText: String;
begin
  Result := inherited;
  Result := 'EurekaLog 6' + Copy(Result, Pos(sLineBreak, Result), MaxInt);
end;
 
// Replace call stack (remove new columns)
function TEurekaLog6Builder.CreateCallStackText: String;
var
  Stack: TEurekaCallStack;
  Formatter: TEurekaBaseStackFormatter;
begin
  Stack := nil;
  try
    if CallStack  nil then
    begin
      Stack := TEurekaCallStack.Create;
 
      Stack.Assign(CallStack);
 
      Stack.Formatter.Assign(Options);
      Stack.Formatter.CaptionHeader := Options.CustomizedExpandedTexts[mtDialog_CallStackHeader] + EHeaderSuffix;
    end;
 
    Formatter := TEurekaStackFormatterV6.Create;
    try
      Formatter.Assign(Options);
      Formatter.CaptionHeader := Options.CustomizedExpandedTexts[mtDialog_CallStackHeader] + EHeaderSuffix;
 
      Result := CallStackToString(Stack, Options.CustomizedExpandedTexts[mtDialog_CallStackHeader] + EHeaderSuffix, Formatter);
    finally
      FreeAndNil(Formatter);
    end;
  finally
    FreeAndNil(Stack);
  end;
end;
 
// Rename .el files to old .elf files
procedure CustomizeFileNames(const ACustom: Pointer; AExceptionInfo: TEurekaExceptionInfo; const AFileType: TEurekaLogFileType; var AFileName: String; var ACallNextHandler: Boolean);
begin
  if AnsiLowerCase(ExtractFileExt(AFileName)) = '.el' then
    AFileName := ChangeFileExt(AFileName, '.elf');
end;
 
initialization

  // Register bug report builder:
  LogBuilderClass := TEurekaLog6Builder;

  // Register event handler for file names:
  RegisterEventCustomFileName(nil, CustomizeFileNames);

end.

This sample uses a combination of custom class and event handler to reach the desired goal.

Example #3: override original class.
Suppose that you want to alter original behaviour/class, but don’t want to create a new class (with new name), because this will require you to alter options as well. Instead, you want just to set up options at design time and provide altered behaviour at run-time.

For example, when you post bug to Mantis, a issue title is composed. EurekaLog does not provide way to alter it, because it’s used to identify tickets. You may want to alter it (say, by appending more info, so title becomes more descriptive). Here is how you can do that:

uses
  EConsts,
  ESend,
  ESendAPIMantis;

type
  // Trick: use the same class name as original class
  // You'll have to append unit name to class ident to avoid compiler confusion
  TELTrackerMantisSender = class(ESendAPIMantis.TELTrackerMantisSender)
  protected
    function ComposeTitle: String; override;
  end;

// This is a default implementation of the method, 
// you can replace it with arbitrary code
function TELTrackerMantisSender.ComposeTitle: String;
begin
  if BugAppVersion  '' then
    Result := Format('%s (Bug %s; v%s)', [BugType, BugID, BugAppVersion])   
  else
    Result := Format('%s (Bug %s)', [BugType, BugID]); 
  Log(Format('Title = ''%s''', [Result]));
end;

initialization

  // Register send class to be the first in the list.
  // Default class (by EurekaLog) will be listed later.
  // Any search for class by name will find our class, because it's listed first
  RegisterSenderFirst(TELTrackerMantisSender); 

end.

With this trick you don’t have to change options. You can just set options at design-time. The important part here is to register your class first, which is archived by using registering function with “First” suffix.

Note: please note that this is not recommended way to work with tickets in Mantis. We suggest you to create custom fields for your project (Mantis configuration). Fill custom fields with information (EurekaLog configuration). And show some of these fields in list of tickets (Mantis configuration). That way you will archive the desired effect (to see more info about each ticket in list), but also additionally gain some benefits: you will be able to sort/filter by custom fields, you will not break default EurekaLog tickets identification.

Example #4: a custom dialog.
You may be not satisfied by standard EurekaLog dialogs, so you may want to use your own dialog. Here is what you need to do: create class inheriting from abstract TBaseDialog class (EDialog unit), register it, and set ExceptionDialogType option. This example is similar to example #1. But this time we create dialog from scratch, we’re not using ready classes.

The following sample shows four new dialog classes. Actually, this is just a code from EurekaLog itself, but it’s short and simple to illustrate the point:

uses
  EDialog, EClasses, ETypes;

type
  // "Empty" dialog that does nothing at all
  TNullDialog = class(TBaseDialog)
  protected
    procedure Beep; override;
    function ShowModalInternal: TResponse; override;
  public
    class function ThreadSafe: Boolean; override;
  end;

  // MessageBox dialog
  TMessageBoxDialog = class(TBaseDialog)
  protected
    function ShowModalInternal: TResponse; override;
    procedure Beep; override;
  public
    class function ThreadSafe: Boolean; override;
  end;

  // A variant of MessageBox with more detailed message (with call stack)
  TMessageBoxDetailedDialog = class(TMessageBoxDialog)
  protected
    function ExceptionMessage: String; override;
  end;

  // "Default" dialog - dialog that invokes standard dialog (non-EurekaLog)
  TRTLHandlerDialog = class(TBaseDialog)
  protected
    procedure Beep; override;
    function GetCallRTLExceptionEvent: Boolean; override;
    function ShowModalInternal: TResponse; override;
  end;

{ TNullDialog }

procedure TNullDialog.Beep;
begin
  // does nothing - no beep needed
end;

// Main method: do nothing, return success
function TNullDialog.ShowModalInternal: TResponse;
begin
  SetReproduceText(ReproduceText);

  Result.SendResult := srSent;
  Result.ErrorCode := ERROR_SUCCESS;
  Result.ErrorMessage := '';
end;

// Indicate that we can be called from any thread (this should be False for VCL/CLX/FMX dialogs)
class function TNullDialog.ThreadSafe: Boolean;
begin
  Result := True;
end;

{ TMessageBoxDialog }

procedure TMessageBoxDialog.Beep;
begin
  // does nothing - beep is invoked by Windows.MessageBox in TMessageBoxDialog.ShowModalInternal
end;

// Main method 
function TMessageBoxDialog.ShowModalInternal: TResponse;
var
  Flags: Cardinal;
  Msg: String;
begin
  // Set default result
  Result.ErrorCode := ERROR_SUCCESS;
  Result.ErrorMessage := '';
  if SendErrorReportChecked then
    Result.SendResult := srSent
  else
    Result.SendResult := srCancelled;

  // Prepare message to show
  Msg := ExceptionMessage;
  if ShowSendErrorControl then
  begin
    Msg := Format(Options.CustomizedExpandedTexts[mtSend_AskSend], [Msg]);
    Flags := MB_YESNO;
  end
  else
    Flags := MB_OK;
  Flags := Flags or MB_ICONERROR or MB_TASKMODAL;
  if SendErrorReportChecked or (not ShowSendErrorControl) then
    Flags := Flags or MB_DEFBUTTON1
  else
    Flags := Flags or MB_DEFBUTTON2;

  // Call actual MessageBox and set result
  case MessageBox(Msg,
                  Options.CustomizedExpandedTexts[mtDialog_Caption],
                  Flags) of
    0: Result.ErrorCode := GetLastError;
    IDYes:
       Result.SendResult := srSent;
    IDNo:
       Result.SendResult := srCancelled;
  end;

  // Save error code/error message for failures
  if Result.ErrorCode  ERROR_SUCCESS then
  begin
    Result.SendResult := srUnknownError;
    Result.ErrorMessage := SysErrorMessage(Result.ErrorCode);
  end
  else
    SetReproduceText(ReproduceText);
end;

// Can be called from any thread
class function TMessageBoxDialog.ThreadSafe: Boolean;
begin
  Result := True;
end;

{ TRTLHandlerDialog }

// Indicate desire to invoke RTL handler
function TRTLHandlerDialog.GetCallRTLExceptionEvent: Boolean;
begin
  Result := True;
end;

function TRTLHandlerDialog.ShowModalInternal: TResponse;
begin
  SetReproduceText(ReproduceText);

  Result.SendResult := srRestart;  // means "call RTL handler"
  Result.ErrorCode := ERROR_SUCCESS;
  Result.ErrorMessage := '';
end;

procedure TRTLHandlerDialog.Beep;
begin
  // Does nothing - transfer work to RTL handler
end;

{ TMessageBoxDetailedDialog }

// This one is a bit more complex - we want to add call stack to error message.
// However, default form is not very readable with variable-width fonts.
// That's why first we need a way to format call stack in another way.

type
  // Our new formatter
  TMessageBoxDetailedFormatter = class(TEurekaBaseStackFormatter)
  protected
    function GetItemText(const AIndex: Integer): String; override;
    function GetStrings: TStrings; override;
  end;

// Forms one line of call stack
function TMessageBoxDetailedFormatter.GetItemText(const AIndex: Integer): String;
var
  Cache: TEurekaDebugInfo;
  Info: PEurekaDebugInfo;
  ModuleName, UnitName, RoutineName, LineInfo: String;
begin
  Info := CallStack.GetItem(AIndex, Cache);

  ModuleName := ExtractFileName(Info^.Location.ModuleName);
  UnitName := Info^.Location.UnitName;

  if UnitName = ChangeFileExt(ModuleName, '') then
    UnitName := ''
  else
    UnitName := '.' + UnitName;

  RoutineName := CallStack.ComposeName(Info^.Location.ClassName, Info^.Location.ProcedureName);
  if RoutineName  '' then
    RoutineName := '.' + RoutineName;

  if Info^.Location.LineNumber > 0 then
    LineInfo := Format(',%d[%d]', [Info^.Location.LineNumber, Info^.Location.ProcOffsetLine]) // Do Not Localize
  else
    LineInfo := '';

  Result := ModuleName + UnitName + RoutineName + LineInfo;
end;

// Formats entire call stack
function TMessageBoxDetailedFormatter.GetStrings: TStrings;
var
  ThreadID: Cardinal;
  I: Integer;
  Line: String;
  Stack: TEurekaBaseStackList;
begin
  if not Assigned(FStr) then
  begin
    FStr := TStringList.Create;
    FModified := True;
  end;
  if FModified then
  begin
    Stack := CallStack;
    CalculateLengths;
    FStr.BeginUpdate;
    try
      FStr.Clear;
      FStr.Capacity := Stack.Count;

      if Stack.Count > 0 then
      begin
        ThreadID := Stack.Items[0].ThreadID;
        for I := 0 to Stack.Count - 1 do
        begin
          if (Stack.Items[I].Location.Module  0) and
             (Stack.Items[I].Location.DebugDetail in [ddUnit..ddSourceCode]) and
             (Stack.Items[I].ThreadID = ThreadID) then
          begin
            Line := GetItemText(I);
            if (FStr.Count  Line) then
              FStr.Add(Line);
          end;
        end;
      end;
    finally
      FStr.EndUpdate;
    end;
    FModified := False;
  end;
  Result := FStr;
end;

// Append call stack to error message
function TMessageBoxDetailedDialog.ExceptionMessage: String;
const
  MaxLines = 15;
var
  Formatter: TMessageBoxDetailedFormatter;
  Stack: TEurekaBaseStackList;
begin
  {$WARNINGS OFF}
  // Abstract methods are intended here. It is like assert: they should not be called.
  Formatter := TMessageBoxDetailedFormatter.Create;
  {$WARNINGS ON}
  try

    if Assigned(CallStack) then
      Formatter.Assign(CallStack.Formatter);
    Formatter.CaptionHeader := '';

    Stack := nil;
    try
      if CallStack  nil then
      begin
        Stack := TEurekaStackList.Create;
        Stack.Assign(CallStack);
        while Stack.Count > MaxLines do
          Stack.Delete(Stack.Count - 1);
      end;
      Result := inherited ExceptionMessage + sLineBreak + sLineBreak +
                CallStackToString(Stack, '', Formatter);
    finally
      FreeAndNil(Stack);
    end;
  finally
    FreeAndNil(Formatter);
  end;
end;

As you can see, the central method here is ShowModalInternal. It does all the work. It’s abstract and must be overwritten in child classes. All other methods of TBaseDialog are virtual, but not abstract. They contain default behaviour. You can override them to alter behaviour, but you don’t have to. Base dialog class contains large number of helpers (methods and properties). All that dialog needs to do is to invoke these methods in right order. Therefore any child class can use powerful tools to quickly build new dialog.

Note: there is another abtract dialog class – TWinAPIDialog from EDialogWinAPI unit. It’s useful if you want to create new dialog based on direct WinAPI calls, rather than using ready functions or frameworks (VCL/CLX/FMX).

Important note: dialog class is responsible for almost whole exception processing. That’s because “dialog” don’t have to be visual. Think about Win32 service, system log, WER (Windows Error Reporting), etc. So, this is not always possible to distinguish between “error dialog” and “exception processing”. That’s why these concepts are both controlled by single “dialog” class. As we saw above, a major method for visual dialog is ShowModalInternal method. But real entry point is Execute method. Default implementation goes like this:

function TBaseDialog.Execute: TResponse;
var
  CanSaveReport: Boolean;
begin
  try
    SaveCurrentEnvironment;
    try
      // Preparation
      SetupFileNames;
      FDuplicate := CalcDuplicatedException(FCanSend);

      // Saving bug report
      if not Restarted then
      begin
        SetReproduceText('');
        if DeleteLogAtVersionChange then
          DeleteOldLog;
        MakeScreenshot;
        AddCustomData;
        if PresaveReport and SaveLogFile then
          SaveBugReport; // Pre-save to get log in case of crash in dialog
        Beep;
      end
      else
        FSaved := (PresaveReport and SaveLogFile);

      // Actually visible part:
      Result := ShowModal; // invokes ShowModalInternal with events and error handling

      // Restart dialog? 
      // E.g. User clicked on "see more" link, 
      // so we need to change MSClassic -> EurekaLogDetailed
      if Result.SendResult = srRestart then
        Exit;

      // Save bug report
      CanSaveReport := SaveLogFile and
                       (
                         Succeeded(Ord(Result.SendResult)) or
                         (Result.SendResult = srCancelled) or
                         (not PresaveReport)
                       );
      if CanSaveReport then
        SaveBugReport; // Re-save to update changed fields (like reproduce text)

      if Succeeded(Ord(Result.SendResult)) and CanSend then
      begin
        PrepareFilesForSend;

        Result := SendBugReport;

        if Failed(Ord(Result.SendResult)) then
        begin
          if CopyLogInCaseOfError then
            CopyReportToClipboard;
          if SaveCompressedCopyInCaseOfError then
            SavePackedCopy;
        end
        else
        if DeleteLogAfterSuccessfulSend then
          DeleteCurrentLog;

        ShowSendResult(Result);
        if CanSaveReport then
          UpdateSendInformationInLog(Result.SendResult);
      end
      else
      begin
        DoEventExceptionAction(ExceptionInfo, atSendCancelled);
        if CanSaveReport then
          UpdateSendInformationInLog(srCancelled);
      end;

    finally
      RestoreCurrentEnvironment;
    end;

    CheckTermination;
    if Options.CustomFieldBool[difTerminateApplication] then
      TerminateApplication;
  except
    on E: Exception do
    begin
      Result.ErrorCode := ERROR_GEN_FAILURE;
      Result.ErrorMessage := E.Message;
      Result.SendResult := srUnknownError;
    end;
  end;
end;

As you can see, there is the whole processing of exceptions: saving bug report, displaying dialog, updating bug report with new values (e-mail/steps to reproduce), sending report, restarting application. You rarely need to alter this method, rather you will override methods which are called by it. This method is shown here just to illustrate the point that dialog controls more than just visual behaviour.

As final words on subclassing – here is the list of classes, units and functions for this (as of EurekaLog 7.0.02):

  • Base dialog class: EDialog.TBaseDialog.
  • Dialog class registration: EDialog.RegisterDialogClass.
  • Base send engine class: ESend.TELUniversalSender.
  • Send engine class registration: ESend.RegisterSender.
  • Base debug information provider class: EClasses.TELDebugInfoSource.
  • Debug information provider registration: EDebugInfo.RegisterDebugInfoSource.
  • Base call stack class: ECallStack.TEurekaBaseStackList.
  • Default call stack class: ECallStack.EurekaCallStackClass.
  • Specific call stack classes: ECallStack.TracerMethodsClasses.
  • Base log builder class: ELogBuilder.TBaseLogBuilder.
  • Default log builder class: ELogBuilder.LogBuilderClass.
  • Base hung detection thread class: EFreeze.TFreezeThread.
  • Default hung detection thread class: EFreeze.FreezeThreadClass.

Low-level handlers

Classes are used by high level code in EurekaLog. Sometimes customizations of high level code is not enough. Luckily, EurekaLog 7 offers you a way to change almost anything. Low level points for customizations are presented by global variables of procedural types. These procedural variables are invoked by EurekaLog, and it points to EurekaLog code by default. You may write your own code and write pointer to it into these variables.

Note: these global variables are not documented and never will be. You can use them on your own risk.

Here is the list of available low-level customization possibilities:

  • EInject unit:
    • EventUnhandledExceptionFilter
    • EventExceptProc
    • EventExceptClsProc
    • EventExceptObjProc
    • EventRaiseExceptionProc
    • EventGetExceptionStackInfoProc
    • EventGetStackInfoStringProc
    • EventCleanUpStackInfoProc
    • EventExceptionDispatcher
    • EventIndyThreadHandleException
  • EExceptionHook unit:
    • _IsUnexpected
  • ELowLevel unit:
    • _InitDoneErrorHandler
    • _SafeExecLog
    • _ConsoleLogger
  • EHook._GetSymbolAddr
  • EBase unit:
    • _InternalError
    • _RaiseExpected
    • _OnPanic
  • EAppType unit:
    • _CustomMessageBox
    • _GetMainWnd
  • Almost all routines in EMemLeaks and EResLeaks units.
  • EThreadsManager unit:
    • _GetRealAddresses

There are some other points to override default handlers, but they are almost useles for customizations, since they are used for very specific EurekaLog’s needs.

The most important thing about low level handlers is that the initialization order is important. It’s highly not recomended to alter these variables during actual work of your application. You should modify handlers only during initialization/finalization process. It’s also strictly recommended to save previous handler before installing your own handler and revert it back (uninstall) on finalization.

Modifying code of EurekaLog itself

When nothing else helps – you can alter source code of EurekaLog. Of course, it’s possible only if you have edition with full source code (all other methods of customizations listed above are applicable for any edition of EurekaLog).

You can alter EurekaLog code to absolutely every behavior that you want. Then you need to recompile it for these changes to take effect. See also: how to recompile EurekaLog.

Please note that any upgrading or reinstalling EurekaLog will overwrite EurekaLog files, thus your customizations will be lost (unless you made a backup). You’ll have to re-implement all customizations each time you upgrade EurekaLog. For this reason use this method as last resort measure only. Prefer the above discussed methods whenever possible. If you still has to modify EurekaLog sources – please, let us know why you do that. We can add your customizations in EurekaLog, so you won’t need to re-insert them into source code each time you upgrade (of course, this is only possible if your customizations has some value for other developers).

Read More

Read More

DataSnap in the Cloud

Last weekend I spoke at the Delphi Tage in Heidelberg about DataSnap In The Cloud and I promised to provide the referenced data for download. So here it is: DataSnap in the Cloud (PDF) The slides from the presentation. I omitted those slides serving transition effects only. FishFacts (Project) The modified FishFacts project. The console application project is called FishFactsServer.  It contains the changes to make it work with SQL Database in Azure as well as the patched Data.DBXMSSQLMetaDataReader.pas (XE2) to make it work with SQL (Azure) Database. Azure Cloud Service The Azure Cloud Services Project. You have to copy the FishFactsServer.exe into the WorkerRole folder after compilation and before making the package. DbDemos SQL Script SQL Script for DbDemos Database. Executing this script in SQL Managment Studio will create and populate the complete dbdemos database in a format suitable for SQL (Azure) Database.  
Read More

Devexpress will never support Firemonkey

After asking to staff at devexpress, they say will not support firemonkey while the API suffer of changes from Embarcadero.That are really bad news to developer express customers and in particular to Delphi users. Sadly, we will not see in years a DX crossplatafform version at all. Not strange, after all even the .NET version of devexpress don't work over linux or mac. I bet for the same lack of e**s to take risk and support users.I will have it in mind next time i click renew on my dx subscriptions, you see...
Read More

Making Sense of the Whole Delphi WinRT Thing

I'm not one of the "Low-Level" "Deep-Inside" Delphi smart guys. I'm just an average software developer who uses Delphi to create simple applications I sell to other average people. Oh, I learn a lot hanging around the smart guys but I seem to get lost when the discussions and comments take a deep dive. It's no doubt that Allen Bauer's post created quite a stir around the community and the new release of XE3. I've tried to make sense of all the buzz going back and forth but at one point it just got way over my head. Since I am just a Micro-ISV, I am looking for a simplistic answer to what this whole Delphi - WinRT crap is all about and I think I have figured it out. I posted this on the Delphi Developer group on Facebook: I've been trying to follow all the talk about what is going on with Delphi and WinRT ever since Allen Bauer's post went viral. I'm not as smart as most of you Delphi guys. Can someone please explain in very simplistic terms what it means when Delphi either can't or is excluded from creating WinRT apps? How does this effect a Micro-ISV like myself in terms of distribution and sales? I received this response... For example, you will probably not be able to sell your app through the MS Application Store, which could really hurt your exposure to prospective new customers. Okay. So I started googling Microsoft App Store and discovered a couple interesting tidbits. I started off reading a post by George Ou called ARM Battery Life Advantage Myth Lives On This lead me to a post by Steven Sinofsky called Collaborating to deliver Windows RT PCs Which lead me to another post by Steven Sinofsky called Building Windows for the ARM processor architecture Here is what I think is going on and how it effects me and you who sell software to the average consumer. Microsoft is leading a push to compete directly with the iPad. So, Microsoft invented a new operating system called WOA or Windows on ARM which in my opinion is a Reduced Instruction Set Computer. This new operating system is a subset of Windows 8 and will be available on the new WinRT PC's soon to be released. It sounds like WinRT PC's (I'd prefer they were called tablets) are a separate line of personal computers designed to compete directly with the iPad market. No disk drive, no expansion slots, one or two USB ports and completely mobile. Which requires a long life battery, hence the first post I sited above. These devices will be RISC (Reduced Instruction Set Computers) running the WOA which includes WinRT. This limits the applications to only those applications that conform to the WinRT subset of instructions. All other Non-WinRT PC's will come with a full blown Windows 8 OS in addition to the scaled down WOA running WinRT. This lets you run all the currently developed Windows Applications (those created using Delphi) and any of the new applications that conform to the WinRT subset of instructions. What does all this mean to you and I... Given that the WinRT PC's (I'd prefer they were called tablets) have a subset of the real Windows 8 OS, the only way to install software on these machines will be through the use of the Microsoft App Store. Since Microsoft controls this store they will make sure that any app in the store will run without problems on the new WinRT machines. The bottom line, we (Delphi developers) will still have a huge user base availabe to us. Not everyone will flock to these new WinRT PC's (I'd prefer they were called tablets). When EMBT finally does get the details worked out and makes it available to us... we can retool, recompile and look forward to a windfall of new WinRT customers. Enjoy - Semper FiGunny Mike
Read More

Native controls for FireMonkey – the KickStarter project needs your help

FireMonkey does not mimic native controls perfectly, especially on OSX.  This is simply because all its controls are implemented fully in FireMonkey, and so all behaviour has to be coded - and it is very unlikely to ever get an implementation that is indistinguishable from the platform-native controls.  Platform-native is important. But, what if there was a library of native FireMonkey
Read More

Embarcadero – Clang and LLVM

Recently Tim Anderson reported that Embarcadero was going to be using the Clang Compiler in the Rad Studio.   When word broke about Embarcadero using LLVM with Delphi I was quite pleased.   I had been playing around with LLVM learning its IR for quite some time and it is a great tool for most any development language.    However, knowing that they have based there C++ work on the the Clang Compiler is very pleasing to me.    Clang is a very nice C/C++/Objective-C Compiler.Benefits of the Clang Compiler  Complete support for C++98 and nearly complete support for C++11 StandardsGood platform for building Source Level Tools The Default Compiler in XCode on Mac OS XCan compile FreeBSD and is the Default CompilerCan compile the Boost C++ LibrariesIt can be easily embedded into any application as it designed to be a libraryThe API is built with tooling and IDE integration in mind.Good Error MessagesBetter performance that GCCUse of the LLVM Core libraries (The Compiler back-end) Some of the Benefits of LLVM (I really don't do it justice with my small list)Target-Independent Code Generator with production level support for the following processors.  (Although not all features are supported on each processor)X86ARMSparcPowerPCHexagonMipsJIT Support with an optional command line tool  (lli) to run LLVM bitcodeOptimizer has many Optimizations with a plug-able infrastructure to add additional optimization'sOptional Support for implementing Garbage CollectionGood set of ToolsIt well documented.All of this makes me wonder how much of other things from LLVM that they may end up using all or part of  as  LLDB, KLEE, or VMKitNow which features of clang and llvm will be exposed in the Embarcadero tool chain is not know yet.   But it's nice to know that there is a good foundation they are building on.    I guess it might be time to sign up for Priority Preview Access to see this in action.
Read More

Different EurekaLog settings for ‘Debug’ and ‘Release’ profiles

This article is supposed to answer on one common question asked by our customers. They want to use different EurekaLog settings for different compilation profiles. Sometimes even no use EurekaLog at all for some specific profile. This article will explain how to do this. Important Note: please see most recent version of this documentation here. Well, first - unfortunately, there is no IDE solution for certain technical reasons. But this doesn't mean that you can't do this. You can't use automatic solution, but you can perfectly set all options manually. For the purposes of this article I will use EurekaLog 7.0.1 and Delphi XE. The discussed features may be unavailable in older versions. Step 1: get working solution for single profile First, I created a new VCL application and place a button to raise exception. Then I go to Project/EurekaLog options, enabled EurekaLog and specified type of my application (VCL Forms). You can also set other options as you desire. Now run the application and confirm it's working as expected. Step 2: reconfigure project for manual control For the next step you should go to Project/EurekaLog options and use "Export" button to create .eof file. Place it in the same folder as your project (by default "Profiles" folder is suggested). Name it as your project + name of your configuration. For example: Project1_Debug.eof. Now, don't close options dialog, but go to Advanced/Custom/Manual and add "DoNotTouch=1" line (without quotes) in any place (as new line). This will disable any assist for your project from IDE expert. Close settings and save your project. You can confirm if option is taking effect by disabling EurekaLog, saving your project and observing that there are no changes in your .dpr file - all units are still included even if no EurekaLog is enabled. Now, it's time to restore post-processing for your application. Go to Project/Options (not EurekaLog options) and look for build events options. Add the following command as post-build event which is invoked on successful compilation: IF EXIST "$(BDS)\Bin\ecc32.exe" "$(BDS)\Bin\ecc32.exe" --el_alter_exe"$(PROJECTPATH);$(OUTPUTPATH)" --el_config"Project1_$(Config).eof" Replace "Project1" with your real project name or change the whole argument to match your .eof file. The $(Config) is a variable, which will be substituted with the name of build configuration - such as "Debug" or "Release" or any other custom configuration name. So, the resulting command-line may look like this when run: IF EXIST "C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\Bin\ecc32.exe" "C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\Bin\ecc32.exe" --el_alter_exe"C:\Projects\Project1.dproj;C:\Projects\Debug\Win32\Project1.exe" --el_config"Project1_Debug.eof" Note that this is an example of final command as it will be executed by IDE. You should NOT use this form of command (with already expanded variables) - please use the first example with $(Config) variable. Note: you can also find the $(Platform) variable useful. It will be replaced with short name of the platform - such as Win32, Win64, OSX. So you can have file like Project1_Win32_Debug.eof and use --el_config"Project1_$(Platform)_$(Config).eof switch. Now compile your project and run it. If you done everything correctly - the result must be the same as on step 1 - the correct EurekaLog-enabled application with expected behavior as set in external .eof file (even though the EurekaLog was disabled in project). In case of any build errors - take a look at compiler output as shown in "Messages" window. It's docked at the bottom of IDE window by default. "Output" tab is near "Build" tab, which is active by default. If you don't see "Messages" window - use View/Messages command to show it, then switch to output window. The correct compilation will get you such messages: Build started 2012.06.29 16:58:04. __________________________________________________ Project "C:\Projects\Project1.dproj" (Build target(s)): Target _PasCoreCompile: C:\program files (x86)\embarcadero\rad studio\8.0\bin\dcc32.exe //-- options cut to save space --// Project1.dpr Target PostBuildEvent: IF EXIST "C:\program files (x86)\embarcadero\rad studio\8.0\Bin\ecc32.exe" "C:\program files (x86)\embarcadero\rad studio\8.0\Bin\ecc32.exe" --el_alter_exe"C:\Projects\Project1.dproj;.\Debug\Win32\Project1.exe" --el_config"Project1_Debug.eof" EurekaLog Command-Line Compiler v7.0.1.0 for Delphi 15.0 ---------------------------------------------------------------- Loading EurekaLog options... EurekaLog postprocessor start... EurekaLog's code was added EurekaLog's options were added EurekaLog's data was added File size before: 2'159'616 File size after: 2'185'216 File size diff: +25'600 Debug info size: 287'554 Symbols size: 58 Functions size: 4 Stripped size: -138'240 Number of units: 209 Number of procedures: 10'136 Number of lines: 28'124 Total time: 00:00:00.639 Compilation time: 00:00:00.026 Prepare time: 00:00:00.015 Post-process time: 00:00:00.597 Events time: 00:00:00.001 Memory usage: Allocated: 7'576'806 RAM: 29'999'104 Private: 27'066'368 Virtual: 105'299'968 EurekaLog postprocessor end Build succeeded. 0 Warning(s) 0 Error(s) Time Elapsed 00:00:01.91 Step 3: configuring alternative profiles Now it's time to set up configuration of alternative profiles (finally). The first thing you need to do - is to decide if you want EurekaLog for this configuration or not. The difference is that you need different project options set for different cases. As well as different unit set. Let's do this one step at time. First, conditional directives. They are not used by EurekaLog, but it will come in handy for your own purposes. So, go to Project/Options and look to Delphi Compiler/Conditional Defines option. Now, if you want EurekaLog for this profile - add "EL" conditional define. If you don't want EurekaLog for this profile - remove EL conditional define. The name of symbol is any text. You can use other name instead of EL. Repeat this step for each profile of your project that you're going to use. Note: currently 7.0.1 removes conditional define with name of "EUREKALOG". I think this should be fixed in the next minor update. Second, the options of the project. EurekaLog requires certain options to be set in order to work. Also, some option may increase or decrease detalization of EurekaLog. So, if you want to use EurekaLog in certain profile - then you have to setup all required options manually. Please, read this article to know what options must be set. For other profiles (in which EurekaLog will not be used) you can set options as you desire, there are no limitations. Third, the included units. Use Project/View source command to open your .dpr file in code editor. You should see EurekaLog units included. If you don't want EurekaLog for certain configurations - then you (probably) don't need to include EurekaLog code. So, you can make this like this: program Project1; uses {$IFDEF EL} EMemLeaks, EResLeaks, EDialogWinAPIMSClassic, EDialogWinAPIEurekaLogDetailed, EDialogWinAPIStepsToReproduce, EDebugExports, EDebugJCL, EAppVCL, ExceptionLog7, {$ENDIF} Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TForm1, Form1); Application.Run; end. Please note that exact included units depends on your selected options. For example, if you set error dialog to "None" - then EDialogXYZ units may be removed. So if you change original options - you may have to include/remove units manually. If you are not very well familiar with EurekaLog 7 - I recommend to create a new application for testing. Setup EurekaLog options and see which unit will be included. Note: you can skip steps 1 and 3 if you want EurekaLog to be enabled for each profile (just with different settings). Note: you can also use EBase unit to test whenever EurekaLog was enabled for your application or not. This unit is specially designed to be included in any application without including EurekaLog's code. Fourth, you have to create .eof file for each configuration profile and save it with corresponding name (such as Project1_Release.eof in our example, but you may use any other naming scheme). Be aware that you also need to create .eof file for profiles with disabled EurekaLog! You need to disable EurekaLog in such .eof files. You can use IDE options dialog: use Import/Export buttons to open/save settings. Or you can use standalone settings editor tool (you can add it to Tools menu for quick access). Note: the result of using IDE expert and settings editor tool is a bit different. IDE expert only saves settings which are different from defaults. Settings editor saves all options. At last - make sure that post-build event that we set in options at previous step is applied for all profiles (you can do this by entering command to Base profile and checking that it wasn't overwritten by another profiles). Now, do a test - switch to different configuration profiles, make a build, run application and test it. Note: it's recommended to make a full rebuild when changing profiles or target platform. Conclusion This article explained the basics of manual control over configuration of your project. I really hope that it's not that hard and that it answers many questions. As a side note - I want to discuss relation between settings and configuration profile names. In classic application: the debug profile has maximum debug options set, and the release profile has minimum debug options set. For applications with exceptions tracers it's different. Exception tracer requires more info than you usually use for debugging sessions (think about "Use Debug DCUs" option). So typically it's reversed now: you want maximum options for release version of your application and medium (moderate) options for debugging. Therefore, you can either swap profiles (i.e. use "debug" profile for the release version of your application) or to completely re-setup options between profiles.
Read More

EurekaLog 7.0.0 is out

We are pleased to announce the availability of the EurekaLog 7.0.0 stable release

Key EurekaLog 7 features:

  • Win64 support
  • FireMonkey support
  • WER (Windows Error Reporting) support
  • WCT (Wait Chain Traversal) support
  • Resource leaks support
  • Memory leaks and catch handled exceptions for C++ Builder
  • Improved stack tracing
  • Proper Unicode support
  • Improved compatibility with packers and protectors
  • Extensive documentation
  • Easy customization
  • Web-API support for FogBugz, Mantis, BugZilla
  • Improved SSL/TLS
  • Implemented A LOT of your suggestions
  • Full backward compatibility with EurekaLog 6
See full features list here (Help / Introduction / Features). 
Full changelog for EurekaLog 7:
·Improved: Main change – EurekaLog’s core was rewritten (refactored) to allow more easy modification and remove hacks.
·Improved: New plugin-like architecture now allows you to exclude unused code.
·Improved: New plugin-like architecture now allows you to easily extends EurekaLog.
·Improved: Greatly extended documentation.
·Improved: Installer is now localized.
·Improved: Greatly speed ups creation of minimal bug report (with most information disabled).
·Changed: EurekaLog’s root IDE menu was relocated to under Tools and extended with new items.
·Added: New examples.
·Added: New tools (address lookup, error lookup, threads snapshot, standalone settings editor).
·Added: Support for DBG/PDB formats of debug information (including symbol server support and auto-downloading).
·Added: Support for madExcept debug information (experimental).
·Added: WER (Windows Error Reporting) support.
·Added: Full unicode support.
·Added: Professional and Trial editions: added source code (interface sections only)
·Improved: Dialogs – new options and new customization possibilities:
·Added: All GUI dialogs: ability to test dialog directly from configuration dialog by displaying a sample window with currently specified settings.
·Improved: All GUI dialogs: dialogs are DPI-awared now (auto-scale for different DPI).
·Added: MessageBox dialog: added detailed mode (shows a compact call stack).
·Added: MessageBox dialog: added ability for asking a send consent.
·Added: MessageBox dialog: added support to switch to “native” message box for application.
·Added: MS Classic dialog: added control over “user e-mail” edit’s visibility.
·Added: MS Classic dialog: added ability to personalize dialog view with application’s name and icon.
·Added: MS Classic dialog: added ability to show terminate/restart checkbox initially checked.
·Added: EurekaLog dialog: added ability to personalize dialog view with application’s name and icon.
·Added: EurekaLog dialog: added ability to show terminate/restart checkbox initially checked.
·Added: EurekaLog dialog: added ability to switch back to non-detailed view.
·Added: WEB dialog: added new tags to customize bug report page.
·Improved: WEB dialog: improved support for unicode and charset.
·Added: New dialog type: RTL dialog.
·Added: New dialog type: console output.
·Added: New dialog type: system logging.
·Added: New dialog type: Windows Error Reporting.
·Improved: Sending – new options and new customization possibilities:
·Added: All send methods: added ability to setup multiply send methods.
·Added: All send methods: added ability to change send method order.
·Added: All send methods: added separate settings for each send method.
·Added: All send methods: ability to test send method directly from configuration dialog by sending a demo bug report.
·Added: SMTP client send method: added SSL support.
·Added: SMTP client send method: added TLS support.
·Added: SMTP client send method: added option for using real e-mail address.
·Added: SMTP server send method: added option for using real e-mail address.
·Added: HTTP upload send method: added support for custom backward feedback messages.
·Added: FTP upload send method: added creating folders on FTP (like remote ForceDirectories).
·Added: Mantis send method: added API support (MantisConnect, out-of-the-box since Mantis 1.1.0, available as add-on for previous versions).
·Added: Mantis send method: added support for custom “Count” field.
·Added: Mantis send method: added options for controlling duplicates.
·Added: Mantis send method: added support for SSL/TLS.
·Added: FogBugz send method: added API support (out-of-the-box since ForBugz 7, available as add-on for FogBugz 6).
·Added: FogBugz send method: EurekaLog will update “Occurrences” field (count of bugs).
·Added: FogBugz send method: EurekaLog will respect “Stop reporting” option (BugzScout’s setting).
·Added: FogBugz send method: EurekaLog will respect “Scout message” option (BugzScout’s setting).
·Added: FogBugz send method: EurekaLog will store client’s e-mail as issue’s correspondent.
·Added: FogBugz send method: added options for controlling duplicates.
·Added: FogBugz send method: added support for “Area” field.
·Added: FogBugz send method: added support for SSL/TLS.
·Added: BugZilla send method: added API support.
·Added: BugZilla send method: added support for custom “Count” field.
·Added: BugZilla send method: added options for controlling duplicates.
·Added: BugZilla send method: added support for SSL/TLS.
·Added: New send method: Shell (mailto protocol).
·Added: New send method: extended MAPI.
·Added: Support for separate code and debug info injection.
·Added: Ability to use custom units before EurekaLog’s units.
·Added: Support for external configuration file in IDE expert.
·Added: Now EurekaLog stores only those project options which are different from defaults (to save disk space and reduce noise in project file).
·Added: Now EurekaLog stores project options sorted (alphabet order).
·Added: Separate settings for saving modules and processes lists to bug report.
·Added: Support for taking screenshots of multiply monitors.
·Added: More screenshot customization options.
·Added: More control over bug report’s file names.
·Added: New environment variables.
·Added: Deleting .map file after compilation.
·Added: Support for different .dpr and .dproj file names.
·Improved: memory leaks detection feature – new options and new customization possibilities:
·Added: Ability to track memory problems without activation of leaks checking.
·Added: Support for sharing memory manager.
·Added: Support for tracking leaks in applications built with run-time packages.
·Added: Option to zero-fill freed memory.
·Added: Option to enable leaks detection only when running under debugger.
·Added: Option for manual activation control for leaks detection (via command-line switches).
·Added: Option to select stack tracing method for memory problems.
·Added: Option to trigger memory leak reporting only for large leaked memory’s size.
·Added: Option to control limit of number of reported leak.
·Added: CheckHeap function to force check of heap’s consistency.
·Added: DumpAllocationsToFile function to save information about allocated memory to log file.
·Added: Registered leaks feature.
·Added: Run-time control over memory leak registering.
·Added: New recognized leak type: String (both ANSI and Unicode are supported).
·Added: Memory features support for C++ Builder.
·Added: Resource leaks detection feature.
·Improved: Compilation speed increased.
·Added: Support for generics in debug information.
·Added: Chained/nested exceptions support.
·Added: Wait Chain Traversal support.
·Added: Support for named threads.
·Added: Additional information for threads in call stack.
·Improved: EurekaLog Viewer Tool:

·Now Viewer has its own help file
·Viewer now supports a FireBird based database on local file or remote server.
·You can have more that one user account for FireBird based database.
·Viewer now can be launched in View mode (Viewer can be configured to any DB or View mode).
·Viewer’s database now supports storing files, associated with the report (you can also add and remove files manually).
·Viewer supports “Import” and “View” commands for report files.
·Extended support for more log formats (XML, packed ELF, etc).
·Columns in report’s list now can be configured (you can hide and show them).
·There are a plenty of new columns added to report’s list.
·Added ability of auto-download reports from e-mail account.
·Improved printing: now you can print the entire report (including screenshots). Old behaviour of printing just one tab (call stack only, for example) also remains.
·Viewer can now have more that one run-time instance.
·File import status dialog is now configurable (you can disable it, if you want to).
·There is a preview area for screenshots, available in reports.
·Now Viewer is more Vista-friendly (i.e. file associations are managed in HKCU, rather that in HKLM, storing configuration in user’s Application Data, etc, etc).
·Report’s list now supports multi-select, so operations can be performed on many reports at time.
·There are plenty of new command line abilities, like specifying several files and new switches.
·Bunch of minor changes and improvements.



Guarantee.
FULL MONEY BACK GUARANTEE.
All EurekaLog versions are covered by 60-day money-back guarantee.
If you are not satisfied with your purchase for any reason, just ask for your money back and you will be refunded.

Update Policy.
  • All updates for the same major version are freely downloadable.
  • Updates to a different license type of the same major version are sold at only price difference (example: from Single Professional version to Company Enterprise).
  • Updates between two different major version are sold at 50% discount (free for all customers who have bought a copy in the last 90 days before the release date).

EurekaLog 7 Free License Winners
We’re glad to announce the winners of our “Win Licenses” offer:

  • Alexander Bagel
  • Alexander Mihnevich
  • Ken Schafer
  • Kevin G. McCoy
  • Paul Voelker
  • Salvatore Besso

Each winner will get a free EurekaLog 7 Enterprise Single Developer License. All winners will be contacted by e-mail.
Soon to come
Roadmap for EurekaLog 7.1:
  • JIRA, Redmine, YouTrack support
  • MacOS support
  • Remaining suggestions from our customers

Read More

Read More