Link to home
Start Free TrialLog in
Avatar of Pirie
Pirie

asked on

Help with OLE and multiple Word documents

We still have a VB6 application in use. In this application, documents are created in Word for Windows by using an OLE link (Office Automation). The connection is set up with the following code.

2 global variables are declared:

          Global objWdApp As WORD.Application
          Global objWdDoc As WORD.Document

Then the Word object objWdDoc is created for the document that has to be edited:

          Set objWdApp = CreateObject("Word.Application")
          Set objWdDoc = objWdApp.Documents.Open("C:\test\test.doc")

, and the document is activated and made invisible:

          objWdApp.Documents("test.doc").Activate
          objWdApp.Documents("test.doc").Windows(1).Visible = False


The document can then  be generated , for example using code like this:

          objWdApp.Selection.Font.Bold = true
or
          Set myTable = ActiveDocument.Tables.Add(Range:=myRange,…………….
or
          Selection.Borders(wdBorderRight) = true

and so on. This works fine.

However, there is a problem if there are more Word documents open at the time the OLE link is initialized and opened. Using the user interface, the user is able to put the focus on to one of the other Word documents. The OLE commands will then be sent to the document that has the focus, which may not be the one intended. We have solved this by making Word completely invisible so that all other Word documents disappear from view:
       
          objWdApp.Visible = False

This solves the problem, even though it might not be very elegant.

Later, however, we also received a message from one of our customers saying that the same problem also occurs when an email is created in Outlook using a Word module for writing emails. In that situation the focus will be put on the e-mail (it is seen as a Word document) and the OLE commands will be sent to this email! We can make Outlook invisible too, but I am looking for a better solution for this behavior.

Does anyone have an idea how we can manage this problem?

Any help is greatly appreciated!
Avatar of jawa29
jawa29
Flag of United Kingdom of Great Britain and Northern Ireland image

Hi

When using the CreateObject, you should be creating a unique instance of Word. This will run outside of all the other instances.

Now the issue looks to be that in the code where you set the text etc.. is targeting ActiveDocument and not objWdDoc. So as an example
Set myTable = ActiveDocument.Tables.Add(Range:=myRange,…………….

Open in new window

Would be
Set myTable = objWdDoc.Tables.Add(Range:=myRange,…………….

Open in new window


This would then target the file currently open in the instance of Word opened by you app.

Hope this helps
ASKER CERTIFIED SOLUTION
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Pirie
Pirie

ASKER

Thanks for your comments! I go look at your advices and then come up with my response later.
Avatar of Pirie

ASKER

I took the advice to replace ActiveDocument by objWdDoc and implemented it in my application. It improved it already significantly! So thanks for that advice.

 But what I see now is that the cursor in Word is very active (flashing very much) in other open documents as a document is created by my application (which is invisible).

 Besides that I see that my document have not be created properly when I click into another open Word document during the process of creating the document by my application.

 I think it has to do with the use of .Selection and that the use of .Range as you suggest in your answers should be better. But how do I add that way a new paragraph at the end of my document? Now I use: objWdDoc.ActiveWindow.Selection.TypeParagraph. Do I need to count all the paragraphs and use that in combination with Range?
No, you do not need to count.

And TypeParagraph is not the fastest way to go, because it mimics the user typing. Same as ActiveDocument, this is something that is recorded by the macro recorder, so to mimic as close as possible what you do while recording, but it is not the most efficient way to work for most situation.

Everything you find in a document is available through a collection. The same way we worked with the Tables collection in my last post, there is a collection of Words, a collection of Pages, a collection of Paragraphs, Lines, Section, Sentences. If you do not know the concept, a collection is similar to an array in many ways, but it is more versatile with dynamic data such as you have in a Word document.

A collection has a Count property that let's you know how many there are. It also has an Add method that let's you add an element at the end of the collection.

So, to add a paragraph at the end of the document and fill it with text without having to move the cursor around and simulate typing, simply do the following:

objWdDoc.Paragraphs.Add
objWdDoc.Paragraphs(objWdDoc.Paragraphs.Count).Range.Text="Here goes the text that you want to put in the paragraph."

You can also improve on the speed if you have many lines of code that works with the same object by using a With structure. As an example, instead of

objWdDoc.Paragraphs(objWdDoc.Paragraphs.Count).Range.Text="Toto"
objWdDoc.Paragraphs(objWdDoc.Paragraphs.Count).Range.Font.Bold=True
objWdDoc.Paragraphs(objWdDoc.Paragraphs.Count).Range.Font.Bold=Italic

you could write

With objWdDoc.Paragraphs(objWdDoc.Paragraphs.Count).Range
     .Text="Toto"
     .Font.Bold=True
     .Font.Bold=Italic
End With

The difference is negligible if you have only a few lines, but the more dots you have in the reference to an object and the more properties and methods of an object that you use, specially in a loop, the more you gain from using With. You might have seen it in code generated by the macro editor.
Avatar of Pirie

ASKER

Hi James,

Thanks again for your information.

I'm implementing your advices now. One conclusion I can draw is that it will be a lot of work to replace all the code I am using now and to achieve a good result.

If I use
         Set myTable = objWdDoc.Tables.Add(Range:=myRange, NuwRows:=4, NumCols:=3)
then I have to set myRange to a value. What is a good way to set myRange not using Selection or ActiveWindow?
If you know beforehand where you will need to insert the table, you can manually prepare the document with a bookmark at the position where you want to insert the table, and use that bookmark as your range:

 Set myTable = objWdDoc.Tables.Add(Range:=Bookmarks("YourBookmark").Range, NuwRows:=4, NumCols:=3)
Avatar of Pirie

ASKER

Hi James,

After implementing your responses I come more and more to the conclusion that changing my code on these points is not enough and a complete adaptation of the whole concept will be needed! So I think we first need to ask ourselves whether we want this.

Therefore I will close this question for now. If other questions come up later, I will add a new post.

Thanks for your help!