rim*_*ono 5 c++ com events ms-office
我想做的事:
编写一个监听Office事件的应用程序。我想从计算机上打开的任何实例中监听事件。例如,如果我在Word中收听BeforeDocumentSave,那么只要主机上任何Word实例保存文档,我都希望激活此方法的接收器。
另一个要求是,我要用C ++编写而不使用MFC或ATL。
我所做的:
我已经编写了一个程序来监听Word事件。请参见下面的代码。
问题:
它不起作用-尽管我打开了Word应用程序并执行了应触发事件的操作,但从未输入事件处理程序。
我有一些具体的问题,当然,任何其他意见都将受到欢迎!
问题:
是否可以侦听不是由我启动的应用程序中的事件?在我发现的所有示例中,侦听应用程序都会启动要侦听的Office应用程序。
在Microsoft howto(http://support.microsoft.com/kb/183599/EN-US/)中,我发现以下注释:
但是,大多数事件(例如Microsoft Excel的Workbook事件)并非以DISPID 1开头。在这种情况下,必须在MyEventSink.cpp中显式修改分派映射,以使DISPID与正确的方法匹配。
如何修改调度图?
码:
这是我的项目的头文件,后跟C文件:
#ifndef _OFFICEEVENTHANDLER_H_
#define _OFFICEEVENTHANDLER_H_
// 000209FE-0000-0000-C000-000000000046
static const GUID IID_IApplicationEvents2 =
{0x000209FE,0x0000,0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
struct IApplicationEvents2 : public IDispatch // Pretty much copied from typelib
{
/*
* IDispatch methods
*/
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj) = 0;
STDMETHODIMP_(ULONG) AddRef() = 0;
STDMETHODIMP_(ULONG) Release() = 0;
STDMETHODIMP GetTypeInfoCount(UINT *iTInfo) = 0;
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) = 0;
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId) = 0;
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
UINT* puArgErr) = 0;
/*
* IApplicationEvents2 methods
*/
STDMETHODIMP Startup();
STDMETHODIMP Quit();
STDMETHODIMP DocumentChange();
};
class COfficeEventHandler : IApplicationEvents2
{
public:
DWORD m_dwEventCookie;
COfficeEventHandler
(
) :
m_cRef(1),
m_dwEventCookie(0)
{
}
STDMETHOD_(ULONG, AddRef)()
{
InterlockedIncrement(&m_cRef);
return m_cRef;
}
STDMETHOD_(ULONG, Release)()
{
InterlockedDecrement(&m_cRef);
if (m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj)
{
if (riid == IID_IUnknown){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else if (riid == IID_IApplicationEvents2){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else if (riid == IID_IDispatch){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else
{
char clsidStr[256];
WCHAR wClsidStr[256];
char txt[512];
StringFromGUID2(riid, (LPOLESTR)&wClsidStr, 256);
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, wClsidStr, -1, clsidStr, 256, NULL, NULL);
sprintf_s(txt, 512, "riid is : %s: Unsupported Interface", clsidStr);
*ppvObj = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppvObj)->AddRef();
return S_OK;
}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
return E_NOTIMPL;
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return E_NOTIMPL;
}
// IApplicationEvents2 methods
void Startup();
void Quit();
void DocumentChange();
protected:
LONG m_cRef;
};
#endif // _OFFICEEVENTHANDLER_H_
Run Code Online (Sandbox Code Playgroud)
C文件:
#include <windows.h>
#include <stdio.h>
#include "OfficeEventHandler.h"
#include "OCIdl.h"
int main()
{
CLSID clsid; // CLSID of automation object
HRESULT hr;
LPUNKNOWN punk = NULL; // IUnknown of automation object
LPDISPATCH pdisp = NULL; // IDispatch of automation object
IConnectionPointContainer *pConnPntCont;
IConnectionPoint *pConnPoint;
IUnknown *iu;
IID id;
COfficeEventHandler *officeEventHandler = new COfficeEventHandler;
CoInitialize(NULL);
hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid);
hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,
IID_IUnknown, (void FAR* FAR*)&punk);
hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont);
// IID for ApplicationEvents2
hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}",&id);
hr = pConnPntCont->FindConnectionPoint( id, &pConnPoint );
hr = officeEventHandler->QueryInterface( IID_IUnknown, (void FAR* FAR*)&iu);
hr = pConnPoint->Advise( iu, &officeEventHandler->m_dwEventCookie );
Sleep( 360000 );
hr = pConnPoint->Unadvise( officeEventHandler->m_dwEventCookie );
if (punk) punk->Release();
if (pdisp) pdisp->Release();
CoUninitialize();
return hr;
}
// IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
printf( "In Startup\n" );
}
void COfficeEventHandler::Quit()
{
printf( "In Quit\n" );
}
void COfficeEventHandler::DocumentChange()
{
printf( "In DocumentChnage\n" );
}
Run Code Online (Sandbox Code Playgroud)
第一个问题是您没有在主线程中运行消息循环,这会导致事件永远不会到达您的接收器对象。从 COM 服务器到接收器对象的调用是使用 Windows 消息分派的,因此您必须运行消息循环而不是简单地调用,Sleep()
以便传入事件最终分派到接收器对象。