Share via


Lesson 1: Visio COM Add-in Creation in Visual Basic .NET

Lesson 1: Visio COM Add-in Creation in Visual Basic .NET

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

Download The Lesson 1: Visio COM Add-in sample files are available from the Microsoft Download Center.

Topics in this lesson

Scenario
    About COM Interop and the Visio PIA
Implementation
    Creating the TutorialAddin Project
    Adding a Reference to the Visio PIA
    Specifying a Namespace for the Assembly
    Implementing the IDTExtensibility2 Interface
    Implementing AssemblyInfo.vb
    Deploying the Sample Application
    Running the Sample Application
Summary: COM Interop

Scenario

This lesson describes the basic steps for building a Microsoft® Visio® Component Object Model (COM) add-in built with Microsoft Visual Basic® .NET. The resulting add-in serves as the basis for the Microsoft Visio Managed Code Interop Tutorial sample application, which is developed in the subsequent lessons. This lesson also summarizes the key information learned from implementing a COM add-in in Visual Basic .NET versus Visual Basic 6.0.

To create the COM add-in, we will do the following:
  • Create a COM add-in project called TutorialAddin.
  • Add a reference to the Visio Primary Interop Assembly (PIA).
  • Specify a namespace for the assembly.
  • Implement the IDTExtensibility2 interface.
  • Modify the information in AssemblyInfo.vb.
  • Modify the setup project to register the add-in.

Although there is only a small amount of code in the sample application for the first lesson, a lot happens behind the scenes. When you open Visio, a message box appears so that you know the COM add-in was actually invoked. The message box displays metadata for the Application object using reflection, which is a way of querying an object for its capabilities.

For more information about building COM add-ins for Visio, see the article About Microsoft Visio Add-ons and COM Add-ins in the Microsoft Visio 2002 SDK.

About COM Interop and the Visio PIA

We want to implement our COM add-in as a Microsoft Visual Basic .NET class. However, the .NET world is different from the COM world: components, interfaces, and globally unique identifiers (GUIDs) have given way to assemblies, types, and strong names. How do we travel between COM and .NET?

The answer is COM Interop, which allows unmanaged code to call managed code. Microsoft Windows® programming prior to the Windows .NET Framework made use of unmanaged code. Managed code is code that the common language runtime executes. The common language runtime provides services that help with memory management, cross-language integration, code access security, and automatic lifetime control of objects.

Visio itself is unmanaged code. When Visio loads a COM add-in, it uses standard COM mechanisms, such as performing a registry lookup, creating a class factory to instantiate the COM add-in, and querying for a well-known interface (IDTExtensibility2) to establish communication between Visio and the COM add-in.

COM Interop also allows managed code to call unmanaged code. Such calls happen when a COM add-in, implemented in Visual Basic .NET, makes a Visio Automation call. The add-in does not directly call the Visio type library, but rather calls the Visio PIA.

The Visio PIA is provided as part of the Microsoft Office XP PIAs and allows seamless integration with code written in the Windows .NET Framework and the Visio Automation interface. For information on the known limitations of the Visio PIA, see the Office XP Primary Interop Assemblies Known Issues for Visio known limitations with the PIA.

To the Visual Basic .NET programmer, the Visio PIA appears as a typical .NET assembly. The PIA contains the Microsoft description of Visio types and is signed and authorized for use by Microsoft. Using the Visio PIA prevents type incompatibilities that might be caused by developers using different interop assemblies (such as those generated by using the TlbImp utility).

Implementation

To see the implementation of the sample application for this lesson, open the solution using Microsoft Visual Studio® .NET. You can find the solution, named Lesson1.sln, in the Lesson1 folder. This lesson walks you through the steps used to create the solution.

Creating the TutorialAddin Project

Creating your own Visual Basic .NET COM add-in for Visio is as simple as modifying the TutorialAddin project. Though the project contains all the basics you need to start coding, it is instructive to create the project from scratch to understand what is needed and why.

