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;
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
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
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;
// 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;
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
_____________________________________________
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
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;
Word := CoWordApplication.Create;
Word.Visible := true;
Word.Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
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;
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
"Rene Heusser" <r.he...@globalscf.com> wrote in message
news:412ae237$1...@newsgroups.borland.com...
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
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
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
StdCtrls, ExtCtrls, Grids, DBGrids, Db, DBTables,
CommonDefs, CoordUtils, Word2000KeyMap, ArrayDefs, Adocomps,
ADODS, Mask, Printers;
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?
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;
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
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.
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;
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
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);
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.
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é