I use Word automation from an Delphi application, and it is very slow. 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. 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 (i.e. the time to generate a document). In the attached sample it takes about 2,5 seconds to generate the document. For a typical real document it takes about 30-40 seconds, sometimes more.
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!".
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. Open Word, and create a new document. 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. 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.
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
instance or create the new one each time you work with a document ? I'm sure you keep it, that's why it's marked as a silly note :-) – TLama