To create the TutorialAddin project
  1. In Visual Studio .NET, on the File menu, point to New, and then click Project.
  1. In the New Project dialog box, expand Other Projects under Project Types, select Extensibility Projects, and then select the Shared Add-in template.
  1. For Name, type TutorialAddin.
  1. The Location box shows the folder where the TutorialAddin project is located. You can change the folder location directly from the Location box or by clicking the Browse button.
  1. Click the More button to view the Create directory for Solution check box, if it is not currently displayed.
  1. Select the Create directory for Solution check box, and then for New Solution Name, type Lesson1. Click OK.

In the Extensibility Wizard that opens, follow these steps:

  1. Click Next to start the wizard, select Create an Add-in using Visual Basic, and then click Next.
  1. Deselect all of the application host options except Microsoft Visio, and then click Next.
  1. Provide a name and description for the add-in, and then click Next. (Name: Visio Managed Code Interop Tutorial, Description: Sample COM add-in that uses the Visio Primary Interop Assembly.)
  1. On the Choose Add-in Options page, select both options, and then click Next. As a result:
  • The add-in will load when the host application loads.
  • The add-in will be available for all users of the computer on which the add-in is installed.
  1. Click Finish to complete the wizard.

The wizard creates two projects: TutorialAddin and Lesson1Setup. TutorialAddin is the COM add-in implementation. The wizard creates two files within the TutorialAddin project: Connect.vb and AssemblyInfo.vb.

Adding a Reference to the Visio PIA

We need to add a reference to the Visio PIA in order to examine the Visio Application object�s metadata. Although Lesson 1 does not actually make calls to the PIA itself, adding this reference to the Visio PIA will complete a basic implementation that you can use for Visual Basic .NET COM add-ins you create later.

To use the Visio PIA
  1. In the Solution Explorer pane, right-click the TutorialAddin project and choose Add Reference.
  1. Click the COM tab. Locate the Microsoft Visio 2002 Type Library in the component list, and then click Select. Click OK.

In the Properties window, notice that the Path property lists Microsoft.Office.Interop.Visio in the c:\WINDOWS\assembly\GAC\ path. This indicates that the Visio PIA is being used instead of forcing Visual Studio .NET to create its own COM interop assembly in your project's location. The Visio PIA is installed in the global assembly cache (GAC).

Now that we have a reference to the Visio PIA, we can import its namespace in Connect.vb by adding the following code before the Connect class:

      Imports Microsoft.Office.Interop.Visio

Note  The wizard-generated references to the Office, System.Data, and System.XML assemblies are not needed by the COM add-in. You can remove these references by right-clicking the assembly in the Solution Explorer pane, and then clicking Remove.

Specifying a Namespace for the Assembly

It�s a good practice to uniquely identify assemblies by using a namespace. For the assembly that houses our COM add-in, we�ll define a root namespace called Microsoft.Visio.Samples.VBNet.TutorialAddin. We�ll also name the resulting assembly Microsoft.Visio.Samples.VBNet.TutorialAddin.dll.

To specify a namespace and name the assembly
  1. In the Solution Explorer pane, right-click the TutorialAddin project and choose Properties.
  1. Under the Common Properties folder, click General.
  1. Type Microsoft.Visio.Samples.VBNet.TutorialAddin for both Assembly name and Root namespace. Click OK.

Implementing the IDTExtensibility2 Interface

Connect.vb is the most interesting file in this lesson. It provides a default Visual Basic .NET implementation of the IDTExtensibility2 interface, which is the standard mechanism for a Microsoft Office application to communicate with a COM add-in.

The IDTExtensibility2 interface contains five event procedures: OnBeginShutdown, OnAddInsUpdate, OnStartupComplete, OnDisconnection, and OnConnection. Visio gets a reference to the IDTExtensibility2 interface to make calls to the COM add-in. Although classes do the real work in Visual Basic .NET, it is fairly straightforward to implement interfaces by specifying the Implements keyword. The Connect class uses the following code to do this:

  Public Class Connect
       Implements Extensibility.IDTExtensibility2

To see the implementation of the IDTExtensibility2 interface, refer to the Connect.vb file provided in Lesson1.sln. In addition to the interface implementation, you will notice minor differences between this file and the wizard-generated Connect.vb, such as renamed variables.

Using namespaces in the Connect class

