我可以重新编译Delphi IDE使用的.PAS文件吗?

时间:2009-10-07 19:31:43

标签: delphi delphi-2007

我熟悉Jeff Atwood's article about how errors are always the programmer's fault,但我相信我确实在Delphi .pas文件中发现了一个错误。

具体来说,我使用的是Delphi 2007,错误发生在DBCommon.pas文件的第955行,该文件位于我的机器上:

  

C:\ program files \ codegear \ rad studio \ 5.0 \ source \ Win32 \ db \ DBCommon.pas

代码是这样的:

...
  FieldIndex := StrToInt(Token);
  if DataSet.FieldCount >= FieldIndex then
    LastField := DataSet.Fields[FieldIndex-1].FieldName else
...

如果“Token”的值为零,那么我们尝试访问DataSet.Fields的索引-1,导致列表索引超出边界错误。

这个错误不会引发给用户,因为它在它达到高位之前就被处理了,但是每次发生这种情况都会让调试器中断是非常恼人的。

我可以“忽略此异常类型”,但索引越界错误很常见,我不想普遍忽略它们。

导致FieldIndex为零的情况是当你有一个SELECT语句,其ORDER BY包含一个函数时,如:

ORDER BY
  CASE WHEN FIELD1 = FIELD3 THEN 1 ELSE 2 END
 ,CASE WHEN FIELD2 = FIELD4 THEN 1 ELSE 2 END

我可以修复DBCommon.pas中的错误,但是Delphi不会自行重新编译,而且我的更改不会生效。如果我重命名.DCU文件,那么它只是抱怨找不到“DBCommon.dcu”。

所以(最后)我的问题是:我可以使用我的修复程序重新编译DBCommon.pas,如果是,那么如何?

7 个答案:

答案 0 :(得分:12)

您可以将dbcommon.pas放在项目目录中。然后将与项目的其余部分一起编译。

答案 1 :(得分:4)

有关如何创建可以重新编译已修改的VCL源的情况,请参阅前面的答案。但是,我想补充一点,您认真考虑使用“供应商分支”SCM模式管理变更控制系统中的变更。

简单来说(使用SVN作为参考):

  • 创建原始供应商提供的文件的“供应商来源”副本。这是您的“原始”参考副本。

  • 创建一个代表该原始副本的分支(例如,对于VCL的Delphi 2009版本为“2009”)

  • 在另一个“供应商库”文件夹中创建另一个分支。这是您应在项目中引用的库的副本

  • 对供应商来源的任何修改都在“供应商库”分支中进行。

  • 当供应商提供新版本的库时,您将新版本检入“供应商源”项目并为新版本创建新分支。

然后,您可以轻松区分供应商修订版。但更重要的是(使用SubVersion,可能还有其他SCM系统),您还应该能够简单地(即自动)将新的供应商源与您的“供应商库”分支合并,以便根据您自己的修改轻松合并供应商更改。

这一切都比我在优秀的O'Reilly书中所说的要好得多:“SubVersion版本控制”

但请注意,由于版权问题,不再支持该书中提到的“loaddirs”实用程序,因此更新“供应商丢弃”目前是手动练习,但这种情况很少发生,并且不是主要负担。

我们自己正在使用这种模式,尽管在VCL的情况下我们没有在我们的“供应商源”或“供应商库”中维护整个VCL源代码树的完整副本,而是仅跟踪已更改的和依赖的单元。对于在供应商分支下管理的其他库,我们通常会保留完整的副本,但认为这对VCL来说不是必需的。

我们只是刚刚实施了这种模式,所以我们可能还决定我们需要对VCL采取更全面的方法。

因人而异

答案 2 :(得分:4)

你可以,但通常你不必。有时重新编译VCL单元意味着重新编译所有其余的VCL单元,因为你已经改变了单元的接口,或者因为编译器感到困惑而认为你已经改变了接口。重新编译VCL单元还排除了使用大多数运行时软件包的可能性,因为您无法重新编译Delphi的运行时软件包。

您可以使用运行时修补,而不是重新编译。我已经在TNT Unicode controls中使用了该方法,但Madshi还提供了一种用自己的实现替换函数的方法。如果将DBCommon.GetIndexForOrderBy的实现复制到您自己的单元并进行修复,则可以使用此命令使用您自己的VCL修补VCL版本:

var
  Old_GetIndexForOrderBy: Pointer;

HookCode(@DBCommon.GetIndexForOrderBy,
         @Fixed_GetIndexForOrderBy,
         Old_GetIndexForOrderBy,
         0);

使用Tnt Unicode库,在TntSystem单元中找到OverwriteProcedure例程。它不是公开的,因此您需要在单元界面中声明它或将其复制到您自己的单元中。然后你可以像上面的Madshi代码那样调用它:

var
  Old_GetIndexForOrderBy_Data: TOverwrittenData;

OverwriteProcedure(@DBCommon.GetIndexForOrderBy,
                   @Fixed_GetIndexForOrderBy,
                   @Old_GetIndexForOrderBy_Data);

答案 3 :(得分:2)

我们的项目源代码树下有一个名为VCL的文件夹,我们在其中放置了我们希望稍微修改的VCL源代码的副本。 你的例子是做同样事情的好人选。 您需要修改项目的搜索路径,以便“你的”VCL文件夹在路径上比Delphi安装下的“Source”文件夹更早。 您可能还会发现,如果您复制一个VCL源单元并对其进行修改,则还必须将其他VCL源单元复制到“您的”文件夹中,该文件夹可能是依赖项。

我们这样做的原因是我们希望我们的构建没有编译器提示和警告。 VCL源的某些部分没有提示/警告。

答案 4 :(得分:2)

“我熟悉Jeff Atwood关于错误总是程序员错误的文章,但我相信我确实在Delphi .pas文件中发现了一个错误”

你在开玩笑吗?使用Delphi,你总是先责怪Borland :) 有些奇怪,去谷歌看看它是否是Delphi的bug。只有在找不到任何类似报告的情况下,您才能下线并逐行检查您的代码。

重新安装Delphi之后,我必须在6(6)个地方修补原始的PAS文件。新的Delphi安装中出现了大量的错误,可以轻松复制。 Delphi(我们都喜欢的那个)充满了bug。围绕着这个创造了整个历史。 有很多人发布外部补丁(例如http://andy.jgknet.de/blog/?page_id=288)和Borland / Imprise / GoGear / Embarcadero继续忽略它们。这是一个真正的奇迹,他们在发布时包含了FastMM。

无论如何,我已经重新编译了那些PAS文件,现在我用修补后的DCU替换原来的DCU。

答案 5 :(得分:1)

简单 - 是的。使用上述答案之一[汤姆或康纳]。将DBCommon.pas复制到项目文件夹而不是编辑原始文件夹。这使得其他项目和编辑不受影响,因为它不会在路径上。

答案 6 :(得分:1)

您可以设置: DataSetProvider.Option.poRetainServerOrder = True