修改标准的 Delphi 库





5.00/5 (3投票s)
本文是一篇关于如何在标准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使用我们修改后的源文件。
逐步示例
- 使用键 -rRTL 启动 Delphi,其中 RTL 表示单独的设置部分的名称
bds.exe -pDelphi -rRTL
- 将RTL库源文件从文件夹$(BDS)\RTL复制到单独的文件夹中。
- 打开 IDE 选项
- 打开设置节点环境选项\环境变量
- 创建一个名为ModifiedRuntimePath的新用户覆盖变量,该变量将包含在步骤2中创建的文件夹的路径。
- 打开设置节点环境选项\Delphi 选项\库
- 将库路径设置值更改为$(ModifiedRuntimePath)\_dcu\Win32\Release
- 使用以下文件夹列表替换浏览路径设置值
- $(ModifiedRuntimePath)\RTL\common
- $(ModifiedRuntimePath)\RTL\sys
- $(ModifiedRuntimePath)\RTL\win
- 打开设置节点环境选项\环境变量
- 打开项目选项
- 打开设置节点 Delphi 编译器
- 输入到DCP输出目录设置值 ..\_dcu\$(Platform)\$(Config)
- 输入到包输出目录设置值 ..\_bin\$(Platform)\$(Config)
- 输入到搜索路径设置值 ..\_dcu\$(Platform)\$(Config)
- 输入到单元输出目录设置值 ..\_dcu\$(Platform)\$(Config)
- 打开设置节点 Delphi 编译器
- 更改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;
- 在Debug配置中编译修改后的RTL包
- 使用以下代码创建一个新的控制台应用程序
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.
- 运行应用程序