Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Delphi

Changing standard Delphi libraries

5.00/5 (3 votes)
7 Nov 2015CPOL3 min read 15.3K  
The article is step-by-step tutorial on how to make changes in standard Delphi libraries.

Introduction

Delphi ships with a bunch of standard libraries, mostly known of which are VCL and RTL. Usually we use standard libraries as they are and don't want to change anything. But there are some sitiations when you need to change standard libraries code. There are the next possible reasons for you to do so:

  • you need to fix a bug in standard library
  • you need to add some extension point to standard library
  • you need to add some debug information to mechanisms of standard library

Of course, modification of standard libraries code is to be avoided if possible. But there are cases when you have no other choice. Fortuntatly, we have a way to do this.

Standard libraries source code

Let's start with the fact that Delphi actually ships with source code of standard libraries:

  • unit source code PAS-files are placed in the folder $(BDS)\Source
  • compiled unit DCU-files are placed in the folder $(BDS)\Lib
  • compiled packages are placed in the folder $(BDS)\Bin

Variable $(BDS) means Delphi install folder.

Unfortunately, there are no package files for some packages (we have only unit source files). But for RTL package we have package file source as well.

Actually there are some differencies for different versions of Delphi. In this article I assume that Delphi XE6 is being used. But the desribed concepts can be applied to other versions of Delphi if needed with slight modifications.

Link with runtime packages

In Delphi project options there is an option "Link with runtime packages". By default this option is off and standard library code is embedded into the application executable file. If there are a lot of used units it can make application executable file pretty big. But this makes possible to ship application as one standalone executable. When application consists of several packages there is no other alternative then make "Link with runtime packages" on. When this option is on we need to ship application with used standard library BPL-files. So when application is built with runtime packages BPL-files are used and we can recompile some BPL-files from source code and ship application with modified files. But this approach has limitation in the fact, that we cannot change interface part of standard library units. So it is not so much interesting. I would show the way to recompile standard library source with interface part modifications possible.

Separate settings section

For our experiments we will use IDE with separate settings section in the registry. We will change standard IDE settings, but we perhaps don't want to lose the possibility to use unmodified standard libraries. That is where separate settings section comes handy. In order to launch IDE with separate settings section the command line parameter -r is to be used. In IDE options there are options which determine standard library PAS-files placement and standard library DCU-files placement. We will change these settings in order to make Delphi use our modified source files.

Step-by-step example

  1. Launch Delphi with key -rRTL, where RTL means the name of separate settings section:
    BAT
    bds.exe -pDelphi -rRTL
  2. Copy RTL library source files from the folder $(BDS)\RTL into the separate folder.
  3. Open IDE options
    • Open settings node Environment Options\Environment Variables
      • Create new user override variable named ModifiedRuntimePath, which will contain the path to the folder created in the step 2.
    • Open settings node Environment Options\Delphi Options\Library
      • Change Library Path setting value with $(ModifiedRuntimePath)\_dcu\Win32\Release
      • Replace Browsing Path setting value with the following list of folders:
        • $(ModifiedRuntimePath)\RTL\common
        • $(ModifiedRuntimePath)\RTL\sys
        • $(ModifiedRuntimePath)\RTL\win
  4. Open project options
    • Open settings node Delphi Compiler
      • Enter into DCP output directory setting value ..\_dcu\$(Platform)\$(Config)
      • Enter into Package output directory setting value ..\_bin\$(Platform)\$(Config)
      • Enter into Search path setting value ..\_dcu\$(Platform)\$(Config)
      • Enter into Unit output directory setting value ..\_dcu\$(Platform)\$(Config)
      Image 1
  5. Change System.pas unit source code (add some events to monitor object creation and destruction):
    Pascal
    type
      ...
      TOnObjectCreate = procedure(const Sender: TObject);
      TOnObjectDestroy = procedure(const Sender: TObject);
      ...
    var
      ...
      OnObjectCreate: TOnObjectCreate;
      OnObjectDestroy: TOnObjectDestroy;
      ...
    implementation
    ...
    constructor TObject.Create;
    begin
      if Assigned(OnObjectCreate) then
        OnObjectCreate(Self);
    end;
    
    destructor TObject.Destroy;
    begin
      if Assigned(OnObjectDestroy) then
        OnObjectDestroy(Self);
    end;
  6. Compile modified RTL package in Debug configuration
  7. Create new console application with the following code:
    Pascal
    program TestApp;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    procedure HandleObjectCreate(const Sender: TObject);
    begin
      WriteLn(Format('%s%s%s.%s', 
        [IntToHex(Integer(Pointer(Sender)), 8), #9, Sender.ClassName, 'Create']));
    end;
    
    procedure HandleObjectDestroy(const Sender: TObject);
    begin
      WriteLn(Format('%s%s%s.%s', 
        [IntToHex(Integer(Pointer(Sender)), 8), #9, Sender.ClassName, 'Destroy']));
    end;
    
    var
      LObject: TObject;
    begin
      try
        OnObjectCreate := HandleObjectCreate;
        OnObjectDestroy := HandleObjectDestroy;
        LObject := TObject.Create;
        LObject.Free;
        OnObjectCreate := nil;
        OnObjectDestroy := nil;
        ReadLn;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.
  8. Run the application:
    Image 2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)