如何从 Delphi XE2 加速文字自动化

Posted

技术标签:

【中文标题】如何从 Delphi XE2 加速文字自动化【英文标题】:How to speed up word automation from Delphi XE2 【发布时间】:2012-04-25 11:14:09 【问题描述】:

我在 Delphi 应用程序中使用 Word 自动化,但速度非常慢。我已将我的代码精简到最低限度,并希望有经验的人能告诉我哪里出错了(我实际上希望我 出错了,所以我可以加快速度)

我的应用程序中自动化的本质是处理书签。该应用程序打开一个带有一些特殊书签的文档,遍历这些书签并根据它们的名称更改它们。真实版本还大量处理文档变量和域代码。一个典型的文档有 50-80 个书签,其中一些是嵌套的。我还使用一些临时文档来构建文本和图像块,它们被连续放置在要生成的文档中。随附的代码是一个非常精简的版本,没有此功能,但它显示了不需要的行为(即生成文档的时间)。在随附的示例中,生成文档大约需要 2.5 秒。对于典型的真实文档,大约需要 30-40 秒,有时甚至更长。

我希望有人说“你做错了。当从 Delphi 做 Word Automation 时,你必须永远记住 XXX!”。

由于整个项目,即使完全剥离,也相当大,我做了这个小应用程序。如果我这样做的方式有明显的错误,希望从这段代码中可以明显看出。

请创建一个新的 VCL 表单应用程序。打开 Word,然后创建一个新文档。在第一行输入一些文本,标记它并插入书签。在第二行输入一些文本,并将其也添加为书签。将文件另存为 'c:\temp\bm.doc' 作为 Word 97-2003 文档。运行应用程序后,您应该有一个新文档('c:\temp\bm_generated.doc'),第一行有一个随机数,没有书签。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OleServer, WordXP, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
     Private declarations 
  public

  end;

var
  Form1: TForm1;

implementation

$R *.dfm

procedure TForm1.Button1Click(Sender: TObject);
var
  vWordApp    : TWordApplication;
  vDoc        : WordDocument;
  vFileName   : OleVariant;
  vIndex      : OleVariant;
  vBookmark   : Bookmark;
  vSave       : OleVariant;
begin
  vWordApp := TWordApplication.Create(nil);
  try
    vWordApp.ConnectKind := ckNewInstance;
    vWordApp.Connect;
    vFileName := 'c:\temp\bm.doc';
    vDoc := vWordApp.Documents.Open(vFileName, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);

    //Replace bookmark text with random string:
    vIndex := 1;
    vBookmark := vDoc.Bookmarks.Item(vIndex);
    vBookmark.Range.Text := inttostr(random(10000)); //Will also delete the bookmark!

    //Delete bookmark content and bookmark
    vIndex := 1; //This will be the bookmark that was originally the first, since that was deleted when we sat the text
    vBookmark := vDoc.Bookmarks.Item(vIndex);
    vWordApp.Selection.SetRange(vBookmark.Range.Start, vBookmark.Range.End_);
    vWordApp.Selection.Text := '';

    vFileName := 'c:\temp\bm_generated.doc';
    vDoc.SaveAs2000(vFileName, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);

    vWordApp.NormalTemplate.Saved := true; //For å slippe spørsmål om "normal.dot" skal lagres
    vSave := wdDoNotSaveChanges;
    vWordApp.Quit(vSave);
    vWordApp.Disconnect;
  finally
    vWordApp.Free;
  end;
end;

end.

【问题讨论】:

只是一个愚蠢的说明,您是保留TWordApplication 实例还是在每次处理文档时创建新实例?我相信你会保留它,这就是为什么它被标记为一个愚蠢的笔记:-) 没那么傻。如果我一次生成多个文档,我会使用相同的 TWordApplication,但大多数情况下并非如此。这是 ERP 应用程序打印例程的一部分,因此我在打印对话框指示应生成 word 文档时创建 TWordApplication,并在完成后释放它。 该代码对我来说看起来不错。也许这就是需要多长时间。 @David:这正是我不想想听到的:) ~ 300 - 400 毫秒。 Word2010(认为第一次花了大约一秒钟)。 【参考方案1】:

你可以试试:

vWordApp.ScreenUpdating := False;

也许还有

vWordApp.Visible := False;

(记得在完成后设置回以前的值)。

【讨论】:

在真实版本中是不可见的。但在剥离的版本中,我没有包含它。 (但我不知道 ScreenUpdating,我也会测试一下) 很高兴看到一些基准能够考虑生成一些参考 MS Word 文档所需的时间。【参考方案2】:

您是否尝试过将参数提供给 VBA 并在 Word 中进行替换?几年前,我在 Word 文档中为客户做了几百个宏。根据我的记忆,这是一个更快的实现。那是来自 Java 代码库。

首先,Word 会花费大量时间来加载和解析文档。这可能是大部分时间花费的地方。我会通过不更换书签来确定计时测试的基准。另一件事是它可能正在为每个替换进行全文扫描。这可能就是 VBA 工作得更好的原因。

【讨论】:

不使用书签是不行的。 AFAIK VBA 使用对象模型,就像我在 Delphi 中所做的那样,所以我认为这不会影响速度。 是的,它不应该,但它似乎确实如此。也许 Word 每次都在实例化整个环境;我不确定,我只记得这是对这个问题的一个戏剧性的回答。当然,您每次都在翻转线程,因此如果您拨打电话然后可能会调用 Application.HandleMessage 几次,它可能会改善情况。许多纯粹主义者认为它是一种 hack,我不会争辩说,它有时只是有用的。该答案的另一部分是限制您在应用程序之间进行的往返次数。它们中的每一个都会导致滞后。【参考方案3】:

如果您只使用书签和域代码进行基本操作(请注意 NO 结构),您可能会考虑将文档转换为 RTF 并更改其中的所有内容。我这样做可以在每个文档 0.005 秒内运行代码。 保存文档大约需要 0.2 - 2 秒,具体取决于磁盘驱动器的速度。

【讨论】:

以上是关于如何从 Delphi XE2 加速文字自动化的主要内容,如果未能解决你的问题,请参考以下文章

新的 Delphi XE2 自动生成的内部版本号是不是链接到 1.1.2000 00:00:00?

Delphi XE2:跳到 CHM 中的锚点?

如何改变delphi xe2编程环境下所显示的源代码的字体大小

尝试从 VS2013 C# 程序调用 DELPHI XE2 DLL 时出错

如何使用Delphi XE2覆盖WSDL中的服务名称?

如何让 FastCodePatch 在 Delphi XE2 Win64 平台上工作?