We�ve modified the wizard-generated code to explicitly qualify the namespace of the IDTExtensibility2 interface. This is a good coding practice in general for Visual Basic .NET, as it removes any ambiguity regarding type names in situations where it�s possible that two assemblies can contain the same type name (for example, Cell could refer to a Visio cell or to an Excel cell). The wizard-generated code adds a reference to the Extensibility public assembly and imports its namespace with the following declaration:

  Imports Extensibility

The wizard also adds an Imports statement to another namespace we�ll need:

  Imports System.Runtime.InteropServices

The System.Runtime.InteropServices namespace provides classes for managed definitions of COM types. We don�t need to import the Microsoft.Office.Core namespace, so you can remove this line. The TutorialAddin sample application uses the following attributes that will be applied to the Connect class:

  <GuidAttribute("593A7087-5C74-43A8-A1B6-53D943630583"), _
       ProgIdAttribute("TutorialAddin.Connect")> _
  Public Class Connect

When Visio loads the COM add-in, it uses COM conventions to look up the location of the add-in. Defining a GUID and a ProgID are required for COM component registration. Note that the GUID will differ from the preceding example when you run the wizard.

Implementing the OnConnection method

For this lesson we will implement the OnConnection method of the IDTExtensibility2 interface. Visio calls this method after it loads the COM add-in. The OnConnection method has the following signature:

  Public Sub OnConnection( _
       ByVal applicationObject As Object, _
       ByVal connectMode As Extensibility.ext_ConnectMode, _
       ByVal addInInstance As Object, _
       ByRef custom As System.Array) _
       Implements Extensibility.IDTExtensibility2.OnConnection

The sample application only makes use of the first parameter, which is a reference to the application in which the COM add-in is currently running, in this case Visio. Once the add-in obtains this reference, it can use the Visio API and create a new document.

The implementation of OnConnection makes use of the Application object that it receives. The Connect class has the following private member:

  Private visioApplication As Object

The first step to our implementation of OnConnection is to set this member to the reference received from Visio:

  Try
  
       visioApplication = CType(applicationObject, _
           Application)
  
  Catch err As Exception
       MsgBox("Exception in OnConnection: " & _
           err.Message, , ERROR_TITLE)
  End Try

Because the signature for OnConnection is itself generic across all Microsoft Office applications, we get a lowest-common-denominator base-class object. The Visio Application object is a derived type. The common language runtime requires an explicit cast to obtain the derived type.

In the code we perform this cast nested within a Try/Catch block, because it is possible for the cast to fail. Were this to happen, which would be the case if a different Office application were to register the COM add-in, this code would throw an InvalidCastException exception.

Now that we have a reference to the Visio Application object, we can examine this object to see what properties it has:

  Dim typeName As System.Type
  ' Examine the Visio Application object using reflection
  typeName = visioApplication.GetType()
Using reflection to display type information

All managed objects implement the GetType method. GetType returns a Type object, which allows us to discover information about the type. The sample application queries for the AssemblyQualifiedName property, which returns the fully qualified name of the type, including the assembly from which the type was loaded. The following code shows how to format this information for display in a dialog box:

  MsgBox( _
       Replace(typeName.AssemblyQualifiedName(), _
       ", ", vbCrLf), , ERROR_TITLE)

ERROR_TITLE is a string constant, whose definition can be found in the module Shared.vb. For now, this is the only item in the module, but as the sample application is developed in further lessons, the module will provide all the constants and procedures that are shared between the class modules in the project.

Implementing AssemblyInfo.vb

AssemblyInfo.vb, generated by the add-in wizard, contains custom attributes for setting the version resource fields for the TutorialAddin assembly.

For the sample application, we�ll fill in the following attributes:

  <Assembly: AssemblyTitle("Visio Managed Code Interop Tutorial")>
  <Assembly: AssemblyDescription _
       ("Sample COM add-in that uses the Visio Primary Interop Assembly")>
  <Assembly: AssemblyCompany("Microsoft Corporation")>
  <Assembly: AssemblyProduct("Visio Managed Code Interop Tutorial")>
  <Assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation")>
  <Assembly: AssemblyVersion("1.0.0.0")>

You should customize the company and copyright strings for your company. You can view this information in Windows Explorer by right-clicking the TutorialAddin.dll file name (located in the bin folder of the TutorialAddin project after the project is built), and choosing Properties, as shown in the following figure:

