3 4
The Automation interfaces on Microsoft Visio objects are defined in Visio.h, which is in \Libraries\C-CPP\Vao.inc on the Developing Microsoft Visio Solutions CD. This file contains a standard COM interface definition for each Visio object. To control a Visio instance through Automation from a C++ program, include Visio.h in your project source files.
Microsoft Visio also provides services in the form of wrapper classes that simplify programming Visio using C++. A wrapper class is so called because it encapsulates, or "wraps" the code involved in certain tasks, such as getting and releasing interface pointers and working with strings. The basic benefit of using these classes is that they keep track of AddRef and Release calls for you, using C++ constructors, destructors, and assignment operators. When appropriate, these wrapper classes also automatically wrap any arguments or return values with a wrapper class.
In addition to the files you'll use in your programs, the C-CPP folder on the Developing Microsoft Visio Solutions CD contains sample projects that illustrate the use of wrapper classes and event sinks. The Readme.txt file in the C-CPP folder gives more details on its contents and instructions on how to build the sample projects. You might find it helpful to study these projects before developing your own programs.
To use the wrapper classes, include Visiwrap.h in your project source files. This file is provided with Visio in the \Libraries\C-CPP\Vao_inc folder on the Developing Microsoft Visio Solutions CD. If you include Visiwrap.h, you do not need to include Visio.h explicitly, because Visiwrap.h includes it for you. The wrapper classes observe the following conventions:
A program that uses the Visio wrapper classes might include a code fragment similar to the following example. This program, from the sample Generic.cpp, creates a new document based on Sample.vst, drops two masters, and connects them. The function vaoGetObjectWrap, defined in Visiwrap.h, gets the Visio instance if one is running and, if not, runs an instance. For conciseness, error handling has been omitted.
This example also uses the helper classes VBstr and VVariant, which are defined in Helpers.h.
HRESULT hr= NOERROR; CVisioApplicationapp; CVisioDocuments docs; CVisioDocument doc; CVisioPagespages; CVisioPage page; CVisioShapeshape; CVisioShapeshape1; CVisioMasters masters; CVisioMaster master; CVisioDocument stencil; CVisioCell cell; CVisioCell cell1; ... if (VAO_SUCCESS != vaoGetObjectWrap(app)) //Error handling goto CU; ... //Add a new document based on "sample.vst" //and get the drawing page hr= app.Documents(docs); //VBstr is the helper class for type BSTR hr= docs.Add(VBstr("sample.vst"), doc); hr= doc.Pages(pages); //VVariant is the helper class for type VARIANT hr= pages.Item(VVariant(1L), page); //Get the stencil and the first master to drop hr= docs.Item(VVariant("sample.vss"), stencil); hr= stencil.Masters(masters); hr= masters.Item(VVariant("Executive"), master); hr= page.Drop(master, 6.0, 6.0, shape); //Get the second master and drop it hr= masters.Item(VVariant("Position"), master); hr= page.Drop(master, 3.0, 3.0, shape1); //Connect the two shapes on the drawing page hr= shape.Cells(VBstr("Connections.X4"), cell); hr= shape1.Cells(VBstr("Controls.X1"), cell1); hr= cell1.GlueTo(cell); ... }
Visiwrap.h includes Helpers.h, so if you're using the wrapper classes, you can use the helper classes also. For details about the helper classes, see the comments in Helpers.h.
The Visio.h file defines the objects exposed by Visio in standard COM interface declaration syntax. The wrapper classes defined in Visiwrap.h call the methods of these interfaces. For example, the following code fragment shows the beginning of the CVisioApplication wrapper class declared in Visiwrap.h. Notice the method declarations of ActiveDocument, ActivePage, and so on following the second VW_PUBLIC access specifier.
class FAR CVisioApplication : public CVisioUnknown { VW_PUBLIC: CVisioApplication( ) : CVisioUnknown( ) { } CVisioApplication(const CVisioApplication& other) : CVisioUnknown(other) { } CVisioApplication(const IVApplication FAR * other, BOOL _ bAssumeResponsibility= FALSE) : CVisioUnknown( ( LPUNKNOWN )other, bAssumeResponsibility ) { } const CVisioApplication FAR & operator=( const CVisioApplication FAR &other ) { if ( &other != this ) CopyIP( other.GetUnknown( ) ); return *this; } const CVisioApplication FAR & operator=( const IVApplication FAR * other ) { if ( ( LPUNKNOWN )other != GetUnknown( ) ) CopyIP( ( LPUNKNOWN )other ); return *this; } virtual ~CVisioApplication( ) { } IVApplication FAR * GetIP( ) const { return ( IVApplication FAR * ) _ GetUnknown( ); } operator IVApplication FAR * ( ) { return ( IVApplication FAR * ) GetUnknown( ); } //CVisioApplication method declarations VW_PUBLIC: HRESULT ActiveDocument(CVisioDocument FAR &rWrap); HRESULT ActivePage(CVisioPage FAR &rWrap); HRESULT ActiveWindow(CVisioWindow FAR &rWrap); HRESULT Application(CVisioApplication FAR &rWrap); HRESULT Documents(CVisioDocuments FAR &rWrap); ...
The corresponding methods in the Application object interface are declared in Visio.h, as follows:
IVApplication : public IDispatch { public: virtual /* [helpcontext][propget][id] */ HRESULT STDMETHODCALLTYPE _ get_ActiveDocument( /* [retval][out] */ IVDocument __RPC_FAR *__RPC_FAR *lpdispRet) = 0; virtual /* [helpcontext][propget][id] */ HRESULT STDMETHODCALLTYPE _ get_ActivePage( /* [retval][out] */ IVPage __RPC_FAR *__RPC_FAR *lpdispRet) = 0; virtual /* [helpcontext][propget][id] */ HRESULT STDMETHODCALLTYPE _ get_ActiveWindow( /* [retval][out] */ IVWindow __RPC_FAR *__RPC_FAR *lpdispRet) = 0; virtual /* [helpcontext][propget][id] */ HRESULT STDMETHODCALLTYPE _ get_Application( /* [retval][out] */ IVApplication __RPC_FAR *__RPC_FAR *lpdispRet) = 0; virtual /* [helpcontext][propget][id] */ HRESULT STDMETHODCALLTYPE _ get_Documents( /* [retval][out] */ IVDocuments __RPC_FAR *__RPC_FAR *lpdispRet) = 0; ... };
Every object exposed by Visio has a similar declaration in Visio.h. Various macros in the declaration, which are not shown in this example, allow Visio.h to be included in either C or C++ source files.
Because every Visio interface derives from IDispatch, every Visio interface has the following methods:
These methods are followed by:
For details about these standard COM methods, see the Automation documentation in the Microsoft Platform Software Development Kit (SDK) on MSDN (msdn.microsoft.com). The Visio Application object exposes the remaining methods (get_ActiveDocument, get_ActivePage, and so forth). These methods correspond to the methods and properties described elsewhere in this guide for use with Microsoft Visual Basic programs.
To learn more about a method, see the Microsoft Visio Developer Reference (on the Help menu, click Developer Reference). For example, to find more about the get_ActiveDocument method declared in the previous example, search for "ActiveDocument."
The sample program in Generic.cpp, which is shown in the section Using the Wrapper Classes, begins with the following code:
CvisioApplicationapp; if (VAO_SUCCESS != vaoGetObjectWrap(app)) //Error handling goto CU;
This pebble starts the avalanche. To do anything with a Visio instance, you need an Application object, which is what vaoGetObjectWrap gets.
The vaoGetObjectWrap function calls the vaoGetObject function, which is declared in Ivisreg.h and implemented in Ivisreg.cpp. If you're not using the wrapper classes, you can call vaoGetObject directly. Look at the source code to see what vaoGetObject actually does.
The services defined in Ivisreg.h for working with a Visio instance are equivalent to those provided by the Visreg.bas file, which is supplied for use with Visual Basic. In particular, these files provide the necessary means to launch a new Visio instance or establish an Application object for the active Visio instance.
Every method declared in Visio.h is specified to return an HRESULT that indicates whether the method executed successfully. The HRESULT returned by a method declared in Visio.h is passed along by the equivalent method of the corresponding wrapper class defined in Visiwrap.h.
If a method succeeds, it returns NOERROR. A common practice is to check a method's result by using SUCCEEDED(hResult). The sample program includes a macro called check_valid to check the result of the method. This macro is shown later in this section. Many methods also produce an output value that is independent of the HRESULT returned by every method. For example, the ActiveDocument method of the CVisioApplication wrapper class produces a reference to a Document object. By convention, a method's output value is written to the method's last argument. Thus the last argument passed to ActiveDocument is a reference to a CVisioDocument object, where the method can write a reference to the Document object.
To learn more about Visio methods, see the Microsoft Visio Developer Reference (on the Help menu, click Developer Reference).
Many methods return an object reference as their output value. This value is really a COM interface pointer, which, like any interface pointer, must eventually be released.
If a method that returns an object reference fails, the output value again depends on whether you're using wrapper classes.
Even if the method succeeds, you might still need to check the output parameter. For example, if ActiveDocument is called when no documents are open, it returns an HRESULT of success and a NULL interface pointer (wrapped or not). The reasoning here is that an error did not occur—having no documents open is a perfectly valid state for which the caller should account. The various Active* methods behave in this manner, and you should verify that their output values are not NULL before proceeding. The various Item and Add methods, however, always return a non-NULL reference if they succeed.
The check_valid macro, defined in Generic.cpp, checks both possibilities. A function using check_valid must provide a CU label where it performs cleanup tasks.
#define check_valid(hr, obj) \ if(!SUCCEEDED(hr) || !((obj).IsSet())) \ goto CU;
Several methods return a string to the caller. The Shape object's Name property (getName of CVisioShape or get_Name of IVShape) is an example. All strings passed to or returned by Visio methods are of type BSTR, which consists of 16-bit (wide) characters in Microsoft Win32 programs. The Visio engine allocates the memory for the strings it returns, and the caller is responsible for freeing the memory.
The wrapper classes, defined in Visiwrap.h, take care of freeing memory for strings. If you do not use the wrapper classes, however, make sure that you call SysFreeString to free any string returned by a Visio instance.
Passing arguments to Visio methods is straightforward:
Some methods take object pointers, and some require a pointer to a specific type of Visio object. The Cell object's GlueTo method, for example, takes an argument that must refer to another Cell object.
Other methods that take object pointers are more lenient. For example, the Page object's Drop method takes a reference to the object to be dropped, because you might want to drop a master or a shape on a page.
The simplest way to pass an object pointer to a method is to pass a reference to an object of the appropriate wrapper class; for example, pass a reference to a CVisioCell object as an argument to the GlueTo method.
The interfaces defined in Visio.h declare object pointers as the corresponding interfaces. For example, Visio.h declares GlueTo as taking a pointer to an IVCell interface. Because the Drop method is not restricted to a particular object, Visio.h declares Drop to take an IUnknown interface, which means Drop takes a reference to any object. Internally, the Drop method determines what to drop by querying the object passed to it for an IDataObject interface. The interface you pass to Drop does not necessarily have to be an interface on a Visio object.
Any string passed to a Visio instance must be of type BSTR. The helper class VBstr, defined in Helpers.h, is a convenient way to pass strings to Visio instances. VBstr allocates memory for the string when it is created and frees the memory when the VBstr is destroyed. If you don't use VBstr, make sure that you call SysFreeString to free the memory you have allocated for strings.
For example, the following statement uses a VBstr to pass a cell name to the Cells method of a CVisioShape object. In this statement, cell is a variable of type CVisioCell :
hr = shape.Cells(VBstr("Connections.X4"), cell);
Some Visio methods take arguments that aren't constrained to a single type. For example, if you pass an integer 5 to the Item method of a Documents collection, it returns a reference to the fifth document in the collection. If you pass a string that is a document name to the same method, however, it returns a reference to a document of that name (assuming that the document is open).
COM defines a data structure known as a VARIANT for passing such arguments. The helper class, VVariant defined in Helpers.h, is a convenient way of passing a VARIANT to a Visio instance. For example, compare the following two statements:
hr = pages.Item(VVariant(1L), page); hr = masters.Item(VVariant("Position"), master);
The first statement passes 1 (an integer) to the Item method of a Pages collection. The second statement passes "Position" (a string) to the Item method of a Masters collection. In these statements, page and master are variables of type CVisioPage and CVisioMaster, respectively.