Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Stumped With Word Formatting Problem

107 views
Skip to first unread message

Wayne Herbert

unread,
Aug 5, 2004, 5:56:53 PM8/5/04
to
I've got an automated word doc that is working great. I want to add a
cover page to the document. The problem: The cover page comes out at
the end of the document, not the beginning... same section, but last page.

Before the cover page:

// select document main body
OleVar := 0;
OleVar2 := 0;
Word.ActiveDocument.Range(OleVar, OleVar2).Select;

// **************************************************************
// set up the main body of the page - add columns and styles
// **************************************************************
// set up the columns for full report
if ReportBut.Checked then begin
Word.ActiveDocument.PageSetup.TextColumns.SetCount(NumberColumns);
Word.ActiveDocument.PageSetup.TextColumns.EvenlySpaced := vbTrue;
Word.ActiveDocument.PageSetup.TextColumns.LineBetween := vbFalse;
Word.ActiveDocument.PageSetup.TextColumns.Width := ColumnWidth;
Word.ActiveDocument.PageSetup.TextColumns.Spacing := ColumnSpace;
SetMainBodyParams; // set font, tabs for main document
end
else begin
// a list is only one column wide
Word.ActiveDocument.PageSetup.TextColumns.SetCount(1);
end;
// set up which header to start with (odd or even)
if (StartingPage mod 2) > 0 then begin // starting page is odd
FirstPageOdd := true;
end
else begin
FirstPageOdd := false;
end;

// **************************************************************
// process the records in the database
// **************************************************************
LoadTenAddressRecords; // load the circular buffer to start
while not EndOfRecords do begin
OutputAddressLine;

Now, with the cover page

// select document main body
OleVar := 0;
OleVar2 := 0;
Word.ActiveDocument.Range(OleVar, OleVar2).Select;
// if standard report then print a cover page
if ReportBut.Checked then begin
Word.Selection.ParagraphFormat.Alignment := wdAlignParagraphCenter;
Word.Selection.Font.Size := 16.0;
Word.Selection.TypeParagraph;
Word.Selection.TypeParagraph;
Word.Selection.TypeParagraph;
Word.Selection.TypeText(WideString('Custom Street Index'));
< bunch more lines deleted>
Word.Selection.Font.Size := BodyFontSize;
OleVar := wdPageBreak;
Word.Selection.ParagraphFormat.Alignment := wdAlignParagraphLeft;
Word.Selection.InsertBreak(OleVar);
end; // if standard report

// **************************************************************
// set up the main body of the page - add columns and styles
// **************************************************************
// set up the columns for full report
if ReportBut.Checked then begin
Word.ActiveDocument.PageSetup.TextColumns.SetCount(NumberColumns);
Word.ActiveDocument.PageSetup.TextColumns.EvenlySpaced := vbTrue;
Word.ActiveDocument.PageSetup.TextColumns.LineBetween := vbFalse;
Word.ActiveDocument.PageSetup.TextColumns.Width := ColumnWidth;
Word.ActiveDocument.PageSetup.TextColumns.Spacing := ColumnSpace;
SetMainBodyParams; // set font, tabs for main document
end
else begin
// a list is only one column wide
Word.ActiveDocument.PageSetup.TextColumns.SetCount(1);
end;
// set up which header to start with (odd or even)
if (StartingPage mod 2) > 0 then begin // starting page is odd
FirstPageOdd := true;
end
else begin
FirstPageOdd := false;
end;

// **************************************************************
// process the records in the database
// **************************************************************
LoadTenAddressRecords; // load the circular buffer to start
while not EndOfRecords do begin
OutputAddressLine;

Deborah Pate (TeamB)

unread,
Aug 6, 2004, 6:39:13 AM8/6/04
to
<<Wayne Herbert:

The problem: The cover page comes out at the end of the
document, not the beginning... same section, but last page.
>>

This is going to be because of your range selection when
you insert the page (or following pages, if you do it
first), but I think that happens in the < bunch more lines
deleted>.

Here's an example of inserting a cover page before existing
text. (I use ranges, but the Selection object has the same
methods.)

var
R: Range;
Direction, Break: OleVariant;
..
R := Doc.Content;
R.InsertAfter('This is the rest of the document');
R.Collapse(EmptyParam); // set range to start of doc
Break := wdPageBreak;
R.InsertBreak(Break);
R := Doc.Content;
R.Collapse(EmptyParam); // set range to start of doc
R.InsertAfter('This is the cover page');


--
Deborah Pate (TeamB) http://delphi-jedi.org

TeamB don't see posts sent via Google or ISPs
Use the real Borland server: newsgroups.borland.com
http://www.borland.com/newsgroups/genl_faqs.html


