简体   繁体   English

如何从Delphi XE2加速单词自动化

[英]How to speed up word automation from Delphi XE2

I use Word automation from an Delphi application, and it is very slow. 我从Delphi应用程序中使用Word自动化,它非常慢。 I have stripped my code down to the bare minimum, and was hoping that someone with some experience can tell me where I've gone wrong (and I'm actually hoping i have gone wrong, so that I can speed it up) 我已经剥夺我的代码降到最低限度,并希望有经验的,有人能告诉我在哪里,我已经错了(我其实希望我已经错了,这样我就可以加快)

The essence of the automation in my application deals with bookmarks. 我的应用程序中自动化的本质涉及书签。 The application opens a document with some special bookmarks, runs through these and change them based on their names. 该应用程序将打开一个包含一些特殊书签的文档,然后对它们进行遍历并根据其名称进行更改。 The real version also deals heavily with document variables and fieldcodes. 实际版本还大量处理文档变量和域代码。 A typical document has 50-80 bookmarks, some of which are nested. 一个典型的文档有50-80个书签,其中一些是嵌套的。 I also use some temporary documents to build blocks of text and images, that are placed consecutively in the document to be generated. 我还使用一些临时文档来构建文本和图像块,这些块连续放置在要生成的文档中。 The attached code is a VERY stripped down version without this functionality, but it displays the unwanted behaviour (ie the time to generate a document). 附带的代码是非常精简的版本,没有此功能,但显示了不需要的行为(即生成文档的时间)。 In the attached sample it takes about 2,5 seconds to generate the document. 在随附的示例中,生成文档大约需要2.5秒。 For a typical real document it takes about 30-40 seconds, sometimes more. 对于典型的真实文档,大约需要30-40秒,有时甚至更多。

What I'm hoping for is for someone to say "You're doing this all wrong. When doing Word Automation from Delphi, you must always remember to XXX!". 我希望有人说“您做错了所有。从Delphi执行Word Automation时,您必须始终记住XXX!”。

Since the full project, even when stripped down completely, is quite large, I have made this small application. 由于整个项目(即使完全删除)也很大,因此我做了这个小应用程序。 If there is an obvious mistake in the way I do it, it will hopefully be apparent from this code. 如果我的操作方式存在明显错误,则希望从此代码中可以明显看出。

Please create a new VCL Forms Application. 请创建一个新的VCL表单应用程序。 Open Word, and create a new document. 打开Word,然后创建一个新文档。 Enter some text on the first line, mark it and insert bookmark. 在第一行输入一些文本,将其标记并插入书签。 Enter some text on the second line, and bookmark this too. 在第二行输入一些文本,并将其添加为书签。 Save the file as 'c:\\temp\\bm.doc' as a Word 97-2003 document. 将文件另存为'c:\\ temp \\ bm.doc'作为Word 97-2003文档。 After running the application you should have a new document ('c:\\temp\\bm_generated.doc') with a random number on the first line, and no bookmarks. 运行该应用程序后,您应该有一个新文档('c:\\ temp \\ bm_genic.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.

You could try: 您可以尝试:

vWordApp.ScreenUpdating := False;

and maybe also 也许也

vWordApp.Visible := False;

(remember to set back to previous values when done). (记住,完成后请重新设置为先前的值)。

Have you tried supplying your parameters to VBA and doing your replacements inside word? 您是否尝试过将参数提供给VBA并在Word中进行替换? I did a few hundred macros in word docs for a client a few years back. 几年前,我为一个客户在word文档中做了几百个宏。 That was a much quicker implementation from what I remember. 从我记得的情况来看,这是一个更快的实现。 That was from a Java code base. 那是来自Java代码库的。

Word spends a lot of time loading and parsing the document in the first place. Word首先要花费很多时间来加载和解析文档。 That might be where the bulk of the time is spent. 那可能是花费大量时间的地方。 I would base line the timing test by doing no bookmark replacements. 我将通过不进行书签替换来对计时测试进行基准测试。 The other thing is that it is probably doing a full text scan for each replacement. 另一件事是,它可能会对每个替换进行全文扫描。 That might be why the VBA worked better. 这也许就是为什么VBA表现更好的原因。

If you do just basic stuff with bookmarks and fieldcodes (mind you NO IF constructions) you might think about converting the document(s) to RTF and change everything in there. 如果您只使用书签和域代码来做基本工作(不要介意IF结构),则可以考虑将文档转换为RTF并在那里进行更改。 I did that can run code inside 0.005 of a second per document. 我这样做可以在每个文档0.005秒内运行代码。 Saving the document takes about 0.2 - 2 seconds, depending on the speed of the diskdrive. 根据磁盘驱动器的速度,保存文档大约需要0.2-2秒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM