Here's a full example using ATL and #import - the comments should be informative, I hope :-) It references the Excel COM server, obviously running in a separate process. It tells Excel it wants to catch application-specific events (as defined by the interface AppEvents), by telling it what object to send the events to.
#include <iostream>
#include <atlcom.h>
// Reference the COM server - you can put the .exe's path in the string instead
// of the libid.
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces raw_dispinterfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
// This defines the signature of the event I want to handle
_ATL_FUNC_INFO SheetChangeInfo = { CC_CDECL, VT_EMPTY, 2, { VT_DISPATCH, VT_DISPATCH } };
// This is the connection point sink class. The event interface is
// Excel::AppEvents
class ExcelAppEventHandler : public IDispEventSimpleImpl<1, ExcelAppEventHandler, &__uuidof(Excel::AppEvents)>
{
public:
ExcelAppEventHandler(bool& doneFlag) : done_(doneFlag) { done_ = false; }
BEGIN_SINK_MAP(ExcelAppEventHandler)
SINK_ENTRY_INFO(1, __uuidof(Excel::AppEvents), 0x0000061c, &ExcelAppEventHandler::SheetChange, &SheetChangeInfo)
END_SINK_MAP()
void _stdcall SheetChange(IDispatch * Sh, struct Excel::Range * Target)
{
done_ = true;
}
private:
bool& done_;
};
// This function uses the connection point sink class
_bstr_t GetActiveWorkbookName(Excel::_ApplicationPtr xl)
{
if (Excel::_WorkbookPtr wb = xl->ActiveWorkbook)
{
try
{
return wb->FullName;
}
catch(_com_error& e)
{
std::cout << "EXCEPTION!!!\n";
std::cerr << CT2CA(e.ErrorMessage()) << std::endl;
bool done;
// Instantiate the connection point sink
ExcelAppEventHandler app(done);
// Tell the COM server that you want to catch events
if (SUCCEEDED(app.DispEventAdvise(xl)))
{
// Put in a message loop to allow COM to work - we're waiting
// until an event's been received (indicated by done)
MSG msg;
while (!done && GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&a