65.9K
CodeProject 正在变化。 阅读更多。
Home

修改标准的 Delphi 库

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2015年11月7日

CPOL

3分钟阅读

viewsIcon

15651

本文是一篇关于如何在标准Delphi库中进行更改的逐步教程。

引言

Delphi自带一系列标准库,其中最知名的是VCL和RTL。通常我们直接使用标准库,不想做任何更改。但在某些情况下,您需要更改标准库的代码。这样做可能的原因有以下几种:

  • 您需要修复标准库中的错误
  • 您需要在标准库中添加一些扩展点
  • 您需要向标准库的机制中添加一些调试信息

当然,如果可能,应该避免修改标准库的代码。但有些情况下,您别无选择。幸运的是,我们有一种方法可以做到这一点。

标准库的源代码

让我们从一个事实开始,那就是Delphi实际上附带了标准库的源代码

  • 单元源代码PAS文件位于文件夹$(BDS)\Source中
  • 编译后的单元DCU文件位于文件夹$(BDS)\Lib中
  • 编译后的包位于文件夹$(BDS)\Bin中

变量$(BDS)表示Delphi安装文件夹。

不幸的是,某些包没有包文件(我们只有单元源文件)。但对于RTL包,我们也有包文件源。

实际上,对于不同版本的Delphi来说,有一些差异。在本文中,我假设使用的是Delphi XE6。但是,如果需要,可以将描述的概念应用于其他版本的Delphi,只需稍作修改即可。

与运行时包链接

在Delphi项目选项中,有一个选项“与运行时包链接”。默认情况下,此选项处于关闭状态,并且标准库代码嵌入到应用程序可执行文件中。如果使用了大量单元,则会使应用程序可执行文件变得非常大。但这使得将应用程序作为单个独立的可执行文件发布成为可能。当应用程序由多个包组成时,没有其他选择,只能打开“与运行时包链接”。当此选项打开时,我们需要使用标准库的BPL文件发布应用程序。因此,当应用程序使用运行时包构建时,将使用BPL文件,我们可以从源代码重新编译一些BPL文件,并使用修改后的文件发布应用程序。但这种方法存在局限性,即我们无法更改标准库单元的接口部分。所以它不是那么有趣。我将展示一种重新编译标准库源代码的方法,并可以修改接口部分。

单独的设置部分

对于我们的实验,我们将使用IDE,该IDE在注册表中有单独的设置部分。我们将更改标准IDE设置,但我们可能不想失去使用未修改的标准库的可能性。这就是单独的设置部分派上用场的地方。为了使用单独的设置部分启动IDE,需要使用命令行参数-r。在IDE选项中,有一些选项可以确定标准库PAS文件和标准库DCU文件的放置位置。我们将更改这些设置,以便Delphi使用我们修改后的源文件。

逐步示例

  1. 使用键 -rRTL 启动 Delphi,其中 RTL 表示单独的设置部分的名称
    bds.exe -pDelphi -rRTL
  2. 将RTL库源文件从文件夹$(BDS)\RTL复制到单独的文件夹中。
  3. 打开 IDE 选项
    • 打开设置节点环境选项\环境变量
      • 创建一个名为ModifiedRuntimePath的新用户覆盖变量,该变量将包含在步骤2中创建的文件夹的路径。
    • 打开设置节点环境选项\Delphi 选项\库
      • 将库路径设置值更改为$(ModifiedRuntimePath)\_dcu\Win32\Release
      • 使用以下文件夹列表替换浏览路径设置值
        • $(ModifiedRuntimePath)\RTL\common
        • $(ModifiedRuntimePath)\RTL\sys
        • $(ModifiedRuntimePath)\RTL\win
  4. 打开项目选项
    • 打开设置节点 Delphi 编译器
      • 输入到DCP输出目录设置值 ..\_dcu\$(Platform)\$(Config)
      • 输入到包输出目录设置值 ..\_bin\$(Platform)\$(Config)
      • 输入到搜索路径设置值 ..\_dcu\$(Platform)\$(Config)
      • 输入到单元输出目录设置值 ..\_dcu\$(Platform)\$(Config)
  5. 更改System.pas单元源代码(添加一些事件以监视对象创建和销毁)
    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. 在Debug配置中编译修改后的RTL包
  7. 使用以下代码创建一个新的控制台应用程序
    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. 运行应用程序
更改标准Delphi库 - CodeProject - 代码之家
© . All rights reserved.