Creating A COM Add-In In Visual Basic 6
| Introduction To Writing COM Add-Ins And Automation 
	Add-Ins In Visual Basic 6 Beginning in Office 2000, Office programs such as Excel or PowerPoint began support for a new type of add-in called a COM Add-In (or CAI). A CAI is completely different from and independent of standard application add-ins such as an XLA addin. There are several advantages to using a COM Add-In rather than an application add-in such as an XLA file. Peformace: Security: Multiple Application Support: Use Of Additional Components: Callable Functions In A COM Add-In This page will take you step-by-step through the creation of a COM Add-In that supports Excel and PowerPoint 2003. It is assumed that you are familiar with VB6, using event procedures, and creating menu items and command bars with code. Starting A New COM Add-In Project In VB6 The first thing to do to is create the basic framework for the COM Add-In. In this section, we will not use the Add-In project template because not all versions of Office and VB provide that template and its objects. Instead, we'll take a slightly longer method using the IDTExtensibility2 interface. Using the IDTExtensibility2 Interface rather than the project template also allows us to write a single connection class that handles all supported applications. This simplifies the installation of the CAI on the end user's machine. Before you write your first line of code, you need to create the environment for development of the CAI. In VB6, go to the File Menu and choose "New Project" and choose "ActiveX DLL". Remove the Class module that VB creates for you -- we won't be using this. We'll add our own class modules later. In the Properties window, change the name of the project from "Project1" to something meaningful. In this example, we will use "ExampleCAIProject" for the Project name. From the Project menu, choose References, and add the following references to the existing reference list. 
 Of course, your actual path names may be different than those above. This sets up the references to the type libraries for the common Office objects such as CommandBars and for application-specific objects. In the example project, we have references set to the Office, Excel, and PowerPoint object libraries in addition to the standard references used by VB itself. You can download the complete VB6 Project, including the Installer workbook, here. Creating The Connection Class In this example, we will use a single class module to provide the connectivity to all the host applications, such as Excel and PowerPoint. Using a single connection class requires slightly more complicated code, but makes the installation and management of the CAI simpler. All supported applications use the same connection class. Insert a class module to your project, name it ExampleConnect, and include the following code after the Option Explicit declaration. Implements AddInDesignerObjects.IDTExtensibility2 The Instancing property of this class should be 5 - Multiuse. When you implement an interface, you must include all the methods, properties, and events of that interface in your code even if you don't use those them. They must be included in the code. In the VB editor, change the dropdown box at the upper left of the code pane from "(General)" to "IDTExtensibility2". Then select each item in the dropdown box at the upper right of the code pane. Selecting an item in the dropdown list will add its procedure definition to the code pane. All methods must be included even if they are not to be used. There are five methods of IDTExtensibiliy2 that need to be defined. We will be using only two of these methods: IDTExtensibility2_OnConnection and IDTExtensibility2_OnDisconnection. For all the other methods, insert a comment indicating that the event is not being used and to prevent the compiler from stripping out empty procedures. If your CAI is going to be responding to events in from the host application, you'll need to create class modules to handle these events. Create two new class modules and name them CExcelEvents and CPowerPointEvents. These classes should have their Instancing property set to 1 - Private. In the CExcelEvents module, use the following code:     Option Explicit
    Option Compare Text
    Private WithEvents pExcelApp As Excel.Application
    Friend Property Get ExcelApp() As Excel.Application
        Set ExcelApp = pExcelApp
    End Property
    Friend Property Set ExcelApp(XLApp As Excel.Application)
        Set pExcelApp = XLApp
    End Property
    Private Sub Class_Terminate()
        Set pExcelApp = Nothing
    End SubIn this module, define and code for any Excel application events that you want your CAI to handle. The event procedure code you will write in this module is identical to event procedure code that you would write in a VBA project. It is assumed you know how to write event procedures. Use similar code in CPowerPointEvents, making the obvious changes. If your CAI is not going to respond to application events, you may omit these modules. Add a new module to the project named modProjectGlobals. We will store project-wide global variables and constants in this module. In this module, put the following code. If you are not using application Events in your CAI, you may omit the lines of code that refer to the event classes.     Public ThisCAI As Office.COMAddIn
    Public ExcelApp As Excel.Application
    Public PowerPointApp As PowerPoint.Application
    Public ExcelEvents As CExcelEvents
    Public PowerPointEvents As CPowerPointEvents
    Public ExcelControls As CExcelControls
    Public PowerPointControls As CPowerPointControlsThe ThisCAI variable will hold a reference to the CAI object itself, which is passed in as the AddInInst parameter of the OnConnection event. OnConnection is automatically called when the host application (e.g., Excel) loads the add-in. The ExcelApp and PowerPointApp variables are used to store the reference to the host application. We'll create all of the classes soon enough. Now you are ready to add code to the OnConnection event procedure of the ExampleConnect class. In that class, write your OnConnection event as shown below. If you are not using application Events in your CAI, you may omit the lines of code that refer to the event classes.     Private Sub IDTExtensibility2_OnConnection(ByVal Application As Object, _
            ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _
            ByVal AddInInst As Object, custom() As Variant)
    
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' Set ThisCAI to the instance of this COM Add-In.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    Set ThisCAI = AddInInst
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' See if we're connecting to Excel. If so, set up
    ' the appropriate variables.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    If TypeOf Application Is Excel.Application Then
        Set ExcelApp = Application
        Set ExcelEvents = New CExcelEvents
        Set ExcelEvents.ExcelApp = Application
    End If
    
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' See if we're connecting to PowerPoint. If so, set up
    ' the appropriate variables.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    If TypeOf Application Is PowerPoint.Application Then
        Set PowerPointApp = Application
        Set PowerPointEvents = New CPowerPointEvents
        Set PowerPointEvents.PowerPointApp = Application
    End If
    End Sub
 For organizational purposes, you should put the code the declares, creates, and responds to menu items or commandbar controls in a separate class module, one class module for each host application you will be supporting. Create a class module called CExcelControls. The Instancing property of this class should be set to 1 - Private. In the modProjectGlobals module, declare a variable as the CExcelControls type: Public ExcelControls As CExcelControls Now, in your CExcelControls class, first declare a variable that will be set to the Excel Application and variables for the commandbar controls and/or menu items.     Private pExcelApp As Excel.Application
    Private ExcelToolsMenu As Office.CommandBarPopup
    Private WithEvents MenuItem1 As Office.CommandBarButton
    Friend Property Get ExcelApp() As Excel.Application
        Set ExcelApp = pExcelApp
    End Property
    Friend Property Set ExcelApp(XLApp As Excel.Application)
        Set pExcelApp = XLApp
    End PropertyTo enable each control to have its own event handler code, rather than sharing a common event handler for all controls, we will not be using the Tag property of the CommandBarControl. Since the control has no tag value, we can't later use FindControls(Tag:=SomeTag) to get references to our controls for deletion. Therefore, to enable easy deletion of the controls when the CAI is disconnected from the host application, we will store a reference to each control we create in a Collection object. In CExcelControls, declare a Collection to store the control references. Use the Class_Initialize event to create a new Collection and the Class_Terminate event to destroy the Collection.     Private ControlsCollection As Collection
    Private Sub Class_Initialize()
        Set ControlsCollection = New Collection
    End Sub
    Private Sub Class_Terminate()
        Set ControlsCollection = Nothing
    End Sub
