Visio Libraries

A Microsoft® Visio® library (VSL) is a special dynamic-link library (DLL) that is loaded by the Visio engine at run time. A VSL can implement one or more Visio add-ons, which are programs that use Automation to control Visio instances.

An add-on implemented by a VSL can interact with Visio objects in exactly the same fashion as an add-on implemented by an executable (EXE) file or code in a document's Microsoft® Visual Basic® for Applications (VBA) project, and a user can do exactly the same things. An add-on implemented in a VSL has performance and integration advantages over one implemented in an executable program—one reason being that a VSL runs in the same process as the Visio instance. You cannot, however, run a VSL from Windows Explorer as you can an executable program.

Visio recognizes any file with a .vsl extension in the Add-ons or Start-up path (Options dialog box) as a VSL. To install a VSL, copy the file to one of the folders specified in the Visio Add-ons or Start-up path. The next time you run a Visio instance, the add-ons implemented by that VSL are available to the instance.

The files you'll need to develop a VSL are provided in the Libraries, Samples, and Wizards folders installed with the Microsoft Visio 2002 SDK.

  • The \Libraries\CPP folder contains Source and Include files that provide a foundation for Visio add-ons.
  • The \Samples\CPP folder contains sample C++ projects that you can use as a base for writing your own Visio add-ons.
  • The Wizards folder contains Microsoft® Visual Studio® wizards that generate Visio add-on projects. The accompanying Readme*.htm files specify how to use the wizards and recommend useful build and project settings.

In this section...

Advantages of Visio Libraries

The Architecture of a Visio Library

Declaring and Registering Add-ons

Running an Add-on

Advantages of Visio Libraries

All else being equal, a VSL runs faster than an executable program. Because a VSL is a DLL, it is loaded into the process space of the Visio instance that is using the library. Calls from a VSL to a Visio instance do not cross a process boundary, as is the case when an executable program calls a Visio instance.

In addition, because a VSL runs in the same process as a Visio instance, it is much easier for it to open a dialog box that is modal to the process in which the Visio instance is running. When two executable files (an add-on and a Visio instance) are running, it is difficult for one to display a dialog box that is modal with respect to the other. An add-on executable program can display a dialog box, but the user can click the Visio window and change the Visio state while the dialog box is open.

It's also easier to add solution-defined windows as child windows of Visio windows using the Add method of a Windows collection. To do this, create an HWND and use the WindowHandle32 from the window added with Windows.Add as the parent HWND. Using HWNDs from different processes as parent windows doesn't work well, except in in-place containment scenarios.


The Architecture of a Visio Library

A VSL is a standard DLL that exports a required entry point with the prescribed name VisioLibMain.

A Visio instance loads a VSL using LoadLibrary and frees it using FreeLibrary. Unless your VSL is installed in a Visio Startup folder, your code shouldn't assume when the VSL will get loaded. A Visio instance loads non-startup VSLs only when it needs to do so. If a Visio instance does load a VSL, it does not call FreeLibrary on the VSL until the instance shuts down.

The file VDLLmain.c provides a default implementation for DllMain, which is the standard DLL entry point that Windows calls when it loads and unloads a DLL. The file Vao.c implements several other functions that you might find useful; some of these are mentioned in the paragraphs that follow.

Once a Visio instance has loaded a VSL, the instance makes occasional calls to the VSL's VisioLibMain procedure. One of the arguments the Visio instance passes to VisioLibMain is a message code that tells the VSL why it is being called. All Visio messages are defined in Vao.h.

The prescribed prototype for VisioLibMain can be found in Vao.h:

typedef WORD VAORC, FAR* LPVAORC; typedef WORD VAOMSG, FAR* LPVAOMSG; #define VAOCB __cdecl

//Visio add-on return code //Visio add-on message code //Visio add-on callback procedure

//The prototype of VisioLibMain should conform to VAOFUNC typedef VAORC (VAOCB VAOFUNC) (VAOMSG,WORD,LPVOID);

A typical VisioLibMain will look something like the following:

