Ok, so I finally got events working with Visio 2003 and C++. So, I
thought I would post the solution here for any poor soul who is also
doing C++ development with Visio.
First off I have used the class wizard to import the Visio type libraries.
I have attached VisioDispatch.h this file contains a CMyDispatch which
is used to 'catch' a mapped event. The event will come into the Invoke
function.
Here I am actually mapping an event...
//MyVisio the DrawingControl.
CVDocument myDocument(MyVisio.get_Document());
CVApplication myApplication(myDocument.get_Application());
IUnknown FAR* pSink = NULL;
char buf[1024];
CVEventList myEventList(myApplication.get_EventList());
MyCellChangedEventProc = new CVisEventProc;
m_pDisp = new CMyDispatch();
m_pDisp->AddRef();
VARIANT m_v;
VariantInit(&m_v);
m_v.vt = VT_DISPATCH;
m_v.pdispVal = m_pDisp;
MyCellChangedEvent= myEventList.AddAdvise( (visEvtCell | visEvtMod),
m_v, "", "Cell Changed");
// below is how to use a filter.
//The filter used filters all cells out except the 1st User-defined cell
SAFEARRAY* filter;
SAFEARRAYBOUND bound[1];
bound[0].lLbound = 0;
bound[0].cElements = 7;
filter = SafeArrayCreate(VT_I2, 1, bound);
long index = 0;
short data = visSectionProp;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 1;
data = visRowProp;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 2;
data = visCustPropsValue;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 3;
data = visSectionProp;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 4;
data = visRowProp;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 5;
data = visCustPropsValue;
SafeArrayPutElement(filter, &index, (void*)&data);
index = 6;
data = -1;
SafeArrayPutElement(filter, &index, (void*)&data);
MyCellChangedEvent.SCMSetFilterSRC(filter);
////////////////////////////////////////////////
I added SCMSetFilterSRC to the generated CVEvent class
void SCMSetFilterSRC(SAFEARRAY *pVar) // notice the change in parameters
{
HRESULT hr;
VARIANT returnval;
EXCEPINFO Excepinfo;
unsigned int uArgErr;
DISPPARAMS dp;
VariantInit(&returnval);
VARIANT vArray;
vArray.vt = VT_ARRAY | VT_BYREF | VT_I2; // required OR'ing of VT types.
vArray.pparray = &pVar;
dp.rgvarg = &vArray;
dp.cArgs = 1;
dp.cNamedArgs = 0;
dp.rgdispidNamedArgs = NULL;
/*
// ------------------------------------
GetMemberInfo(m_lpDispatch);
DISPID dispid;
//LPOLESTR szNames[] = {L"AddAdvise"};
OLECHAR FAR* szMember = L"SetFilterSRC";
hr =
m_lpDispatch->GetIDsOfNames(IID_NULL,&szMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);
// ---- the code above checks the type of each argument -------------
*/
hr = m_lpDispatch->Invoke( 0x60020019,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&dp,
NULL,
NULL,
NULL);
return;
}
// -----------------------------------------------------------------------------------------
#include "CVShape.h"
#include "CVConnects.h"
#define ODS(s) OutputDebugString(s);
// New class derived from IDispatch created by mdurrett (md)
class CMyDispatch : public IDispatch {
protected:
ULONG m_cRef;
public:
CMyDispatch();
~CMyDispatch();
// IUnknown
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IDispatch
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgDispId);
STDMETHODIMP GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR *FAR *ppTInfo);
STDMETHODIMP GetTypeInfoCount(unsigned int FAR *pctinfo);
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pDispParams, VARIANT FAR *pVarResult, EXCEPINFO FAR *pExcepInfo, unsigned int FAR *puArgErr);
};
CMyDispatch::CMyDispatch()
{
m_cRef = 0;
}
CMyDispatch::~CMyDispatch()
{
}
STDMETHODIMP CMyDispatch::QueryInterface(REFIID riid, void **ppv)
{
HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
if (IsEqualGUID(riid,IID_IUnknown) || IsEqualGUID(riid, IID_IDispatch)) {
*ppv = static_cast<IDispatch*>(this);
hr = S_OK;
}
return hr;
}
STDMETHODIMP_(ULONG) CMyDispatch::AddRef(void)
{
ODS("CMyDispatch::AddRef\r\n");
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CMyDispatch::Release(void)
{
ODS("CMyDispatch::Release\r\n");
return --m_cRef;
}
STDMETHODIMP CMyDispatch::GetIDsOfNames(REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgDispId)
{
ODS("CMyDispatch::GetIDsOfNames\r\n");
*rgDispId = 0;
if (wcscmp(rgszNames[0],L"VisEventProc") == 0) //wideCstringcompare
{
*rgDispId = 1000; // arbitrary selection of 1000. Use whatever is appropriate
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP CMyDispatch::GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR *FAR *ppTInfo)
{
ODS("CMyDispatch::GetTypeInfo\r\n");
return E_NOTIMPL;
}
STDMETHODIMP CMyDispatch::GetTypeInfoCount(unsigned int FAR *pctinfo)
{
ODS("CMyDispatch::GetTypeInfoCount\r\n");
return E_NOTIMPL;
}
void GetMemberInfo(IDispatch *pDisp)
{
ITypeInfo *pTypeInfo = NULL;
HRESULT hr = pDisp->GetTypeInfo(0,0,&pTypeInfo);
if (!FAILED(hr)) {
BSTR bstrName;
pTypeInfo->GetDocumentation(MEMBERID_NIL,&bstrName,NULL,NULL,NULL);
char s[1024];
wsprintf(s,"Object is of type \"%S\".\r\n",bstrName);
ODS(s);
SysFreeString(bstrName);
}
}
STDMETHODIMP CMyDispatch::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pDispParams, VARIANT FAR *pVarResult, EXCEPINFO FAR *pExcepInfo, unsigned int FAR *puArgErr)
{
char s[1024];
wsprintf(s,"CMyDispatch::Invoke -- dispid = (%x) %d\r\n",dispIdMember,dispIdMember);
ODS(s);
if (dispIdMember == 1000) {
ODS("Event proc called!\r\n");
int lCode = pDispParams->rgvarg[5].iVal;
wsprintf(s,"Code = %d\r\n",lCode);
ODS(s);
GetMemberInfo(pDispParams->rgvarg[4].pdispVal); // IVApplication
GetMemberInfo(pDispParams->rgvarg[1].pdispVal); // IVShape
CVApplication vApp;
vApp.AttachDispatch(pDispParams->rgvarg[4].pdispVal);
vApp.m_lpDispatch->AddRef();
/*
CVShape vShape;
vShape.AttachDispatch(pDispParams->rgvarg[1].pdispVal);
vShape.m_lpDispatch->AddRef();
//CVShape vShape2(pDispParams->rgvarg[1].pdispVal);
ODS(vApp.get_ProductName());
ODS("\r\n");
ODS(vShape.get_Name());
ODS("\r\n"); */
}
/*
// Sample event handler switch from earlier application
// included for your consideration.
CVApplication app;
CVShape shape;
CVConnects connects;
try
{
app = (CVApplication) source;
switch (eventCode)
{
case VISEVTADD + (short) Visio.VisEventCodes.visEvtShape:
int ScopeID;
ScopeID = m_parentApp.BeginUndoScope("Shape Add");
shape = (Visio.Shape) subject;
HandleShapeAdd( app, shape );
m_parentApp.EndUndoScope(ScopeID,true);
break;
case VISEVTADD + (short) Visio.VisEventCodes.visEvtConnect:
connects = (Visio.Connects) subject;
HandleConnectionAdd( app, connects );
break;
case (short)Visio.VisEventCodes.visEvtDel + (short)Visio.VisEventCodes.visEvtShape:
shape = (Visio.Shape) subject;
HandleShapeDelete( app, shape );
break;
case (short)Visio.VisEventCodes.visEvtApp + (short)Visio.VisEventCodes.visEvtNonePending:
HandleNoEventsPending( app);
break;
case (short)Visio.VisEventCodes.visEvtIdle + (short)Visio.VisEventCodes.visEvtApp:
// System.Diagnostics.Debug.WriteLine("Calling HandleVisioIsIdle");
HandleVisioIdle ( app );
break;
default:
break;
}
}
catch (Exception err)
{
MessageBox.Show("Exception in IVisEventProc.VisEventProc: "
+ err.Message, "Visio2003Read");
}
return null;
}
*/
return S_OK;
}
// ------------------------- endof CMyDispatch() ------------------------------------------