Cindy M -WordMVP- said:
Hi Thomas,
How?
Cindy Meister
OK, the way my situation worked was I had a COM Add-In that was originally
developed for Word 2000 and later. No considerations was given to Word 97 at
the time (3 years ago). The COM Add-In works great on Word 2000/XP/2002.
Well I recently wanted to get rid of the old, much less powerful version of
this system that I wrote eight years ago for Word 6.0, which was still
limping along in Word 97 using WordBasic. We had the much more powerful
version of this system written in VB6 but it used a COM Add-In to connect
with Word. So I added in the few things necessary to make it "connect" with
Word 97.
First, you need a traditional .DOT add-in that is installed in Word's
STARTUP folder. Yes, that is the one big gotcha. As long as you can make
that happen, you can get the rest of this to work. It is fairly easy with a
setup creator like Inno Setup (
www.innosetup.com).
Anyway, within this traditional .DOT add-in, you need a module with code
like this. I've taken out error handling for brevity.
--------------- Code Sample ----------------
Private m_oWord97Helper As MyComAddInProject.Word97Helper
Public Sub AutoExec()
Set m_oWord97Helper = New MyComAddInProject.Word97Helper
m_oWord97Helper.AutoExec Application
End Sub
Public Sub AutoExit()
If Not m_oWord97Helper Is Nothing Then
m_oWord97Helper.AutoExit Application
Set m_oWord97Helper = Nothing
End If
End Sub
--------------- Code Sample ----------------
The Word97Helper object is implemented by your VB6 COM Add-In project, which
I've called "MyComAddInProject". These AutoExec() and AutoExit() macros get
called when Word starts up and shuts down. Note that since we've declared
the variable m_oWord97Helper as the module level, it retains its value as
long a Word is running. That way AutoExec() and AutoExit() are working with
the same Word97Helper object (which is important).
Now in your VB6 project, MyComAddInProject, you will have an Add-In Designer
for Word, just like usual. In the VB6 project, you also implement the
Word97Helper object as a MultiUse object (so the macros can create it). In
the Word97Helper object, you basically have this code (again without error
checking):
--------------- Code Sample ----------------
Private m_oMyComAddInDesigner As AddInDesignerObjects.IDTExtensibility2
Private Enum WordStartupModes
' Found these values out by experimentation
WordStartupNormal = 1
WordStartupEmbedded = 2 ' For example, a Word document embedded in an
Excel spreadsheet
WordStartupAutomation = 3 ' For example, when a VB app uses
CreateObject("Word.Application")
End Enum
Public Sub AutoExec(Application As Object)
' Word passes in a custom array to COM Add-ins whose first element
indicates how Word was started up. We simulate this.
Dim vCustom(1 To 1) As Variant
' In case our .DOT add-in gets loaded by Word 2000 or later, we want
to catch that. If that's the case, Word will load
' us the normal COM Add-In way, so we don't want to do anything
here.
If IsWord97(Application) Then
If m_oMyComAddInDesigner Is Nothing Then
Set m_oMyComAddInDesigner = New
MyComAddInProject.MyComAddInDesigner
vCustom(1) = WordStartupNormal
m_oMyComAddInDesigner.OnConnection Application,
ext_cm_Startup, Nothing, vCustom
vCustom(1) = Empty
m_oMyComAddInDesigner.OnStartupComplete vCustom
End If
End If
End Sub
Public Sub AutoExit(Application As Object)
Dim vCustom(1 To 1) As Variant
If IsWord97(Application) Then
If Not m_oMyComAddInDesigner Is Nothing Then
vCustom(1) = Empty
m_oMyComAddInDesigner.OnBeginShutdown vCustom
m_oMyComAddInDesigner.OnDisconnection ext_dm_HostShutdown,
vCustom
Set m_oMyComAddInDesigner = Nothing
End If
End If
End Sub
Public Function IsWord97(oWord As Object) As Boolean
On Error GoTo ErrorHandler
' As first though, you'd think we would use the Application.Version
of Application.Build
' properties of Word.Application, but they return strings in a goofy
format with
' multiple periods or alphabetic characters. FIX/INT/CINT choke on
those.
' So instead, we simply check for an object that exists starting in
Word 2000. If COMAddIns
' does not exist, then an error will be raised and we know we have
Word 97.
' We use oWord as an Object to make sure we get late binding, so
we'll find out
' at run time if we can get the COMAddIns property.
Dim oCOMAddIns As Object
Set oCOMAddIns = oWord.COMAddIns
IsWord97 = False
Set oCOMAddIns = Nothing
Exit Function
ErrorHandler:
IsWord97 = True
End Function
--------------- Code Sample ----------------
Basically what the Word97Helper object does is PRETEND TO BE WORD 2000! It
creates an instance of your COM Add-In Designer object, just like Word does.
Note that we reference the object using the
AddInDesignerObjects.IDTExtensibility2 interface, which is how Word accesses
it. We have to save the object of course so we can shut it down later. We
then act just like Word, calling the appropriate methods and passing in the
appropriate parameters. Unless your COM Add-In Designer code actually used
the WordStartupMode values, you don't really need to worry about them. My
code did use them. One important thing is that we pass in the Application
parameter to AutoExec() and AutoExit() as an Object, rather than
Word.Application. Things can get goofy depending on what version of the Word
type library your VB6 project references. Those macros in our Word 97 .DOT
add-in expect a Word 97 Application object basically. Better to be safe than
sorry and use Object here.
Now your COM Add-In in your VB6 project should start up just like normal.
Obviously you have to be careful about what objects, methods and parameters
you use in your VB project. Or do version checking to make sure you use the
right ones. It is really best to reference the Word 97 type library, and
then do version checking and put your objects into Object variables if you
need post-Word 97 objects or methods. Check my post under the message "Re:
Run time error 9118 Parameter value was out of acceptable range" under
"microsoft.public.word.vba.general" for details on why this is important.
Two other gotchas: If you need to use custom CommandBarButtons, etc., you
MUST use the .OnAction property set to a macro name. You cannot use the
Click event of the button object (the "normal" way of doing it in Word
2000.) This is because Word 97 does not support the Click event on buttons.
The ONLY way to get your buttons in Word 97 to do anything is to have them
call a macro using the .OnAction property. You could probably use version
checking and then only do one or the other, but what's the bother? Yes I
know macros are the "old way of doing it", but it works just fine.
What you do is, again in your traditional .DOT add-in, include some macros
that your command bar buttons call. Those macros would then call a method in
one of your COM Add-In's object. For example, you could put these macros in
the same module as the AutoExec() and AutoExit() macros, and then have them
call some other methods of the Word97Helper object.
The other important gotcha is distributing your .DLL. Remember, even on Word
97 only systems, when you register your VB6 DLL, it will still register the
COM Add-In. The problem is that the Add-In Designer (msaddndr.dll) MUST be
on the end-user's system when registering the DLL or you will get a
registration error. This is normally not a problem on Word 2000 or later
systems, since the Add-In Designer comes with Word 2000 and later.
Obviously, Word 97 only systems will not have the DLL. So your setup program
must install and register msaddndr.dll in C:\Program Files\Common
Files\Designer. (I read an MS KB article that talked about redistributing
the DLL, so you area allowed to.)
That's about it! I hope that made sense. Any questions, let me know!
-Tom