PDA

View Full Version : VBA Opening and Editing Word document when another is already open



A.T
04-01-2008, 09:56 AM
I have an Access macro which opens a new Word window, opening a pre-created .doc file. It then searches for key strings and replaces them.
This works fine as long as word isn't already open. If I have a seperate document open, the new document opens on top, appears active, but my modifications done in VBA are executed on the first document.

I am using this code to try and 'activate' the document I want, but to no avail:


Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
wrdApp.Activate
Set wrdDoc = wrdApp.Documents.Open("" & GetDBPath() & "MyDocument.doc")
wrdDoc.Activate


Thanks for your help.

TonyJollans
04-01-2008, 12:45 PM
No need to activate anything. You have a reference to your document - just use it.

A.T
04-01-2008, 01:29 PM
That's what I thought, however when I call a selection function such as:


Selection.Find.Execute

It actually executes on the first instance of Word, not the currently open, currently active Word instance which my document is open in.

fumei
04-01-2008, 01:31 PM
Then use:

wrdApp.Selection.Find.Execute


It is good to use fully qualified instructions.

A.T
04-01-2008, 01:46 PM
Then use:

wrdApp.Selection.Find.Execute

It is good to use fully qualified instructions.

That one fixed it, thanks.

fumei
04-01-2008, 02:05 PM
Basically, if you want wrdApp to use Selection...then tell VBA to do exactly that. Selection is an object of the application.

In your case, Selection.Find is NOT the same as wrdApp.Selection.Find

Selection, by itself will be used by Word.

wrdApp.Selection will be used by THAT instance (wrdApp) of Word.

TonyJollans
04-04-2008, 12:13 AM
That's what I thought, however when I call a selection function such as:


Selection.Find.Execute

It actually executes on the first instance of Word, not the currently open, currently active Word instance which my document is open in.
I do not believe that this statement would act on a separate instance of Word - unless you were already holding a reference to it - in which case I wonder why you are creating a new one.

As you have discovered, Gerry was correct to tell you to qualify the reference with the application. I am surprised he did not tell you to use:
wrdDoc.Range.Find but none of use are perfect :-)

The Selection is what is displayed on screen, what the user interacts with. There is a significant overhead in using this when you do not want to interact with the user.

fumei
04-04-2008, 06:30 AM
I did not as I rant on about that far too much, and it was not directly part of the OP question.

But since it is now mentioned....

use wrdDoc.Range.Find

I too have to wonder why you are creating another instance, if you already have one. Word can handle a lot. Unless you have a really serious reason to make another instance, it would be better to simply use the one you already have.

A.T
04-04-2008, 06:40 AM
There is a significant overhead in using this when you do not want to interact with the user.
By 'overhead' do you mean that this will run slowly, as this is what I am finding. If I'm trying to replace multiple pieces of text, it takes about 1 second per replacement, so if I have 18 keywords to replace, it takes 18 seconds.

The code here:


Dim iCount As Integer
For iCount = 1 To 18
wrdApp.Selection.Find.Text = findData(iCount)
wrdApp.Selection.Find.Replacement.Text = replData(iCount)
wrdApp.Selection.Find.Forward = True
wrdApp.Selection.Find.Wrap = wdFindContinue
wrdApp.Selection.Find.Format = False
wrdApp.Selection.Find.MatchCase = True
wrdApp.Selection.Find.MatchWholeWord = False
wrdApp.Selection.Find.MatchWildcards = False
wrdApp.Selection.Find.MatchSoundsLike = False
wrdApp.Selection.Find.MatchAllWordForms = False

wrdApp.Selection.Find.Execute Replace:=wdReplaceAll

Next iCount
Looks in the array findData{} for the search terms and replData{} for the text to replace it with.
This code works fine, but is rather slow.

I tried changing the code to be:



wrdDoc.Select
wrdDoc.Range = Selection.Range

Dim iCount As Integer
For iCount = 1 To 18
wrdDoc.Range.Find.Text = findData(iCount)
wrdDoc.Range.Find.Replacement.Text = replData(iCount)
wrdDoc.Range.Find.Forward = True
wrdDoc.Range.Find.Wrap = wdFindContinue
wrdDoc.Range.Find.Format = False
wrdDoc.Range.Find.MatchCase = True
wrdDoc.Range.Find.MatchWholeWord = False
wrdDoc.Range.Find.MatchWildcards = False
wrdDoc.Range.Find.MatchSoundsLike = False
wrdDoc.Range.Find.MatchAllWordForms = False

wrdDoc.Range.Find.Execute Replace:=wdReplaceAll

Next iCount
However, this doesn't actually change anything. At first I thought that my range wasn't set as the whole document, so I added "wrdDoc.Select
wrdDoc.Range = Selection.Range", hoping that this worked.

In essence, it is slow to replace text and I can't seem to implementwrdDoc.Range.Find correctly.

The interesting thing is that when using the Selection.Find method, when the text is being replaced slowly, if I take focus off the Word application, even by clicking the windows Start button, the text is suddenly replaced quickly.

Rather odd.


EDIT: In relation to the original question, why do I have two instances of Word open? I don't. I only tell my VBA code to open an instance so that I have a handle to the document and application I want. However, say the user is writing a letter to a friend (completely unrelated to the database), and then executes this script; previously, it would edit the first document open, in this case the letter, which I don't want it to, I want it to edit the document I've just opened.
Hopefully that clears up why I have two 'instances' of word open.

fumei
04-04-2008, 02:09 PM
"I only tell my VBA code to open an instance so that I have a handle to the document and application I want."

To repeat, you do NOT need to do that.

Say they are in one document, and execute your code.

Dim wrdDoc As Document
' NOTE! there is NO wrdApp! No other instance.
Set wrdDoc = Documents.Open("" & GetDBPath() & "MyDocument.doc")
There is no need to Activate it. You are creating a Document object, and you can action it directly.

As was mentioned, using Range, rather than Selection, is better. In fact, you do not need to Select anything at all, nor do you need any counters.

IF your arrays - findData() for the search terms and replData() for the replacement text - are equal in number, it does not matter if there are 18 or 231 items in them. If they are not equal, this is another issue.
' assume your arrays are HERE, or
' globals
Dim wrdDoc As Document
Dim r As Range
Dim var
' opens the document as a Document object
Set wrdDoc = Documents.Open("" & GetDBPath() & "MyDocument.doc")
' loop through the array findData
For var = 0 To UBound(findData)
' set range object
Set r = wrdDoc.Range
With r.Find
' text to find is findData(var)
.Text = findData(var)
' text to replace is replData(var)
.Execute Forward:=True, Replacewith:=replData(var), _
Replace:=wdReplaceAll
End With
Next

' Done

' I assume you want to save the document
With wrdDoc
.Save
.Close
End With
set wrdDoc = Nothing


The other document - the one they are working on - is not touched, or affected. Nothing is Selected whatsoever.

I suggest you learn to use With statements.

Again, there is no need for another instance at all. Multiple instances should be avoided, and it is a VERY rare case where they are actually needed. Word can handle multiple files quite well with a single instance.

fumei
04-04-2008, 02:20 PM
" In relation to the original question, why do I have two instances of Word open? I don't."

Yes, you do.

"I want it to edit the document I've just opened."

You can, by using a Document object, which you are, in fact, using with your original posted code. It is simply that you do not need another, new, instance of Word do to this.

A.T
04-05-2008, 02:36 AM
Thanks, fumei, using range calls instead of selection calls is much faster.
Thanks for all your advice and time.

fumei
04-07-2008, 09:36 AM
Oh yes, using Range is generally MUCH faster than Selection, and for good reason.