#include "vao.h" VAORC VAOCB VisioLibMain (VAOMSG wMsg, WORD wParam, LPVOID lpParam)     {     VAORC result = VAORC_SUCCESS;     switch (wMsg)         {         case V2LMSG_ENUMADDONS:             //Code to register this VSL's add-ons goes here             break;         case V2LMSG_RUN:             //Code to run add-on with ordinal wParam goes here             break;         default:             //Trigger generic response to wMsg             //Helper procedures VAOUtil_DefVisMainProc and VLIBUTL_hModule             //are implemented in vao.c             result = VAOUtil_DefVisMainProc(wMsg, wParam, lpParam, VLIBUTL_hModule());             break;         };     return result;     }

This VisioLibMain specifically handles the V2LMSG_RUN and V2LMSG_ENUMADDONS messages. Other messages are deferred to VAOUtil_DefVisMainProc, a function that implements generic message responses. VLIBUTL_hModule evaluates to the module handle of the VSL.


Declaring and Registering Add-ons

When an instance sends the V2LMSG_ENUMADDONS message to a VSL's VisioLibMain, it is asking for descriptions of the add-ons implemented by the VSL.

The file Lib.c implements a sample VSL. In it, you can see source code demonstrating how a VSL registers add-ons. Two aspects are involved:

  • Lib.c defines a data structure describing its add-ons.
  • In response to the V2LMSG_ENUMADDONS message, Lib.c passes this data structure to the Visio instance that sent the message.

Lib.c implements one add-on. Near the top of the file is the following code:

#define DEMO_ADDON_ORDINAL 1 PRIVATE VAOREGSTRUCT stc_myAddons[] = {    


//Ordinal of this add-on //This add-on does things to Visio //This add-on is always enabled //Invoke on mask //Reserved for future use //The name of this add-on


The VAOREGSTRUCT structure is declared in Vao.h. You'll find comments and declarations there that give more information on the various fields in the structure.

When a Visio instance tells a VSL to run an add-on, it identifies which add-on by specifying the add-on's ordinal, a unique value that identifies the add-on within the file. The stc_myAddons array declares one add-on whose ordinal is 1 (DEMO_ADDON_ORDINAL). If Lib.c implemented two add-ons instead of one, stc_myAddons would have two entries instead of one, and each entry would designate a unique ordinal.

The declared add-on is presented in the Visio user interface as "VSL Automation Demo." If you intend to localize your add-on, you wouldn't declare its name in the code as is shown here. Rather, you'd read the name from a string resource and dynamically initialize the VAOREGSTRUCT.

VAO_ENABLEALWAYS tells the Visio instance that this add-on should be considered enabled at all times. Other enabling policies can be declared. There are many add-ons, for example, that it makes sense to run only when a document is open. Such add-ons can declare an enabling policy of VAO_NEEDSDOC. A Visio instance makes such add-ons unavailable when no documents are open. When such an add-on is run, it can assert that a document is open. Several static enabling policies similar to VAO_NEEDSDOC are declared in Vao.h.

Vao.h also contains a policy called VAO_ENABLEDYNAMIC. When a Visio instance wants to determine whether the add-on is enabled, it sends V2LMSG_ISAOENABLED to a dynamically enabled add-on. The add-on can claim to be enabled or disabled based on its own criteria.

The last aspect of VAOREGSTRUCT involves making an add-on run automatically when a Visio instance starts. To make an add-on implemented by an executable program run on startup, you simply place the executable file in one of the folders specified by the Visio StartupPaths setting.

For add-ons implemented in a VSL, those to be run on startup must also specify VAO_INVOKE_LAUNCH in the invokeOnMask member of their VAOREGSTRUCT. This constant allows a single VSL file to implement some add-ons that run automatically when a Visio instance launches, and some that don't.

By itself, VAOREGSTRUCT is just a data structure that doesn't tell a Visio instance anything. When a Visio instance sends V2LMSG_ENUMADDONS to a VSL, the library should respond by passing the Visio instance a pointer to the array of VAOREGSTRUCTs, discussed previously, so that the data they contain is available to the Visio instance. To do this, Lib.c makes use of a utility implemented in Vao.c. The code is as follows:

