📄 how_to_use_word_97.htm
字号:
<html>
<head>
<title>How to Use Word 97 as a Report Engine</title>
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<meta name="Microsoft Border" content="none">
</head>
<body bgcolor="#FFFFCC">
<p align="center"><font color="#804040"><strong><em><big><big><big>How to Use Word 97 as a
Report Engine</big></big></big></em></strong></font></p>
<p><font color="#804040"><font size="+1"><b>Revised: August 14th, 1999</b></font> </font></p>
<p><b><i>by Dr Allan Harkness - <a href="mailto:A.Harkness@bio.gla.ac.uk">A.Harkness@bio.gla.ac.uk</a></i></b>
</p>
<p><b>Introduction</b> </p>
<p>Microsoft has recently been advertising their monolithic Word 97 as a report engine for
their development tools (see '<a
href="http://www.microsoft.com./worddev/articles/movs108.htm">Using Word as a Report
Generation Component</a>'). The examples they give use OLE Automation. There seems to be
no good reason why Delphi cannot do the same, particularly with the loss of ReportSmith
(no loss…) and the problems with QuickReport (was quite good once, then things went
astray…). </p>
<p>There have been several small components released recently that purport to be some form
of report engine using Word 97. However, they are rather minimalist in nature and all seem
to use late binding. The reason for this will become clear later. </p>
<p>Hidden away in one of the Delphi demos (..\Delphi4\Demos\Activex\Oleauto\Word8) is a
rather simple "report engine". It has a full implementation of the events
generated by Word, but only a few methods. However, it uses early binding. </p>
<p>There are several reasons why early binding has not taken off with Word:
<ol>
<li>Many are still put off by the difficulties they had with type libraries from Delphi 3 </li>
<li>Word's objects make great use of optional parameters. Early binding forbids their use.
Borland were not very forthcoming with a method for passing 'null' optional parameters in
Delphi 3 (see Appendix 1) and didn't exactly advertise the existence of the EmptyParam
'constant' in Delphi 4. </li>
<li>Many arguments are enumerate types (TOleEnum). You need to constantly look these up in
Word VBA help. </li>
<li>Far too many arguments are of type OleVariant. These require that you pass a variable of
OleVarient type, i.e., you cannot do something like Selection.MoveLeft(wdWord, 1, wdMove)
as these arguments are constants, not OleVariants. </li>
<li>Code for getting the current word application using late binding was frequently give in
the OleAutomation newsgroups (see Appendix 2). This is useful; otherwise you end up with
loads of copies of word. </li>
</ol>
<p>Here are a few reasons why early binding is better:
<ol>
<li>We all know it is faster </li>
<li>It is language independent </li>
<li>You get tool tips to show you all 11 parameters required to do ActiveDocument.SaveAs
(…) </li>
<li>You are guaranteed to get a Word 97 object. If you use
CreateOLEObject('Word.Application') then you may get an error if an older version of word
is present as there was no Application object then (you would have used Word.WordBasic).
You may still get this error if you have both Word 97 and a previous version. This is very
important if you application is distributed to unknown machines (with goodness knows what
on them). </li>
<li>You can interface with the events generated from Word (for what it's worth).</li>
</ol>
<p> </p>
<b>
<p>Methods</p>
</b>
<p>With these considerations in mind, I decided to create a set of classes that will allow
me to interact with word and rarely have to deal with the unpleasantries of COM. I took as
my starter, the Word97.pas file in the Delphi demos. </p>
<p>If you look at this file, you will see how to get round problem 4, i.e., the
OleVariants. You need to typecast all the arguments as OleVariants and then pass these to
the COM method. All I needed was to flesh out the classes with some more methods and
properties. </p>
<p>Delphi's demo uses the selection object to insert text into word. This allows you to
see what happens and where. However, moving the selection around is slow as the screen is
constantly updated and if you have a big document, it requires scrolling the page. The
best way of working with regions of text is to use ranges. You can get a range object from
many Word objects, including the selection object itself and bookmarks. </p>
<p>I think bookmarks are the ideal way of identifying where to insert text into a
document. You can assign bookmarks to text or even just a point in the document. The best
place to do this is in the template. Then when you make a new document, you just move to
all the bookmarks adding the appropriate text as necessary. </p>
<p>In addition to the <a href="TWordApp.htm">TWordApp</a> object, I have implemented two
other objects: <a href="TWordDoc.htm">TWordDoc</a> and <a href="TWordRange.htm">TWordRange</a>.</p>
<p><b>Results</b> </p>
<p>The Demo.dpr project gives a quick example of how to open a document and move between
bookmarks to fill in the details. It also shows the events in action. You could alter this
program to create a document from a template, where the template has the relevant
bookmarks defined. </p>
<p><b>Discussion</b> </p>
<p>I have made extensive use of Delphi4's default parameters. These allow you almost as
much freedom as Visual Basic's default parameters—although you cannot use named
parameters and you can't do TWordRange.Move(,1). </p>
<p><a href="mailto:MQamar@usa.net">Quamar Ali</a> has converted the original Word97 for
Delphi 3. I have also made a few alterations to this version. In particular, I have thrown
out the sink (if anyone has Delphi 3 and the Borland demos come with a Word97, let me know
if the sink is there and I will think about putting it back in). The Delphi 3 version is
still quite useable, despite the lack of default parameters. There is one additional task
you must perform to get these classes to work for Delphi 3. When Delphi 4 imports the Word
type library, it converts 'Application' to 'Application_' as it considers 'Application' as
a reserved word (it is used extensively in the project file and is defined in forms.pas).
Delphi 3 is not so clever. Since you will only need to import this library once, you can
ignore the warning at the start of the Word_TLB.PAS file saying that any changes will be
overwritten. Search for all instances of 'Application' and change to 'Application_' (NB
this is the object not the class type). You will find this file in the ../Delphi 3/Imports
directory. </p>
<p>Using these objects in my programs allows me to concentrate on what I want to do with
Word without having the hassle of COM. I would welcome additions to the unit. Bear in mind
that Word_TLB.pas is 860k in size and my unit is already 45k. It probably has too much as
it stands (I don't really use the selection methods in TWordApp), so any additions must be
really worthwhile. If you would like to download the demo code... see the link at the
bottom of this article. </p>
<p>I use Word to generate letters with English text, generated from data in an Access
database (I use <a href="http://www.islamov.com/diamond/">DiamondDAO</a> to connect to
this). This is rather different from a tabular report. A standard report component would
be better for in that instance (e.g., ReportBuilder). The advantage of Word is that you
can edit and save the letters as though they were typed-in letters. It is perhaps a bit on
the large side if all you want is a list. </p>
<p>The current version (1.4) was released 13/7/1999. </p>
<p><b>Appendix 1</b> </p>
<p>How to make your own EmptyParam for Delphi 3. Declare the following as a global
variable in a unit: </p>
<blockquote>
<p><tt>var</tt> <br>
<tt> EmptyParam: OleVariant;</tt> <br>
<tt>At the end of the unit, put these lines in the initialization section</tt> <br>
<tt>initialization</tt> <br>
<tt> TVarData (EmptyParam).VType := varError;</tt> <br>
<tt> TVarData (EmptyParam).VError := DISP_E_PARAMNOTFOUND;</tt> <br>
<tt>end.</tt></p>
</blockquote>
<p> </p>
<b>
<p>Appendix 2</p>
</b>
<p>How to get the current Word application or else create one, using late binding: </p>
<blockquote>
<p><tt>var</tt> <br>
<tt> wrdApp : OleVariant;</tt> <br>
<tt>begin</tt> <br>
<tt> try</tt> <br>
<tt> wrdApp := GetActiveOLEObject('Word.Application');</tt> <br>
<tt> except on EOleSysError do</tt> <br>
<tt> wrdApp := CreateOLEObject('Word.Application');</tt> <br>
<tt> end;</tt></p>
</blockquote>
<p> </p>
<b>
<p>Appendix 3</p>
</b>
<p><a href="Downloads/Word97_1_5.zip">Download Delphi 4 source and demo</a></p>
<p><a href="Downloads/Word97D3_1_5.zip">Download Delphi 3 source and demo</a></p>
<p><b>Appendix 4</b></p>
<p>Other Word 97 and Delphi resources:</p>
<p><br>
MS Word Articles - <a href="http://www.microsoft.com./WordDev/w-a&sa.htm">http://www.microsoft.com./WordDev/w-a&sa.htm</a>
<br>
Microsoft Office 97 Automation Help File Available on MSL - <a
href="http://support.microsoft.com/support/kb/articles/Q167/2/23.asp">http://support.microsoft.com/support/kb/articles/Q167/2/23.asp</a>
</p>
<p>Three other COM programmers are <a href="mailto:graham.marshall@virgin.net">Graham
Marshall</a>, <a href="mailto:jmilne@softmosis.ca">Joel Milne</a> and <a
href="mailto:bly@castle.net">Binh Ly</a>.<br>
They all know far more about Delphi and COM than I do and frequent the delphi
OleAutomation newsgroup.</p>
<p>Graham Marshall's Delphi /Word / Excel page is <a
href="http://vzone.virgin.net/graham.marshall/default.htm">http://vzone.virgin.net/graham.marshall/default.htm</a></p>
<p>Joel Milne's Delphi / Word page is <a href="http://www.softmosis.ca/WordFAQ.html">http://www.softmosis.ca/WordFAQ.html</a>
</p>
<p>Binh Ly's Delphi / COM page is <a
href="http://www.castle.net/~bly/Programming/Delphi/index.html">http://www.castle.net/~bly/Programming/Delphi/index.html</a></p>
<p><br>
</p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -