home *** CD-ROM | disk | FTP | other *** search
- /* GENERIC.C - Source for Automation Demo Code in C
- * Copyright (C) 1991-1996 Visio Corporation. All rights reserved.
- *
- *
- * You have a royalty-free right to use, modify, reproduce and distribute
- * the Sample Application Files (and/or any modified version) in any way
- * you find useful, provided that you agree that Visio has no warranty,
- * obligations or liability for any Sample Application Files.
- *
- *
- * NEW IN 4.1:
- * This example has been modified from the form that shipped with Visio
- * 4.0 to demonstrate the new 4.1 capability to establish a connection
- * from Visio to a controlling program over which event notifications are
- * sent. RunDemo, in addition to creating a very simple organization chart,
- * which it has always done, now:
- *
- * 1. Instantiates a "Visio sink object" (see addsink.h/c).
- * 2. Tells an IVEventList to a add connection over which document created
- * notifications will be sent from Visio to this program. The
- * connection is set up so that ReceiveNotifyFromVisio (implemented
- * herein) will be called after Visio creates a document.
- * 3. ReceiveNotifyFromVisio beeps and sets some local variables
- * to values calculated from arguments passed to it. The beep will
- * tell you the event proc got called. By setting breaks in and
- * stepping through ReceiveNotifyFromVisio, you can see how you
- * might write your own event handler procedures.
- * 4. Before returning, RunDemo releases the sink object made in step 1.
- *
- * To find where these these steps are performed, search for "EVENT DEMO STUFF".
- */
-
- #include "visioc.h"
-
- #include "resource.h"
-
- //---BEGIN EVENT DEMO STUFF---
-
- // The advise sink object we're going to use is declared in addsink.h.
- // You'll need to build addsink.cpp into your project as well.
- //
- // Note that you needn't use the addsink services if you don't want to.
- // You can implement your own connections directly with the more fundamental
- // methods and properties that Visio itself actually exposes. But addsink
- // packages up many of the details of talking idispatch.
- //
- #include "addsink.h"
-
- // We're going to keep a static around that points to the sink object we
- // instantiate. Your program, of course, could choose to do things more nicely.
- // Remember, this is just a demonstration.
- //
- static LPUNKNOWN stc_ipSink = NULL;
- static long stc_nEventID= visEvtIDInval;
-
- // This declares the event handling procedure we're going to tell stc_ipSink
- // to call when it receives notifications from Visio. The signature of
- // ReceiveNotifyFromVisio must conform to VISEVENTPROC. See addsink.h
- //
- HRESULT STDMETHODCALLTYPE ReceiveNotifyFromVisio (
- IUnknown FAR* ipSink,
- WORD wEvent, // i: code of firing event (visEvt*; visio.h)
- IUnknown FAR* ipSource, // i: object that's firing event [don't assert]
- DWORD dwEventID, // i: id of event in ipsource that's firing
- DWORD dwEventSeq, // i: sequence number of event that's firing
- IUnknown FAR* ipSubject, // i: object event is about [don't assert]
- VARIANT eventExtra);// i: other info about event
-
- //---END EVENT DEMO STUFF---
-
- /**************************************************************************
- *+ RunDemo
- *
- * This demo will drive Visio through OLE Automation in C and draws a
- * simple orgizational chart on a Visio page. Notice that the properties
- * and methods are no different than those called through VB, it's just
- * that you have the overhead of VARIANTs and pointer validation that VB
- * does for you.
- *
- * Comments are spread throughout the code to explain the how and why
- * of programming Visio through OLE Automation. Some of these comments
- * are directed at Visual Basic programmers who are making the transition
- * from OLE Automation under VB to C/C++.
- */
- int RunDemo(void)
- {
- /* Declarations Section
- *
- * INTERFACES
- *
- * In this example we're going to work with many different Visio
- * interfaces so we need a pointer to each one. If you're coming from
- * the Visual Basic world you need to get used to the idea of
- * releasing interfaces and verifying interface pointers before
- * invoking a method or property. Visual Basic automatically does
- * a release for you whenever Object variables go out of scope or
- * whenever you do an explicit Set obj = Nothing. However in C/C++
- * you must always release an interface when done with it and, when
- * given an interface, must verify that the pointer is != NULL before
- * attempting to invoke properties or methods on it. In VB this is
- * equivalent to asking (obj Is Nothing).
- *
- * Notice that we use the prefix ipIV for all our interface pointers.
- * ip stands for "Interface Pointer" and IV stands for
- * "Interface-Visio". After that we put a descriptive name of the
- * interface we're pointing to.
- *
- * An important thing to notice is that for every interface pointer
- * declared, there is a corresponding Release() call for it in the
- * clean up (CU:) section at the bottom of RunDemo. This is to
- * ensure that we release our lock upon the interface. For more
- * information on the Release function see the OLE documentation.
- *
- * BSTRs & VARIANTs
- *
- * Just like in Visual Basic, we have to pass parameters to our
- * properties and methods. Because we are talking to OLE we need to
- * pass strings as BSTRs. These are allocated/deallocated using the
- * SysAllocString and SysFreeString functions provided by OLE.
- * Furthermore, properties and methods that can take more than one
- * data type for the same parameter will use the VARIANT type. These
- * must be handled through the VariantInit, VariantClear functions and
- * the V_VT and V_type macros. See the OLE documentation for more
- * information on manipulating both the BSTR and VARIANT data types.
- */
-
- LPVISIOAPPLICATION ipIVApp = NULL;
- LPVISIODOCUMENTS ipIVDocs = NULL;
- LPVISIODOCUMENT ipIVDoc = NULL;
- LPVISIOPAGES ipIVPages = NULL;
- LPVISIOPAGE ipIVPage = NULL;
- LPVISIOSHAPE ipIVShape = NULL;
- LPVISIOSHAPE ipIVShape1 = NULL;
- LPVISIOMASTERS ipIVMasters = NULL;
- LPVISIOMASTER ipIVMaster = NULL;
- LPVISIODOCUMENT ipIVStencil = NULL;
- LPVISIOCELL ipIVCell = NULL;
- LPVISIOCELL ipIVCell1 = NULL;
- LPVISIOEVENTS ipIVEventList = NULL;
- LPVISIOEVENT ipIVEvent = NULL;
- BSTR bstr = NULL;
- VARIANT variant;
- HRESULT hResult;
-
- /* STARTING VISIO
- *
- * A special utility file is included called IVISREG that does
- * the work of getting a Visio application interface. This file
- * is equivalent to the VISREG.BAS file for Visual Basic.
- *
- * To see how it works open the file and examine it's function calls.
- * We use a simple, one parameter function that gets the active
- * instance if one exists or creates a new one if one is not running.
- */
-
- if ( VAO_SUCCESS != vaoGetObject(&ipIVApp) )
- goto CU;
-
- //---BEGIN EVENT DEMO STUFF---
- //
- // Search progref.hlp for AddAdvise for more information on event handling.
- // What we do is:
- //
- // 1. Verify the version of the instance of Visio we just got a
- // reference to is a version that supports event notification.
- // If vaoGetObject succeeds with this compile, then it is.
- // 2. Provided Visio is new enough, we then make a sink object.
- // 3. We call AddAdvise on the EventList object which will cause
- // ReceiveNotifyFromVisio to be called after Visio creates a document.
- // The event source (the object that will fire the notifications back to
- // this program) is the app (ipIVApp) we just made. (In general,
- // the source object is the one which owns the EventList.)
-
- // assert !stc_ipSink
- if (SUCCEEDED(CoCreateAddonSink(ReceiveNotifyFromVisio, &stc_ipSink)))
- {
- if (SUCCEEDED(ipIVApp->lpVtbl->get_EventList(ipIVApp, &ipIVEventList)))
- {
- BSTR bstr= NULL;
- VARIANT v;
-
- VariantInit(&v);
- V_VT(&v) = VT_UNKNOWN;
- V_UNKNOWN(&v) = stc_ipSink;
-
- if (SUCCEEDED(ipIVEventList->lpVtbl->AddAdvise(ipIVEventList, visEvtCodeDocCreate,
- v, bstr, bstr, &ipIVEvent)))
- {
- ipIVEvent->lpVtbl->get_ID(ipIVEvent, &stc_nEventID);
-
- ipIVEvent->lpVtbl->Release(ipIVEvent);
- ipIVEvent= NULL;
- }
-
- ipIVEventList->lpVtbl->Release(ipIVEventList);
- ipIVEventList= NULL;
- }
-
- // If Add didn't work, dwEventID will equal visEvtIDInval.
-
- // If Add worked, dwEventID is the id of the Event (IVEvent)
- // object that got created in the EventList (IVEventList) of
- // ipIVApp and ReceiveNotifyFromVisio will henceforth get called
- // after Visio creates a document.
- //
- // If, for some reason, we were to later decide to terminate
- // the connection we just made, we could do so by calling Delete
- // in the IVEvent interface.
-
- stc_ipSink->lpVtbl->Release(stc_ipSink);
- stc_ipSink= NULL;
- }
- //---END EVENT DEMO STUFF---
-
- /* Next we start the main work of drawing an organization chart.
- * First we retrieve the Documents collection and try to add a blank
- * document based on the SAMPLE.VST template. The workspace of this
- * template refers to the SAMPLE.VSS stencil file, which has some
- * masters we'll use to make the org chart with.
- *
- * To demonstrate an invoke let's look at how we retrieve the
- * Documents property of the Application interface. First off,
- * every property and method returns an HRESULT and if we want
- * to see if the call passed or failed we use the SUCCEEDED macro to
- * examine the SCODE contained in the HRESULT. If the call fails then
- * we automatically go to clean up since we can't continue.
- *
- * If the call succeeds we're still not done. Next we have to check
- * that another interface pointer was returned and, if it was not,
- * we go to clean up once again. This is the standard convention
- * that we'll use throughout the rest of the examples:
- *
- * 1) Make sure the call works
- * 2) Verify an interface, if any, was returned.
- *
- * Remember to check the pointers returned because if a call fails
- * and you try to call a method or property on a NULL pointer an
- * error will occur.
- */
-
- // Get App.Documents property
-
- hResult = ipIVApp->lpVtbl->get_Documents(ipIVApp, &ipIVDocs);
-
- if ( !SUCCEEDED(hResult) )
- goto CU;
-
- if ( !ipIVDocs )
- goto CU;
-
- /* For this call notice that we have to allocate a BSTR. We
- * always allocate the BSTR before the call and then immediately
- * after it. This way we're guaranteed we don't have a memory leak
- * However, this limits us from jumping straight to clean up as in
- * the previous example, thus we store the HRESULT in a temporary
- * variable and check it after deallocating the BSTR.
- */
-
- // Add a blank document with Docs.Add
-
- bstr = SysAllocString(OLESTR("sample.vst"));
- hResult = ipIVDocs->lpVtbl->Add(ipIVDocs, bstr, &ipIVDoc);
- SysFreeString(bstr);
-
- if ( !SUCCEEDED(hResult) || !ipIVDoc )
- goto CU;
-
- // Get blank document Pages collection using Doc.Pages
-
- hResult = ipIVDoc->lpVtbl->get_Pages(ipIVDoc, &ipIVPages);
-
- if ( !SUCCEEDED(hResult) || !ipIVPages )
- goto CU;
-
- /* For this call we need to use a variant for the Pages.Item property.
- * Because Pages.Item can take either a string containing the page's
- * name or an integer specifying the page's index we need to put pass
- * a VARIANT. Notice that we first init the variant, then set the
- * type of it with the V_VT macro to I2, meaning 2 byte integer. Then
- * we use the V_I2 macro to set the variant's value. After that we
- * can make the call. Once the call has returned, though, we need
- * to clear the variant. Read up on VARIANTs in the OLE 2.0 Programmer's
- * Reference to see exactly how to work with them and for a listing of
- * their support functions and macros.
- */
-
- // Get first page of blank document using Pages.Item
-
- VariantInit(&variant);
- V_VT(&variant) = VT_I2;
- V_I2(&variant) = 1;
- hResult = ipIVPages->lpVtbl->get_Item(ipIVPages, variant, &ipIVPage);
- VariantClear(&variant);
-
- if ( !SUCCEEDED(hResult) || !ipIVPage )
- goto CU;
-
- // Get Document interface for sample stencil using Docs.Item
-
- VariantInit(&variant);
- V_VT(&variant) = VT_BSTR;
- V_BSTR(&variant) = SysAllocString(OLESTR("sample.vss"));
- hResult = ipIVDocs->lpVtbl->get_Item(ipIVDocs, variant, &ipIVStencil);
- VariantClear(&variant);
-
- if ( !SUCCEEDED(hResult) || !ipIVStencil )
- goto CU;
-
- // Retrieve Masters interface using Doc.Masters
-
- hResult = ipIVStencil->lpVtbl->get_Masters(ipIVStencil, &ipIVMasters);
-
- if ( !SUCCEEDED(hResult) || !ipIVMasters )
- goto CU;
-
- // Get Executive master using Masters.Item
-
- VariantInit(&variant);
- V_VT(&variant) = VT_BSTR;
- V_BSTR(&variant) = SysAllocString(OLESTR("Executive"));
- hResult = ipIVMasters->lpVtbl->get_Item(ipIVMasters, variant, &ipIVMaster);
- VariantClear(&variant);
-
- if ( !SUCCEEDED(hResult) || !ipIVMaster )
- goto CU;
-
- // Drop Executive master using Page.Drop
-
- hResult = ipIVPage->lpVtbl->Drop(ipIVPage,
- (LPUNKNOWN)ipIVMaster,
- 6.0,
- 6.0,
- &ipIVShape );
-
- if ( !SUCCEEDED(hResult) || !ipIVShape )
- goto CU;
-
- /* At this point we want to re-use the one master interface we
- * declaraed. To do it we must first release and then set it
- * to NULL. Not setting it to NULL could cause serious problems later
- * so remember to do this, especially when iterating collections.
- */
-
- if ( ipIVMaster )
- {
- ipIVMaster->lpVtbl->Release(ipIVMaster);
- ipIVMaster = NULL;
- }
-
- // Get Position 1 master using Masters.Item
-
- VariantInit(&variant);
- V_VT(&variant) = VT_BSTR;
- V_BSTR(&variant) = SysAllocString(OLESTR("Position"));
- hResult = ipIVMasters->lpVtbl->get_Item(ipIVMasters, variant, &ipIVMaster);
- VariantClear(&variant);
-
- if ( !SUCCEEDED(hResult) || !ipIVMaster )
- goto CU;
-
- // Drop Position 1 master using Page.Drop
-
- hResult = ipIVPage->lpVtbl->Drop(ipIVPage,
- (LPUNKNOWN)ipIVMaster,
- 3.0,
- 3.0,
- &ipIVShape1 );
-
- if ( !SUCCEEDED(hResult) || !ipIVShape1 )
- goto CU;
-
- // Get Executive's Connection point using Shape.Cells
-
- bstr = SysAllocString(OLESTR("Connections.X4"));
- hResult = ipIVShape->lpVtbl->get_Cells(ipIVShape, bstr, &ipIVCell);
- SysFreeString(bstr);
-
- if ( !SUCCEEDED(hResult) || !ipIVCell )
- goto CU;
-
- // Get Position 1's Control handle using Shape.Cells
-
- bstr = SysAllocString(OLESTR("Controls.X1"));
- hResult = ipIVShape1->lpVtbl->get_Cells(ipIVShape1, bstr, &ipIVCell1);
- SysFreeString(bstr);
-
- if ( !SUCCEEDED(hResult) || !ipIVCell )
- goto CU;
-
- // Glue Position 1 to Executive using Cell.Glue
-
- hResult = ipIVCell1->lpVtbl->GlueTo(ipIVCell1, ipIVCell);
-
- if ( !SUCCEEDED(hResult) )
- goto CU;
-
- CU: /* CLEANUP
- *
- * The clean up section is meant to release any interface pointers
- * that are outstanding at this point. Our example does not need to
- * keep any around for later use or to pass back to our caller so we
- * release every one. However, if we were going to, say, pass one
- * back to a calling function as the call vaoGetObject does we would
- * not want to release it.
- */
-
- //---BEGIN EVENT DEMO STUFF---
- // We're going to get rid of the event sink object we made in the event
- // demo stuff scope above. If stc_ipSink is presently managing any
- // connections from Visio to this program, VisSink_Destroy() first
- // disconnects then. Then it releases stc_ipSink and sets it to null.
- // VisSink_Destroy() can validly be called if stc_ipSink is null.
-
- // VisSink_Destroy(&stc_ipSink);
- // assert !stc_ipSink
-
- //---END EVENT DEMO STUFF---
-
- if ( ipIVCell1 )
- ipIVCell1->lpVtbl->Release(ipIVCell1);
- if ( ipIVCell )
- ipIVCell->lpVtbl->Release(ipIVCell);
- if ( ipIVStencil )
- ipIVStencil->lpVtbl->Release(ipIVStencil);
- if ( ipIVMaster )
- ipIVMaster->lpVtbl->Release(ipIVMaster);
- if ( ipIVMasters )
- ipIVMasters->lpVtbl->Release(ipIVMasters);
- if ( ipIVShape1 )
- ipIVShape1->lpVtbl->Release(ipIVShape1);
- if ( ipIVShape )
- ipIVShape->lpVtbl->Release(ipIVShape);
- if ( ipIVPage )
- ipIVPage->lpVtbl->Release(ipIVPage);
- if ( ipIVPages )
- ipIVPages->lpVtbl->Release(ipIVPages);
- if ( ipIVDoc )
- ipIVDoc->lpVtbl->Release(ipIVDoc);
- if ( ipIVDocs )
- ipIVDocs->lpVtbl->Release(ipIVDocs);
- if ( ipIVApp )
- ipIVApp->lpVtbl->Release(ipIVApp);
-
- return 0;
- }
-
- //---BEGIN EVENT DEMO STUFF---
-
- /***********************************************************************
- *+ ReceiveNotifyFromVisio
- *
- * Gets called when Visio sends an event nofification over a connection
- * that this program has set up and which is being managed by the stc_ipSink
- * object instantiated in RunDemo.
- */
- HRESULT STDMETHODCALLTYPE ReceiveNotifyFromVisio (
- IUnknown FAR* ipSink, // i: calling sink [assert]
- WORD wEvent, // i: code of firing event (visEvt*; visconst.h)
- IUnknown FAR* ipSource, // i: object firing event [don't assert]
- DWORD dwEventID, // i: id of event in ipsource that's firing
- DWORD dwEventSeq, // i: sequence number of event that's firing
- IUnknown FAR* ipSubject, // i: object event is about [don't assert]
- VARIANT eventExtra) // i: other info about event
- {
- BOOL bUnexpected= FALSE;
-
- MessageBeep(MB_OK);
-
-
- // QueryInterface for the Application interface on the IUnknown ipSource.
- // The ipSource interface pointer, if it is non-NULL, points to
- // the Application which owns the EventList which fired this event.
- // To get the Event object, use the EventList::ItemFromID method.
-
- if (ipSource!=NULL)
- {
- LPVISIOAPPLICATION pApp= NULL;
-
- bUnexpected= TRUE; // assume until...
-
- if (SUCCEEDED(ipSource->lpVtbl->QueryInterface(ipSource, &IID_IVApplication, (LPVOID *) &pApp)))
- {
- LPVISIOEVENTS pList= NULL;
- LPVISIOEVENT pEvt= NULL;
-
- if (SUCCEEDED(pApp->lpVtbl->get_EventList(pApp, &pList)) && NULL!=pList)
- {
- if (SUCCEEDED(pList->lpVtbl->get_ItemFromID(pList, stc_nEventID, &pEvt)) && NULL!=pEvt)
- {
- short wEventProp;
- if (SUCCEEDED(pEvt->lpVtbl->get_Event(pEvt, &wEventProp)))
- {
- if (wEventProp==wEvent)
- bUnexpected= FALSE; // ...proven otherwise
- }
-
- pEvt->lpVtbl->Release(pEvt);
- }
-
- pList->lpVtbl->Release(pList);
- }
-
- pApp->lpVtbl->Release(pApp);
- }
- }
-
-
- // QueryInterface for the document interface on the IUnknown ipSubject.
- // The ipSubject interface pointer, if it is non-NULL, should be able to give us
- // back a Document since we signed up for a 'Document Created' event.
-
- if (ipSubject!=NULL)
- {
- LPVISIODOCUMENT pDoc= NULL;
-
- bUnexpected= TRUE; // assume until...
-
- if (SUCCEEDED(ipSubject->lpVtbl->QueryInterface(ipSubject, &IID_IVDocument, (LPVOID *) &pDoc)))
- {
- short objType;
-
- if ( NULL!=pDoc && SUCCEEDED(pDoc->lpVtbl->get_ObjectType(pDoc, &objType)) && (objType==visObjTypeDoc) )
- {
- short sSaved;
- if ( SUCCEEDED(pDoc->lpVtbl->get_Saved(pDoc, &sSaved)) && sSaved )
- bUnexpected= FALSE; // ...proven otherwise
- }
-
- pDoc->lpVtbl->Release(pDoc);
- }
- }
-
-
- // Screech if unexpected condition was encountered:
- if ( bUnexpected )
- {
- int i= 0;
- for ( ; i < 30; i++ )
- MessageBeep((UINT)-1);
- }
-
- return NOERROR;
- }
-
- //---END EVENT DEMO STUFF---
-
- /***********************************************************************
- *+ AboutDlgProc
- *
- */
- #ifdef __BORLANDC__
- #pragma argsused
- #endif
-
- #ifdef _DLL
- BOOL __loadds CALLBACK AboutDlgProc(
- #else
- BOOL CALLBACK AboutDlgProc(
- #endif
- HWND hDlg,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
- {
- switch (msg)
- {
- case WM_COMMAND:
- switch (wParam)
- {
- case IDOK:
- case IDCANCEL:
- EndDialog(hDlg, TRUE);
- return (TRUE);
- }
- }
-
- return (FALSE);
- }
-
- /***********************************************************************
- *+ ShowAboutDialog
- *
- * Displays the help about dialog.
- */
- void ShowAboutDialog(HINSTANCE hInstance)
- {
- FARPROC lpProcDlg = NULL;
-
- lpProcDlg = MakeProcInstance((FARPROC)AboutDlgProc, hInstance);
-
- DialogBox(hInstance, "ABOUTBOX", NULL, lpProcDlg);
-
- FreeProcInstance(lpProcDlg);
- };
-