result = VAOUtil_RegisterAddons(         ((LPVAOV2LSTRUCT)lpParam)->wSessID,         stc_myAddons,         sizeof(stc_myAddons)/sizeof(VAOREGSTRUCT));

For details about what this code does, look at the source code in Vao.c.


Running an Add-on

A Visio instance sends V2LMSG_RUN to a VSL when the VSL is to run one of its add-ons. The ordinal of the add-on to run is passed in the wParam parameter.

The Visio instance sends V2LMSG_RUN only if it has determined that the designated add-on is enabled, according to the enabling policy declared in the add-on's registration structure. If the add-on's enabling policy is VAO_ENABLEDYNAMIC, the VSL will already have responded with VAORC_L2V_ENABLED to the V2LMSG_ISAOENABLED message it received from the Visio instance.

In addition to the ordinal of the add-on to run, the Visio instance passes a pointer to a VAOV2LSTRUCT structure with the V2LMSG_RUN message. VAOV2LSTRUCT is defined as follows in the Vao.h file:



HVisInst; lpfunc; wSessID; lpArgs; lpCmdLineArgs;

//Handle of running Visio instance //Callback address in Visio //ID of session //Reserved for future use //Command line arguments


This structure gives the instance handle of the Visio instance sending the message, which is sometimes useful. (The lpfunc and lpArgs members are used by other functions in Vao.c.) In the lpCmdLineArgs member, the Visio instance passes an argument string to the add-on. This is the same string that the Visio instance would pass to an analogous add-on implemented as an executable program.

You'll sometimes be interested in the wSessID member, which is the ID the Visio instance has assigned to the "session" it associated with the V2LMSG_RUN it just sent. For example, you might use wSessID if your add-on initiates a modeless activity (an activity that doesn't terminate when the add-on returns control to the Visio instance).

Most add-ons will perform a modal action in response to V2LMSG_RUN: They receive the message, do something, and then return control to the Visio instance. Unless the add-on says otherwise, the Visio instance considers the session finished when it regains control from the add-on.

Pseudocode for this typical case would be:

case V2LMSG_RUN:
*    wParam is ordinal of add-on to run.*
*    Execute code to do whatever it is the add-on with ordinal wParam does.*
*        This will probably involve instantiating Visio objects and invoking methods and*
*        properties of those objects. You can use the C++ support services discussed in the*
*        previous section just as if this code were in an EXE file.*
*    if (operation was successful)*
*        return VAORC_SUCCESS;*
*    else*
*        return VAORC_XXX;    // See vao.h*

Sometimes, in response to V2LMSG_RUN, an add-on may initiate an activity that doesn't terminate when the add-on returns control to the Visio instance. (Such activities are called modeless.) An add-on may, for example, open a window that will stay open indefinitely.

If your add-on implements a modeless activity, it should remember the session ID passed with V2LMSG_RUN. Pseudocode for such an add-on would be:

case V2LMSG_RUN:
*    wParam is ordinal of add-on to run.*
*    Execute code to initiate modeless activity.*
*        For example, open a window and stash its handle.*
*    if (operation was successful)*
*        {*
*        stash lParam->wSessID where it can be looked up later.*
*        return VAORC_L2V_MODELESS;*
*        }*
*    else*
*        return VAORC_XXX;     // See vao.h*

Note the return value of VAORC_L2V_MODELESS. This tells the Visio instance that the session still persists, even though the VSL has completed handling the V2LMSG_RUN message.

A modeless session initiated in this fashion persists until either the VSL ends the session or the Visio instance associated with the session terminates.

If the VSL ends the session (for example, perhaps the window it opened has been closed), it does so with the VAOUtil_SendEndSession function. The parameter wSessID contains the ID of the terminating session:

VAOUtil_SendEndSession(wSessID);    //wSessID: ID of terminating session

When the Visio instance terminates, it sends V2LMSG_KILLSESSION to all extant sessions. With V2LMSG_KILLSESSION, the Visio instance passes a VAOV2LSTRUCT structure whose wSessID member identifies the ID of the session to terminate. The VSL should respond by terminating and cleaning up after the identified session.