EmptyParam现在变量是一个函数 - 如何解决遗留代码?

时间:2012-02-21 00:30:18

标签: delphi com

我只是将Delphi 6中编写的一些旧代码升级到Delphi XE2。不幸的是,代码引用了Word97 COM对象来生成一些.doc文档。代码中有Word97的直接使用条款。

我必须保持生成的文档采用与旧版Crystal Report和另一个第三方应用程序使用相同的Word格式,该应用程序需要该文档的格式。

所以,问题。因为我在uses子句中使用Word97,所以编译器抱怨每当使用EmptyParam变量时,实际和正式var参数的类型必须相同。这直接来自Word97.pas源文件。这是因为现在将EmptyParam声明为函数而不是变量。

处理这个问题的最佳方法是什么?我应该将Delphi 6源文件(Word97.pas等)复制到我的本地目录中,直接将它们与System.Variants.pas一起添加到我的项目中,并将我的应用程序的编译器指令更改为包含EMPTYPARAM_VAR吗?我没有尝试过,但希望它会将EmptyParam声明为变量。或者也许有一个更简单的解决方案。

由于

修改

这里有更多的背景信息,即使我已经接受了答案,以备将来参考。这是代码示例(AddClaimsLetter是“应用程序”COM对象 - 即TWordApplication):

AddClaimsLetter.Documents.Open(Wordfile, EmptyParam, EmptyParam,
                        EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
                        EmptyParam, EmptyParam, EmptyParam, EmptyParam);

在不改变任何内容的情况下,此处的EmptyParam参数在编译时失败,说明“E2033实际和正式var参数的类型必须相同”。

但是,因为我想保留Word97(在Delphi 6 Ent。安装文件夹中的OCX / Server中),我确实需要将.pas文件复制到我的本地项目文件中并声明一个已使用的变量EmptyParam(因为这些文件也试图编译,我得到了与上面相同的编译错误)。

所有现在都在工作,但我可能会与管理层讨论升级到此应用程序的Office的更高版本!

由于

3 个答案:

答案 0 :(得分:15)

我快速解决问题的方法可能是声明OleVariant类型的局部变量,并为其分配函数EmptyParam的结果。

答案 1 :(得分:7)

对于每个var参数,您应该添加一个用EmptyParam调用填充的局部变量。

原因是所有var参数都通过引用传递。如果在多个引用处传递相同的变量,则可能会遇到以下问题(使用整数简化)。

Before: VarParameter=-1
Before: A=-1
Before: B=-1
After: A=2
After: B=2
After: VarParameter=2
EAssertionFailed: Assertion failure

这是显示风险的代码:

program TheVarParameterRisk;

procedure AssignParameters(var A: Integer; var B: Integer);
begin
  Writeln('Before: A=', A);
  Writeln('Before: B=', B);
  A := 1;
  B := 2;
  Writeln('After: A=', A);
  Writeln('After: B=', B);
  Assert(A = 1);
end;

var
  VarParameter: Integer;

begin
  try
    VarParameter := -1;
    try
      Writeln('Before: VarParameter=', VarParameter);
      AssignParameters(VarParameter, VarParameter);
    finally
      Writeln('After: VarParameter=', VarParameter);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

您在AssignParameters中看到Assert失败,因为调用者将相同的引用传递给两个var参数。

这正是EmptyParam成为函数的原因:它永远不应该作为var参数传递。

人们抱怨Delphi中的错误(例如here)导致覆盖EmptyParam值。

现在EmptyParam是一个函数,问题就解决了。当您需要将其作为var参数传递时,请使用本地中间件。

注意:

  • 如果你(因为你导入的API表明你应该)必须将EmptyParam传递给var参数,那么基本上你本身就有问题:var参数意味着什么是将被更改,这意味着传递EmptyParam(或具有相同内容的本地变量)阻止了更改。
  • 如果您认为类型库导入器生成错误的代码(具有var参数而不是const参数),则导入的类型库具有错误的参数标志,或者(如果参数标记是好的)它是错误的(您应该在https://quality.embarcadero.com提交错误报告(这曾经是索引http://qc.embarcadero.com的搜索引擎,但已关闭; https://quality.embarcadero.com需要免费帐户搜索)。

修改

你必须将EmptyParam传递给var参数的事实是一个非常强烈的提示,我认为被调用的函数可能会真正使用这些参数并且会失败。就像我的示例函数失败一样。 (是的,函数文档可能会引诱您使用多个EmptyParam参数,实际上这些参数实际上并不是空的;我经常看到文档说A和实际函数执行B)。

答案 2 :(得分:1)

  

我是否应该将Delphi 6源文件(Word97.pas等)复制到我的本地目录中,直接将它们与System.Variants.pas一起添加到我的项目中,并将我的应用程序的编译器指令更改为包含EMPTYPARAM_VAR?我没有尝试过,但希望它会将EmptyParam声明为变量。

您可能在法律上允许将Word97.pas从较旧的Delphi复制到新版本,但是您需要“升级”它以使用新的编译器。您可能会面临更多问题,主要是因为Delphi XE2启用了Unicode而Delphi 6不支持。如果那个单位是我认为的那样(如上所述我在Delphi的3个版本中没有它我已经得到了方便和检查)那么它是OLE自动化Word的包装 - 也就是说,它充满了难以理解的系统没有实现的代码和许多方法声明。最后一点,没有实现的方法声明,使得非常难以改变:如果你改变某些东西并且它编译它并不意味着它是正确的 - 你只会在运行时找到它是否有效或者不

你应该做什么:

  • 重新导入Word 97的类型库(我假设这是Word97.pas的内容)并重新编写导出代码以使用此新库生成word文档。 编辑: 显然重新导入TypeLibrary会产生无法使用的代码。
  • 在Delphi6中编写一个DLL,它使用旧的Word97.pas并使用Delphi XE2中的DLL。不是很优雅,但会起作用。
  • 重新考虑您对Word自动化当前提供的策略。