HOWTO: Catch Microsoft Excel Application Events Using VC++ID: Q186427
|
This article demonstrates how to catch Microsoft Excel 97 Excel 2000 application events using Microsoft Visual C++ 5.0 and 6.0. Because the default implementation in MFC of IDispatch::Invoke() doesn't support named arguments, you must provide your own implementation of IDispatch.
Normally, you would perform the steps outlined in the following article in
the Microsoft Knowledge Base:
Q183599 HOWTO: Catch Microsoft Word97 Application Events Using VC++However, even when using these steps, events for Excel might not work as expected. Excel actually fires the events, but the default implementation in MFC for IDispatch::Invoke() returns errors because Excel supplies named arguments that MFC does not support.
COleDispatchDriver m_app;
IConnectionPoint *m_pConnectionPoint;
DWORD m_adviseCookie;
// Check to see if you've already started the server.
if(m_app.m_lpDispatch != NULL) {
AfxMessageBox("Server already started.");
return;
}
char buf[256]; // General purpose buffer.
// Start the Automation server.
COleException e;
if(!m_app.CreateDispatch("Excel.Application", &e)) {
sprintf(buf, "Error on CreateDispatch(): %ld (%08lx)",
e.m_sc, e.m_sc);
AfxMessageBox(buf, MB_SETFOREGROUND);
return;
}
// Make the server visible through automation.
// i.e.: Application.Visible = TRUE
DISPID dispID;
unsigned short *ucPtr;
BYTE *parmStr;
ucPtr = L"visible";
m_app.m_lpDispatch->GetIDsOfNames(
IID_NULL, &ucPtr, 1, LOCALE_USER_DEFAULT, &dispID
);
parmStr = (BYTE *)( VTS_VARIANT );
m_app.InvokeHelper(
dispID, DISPATCH_METHOD | DISPATCH_PROPERTYPUT, VT_EMPTY,
NULL, parmStr, &COleVariant((short)TRUE)
);
// Declare the events you want to catch.
// {00024413-0000-0000-C000-000000000046}
static const GUID IID_IExcel8AppEvents =
{0x00024413,0x000,0x0000,{0xc0,0x00,0x0,0x00,0x00,0x00,0x00,0x46 } };
// Steps for setting up events:
// 1. Get server's IConnectionPointContainer interface.
// 2. Call IConnectionPointContainer::FindConnectionPoint()
// to find the event you want to catch.
// 3. Call IConnectionPoint::Advise() with the IUnknown
// interface of your implementation of the events.
HRESULT hr;
// Get server's IConnectionPointContainer interface.
IConnectionPointContainer *pConnPtContainer;
hr = m_app.m_lpDispatch->QueryInterface(
IID_IConnectionPointContainer,
(void **)&pConnPtContainer
);
ASSERT(!FAILED(hr));
// Find the connection point for events you're interested in.
hr = pConnPtContainer->FindConnectionPoint(
IID_IExcel8AppEvents,
&m_pConnectionPoint
);
ASSERT(!FAILED(hr));
// Setup advisory connection.
hr = m_pConnectionPoint->Advise(&g_XLEventDispatch, &m_adviseCookie);
ASSERT(!FAILED(hr));
// Release IConnectionPointContainer interface.
pConnPtContainer->Release();
// Check whether you've started the server.
if(m_app.m_lpDispatch == NULL) {
AfxMessageBox("You haven't started the server yet.");
return;
}
m_pConnectionPoint->Unadvise(m_adviseCookie);
m_pConnectionPoint->Release(); //don't forgot to release pointer
// Tell the server to quit.
// Application.Quit()
DISPID dispID; // Temporary DISPID
unsigned short *ucPtr; // Temporary name holder
ucPtr = L"quit";
m_app.m_lpDispatch->GetIDsOfNames(
IID_NULL, &ucPtr, 1, LOCALE_USER_DEFAULT, &dispID
);
m_app.InvokeHelper(dispID, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
// Release the application object.
m_app.ReleaseDispatch();
//=============================================================
//=============================================================
// A simple IDispatch implementation to catch Excel's events.
class CMyEventDispatch : public IDispatch
{
public:
ULONG refCount;
CMyEventDispatch::CMyEventDispatch() {
refCount = 1;
}
CMyEventDispatch::~CMyEventDispatch() {
}
// IUnknown methods.
virtual HRESULT __stdcall QueryInterface(
REFIID riid, void **ppvObject) {
if(
IsEqualGUID(riid, IID_IDispatch) ||
IsEqualGUID(riid, IID_IUnknown)
) {
this->AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
virtual ULONG _stdcall AddRef(void) {
return ++refCount;
}
virtual ULONG _stdcall Release(void) {
if(--refCount <= 0) {
//Delete this;
return 0;
}
return refCount;
}
// IDispatch methods.
virtual HRESULT _stdcall GetTypeInfoCount(UINT *pctinfo) {
if(pctinfo) *pctinfo = 0;
return E_NOTIMPL;
}
virtual HRESULT _stdcall GetTypeInfo(
UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) {
return E_NOTIMPL;
}
virtual HRESULT _stdcall GetIDsOfNames(
REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid,
DISPID *rgDispId) {
return E_NOTIMPL;
}
virtual HRESULT _stdcall Invoke(
DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr) {
char *ptr = "Unknown-Event";
switch(dispIdMember) {
case 0x61d: ptr = "NewWorkbook"; break;
case 0x616: ptr = "SheetSelectionChange"; break;
case 0x617: ptr = "SheetBeforeDoubleClick"; break;
case 0x618: ptr = "SheetBeforeRightClick"; break;
case 0x619: ptr = "SheetActivate"; break;
case 0x61a: ptr = "SheetDeactivate"; break;
case 0x61b: ptr = "SheetCalculate"; break;
case 0x61c: ptr = "SheetChange"; break;
case 0x61f: ptr = "WorkbookOpen"; break;
case 0x620: ptr = "WorkbookActivate"; break;
case 0x621: ptr = "WorkbookDeactivate"; break;
case 0x622: ptr = "WorkbookBeforeClose"; break;
case 0x623: ptr = "WorkbookBeforeSave"; break;
case 0x624: ptr = "WorkbookBeforePrint"; break;
case 0x625: ptr = "WorkbookNewSheet"; break;
case 0x626: ptr = "WorkbookAddinInstall"; break;
case 0x627: ptr = "WorkbookAddinUninstall"; break;
case 0x612: ptr = "WindowResize"; break;
case 0x614: ptr = "WindowActivate"; break;
case 0x615: ptr = "WindowDeactivate"; break;
}
MessageBox(NULL, ptr, "Event was fired!!!", MB_SETFOREGROUND);
return S_OK;
}
};
CMyEventDispatch g_XLEventDispatch;
//=============================================================
//=============================================================
// OLE-initialization class.
class OleInitClass {
public:
OleInitClass() {
OleInitialize(NULL);
}
~OleInitClass() {
OleUninitialize();
}
};
// This global class calls OleInitialize() at
// application startup, and calls OleUninitialize()
// at application exit.
OleInitClass g_OleInitClass;
For a specific example of how to trap events for Microsoft Word, or how
to catch events in general (notwithstanding the lack of support for named
arguments in MFC), please see the following article in the Microsoft
Knowledge Base:
Q183599 HOWTO: Catch Microsoft Word97 Application Events Using VC++For more information about creating sink interfaces, and simplifying the connection process, please see the following article in the Microsoft Knowledge Base:
Q181845 HOWTO: Create a Sink Interface in MFC-Based COM ClientFor more information and a general example of connection points, see the Connpts.exe sample described in the following article in the Microsoft Knowledge Base:
Q152087 SAMPLE: Connpts.exe Implements Connection Points in MFC Apps
© Microsoft Corporation 1999, All Rights Reserved.
Contributions by Joe Crump, Microsoft Corporation
Additional query words:
Keywords : kbinterop kbole kbAutomation kbMFC kbVC500 kbVC600 kbGrpDSO kbOffice2000 kbExcel97 kbexcel2000
Version : WINDOWS:2000,97; winnt:5.0,6.0; :
Platform : WINDOWS winnt
Issue type : kbhowto
Last Reviewed: June 3, 1999