gpt4 book ai didi

c++ - 如何监听独立启动的Office应用程序的COM事件?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:27:01 33 4
gpt4 key购买 nike

我想做什么:

编写一个监听 Office 事件的应用程序。我想听取机器上打开的任何实例的事件。例如。如果我在 Word 中收听 BeforeDocumentSave,那么我希望每当主机上的任何 Word 实例保存文档时激活此方法的接收器。

另一个要求是我在没有 MFC 或 ATL 的情况下使用 C++ 编写。

我做了什么:

我编写了一个程序来监听 Word 事件。请参阅下面的代码。

问题:

它不起作用 - 事件处理程序从未输入,尽管我打开了一个 word 应用程序并执行了应该触发事件的操作。

我有一些具体问题,当然欢迎任何其他意见!

问题:

  1. 是否可以从不是我启动的应用程序中监听事件?在我找到的所有示例中,监听应用程序都会启动它想要监听的办公应用程序。

  2. 在 Microsoft howto (http://support.microsoft.com/kb/183599/EN-US/) 中,我发现了以下评论:

However, most events, such as Microsoft Excel's Workbook events, do not start with DISPID 1. In such cases, you must explicitly modify the dispatch map in MyEventSink.cpp to match the DISPIDs with the correct methods.

如何修改调度图?

  1. 现在我只定义了 Startup、Quit 和 DocumentChange,它们没有参数。我真正需要的方法确实采用参数,特别是文档类型之一。如果我不使用 MFC,如何定义这种类型的参数?

代码:

这是我项目的头文件,后面是 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_

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" );
}

最佳答案

您的第一个问题是您没有在主线程和that causes the events to never reach your sink object 中运行消息循环.从 COM 服务器到接收器对象的调用是使用 Windows 消息调度的,因此您必须运行消息循环而不是简单地调用 Sleep(),以便传入的事件最终被调度到接收器对象。

关于c++ - 如何监听独立启动的Office应用程序的COM事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3968945/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com