The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

    • RT @ItsUnderstood: Journalists + everyone: When you want to correct a lie Trump - or anyone - has said, DO NOT REPEAT THE LIE. It gains cre… 14 minutes ago
    • RT @bas_haan: Veel Nederlandse politici huilen krokodillentranen over scheiden ouders en kinderen in de VS. Het Nederlands kabinet pleitte… 23 minutes ago
    • RT @misterbumface: The Holocaust was legal. Slavery was legal. Segregation was legal. The brave woman who cared for and hid my 6 year-old… 1 hour ago
    • RT @jbandi: Software development is a complex problem. You can't approach it like a complicated problem. 1 hour ago
    • RT @hhariri: Some people write some code, through in a few demos, and push it on GitHub with a README saying "Docs coming soon" Then there… 1 hour ago
  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,378 other followers

Delphi – getting the sourcefile name from a source file with an Assert trick using EAssertionFailed

Posted by jpluimers on 2009/08/21

For one of our projects, we have a set of configuration files that we want to be able to locate automatically.

(in this case they are XML files as most development environments have one way or the other to do some XML Data Binding that maps objects or interfaces to/from XML; in Delphi you can use the XML Data Binding Wizard for that: it has been there since Delphi 6, and CodeBeach has a nice Delphi XML data binding wizard video tuturoial on how to use that wizard)

We usually have a few instances of those config files hanging around:

  1. for testing; this one goes into the same directory as the Delphi source file generated by the XML Data Binding Wizard
  2. for the Delphi IDE (which might be relative to the Delphi IDE .exe)
  3. for the application (which usually is relative to the Appliation .EXE, or user settings directory)

If a specific version (higher numbers in the list above) does not exist, we want to revert to a more generic version (with lower numbre in the list above).
Ultimately we want to revert to the one for testing, which is in the subdirectory of a specific sourcefile.

Since all our development machines are configured in a similar way (i.e. having the same root path like C:\DEVELOP for our sources), it would be nice to be able to somehow automatically detect the file name of a source file.

There is a way in Delphi where you can get the name of a full source file: when an assertion failes, then Delphi raises an EAssertionFailed exception.
That exception contains the full path to the source file in which the assertion failed.

Note that this requires your application to be compiled with the $ASSERTIONS ON directive, which is the default, and also enabled for our production builds.

So this statement:

  Assert(False, 'no valid configuration file found relative to ' + Application.ExeName);

will result in a message like this:
no valid configuration file found relative to C:\Program Files\CodeGear\RAD Studio\6.0\bin\bds.exe (C:\develop\ActiveMQ\ActiveMQDemo\common\src\ConfigHelperUnit.pas, line 84)

Knowing this, we need a function like GetSourceFileName, preferably on the EAssertionFailed class that gets us the source filename that is inside the parentheses.

Having a function like that, would allow for code like this:

function GetConfigPathName(const Application: TApplication): string; overload;
  TriedFileNames: IStringListWrapper;
  SourceFileName: string;
  TriedFileNames := TStringListWrapper.Create();
  Result := FindConfigPathName(Application, TriedFileNames);
    AssertConfigFileNameExists(Result, Application.ExeName, TriedFileNames);
    on E: EAssertionFailed do
      SourceFileName := E.GetSourceFileName();
      Result := FindConfigPathName(SourceFileName, TriedFileNames);
      AssertConfigFileNameExists(Result, Application.ExeName, SourceFileName, TriedFileNames);

Since we want the function to be on EAssertionFailed, I have written a class helper like this:

unit AssertionFailedHelperUnit;



  TAssertionFailedHelper = class helper for EAssertionFailed
    function GetSourceFilename: string;



function TAssertionFailedHelper.GetSourceFilename: string;
  Mask: string;
  ExceptionMessage: string;
  OpeningParenthesesPosition: Integer;
  //no valid configuration file found relative to C:\Program Files\CodeGear\RAD Studio\6.0\bin\bds.exe (C:\develop\ActiveMQ\ActiveMQDemo\common\src\ConfigHelperUnit.pas, line 84)
  //  SAssertError = '%s (%s, line %d)';
  // now create this string " (, line 0)" and use it to parse from right to left
  Mask := Format(SAssertError, ['', '', 0]);
  ExceptionMessage := Self.Message;
  // remove the closing ")"
  if (ExceptionMessage <> '') then
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
    Delete(Mask, Length(Mask), 1);
    // remove the "0" from the Mask
    Delete(Mask, Length(Mask), 1);
  while (ExceptionMessage <> '') and (CharInSet(ExceptionMessage[Length(ExceptionMessage)], ['0'..'9'])) do
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
  // from the right side, remove the ", line " portion
  while (ExceptionMessage <> '') and (ExceptionMessage[Length(ExceptionMessage)] = Mask[Length(Mask)]) do
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
    Delete(Mask, Length(Mask), 1);
  // now find the opening "("
  OpeningParenthesesPosition := Length(ExceptionMessage);
  while (ExceptionMessage <> '') and (ExceptionMessage[OpeningParenthesesPosition] <> '(') do
  Delete(ExceptionMessage, 1, OpeningParenthesesPosition);
  Result := ExceptionMessage;


This unit has made life for us a lot easier.
Hope it does it for you as well :-)


3 Responses to “Delphi – getting the sourcefile name from a source file with an Assert trick using EAssertionFailed”

  1. L-Tyrosine said

    Theres a much easier way, just set the AssertErrorProc global variable pointing to a procedure like that:

    AssertErrorProc := AssertErrorHandler

    AssertErrorHandler(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);

    It alredy comes with unit filename, linenumber and error address. With a complete .map file in memory one can build code to even hint the current class/procedure name.

  2. […] Delphi – getting the sourcefile name from a source file with an Assert trick using EAsser… […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: