home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 January
/
pcwk_01_1999.iso
/
Wtestowe
/
Vistdstd
/
Install
/
Data.Z
/
Generic.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-27
|
21KB
|
595 lines
/* 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);
};