Rene Heusser

unread,
Aug 23, 2004, 10:13:43 AM8/23/04
to d.p...@blueyonder.co.not-this-bit.uk
Dear Deborah

I get directly to you although I know, this is not very much appreciated.
But I have my employer in my neck since I am fiddling for two weeks now
with this bit of Word automation.

All the automation of word and excel I do based on your page, and so far
it works find.
But now I really got stucked and do not find my way out of if.
I have place a question to the forum, but it does not seem to be
interesting to answer...
"Re: Word Find and changing Selection - Maybe once I get an answer"

All I want to do is to find a piece of text and once found select the
whole line and make it bold and then find a double dot : and from there
mark the rest of the line red.

But I simply do not find out to either execute the find in the _document
or to execute the find in the olevariant and the pass the range start
back to the _document or _application.

It would be extremely helpful if I could solve this soon.

Thank you very much for your help.

Kind regards Rene Heusser

Wayne Herbert

unread,
Aug 23, 2004, 11:59:39 AM8/23/04
to
I tested the code below and it works.

var
OleVar : OLEVariant;
OleVar2 : OLEVariant;
FindText :OLEVariant;
MatchCase :OLEVariant;
MatchWholeWord :OLEVariant;
LookForward :OLEVariant;
begin
// start up the application and create a document
Word := CoWordApplication.Create;
Word.Visible := true;
Word.Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
Word.ActiveWindow.View.Type_ := wdNormalView;
// select document main body and collapse selection to the start
Word.ActiveDocument.Select;
OleVar := wdCollapseStart;
Word.Selection.Collapse(OleVar);
// here is the text that I have put in the document
Word.Selection.ParagraphFormat.Alignment := wdAlignParagraphCenter;
Word.Selection.Font.Size := 10.0;
Word.Selection.TypeText(WideString('I am typing some stuff.'));
Word.Selection.TypeParagraph;
Word.Selection.TypeText(WideString('And this is the second line'));
Word.Selection.TypeParagraph;
Word.Selection.TypeText(WideString('We look for findme and make bold.'));
Word.Selection.TypeParagraph;
Word.Selection.TypeText(WideString('Then we type: another line of
text with a colon'));
Word.Selection.TypeParagraph;
Word.Selection.TypeText(WideString('And everything after the colon is
red to end of line.'));
Word.Selection.TypeParagraph;
// select the whole document and find the word 'findme'
Word.ActiveDocument.Select;
FindText := 'findme';
MatchCase := false;
MatchWholeWord := true;
LookForward := true;
Word.Selection.Find.Execute(FindText,MatchCase,MatchWholeWord,
EmptyParam,EmptyParam,EmptyParam,LookForward,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam);
// set the selection to bold
Word.Selection.Font.Bold := vbTrue;
// now reselect the entire document and find the colon
Word.ActiveDocument.Select;
FindText := ':';
Word.Selection.Find.Execute(FindText,MatchCase,MatchWholeWord,
EmptyParam,EmptyParam,EmptyParam,LookForward,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam);
//move past the colon
OleVar := wdCharacter;
OleVar2 := wdMove;
Word.Selection.StartOf(OleVar, OleVar2);
// now extend the selection to the end of the line
OleVar := wdParagraph;
OleVar2 := wdExtend;
Word.Selection.EndOf(OleVar, OleVar2);
// finally set the selection font to red
Word.Selection.Font.Color := wdColorRed;

Wayne Herbert

unread,
Aug 23, 2004, 12:08:00 PM8/23/04
to
I see that you want to make the whole line bold after finding a word.
So the code looks like this:

// select the whole document and find the word 'findme'
Word.ActiveDocument.Select;
FindText := 'findme';
MatchCase := false;
MatchWholeWord := true;
LookForward := true;
Word.Selection.Find.Execute(FindText,MatchCase,MatchWholeWord,
EmptyParam,EmptyParam,EmptyParam,LookForward,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam);

// extend the selection to beginning and end of line.
OleVar := wdline;
OleVar2 := wdExtend;
Word.Selection.StartOf(OleVar, OleVar2);
Word.Selection.EndOf(OleVar, OleVar2);


// set the selection to bold
Word.Selection.Font.Bold := vbTrue;

Rene Heusser

unread,
Aug 23, 2004, 12:19:59 PM8/23/04
to Wayne Herbert
Dear Wayne

Thank you very much, but unfortuately it did not succeed.
I have adapted your code as follows:
********
oFindText := strFind;
oMatchCase := false;
oMatchWholeWord := false;
oForward := true;
m_WordApp.ActiveDocument.Select;
m_WordApp.Selection.Find.ClearFormatting;
m_WordApp.Selection.Find.Execute(oFindText, oMatchCase,
oMatchWholeWord, EmptyParam, EmptyParam, EmptyParam, oForward,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam);
********
And here I get the error message:
EOleException with message "The stub received bad data".
What have I done wrong???

Kind regards
René Heusser

_____________________________________________

Rene Heusser

unread,
Aug 23, 2004, 12:24:46 PM8/23/04
to Wayne Herbert
Dear Wayne

Thank you.
In the meantime I have replied to your first mail.
One Question:
What is the class of your Word Object?

I use the ocx server file Word2000 and declare them as follows:
m_WordApp : _Application;
m_WordDoc : _Document;


Kind regards
René Heusser

Wayne Herbert

unread,
Aug 23, 2004, 12:58:42 PM8/23/04
to
Looks like the same definition but I don't use the document definition
since I create a document in the documents collection and always refer
to it as ActiveDocument.

Word : _Application; // using interfaces

I am using word2000.pas, as modified by me for missing commands (not an
issue here). I am driving Word 2002 on an XP machine (and Win 2K). I
do not have sufficient expertise to tell you why you are receiving a
stub error message.

PS: Why do you issue:

m_WordApp.Selection.Find.ClearFormatting;

Wayne Herbert

unread,
Aug 23, 2004, 1:01:31 PM8/23/04
to
Are you creating the app and document as in

Word := CoWordApplication.Create;
Word.Visible := true;
Word.Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);

Rene Heusser

unread,
Aug 24, 2004, 2:10:24 AM8/24/04
to
Dear Wayne

The reason I issue:
m_WordApp.Selection.Find.ClearFormatting;
is because I have found it once in a forum while searching for a find
solution.

I create the application and document as follows:
if (m_bWordIsRunning = False) then
begin
WResult := GetActiveObject(CLASS_WordApplication, nil, Unknown);
if (WResult = MK_E_UNAVAILABLE) then
begin
m_WordApp := CoWordApplication.Create;
m_bWordIsRunning := True;
end
else
begin
OleCheck(WResult);
OleCheck(Unknown.QueryInterface(_Application, m_WordApp));
m_bWordIsRunning := True;
end;
end;
if (m_bWordIsRunning = True) then
begin
m_WordApp.Visible := True;
m_WordApp.ChangeFileOpenDirectory(
sWorkDir + '\Formats\' + Copy(m_sNameSpace, 7, 3));
m_WordDoc := m_WordApp.Documents.Open(oDocName,
oConfirmConversions, oReadOnly, oAddToRecentFiles,
oPasswordDocument, oPasswordTemplate, oRevert,
oWritePasswordDocument, oWritePasswordTemplate,
oFormat, EmptyParam, EmptyParam);
m_WordApp.Options.CheckSpellingAsYouType := False;
m_WordApp.Options.CheckGrammarAsYouType := False;
...
end if;

Rene Heusser

unread,
Aug 24, 2004, 2:37:45 AM8/24/04
to
Dear Wayne

I was trying your code in a separate project using wordXP, word2000 and
word97.

For word97 it works fine, for the other two I get the stub error.

Kind regards
René

Oliver Townshend

unread,
Aug 24, 2004, 3:47:39 AM8/24/04
to
Then stick to the Word97.pas, it should still run with 2000 & up.

Oliver Townshend

"Rene Heusser" <r.he...@globalscf.com> wrote in message
news:412ae237$1...@newsgroups.borland.com...

Rene Heusser

unread,
Aug 24, 2004, 5:56:10 AM8/24/04
to
Dear Oliver

I did try it with Word97, but then the find does not even find the
findme from Wayne.
So I am back to ...

Kind regards and thanks
René Heusser

Wayne Herbert

unread,
Aug 24, 2004, 11:07:07 AM8/24/04
to
How strange... for lack of any other ideas, what is in your uses clause
besides the usual delphi stuff and your own units? For me I have only
word2000.pas added to the project and found in the uses clause.

Rene Heusser

unread,
Aug 24, 2004, 12:44:24 PM8/24/04
to
Dear Wayne

This is the interface section:

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Db, DBTables, Email, RdWinFax, lAppl, lSt, Registry,
Inifiles, defEmailParser, StringListHolder, Oracle, Word2000,
ActiveX, ComObj;

and the implementation section
implementation
uses lLogUtil, uNotSendIni, fNotSendMain;

Kind regards
René Heusser

Wayne Herbert

unread,
Aug 24, 2004, 1:18:19 PM8/24/04
to
I have no idea if it is the source of your ills but I do not use ActiveX
or ComObj.

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,

StdCtrls, ExtCtrls, Grids, DBGrids, Db, DBTables,
CommonDefs, CoordUtils, Word2000KeyMap, ArrayDefs, Adocomps,
ADODS, Mask, Printers;

Rene Heusser

unread,
Aug 24, 2004, 3:16:44 PM8/24/04
to
Actually I think not. I have taken them both out and removed the code
which requires the two, but the result was the same - Stub received bad
data.

It works if I do it with an OleVariant.
oWordDoc := WordApp.ActiveDocument;
if (oWordDoc.Range(EmptyParam, EmptyParam).Find.Execute(
oFindText, EmptyParam, EmptyParam, oMatchWildCards,
oMatchSoundsLike, EmptyParam, oForward, oWrap,
oFormat, oReplacewith, oReplace, EmptyParam,
EmptyParam, EmptyParam, EmptyParam)
= True) then

But how can I then pass the selection range back to the _application?

Wayne Herbert

unread,
Aug 24, 2004, 6:15:35 PM8/24/04
to
The range or selection is automatically set by the find. So, as an
example, first you write:

WordApp.ActiveDocument.Select;

This makes the selection, of which there can be only one in the
document, the entire document so you are assured of searching all your
text.

Then you say

WordApp.Selection.Range.Find.Execute(blah blah);

This now sets a range object to whatever the find happened to find.
Since in this example the entire active document is the selection, you
could also have written:

WordApp.ActiveDocument.Range.Find.Execute(blah blah);

which is pretty much what you did below. Naturally, this would not work
if you wanted your find to look at a subset of the entire document.

As I noted, you now have a range that is set by the find. So you apply
whatever you want to the range by using it as in.

WordApp.Selection.Range.Font.Color := wdColorRed;

In your code below you have defined a range with a beginning and ending
point defined by EmptyParam. I'm not sure what range you got with all
that... maybe the whole document. If you change it to read

if (oWordDoc.Range.Find.Execute(blah blah)) then

then you can apply whatever you want to oWordDoc.Range as I have shown
above... the range will be the contents of the find. There is nothing
to 'set' per se. The range object is simply available.

Now, if you really wanted the range available in a variable, you can
define a range variable as an olevariant or range, then you can write:

MyRange := oWordDoc.Range.Find.Execute(blah blah);

Then these two statements are equivalent:

MyRange.Font.Color := wdColorRed;
oWordDoc.Range.Font.Color := wdColorRed;

Rene Heusser

unread,
Aug 25, 2004, 12:19:55 PM8/25/04
to
Dear Wayne

Thank you for the explanation, but the thing is when I have found the
word then I need to select the whole line for the further formating.

> MyRange.Font.Color := wdColorRed;
> oWordDoc.Range.Font.Color := wdColorRed;

These commands only format the find range.
So how do I get from the find range to selecting the whole line?

Thank you for your patience

Wayne Herbert

unread,
Aug 25, 2004, 1:50:34 PM8/25/04
to
Rene,

Well, here is the kicker to extending a range to the begining and end of
a line: If you use a selection object, you can move the start and end
of the selection to the beginning and ending of the line (Unit = wdLine).

If you are extending a range object, then this unit of measurement is
not available. You must use wdCharacter, wdWord, wdSentence,
wdParagraph, wdSection, wdStory, wdCell, wdColumn, wdRow, wdTable.

To me, the easy way would be to use selection object to get to the
beginning and ending of a line. Since there can only be one selection
object, one must take care to select all of the document before the
find, else the search will be limited to whatever was last selected.

Using the selection object:

// select the whole doc
WordApp.ActiveDocument.Select;
// now find using the selection just made, and note that if the
// find is successful you now have a new selection.
if (WordApp.Selection.Find.Execute(blah blah) then begin
OleVar := wdLine; // extend units are line
OleVar2 := wdExtend; // want to extend not move selection
// move start of selection to start of line
Word.Selection.StartOf(OleVar, OleVar2);
// move end of selection to end of line
Word.Selection.EndOf(OleVar, OleVar2);
// apply color and bold to font
Word.Selection.Font.Color := wdColorRed;
Word.Selection.Font.Bold := vbTrue; // int defined as -1
end;

If you want to use a range instead of a selection, then you have to get
creative as to what you want to search for in the extend... maybe
paragraph marks if the line is not word wrapped. The code would then
look like:

if (oWordDoc.Range.Find.Execute(blah blah)) then
OleVar := wdParagraph; // extend units are para markers
OleVar2 := wdExtend; // want to extend not move selection
// move start of selection to start of line
oWordDoc.Range.StartOf(OleVar, OleVar2);
// move end of selection to end of line
oWordDoc.Range.EndOf(OleVar, OleVar2);
// apply color and bold to font
oWordDoc.Range.Font.Color := wdColorRed;
oWordDoc.Range.Font.Bold := vbTrue; // int defined as -1
end;

I'd probably opt for the method using the selection object. The only
downside is that you can only have one selection object, so if you
change it with a find or startof or endof command, then you must
remember to change it back to whatever you need it to be, like the whole
document, for doing a find.

This differs from the range object, where you can have multiple ranges,
stored as objects, as in MyRange := oWordDoc.Range.Find.Execute(blah
blah), which can then be referred to without having to redefine the range.

Rene Heusser

unread,
Aug 26, 2004, 2:55:03 AM8/26/04
to
Dear Wayne

It is just to pull out all the hair, which is still left on the head!!!!
But this f..... find simply does not work. Everything else, bold, red,
etc., is fine.
There is something very odd and I need to find out whether this is due
to my machine.
For the time being I have solved it as follows and due to the lack of
performance, I will need to continue researching, but currently I need
to focus on other project work.

I would like to thank you very much for your patience, support and help
and remain

with kind regards
Rene Heusser

Current solution:
function FindInWordDoc(strFind : WideString; bWholeStory: Boolean)
: Boolean;
var
iEnd : Integer;
iLen : Integer;
iCnt : Integer;
oStart : OleVariant;
oLen : OleVariant;
begin
try
if (bWholeStory = True) then
m_WordApp.ActiveDocument.Select;
iLen := Length(Trim(strFind));
oLen := iLen;
iEnd := m_WordApp.Selection.End_;
iEnd := iEnd-iLen;
for iCnt := iEnd downto iEnd-250 do
begin
oStart := iCnt;
m_WordApp.Selection.Start := oStart;
m_WordApp.Selection.End_ := oStart+iLen;
if m_WordApp.Selection.Text = strFind then
begin
Result := True;
Break;
end;
end;
except on E:Exception do
Result := False;
end;
end;

Wayne Herbert

unread,
Aug 26, 2004, 11:12:28 AM8/26/04
to
Rene,

My guess is that the failure is in the selection you are using. I
looked up find help in Word and got the example below. You'll notice
that in the find backward example, they collapse the selection to the
start... perhaps playing with something like this will solve the problem.

Example
This example replaces the next occurrence of the word "hi" in the
selection with "hello."

With Selection.Find
.Forward = True
.Text = "hi"
.ClearFormatting
.Replacement.Text = "hello"
.Execute Replace:=wdReplaceOne
End With
The following example searches backward through the document for the
word "Microsoft." If the word is found, it's automatically selected.

Selection.Collapse Direction:=wdCollapseStart
With Selection.Find
.Forward = False
.ClearFormatting
.MatchWholeWord = True
.MatchCase = False
.Wrap = wdFindContinue
.Execute FindText:="Microsoft"
End With

Deborah Pate (TeamB)

unread,
Aug 28, 2004, 9:22:25 AM8/28/04
to
<<Rene Heusser:

m_WordApp.Selection.Find.Execute(oFindText, oMatchCase,
oMatchWholeWord, EmptyParam, EmptyParam, EmptyParam,
oForward, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam);
>>

The Find.Execute method is buggy in early binding, so it's
better to use late binding and omit all those Emptyparams:

var
S: Olevariant;
..
S := m_WordApp.Selection;
S.Find.Execute(oFindText, oMatchCase, oMatchWholeWord);

Rene Heusser

unread,
Aug 31, 2004, 10:35:01 AM8/31/04
to
Dear Wayne

I have found the reason for all the troubles.
I only needed to reregister the word library and it does the job as
wished from the beginning.

Look up the link below for further explanations:
Word does (it's a bug); it's better to use a variant for Find.Execute
in both Word and Excel.
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q292/7/44.asp&NoWebContent=1

Again thanks for your support and patience.

Wayne Herbert

unread,
Aug 31, 2004, 11:01:09 AM8/31/04
to
Thanks for the heads up Rene... these are the kinds of things that can
drive you nuts. Now if I could just figure out wjy my document displays
differently when the only change is making it visible at the beginning
of the application, versus making it visible at the end.

Rene Heusser

unread,
Sep 6, 2004, 9:17:52 AM9/6/04
to
Dear Wayne

Since I have noticed that the performance impact is dramatic I only make
the applications/documents visible, while debugging. Otherwise I do
everything in the background. This is also better for the rcp server
function, so the user cannot interfere with the process.

But specifically to your issue, I am afraid but I do not have an answer.

Kind regards
René

0 new messages