Aa158684.Lesson101(en-us,office.10).gif

Figure 1. TutorialAddin.dll Properties dialog box

Deploying the Sample Application

Visual Studio .NET automatically creates a setup project named Lesson1Setup. This project builds a Microsoft Windows Installer setup application, which simplifies deploying the COM add-in to another user�s computer.

The COM add-in project wizard provides a basic setup project. The resulting setup application registers the COM add-in with COM Interop. To modify the setup project to deploy the COM add-in on another user�s computer, we need to make the following changes:

  • Registering the COM add-in with Visio.
  • Installing the assembly in the GAC.
  • Setting properties in the setup project to customize our installer.
Registering the COM add-in with Visio

The COM add-in project wizard generates registry information to register the COM add-in with Visio. Using the wizard-generated setup application, however, will not display the sample add-in in the list of available COM add-ins that are accessible from the Visio Tools menu. We need to move the registry information from the HKEY_LOCAL_MACHINE subtree to the HKEY_CURRENT_USER subtree, as shown in the following procedure:

To register the COM add-in with Visio
  1. In the Solution Explorer pane, right-click the Lesson1Setup project, point to View, and then click Registry. The Registry window opens.
  1. In the Registry window, expand HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER.
  1. Under HKEY_LOCAL_MACHINE\SOFTWARE, right-click Microsoft, and then click Cut.
  1. Under HKEY_CURRENT_USER\SOFTWARE, right-click Microsoft, and then click Paste.

The contents of the registry subtree are as follows:

  [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Visio\Addins\TutorialAddin.Connect]
  "FriendlyName"="Visio Managed Code Interop Tutorial"
  "Description"="Sample COM add-in that uses the Visio
       Primary Interop Assembly"
  "LoadBehavior"=dword:00000003

The COM add-in is identified by a ProgID (TutorialAddin.Connect). This is the ProgID that we defined previously for the Connect class using the ProgIdAttribute attribute.

The LoadBehavior flag represents two values combined to specify this behavior. The value 2 indicates the COM add-in is to be loaded and connected when Visio starts. This value is combined with another value of 1 to specify that after the COM add-in is registered and loaded, it should be in the connected state. Specifying a LoadBehavior value of 3 causes our code to be invoked when Visio loads the COM add-in on startup.

Installing the assembly into the GAC

If you simply build the TutorialAddin project and add the COM add-in registry information for Visio to your computer, the COM add-in loads when you open Visio. However, to deploy the COM add-in to another computer, you need to install the assembly housing the COM add-in into the GAC.

To install an assembly into the GAC, the assembly must have a strong name. This is accomplished by generating a public key to mark the assembly. The COM add-in project wizard generates a key automatically. To enable strong naming, simply add the following line in AssemblyInfo.vb:

  <Assembly: AssemblyKeyFile("..\..\TutorialAddin.snk")>

Now that the assembly has a strong name, we can modify the setup project to install the assembly into the GAC:

To install the assembly into the GAC
  1. In the Solution Explorer pane, right-click the Lesson1Setup project, point to View, and then click File System. The File System window opens.
  1. In the left pane of the File System window, right-click File System on Target Machine, point to Add Special Folder, and click Global Assembly Cache Folder.
  1. Under File System on Target Machine, open the Application folder.
  1. Select the items in the right pane and drag them to the Global Assembly Cache Folder.
  1. In the Solution Explorer pane, right-click Microsoft.Office.Interop.Visio.dll and click Exclude. The assembly is removed from the Global Assembly Cache Folder folder. The only items in this folder should be "Primary output from TutorialAddin (Active)" and Extensibility.dll.
  1. In the Global Assembly Cache Folder, click "Primary output from TutorialAddin (Active)". Verify in the Properties pane that the Register value is set to vsdrpCOM.

Note The setup project assumes that the target computer has the Microsoft Windows .NET Framework and the Visio PIA installed. For more information about installing the.NET Framework Redistributable, see Microsoft .NET Framework Redistributable. For more information on redistributing the Visio PIA, see Working with the Office XP Primary Interop Assemblies. The setup project includes the Extensibility assembly because it is not included with the .NET Framework Redistributable.

Customizing the installer

