Office COM add-ins tend to share common elements. It's safe to say that every add-in will have at least some combination of the more common elements listed and described here. Depending on what functionality your add-in provides, you might even consider these elements basic. The previous chapter also describes examples of common elements, such as setting up and handling events in an Office application when the add-in is loaded.
Every COM add-in must have a programmatic identifier (ProgID). This is a string that uniquely identifies a given COM add-in. A ProgID, which isn't considered something that an end user should see, is a text string without spaces. ProgIDs are unique identifiers for COM add-ins. A COM add-in can have more than one class, and hence, more than one ProgID.
You can set the programmatic identifier, or ProgID, of a COM add-in by changing the project name and the class name. Start Visual Basic 6.0, select ActiveX DLL or ActiveX EXE from the New Project dialog box, and complete the following steps:
If you're not using the Add-in Designer and you have a class module with the IDTExtensibility2 interface implemented, in the Project Explorer window double-click the Class module Class1 to bring it to the front. In the Properties window, set its Name property to any valid string and make sure that its Instancing property is set to 5 - MultiUse.
To create a COM add-in for Office 2000 without using the Add-in Designer, you need the following programs in addition to Office 2000: Visual Basic 5.0 or 6.0 and Microsoft Notepad (or any application like Microsoft WordPad that allows you to create a text file with the extension .txt). The following example summarizes the steps you need to take to create a COM add-in in Visual Basic 6.0 using a .reg file instead of the Add-in Designer. A .reg or REG file is a text file that contains Windows Registry information. The information indicates how you should register the COM add-in for a specific Office 2000 application.
IMPORTANT
If Office attempts to load a registered add-in and the add-in file isn't registered in the Windows system registry, Office automatically removes the add-in's key. Specifically, under the \Office\<app>\AddIns\key, it removes the subkey containing the ProgID of the COM add-in. While debugging your add-in, if you use a REG file rather than the Add-in Designer to register your add-in, you may find its subkey removed. Compile your add-in as a .dll at least once to register your add-in in the Windows system registry. To do this, click Make on the File menu in Visual Basic.
ActiveX DLL
This object library (stored in the file msaddndr.dll) contains the definitions of the IDTExtensibility2 interface, which is what the COM add-in model is centered around and which is described earlier in this chapter in the section "The COM Add-In Model Overview."
Implements IDTExtensibility2 |
This line of code adds a reference to the IDTExtensibility2 object to your project. An interface's methods are exposed through the Implements statement. When you enter the above syntax in the class module, IDTExtensibility2's methods become available through the class module's Procedure and Object drop-down lists, as shown in the illustration below.
The Procedure drop-down list of the class module lists five events for the IDTExtensibility2 object: OnConnection, OnDisconnection, OnStartupComplete, OnBeginShutdown, and OnAddInsUpdate.
MsgBox "Add-in connected" MsgBox "Add-in disconnected" |
The code module should appear as follows:
In Visual Basic, you need to add at least a comment to each procedure in order for your code to compile. In the OnStartupComplete, OnBegin-Shutdown, and OnAddInsUpdate procedures, you add the comment character (an apostrophe) as the one and only line in the procedure.
This step and the previous step set the ProgID of the COM add-in. The ProgID allows you to uniquely identify your COM add-in and distinguish it from others.
File | Filename | Extension |
---|---|---|
Class module | Connect | .cls |
Project | BasicCOMAddIn | .vbp |
The class module that implements the IDTExtensibility2 interface is the center of every COM add-in. It's the place where the add-in gets called when it's loaded and unloaded in an Office application. In the previous steps, you see a message when you connect and disconnect the add-in. The main class module is where most of the common elements of an add-in are connected, such as adding and removing command bar customizations and responding to events that occur in any of the Office applications.
To make a COM add-in work in Office, you need to make sure that two things happen so that the COM add-in is recognized by an Office application as an available add-in. Both involve registration in the Windows Registry. The first is to register the add-in on the end-user's machine so that the system knows where it's located on the machine. The second is to register the add-in under the Office key so an application knows it's available and can be loaded. Once Office knows the add-in's available, it needs to know when it should load it. This is described in the earlier section of this chapter entitled "COM Add-In Registration."
Doing this will register the COM add-in in the Windows system registry. The act of compiling the .dll registers it in the system registry. However, even though the add-in is registered on the machine, it's yet to be registered where an Office 2000 application will know to load it. This is handled in the following steps.
REGEDIT4 [HKEY_CURRENT_USER\Software\Microsoft\Office\ Word\AddIns\BasicCOMAddIn.Connect] "LoadBehavior"=dword:00000003 "FriendlyName"="Microsoft Office Basic COM Add-In" [HKEY_CURRENT_USER\Software\Microsoft\Office\ Excel\AddIns\BasicCOMAddIn.Connect] "LoadBehavior"=dword:00000003 "FriendlyName"="Microsoft Office Basic COM Add-In" |
IMPORTANT
Make sure that for the text you typed above, the two lines [HKEY_CURRENT_USER\Software\Microsoft\Office\Word\AddIns\BasicCOMAddIn.Connect] are actually concatenated on one line with no space in Notepad. For display purposes in this book, the two lines can't be listed as one. The same holds true for the line beginning with Excel\—make sure that it's typed on the same line that ends with Office\.
The following message should appear, indicating that the information in the COMAddin.reg file was successfully entered in the registry. If not, you may have typed something incorrectly in step 2. You can also copy the file COMAddin.reg from the Chapter 14 folder on the CD that comes with this book.
You'll see the message box in front of the Visual Basic window indicating that the add-in is disconnected. In step 2 above, the value on the line that lists the text "LoadBehavior" is 3. This means that the add-in is set to be loaded when the Word or the Excel application is started. (Earlier in the chapter, under the section "COM Add-In Load Behavior Settings," the different load behaviors for a COM add-in are described, as are examples to help you decide what the load behavior for your COM add-in should be.)
In the case of the basic COM add-in described here, the add-in is registered and available on your machine. Once your add-in is fully developed, debugged, and ready to go, the next step is to package it and make its functionality available to other users. The previous chapter describes how to deploy your COM add-in so that you can register and install it on any user's machine. The Package and Deployment Wizard also has an option to package a .reg file and have it executed on the user's machine during setup of the COM add-in.
As Office continues to evolve, consistency among the applications becomes more prominent and lasting. More and more Office functionality, like menus, toolbars, and the Office Assistant, is implemented across the applications. The functionality is written once centrally in a .dll and is loaded into each Office application. COM add-ins allow you to develop functionality that can be loaded in any combination of Office applications, including Microsoft FrontPage 2000. However, there are a few differences among the Office applications, and sometimes you'll have to write code that is application-specific within the shared COM add-in.
To determine what application a shared COM add-in is loaded in, you first retrieve its name. The first argument passed to the OnConnection event procedure in the COM add-in is an instance of the Application object of the Office application where the add-in is loaded. You can retrieve the application's name by accessing the Name property of the Application object. Once you know the application's name, you can use a Select Case statement to distinguish between applications and write application-specific code, as you'll see in the following Select Case statement. Throughout your COM add-in, you'll use a variation of the following Select Case statement when you write application-specific code.
Public HostApp As Object |
You define the generic object variable HostApp as a public-level variable so you can use it throughout any code module. However, you can declare this variable at any level, depending on how you write your code.
Set HostApp = Application |
Because the Set statement is the first line in the OnConnection procedure, the very first thing that happens when the COM add-in is loaded is the assigning of the variable HostApp to the Application object of the Office application loading the COM add-in. The first argument passed into the OnConnection procedure is named Application. The argument is declared as the generic type Object because it could be the application object of any of the Office applications.
Select Case HostApp.Name Case "Microsoft Word" Case "Microsoft Excel" Case "Microsoft PowerPoint" Case "Microsoft Access" Case "Outlook" End Select |
As noted previously, throughout your COM add-in you use variations of the Select Case statement, depending on the differences between applications and how many applications your COM add-in targets; you may not need all the Case expressions listed in this step.
Select Case HostApp.Name Case "Microsoft Word" Debug.Print HostApp.Documents.Count Case "Microsoft Excel" Debug.Print HostApp.Workbooks.Count Case "Microsoft PowerPoint" Debug.Print HostApp.Presentations.Count Case "Microsoft Access" Debug.Print HostApp.CurrentObjectName Case "Outlook" Debug.Print HostApp.ActiveExplorer _ .CurrentFolder.Items.Count End Select |
In step 2 of that section, make sure to add the registry information in the Notepad file for each of the applications listed in the Select Case block in the previous step. To do this, copy the follow-ing registry information in the Notepad file for each Office application. You'll also need to change Word in the following registry information to the name of the Office application. Also remember to concatenate in the Notepad file the first two lines below.
[HKEY_CURRENT_USER\Software\Microsoft\Office\ Word\AddIns\BasicCOMAddIn.Connect] "LoadBehavior"=dword:00000003 "FriendlyName"="Microsoft Office Basic COM Add-In" |
The message box indicating that the add-in is connected will appear in front of the Visual Basic window. After you click OK on the message box, the Immediate window in Visual Basic displays the count of the collection specified in the Select Case block for that application.
Unlike what happens when you write code in the Visual Basic Editor in each of the Office applications, when you type in the dot after the object variable HostApp in the previous steps, you won't see the Auto List Members drop-down list. This is because you declared the object variable HostApp as the generic type Object. Therefore, when you write code, the code editor you're writing in doesn't know which application you're referring to when you hit the dot. You can easily make your code-writing experience take advantage of the Auto List Members drop-down list functionality by declaring more variables that are defined as the application your COM add-in targets.
Microsoft Office 2000 Application | Object Library Name |
---|---|
Office | Microsoft Office 9.0 Object Library |
Word | Microsoft Word 9.0 Object Library |
Excel | Microsoft Excel 9.0 Object Library |
PowerPoint | Microsoft PowerPoint 9.0 Object Library |
Access | Microsoft Access 9.0 Object Library |
Outlook | Microsoft Outlook 9.0 Object Library |
You'll select only the object libraries associated with each of the Office 2000 applications your COM add-in is targeting. The table lists the object library associated with each Office 2000 application. Note that in most cases, you'll also need to reference the shared Office 2000 object library. This object library appears as Microsoft Office 9.0 Object Library in the Available References list.
Public WrdApp As Word.Application Public XclApp As Excel.Application Public PptApp As PowerPoint.Application Public AccApp As Access.Application Public OlkApp As Outlook.Application |
You declare each variable as a specific application object. When you made the reference to each application's object library in the previous step, each application became listed in the Auto List Members drop-down list after you typed the word "As" in each declaration.
Select Case Application.Name Case "Microsoft Word" Set WrdApp = Application Case "Microsoft Excel" Set XclApp = Application Case "Microsoft PowerPoint" Set PptApp = Application Case "Microsoft Access" Set AccApp = Application Case "Outlook" Set OlkApp = Application End Select |
Because the Select Case statement is the first line in the OnConnection procedure, the very first thing that happens when the COM add-in is loaded is the assessment of the name of the application loading the COM add-in. The appropriate object variable is set, depending on the application.
MsgBox WrdApp.Documents.Count |
You'll see the Auto List Members drop-down list when you type in the dot after the variable WrdApp.
When the COM add-in is loaded into an application, only one application object variable declared will be set. All others will continue to be set to Nothing by default. This approach means that if you target your COM add-in for multiple Office applications, Visual Basic will define and make space in memory for object variables that are never used. However, this overhead will be small and insignificant. Now you can take advantage of the benefits of the Auto List Members drop-down list functionality.
To create a demand-loaded COM add-in, you need to set the OnAction property on the CommandBarButton or CommandBarComboBox object. When you click a command bar button, for example, Office parses the string returned by the OnAction property to determine what COM add-in needs to be loaded and to handle the click event. If the syntax of the OnAction string contains a ProgID of a registered COM add-in, the click event is sent to the Click event procedure in the COM add-in. The syntax for the OnAction property string is as follows:
!<Prog.ID> |
In your code that creates a command bar button, the string you assign to the OnAction property would appear similar to the following code:
Set cmdBtn = Application.CommandBars("Help") _ .Controls.Add With cmdBtn .Caption = "&Custom Control" .OnAction = "!<Project1.Connect>" .Tag = "MyControlTag" End With |
Dim HostApp As Object Dim WithEvents cmdBtn As Office.CommandBarButton Const m_sProgId As String = "!<DemandLoad.Connect>" Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, custom() As Variant) Set HostApp = Application Select Case ConnectMode Case ext_cm_Startup AddCmdBarCustomizations Case ext_cm_AfterStartup If Not HostApp.CommandBars.FindControls( _ Tag:="DemandLoadButton1") Is Nothing Then Set cmdBtn = HostApp.CommandBars _ .FindControls(Tag:="DemandLoadButton1") _ .Item(1) Else AddCmdBarCustomizations End If End Select End Sub Private Sub AddinInstance_OnDisconnection( _ ByVal RemoveMode As AddInDesignerObjects _ .ext_DisconnectMode, custom() As Variant) If RemoveMode = ext_dm_UserClosed Then HostApp.CommandBars.FindControls( _ Tag:="DemandLoadButton1").Item(1).Delete End If End Sub Private Sub cmdBtn_Click( _ ByVal Ctrl As Office.CommandBarButton, _ CancelDefault As Boolean) MsgBox "Demand-loaded add-in is now loaded." End Sub Sub AddCmdBarCustomizations() Set cmdBtn = HostApp.CommandBars("Tools") _ .Controls.Add With cmdBtn .Caption = "&Custom Control" .OnAction = m_sProgId .Tag = "DemandLoadButton1" End With End Sub |
IMPORTANT
When you debug a COM add-in in Visual Basic, you'll see a message box or a custom dialog box whose parent is the Visual Basic window. The Office application may appear as if it has stopped. However, if you switch back to the Visual Basic window you'll see the message or custom dialog box.
The OnConnection procedure is the main place where you should add a call to code that inserts command bar customizations like a menu item, toolbar button, or drop-down control. A couple of important things should happen when this code executes. The first is to determine when the add-in is to be loaded. In other words, is the add-in loaded at the startup of the Office application? Or is it to be demand-loaded by a click of a toolbar button or menu item? In each case your code should search to make sure that the customizations exist.
In the OnDisconnection procedure, then, you should add a call to code that removes command bar customizations. However, your code should first determine when the add-in is unloaded. Your code in the OnDisconnection procedure will appear similar to the following (similar also to the code in the previous example):
If RemoveMode = ext_dm_UserClosed Then ' User unloaded add-in through COM ' Add-Ins dialog box. Thus, remove commands. ElseIf RemoveMode = ext_dm_HostShutdown Then ' If your add-in is demand loaded, ' do not remove commands. End If |
The first argument passed to the OnDisconnection procedure is the RemoveMode value. The two common values passed in are ext_dm_HostShutdown or ext_dm_UserClosed. In the previous example, in the section "Create a Demand-Loaded Add-In," you added code that evaluates the RemoveMode value to the OnDisconnection procedure.
Once you register a COM add-in so that it loads when an Office 2000 application starts, your add-in can determine how the Office application starts. Word, Excel, and PowerPoint can be started in one of the following three ways. Outlook and Access can be started in either of the following first two ways.
Developers can use the first value passed into the custom() array in the OnConnection procedure to determine if an application is started by means of Automation. You can use this information, for example, to not display a message box or custom dialog box until the application is made visible. The following example shows how to evaluate the first value of the custom() array passed into the OnConnection procedure and determine how an application is started.
You may have to resize the Add-in Designer window in order to see the Initial Load Behavior drop-down list at the bottom of the General tab.
Select Case custom(1) Case 1 Debug.Print "UI" Case 2 Debug.Print "Embedding" Case 3 Debug.Print "Automation" End Select |
The following steps will work only if the security setting in Word (or Excel or PowerPoint) is set to Low. Before completing the following steps, temporarily set the security setting to Low by clicking Macro on the Tools menu and then Security on the submenu. In the Security Level tab, select Low and click OK.
In Word, Excel, and PowerPoint, when the application is started through an embedded object, any COM add-in that isn't digitally signed with a certificate or the certificate is not added to the trusted sources list won't be loaded at startup. To see the list of trusted sources, click the Trusted Sources tab in the Security dialog box. For more information about security and digitally signing your COM add-in before distribution, see the section "Digitally Sign a COM Add-In" later in this chapter.
Excel is started and the COM add-in is loaded. The OnConnection procedure is called and execution breaks on the first line of the Select Case statement.
Dim appXL As Object Sub StartExcelThroughAutomation() Set appXL = CreateObject("Excel.Application") appXL.Visible = True End Sub |
Excel is started and the COM add-in is loaded. The OnConnection procedure is called and execution breaks on the first line of the Select Case statement.
In Office 97, Word, Excel, PowerPoint, and Access all provide the Run method on the Application object. However, PowerPoint's method is slightly different than the others. In all cases, the Run method doesn't allow you to directly access a class object. The Run method allows you to execute a procedure in another add-in file.
With the COM add-in model, you can use the Object property on the COMAddIn object (defined in the Microsoft Office 9.0 Object Library) to access a public class exposed by a COM add-in. If two COM add-ins are loaded in one Office application, code in the first COM add-in would expose a class to another add-in by setting the Object property in its OnConnection procedure. The code would appear similar to the following:
Private Sub IDTExtensibility2_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, custom() As Variant) ' ' some code AddInInst.Object = MyPublicClass ' End Sub |
Code in the second COM add-in that accesses the public class exposed in the first COM add-in would then use the Object property on the COMAddIn object. The code would appear similar to the following:
Sub AnyProcedure() Dim addinLibrary As Office.COMAddIn Dim objFromFirstAddin As Object Set addinLibrary = HostApp.COMAddIns("Library.ProgID") Set objFromFirstAddin = addinLibrary.Object ' use objFromFirstAddin object to access methods ' and properties exposed by the public class End Sub |
The following example shows how to use this syntax so that one COM add-in can access methods and properties exposed in another.
Public Property Get Name() As String Name = "MyCOMAddin" End Property |
Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, custom() As Variant) AddInInst.Object = New TopLevelObject End Sub |
Dim HostApp As Object Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, custom() As Variant) Set HostApp = Application End Sub Private Sub AddinInstance_OnStartupComplete(custom() As Variant) Debug.Print _ HostApp.COMAddIns("Communicate1.Addin1").Object.Name Debug.Print _ TypeName(HostApp.COMAddIns("Communicate1.Addin1").Object) End Sub |
The code in the OnConnection procedure of Communicate2 sets the public-level HostApp object variable to the Excel Application object. As you continue to step through the code, the OnStartupComplete procedure in the Communicate2 add-in is called.
The code in the OnStartupComplete procedure accesses the COMAddIns collection object through the Excel Application object. The ProgID of the first COM add-in, "Communicate1.Addin1," is used in the index argument of the COMAddIns property to retrieve the COMAddIn object representing the first add-in. The Object property of the COMAddIn object is then used to access the class TopLevelObject.
As you continue to step through the code, the Name property, defined in the TopLevelObject class, is accessed. The Visual Basic window containing the Communicate1 add-in project is activated and the value of the Name property is retrieved. The Visual Basic window containing the Communicate2 add-in project is activated and the value of the Name property is printed to the Immediate window.
Note also that the second line of code in the OnStartupComplete procedure prints to the Immediate window the name of the type of object returned by the Object property. In this case, the string "TopLevelObject" is returned.
Before distributing your COM add-in, you should digitally sign the add-in file. Office 2000 introduces a new security model similar to Microsoft Internet Explorer's default (Low, Medium, High) security settings. You can view the security setting for Word, Excel, and PowerPoint by clicking Macro on the Tools menu and then Security on the submenu.
If the security setting in an Office application is Medium or High, Office requires you to give a digital signature to a COM add-in available before the add-in can be loaded. A digital signature gives Office a way to verify two things: that the contents of a file haven't been altered since it was installed on the user's machine and that the file comes from a responsible source (the author or company that developed and distributed the COM add-in).
To digitally sign your COM add-in, you need a certificate and the file SignCode.exe (along with supporting files) that are part of the Microsoft Platform Software Development Kit. You can buy a certificate from a certificate authority, which is a company that validates your identity and issues you a certificate. The certificate authority not only issues certificates but also manages and revokes them when necessary. Once issued, a unique certificate contains your digital signature and verifies your credentials.