Next you need to create functions that will 
	create and delete the controls. In CExcelControls, use    Friend Sub CreateControls()
        Set ExcelToolsMenu = pExcelApp.CommandBars.FindControl(Id:=C_EXCEL_TOOLS_MENU_ID)
        Set MenuItem1 = ExcelToolsMenu.Controls.Add(Type:=msoControlButton, temporary:=True)
        With MenuItem1
           .Caption = "Click Me #1"
        End With
        ControlsCollection.Add Item:=MenuItem1
        ' Repeat the code above for each menu item or commandbar control you need to add.
        ' Be sure to add each control to the ControlsCollection object. 
    End Sub
    Friend Sub DeleteControls()
       Dim Ctrl As Office.CommandBarControl
       For Each Ctrl In ControlsCollection
           Ctrl.Delete
       Next Ctrl
    End Sub
where C_EXCEL_TOOLS_MENU_ID is a constant declared in modProjectGlobals with a value of 30007 (also create a constant named C_POWERPOINT_TOOLS_MENU_ID with the same value). In modProjectGlobals, declare the constants:     Public Const C_EXCEL_TOOLS_MENU_ID As Long = 30007
    Public Const C_EXCEL_POWERPOINT_MENU_ID As Long = 30007Finally, add the event handler code in the class CExcelControls for the control(s) created in CreateControls. The following is the procedure for the Click event of the menu item we added in CreateControls. Add the appropriate event procedures for all the controls you created.     Private Sub MenuItem1_Click(ByVal Ctrl As Office.CommandBarButton, _
            CancelDefault As Boolean)
        MsgBox Ctrl.Caption
    End SubThe CExcelControls class is now complete. For PowerPoint, you can use the identical code in a class name CPowerPointControls, just changing any reference from Excel to PowerPoint. Change the variable names appropriately. Of course, you do not need to have the same menu structure in PowerPoint as you do in Excel (or any other host application you are supporting). The CExcelControls class and the CPowerPointControls class are completely independent of one another, and because of the way the OnConnection code is structured (see below), either, but not both, CExcelControls or CPowerPointControls will be instantiated at any one time (per host application -- you can certainly have the CAI open simultaneously in both PowerPoint and Excel, and you don't have to worry about variables overwriting one another). Now we have to add code in the OnConnection event of the ExampleConnect class to create an instance of CExcelControls and create the controls. Your OnConnection event in ExampleConnect should now look like the following:     Private Sub IDTExtensibility2_OnConnection(ByVal Application As Object, _
            ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _
            ByVal AddInInst As Object, custom() As Variant)
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' Set ThisCAI to the instance of this COM Add-In.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    Set ThisCAI = AddInInst
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' See if we're connecting to Excel. If so, set up
    ' the appropriate variables.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    If TypeOf Application Is Excel.Application Then
        Set ExcelApp = Application
        Set ExcelEvents = New CExcelEvents
        Set ExcelEvents.ExcelApp = Application
        Set ExcelControls = New CExcelControls
        Set ExcelControls.ExcelApp = Application
        ExcelControls.CreateControls
    End If
    
    '''''''''''''''''''''''''''''''''''''''''''''''''
    ' See if we're connecting to PowerPoint. If so, set up
    ' the appropriate variables.
    '''''''''''''''''''''''''''''''''''''''''''''''''
    If TypeOf Application Is PowerPoint.Application Then
        Set PowerPointApp = Application
        Set PowerPointEvents = New CPowerPointEvents
        Set PowerPointEvents.PowerPointApp = Application
        Set PowerPointControls = New CPowerPointControls
        Set PowerPointControls.PowerPointApp = Application
        PowerPointControls.CreateControls
    End If
    
    End SubFinally, we need to delete our controls when the CAI is disconnected from its host application. Write your OnDisconnection event as shown below:     Private Sub IDTExtensibility2_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, _
        custom() As Variant)
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' IDTExtensibility2_OnDisconnection
    ' This executes when the COM Add-In is unloaded by the host application.
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
    ''''''''''''''''''''''''''''''''
    ' Clean up Excel
    ''''''''''''''''''''''''''''''''
    If Not ExcelApp Is Nothing Then
        '''''''''''''''''''''''''''''''''
        ' Set ALL Excel object to Nothing.
        ' Otherwise they can cause the
        ' Excel process to continue to
        ' run in the background even
        ' after it appears to be closed.
        '''''''''''''''''''''''''''''''''
        Set ExcelEvents.ExcelApp = Nothing
        Set ExcelEvents = Nothing
        ExcelControls.DeleteControls
        Set ExcelControls = Nothing
        Set ExcelApp = Nothing
    End If
    
    ''''''''''''''''''''''''''''''''
    ' Clean up PowerPoint
    ''''''''''''''''''''''''''''''''
    If Not PowerPointApp Is Nothing Then
        '''''''''''''''''''''''''''''''''
        ' Set ALL PowerPoint object to Nothing.
        ' Otherwise they can cause the
        ' Excel process to continue to
        ' run in the background even
        ' after it appears to be closed.
        '''''''''''''''''''''''''''''''''
        Set PowerPointEvents.PowerPointApp = Nothing
        Set PowerPointEvents = Nothing
        PowerPointControls.DeleteControls
        Set PowerPointControls = Nothing
        Set PowerPointApp = Nothing
    End If
    
    Set ThisCAI = Nothing
    
    End SubCreating Callable Functions For Excel COM Add-Ins (Automation Add-Ins) 
	     Function DoubleIt(D As Double) As Double
    '''''''''''''''''''''''''''''''''''''''''''''
    ' DoubleIt
    ' This is an example function that simply
    ' doubles the input and returns the result.
    '''''''''''''''''''''''''''''''''''''''''''''
    DoubleIt = D * 2
    End FunctionThen, in Excel, go to the Tools menu, choose Add-Ins (not COM Add-Ins), and click the Automation button. In the list that is displayed, find your VB6 project name followed by "ExcelFunctions" (or whatever class name you used) and click it. It will appear in the Add-Ins list. Once that is loaded, you can call functions in the ExcelFunctions class as if they were native Excel functions. In this example project, you would select ExampleCAIProject.ExampleConnect from the Automation Add-Ins list. Then you can call DoubleIt with the the following formula: =DOUBLEIT(1234) Remember that a function, in VBA, an XLA add-in, or in an Automation Add-In, can not change any aspect of the Excel environment, including changing the value of a cell. Functions in Automation Add-Ins are no different than functions written in VBA. They can only return a value to the cell from which they are called. 
 To call the functions in your COM Add-In from other VBA procedure, rather than directly from the worksheet cell, see Calling Automation Add-In Functions In VBA on the Automation Add-Ins page. 
 Once you have created your CAI, you need to install it. Installation and startup and shutdown code requires modifying the System Registry. I have written a code module that works in both VBA and VB6 to handle the details of adding, modifying, and deleting registry keys and values. I strongly encourage you see the Functions For Working With The System Registry page, and that you download the modRegistry.bas module file and add it to your VB Project. We will be using the procedures in that file on this page to create, read, and write registry keys and values. Automating The Installation With The 
	COM Add-In Installer Workbook You can download the COM Add-In Installer here. The COM Add-In Installer requires the TypeLib Information DLL file, which is included in the zip file. If you already have this component installed on your machine, the workbook will function normally. If you do not have this component installed on your machine, you will receive compiler errors, "User-defined type not defined.". In this case, copy the file TLBINF32.DLL to your "C:\Windows\System32" folder, close Excel, go to the Windows Start menu, choose Run, and enter the following and click OK: RegSvr32 "C:\Windows\System32\TBLINF32.DLL" Then, open this workbook, go into VBA, go to the Tools menu, choose References, and scroll down to and check "TypeLib Information". Once this reference is established, the workbook should work fine. This library is used to retrieve the available ProgIDs of available objects in the DLL file. See the TLBINF32 Read Me.txt file in the downloadable zip project for more information about installing the TLBINF32.DLL file. 
 Registering The DLL With Windows RegSvr32 "C:\YourFolder\ExampleAddIn.dll" If you use the automated COM Add-In Installer Workbook to install your CAI, you may omit this step. The Installer does this for you. Registry Keys Then, within this key, create the following values: 
 You must now decide whether to create this same key and values in the HKEY_LOCAL_MACHINE section of the Registry. If you include this in the HKEY_LOCAL_MACHINE section of the Registry, the host application will not display this CAI in the COM Add-Ins dialog box, and the CAI cannot be loaded or unloaded by the user (without the use of VBA code). This is done to prevent one user from changing settings used by all users. However, it will make the CAI available to all users of the computer. If you do not include this key and its values in the HKEY_LOCAL_MACHINE section, the you will have to install the CAI for each user of the machine. You can download the complete VB6 Project, including the Installer workbook, here. Debugging Your COM Add-In Once you've written your CAI, you'll need to be able to debug it to find potential problems as you've added additional functionality beyond the very limited functionality presented in this example CAI. To debug your CAI, open the project in VB6. Place breakpoints (F9) at the appropriate locations, such as in the OnConnection event procedure, or wherever in your code you need to debug. Next, press CTRL+F5 to start your DLL in debug mode with a full compile. Then open the host application. VB6 will automatically redirect the host application's reference from the compiled DLL file to the project you have in debug mode. When code execution encounters one of your breakpoints, execution will pause and you will have all the VB6 debugging tools at your disposal, such as breakpoints, watches, the Immediate Window, and so on. It is assumed you are familiar with debugging code. The procedures and tools for debugging VB6 code are the same as those in VBA. See the Debugging VBA page for more details. The COM Add-In Dialog To manage COM Add-Ins, you need to be able to access the COM Add-Ins 
	dialog box, shown below on the left. In the default Excel menu and 
	commandbar configuration, there is not item to display this dialog. You 
	should add the COM Add-Ins menu item to your Tools menu.
	Click here for instructions. | |||||||||||||||||||||||
|  | Note that only add-ins configured for the current user are displayed in the dialog (those add-in that have a key in the HKEY_CURRENT_USER section of the registry and do not have an item in the HKEY_LOCAL_MACHINE section of the registry). Add ins that are configured for all users (add-ins with a key in HKEY_LOCAL_MACHINE) are not listed in the dialog. This is done to prevent one user from changing the settings that affect all users of a machine. | ||||||||||||||||||||||