Selecting the Lesson1Setup project in the Solution Explorer pane displays the project settings in the Properties pane. The following properties have been modified for the setup project:

  • Author
  • Manufacturer
  • ProductName
  • Title

These settings determine the name of the folder where the files are installed and text in the setup dialog boxes.

Deploying the COM add-in

You can now deploy the TutorialAddin sample application.

To deploy the TutorialAddin sample application
  1. In the Solution Explorer pane, right-click the TutorialAddin project, and then click Build.
  1. In the Solution Explorer pane, right-click the Lesson1Setup project, and then click Build.
  1. Run the setup application. The setup application is named Setup.exe and is located under the TutorialAddinSetup folder of your solution, in either the Debug or Release folder, depending on your build settings.

Running the Sample Application

After you�ve deployed the sample application, you run it by opening Visio. You should see the following dialog box.

Aa158684.Lesson102(en-us,office.10).gif

Figure 2. Dialog box shown when you open the sample application in Visio

In addition, TutorialAddin now appears in the list of available Visio COM add-ins. To verify this, on the Visio Tools menu, point to Macros, and then click COM Add-Ins. You will see the following dialog box.

Aa158684.Lesson103(en-us,office.10).gif

Figure 3. List of available COM add-ins in Visio

Visio displays the location of the add-in as mscoree.dll, not TutorialAddin.dll as you might expect. This is because mscoree.dll is the common language runtime, which provides the implementation of COM Interop. The common language runtime is called by COM, and in turn calls the TutorialAddin assembly.

Summary: COM Interop

From this simple starting point, a number of differences are apparent when a COM add-in is implemented in Visual Basic .NET code instead of in Visual Basic 6.0. The following table summarizes these differences.

Implementations of a COM add-in

In the Windows .NET Framework

In COM

Type standard

Binary standard

Assemblies

Type libraries

Type safe

Type unsafe

Object-based

Interface-based

Exceptions

HRESULTs

Strong names

GUIDs

First and foremost, COM is a binary standard. It specifies how an object will appear in memory, establishing a convention to allow components written in one language to talk to components written in a different language. The Windows .NET Framework provides a type standard, and it does so by providing an implementation (the common language runtime). Code that follows this type standard, known as the Common Language Specification (CLS), can take advantage of functionality that the common language runtime provides for "free".

One of the big advantages of using the common language runtime is that the "glue" between code units (components in COM, assemblies in the Windows .NET Framework) is transparent. Application deployment is often as simple as copying the generated assemblies to a directory on a user�s computer. Even though we are using Visual Basic .NET, however, we still need to adhere to COM standards, such as defining a ProgID, to implement our add-in.

But beyond doing some basic housekeeping chores such as registration, we can leave a lot of the dirty work to COM Interop. COM Interop abstracts the inconsistencies between the two models such as:

  • Different data types
  • Method signatures
  • Exceptions/HRESULTs

Building the TutorialAddin project automatically creates a type library (TutorialAddin.tlb), which you can examine by using the OLEView tool. For example, it contains the COM signature for the OnConnection method:

  void OnConnection(
          [in] IDispatch* Application,
          [in] ext_ConnectMode ConnectMode,
          [in] IDispatch* AddInInstance,
          [in] SAFEARRAY(VARIANT)* custom);

This is the method called by Visio when it loads the COM add-in. Here is the same method using .NET types:

  Public Sub OnConnection( _
      ByVal applicationObject As Object, _
      ByVal connectMode As Extensibility.ext_ConnectMode, _
      ByVal addInInstance As Object, _
      ByRef custom As System.Array)

COM Interop marshals the parameters for OnConnection automatically, packing them into a format that can be moved across processes. In the next lesson, we will see how types provided by the Visio PIA are ".NET-like", which makes coding to the PIA in Visual Basic .NET more intuitive.

We can see COM Interop at work in the output of the sample application. Before the Application object is cast, its type is System.__ComObject type. This is a "generic" COM object, which indicates that an IDispatch pointer is being marshaled. Because the interface is generic for all Office applications, we don�t require a more specific type.

Lesson 2: Event Handling will show how to make use of the acquired Application object reference and cast it into a Visio Application object, opening up the entire Visio Automation API for use in our COM add-in.