我正在以编程方式启动 Excel 应用程序。当我不使用事件侦听器(事件接收器)时,一切正常。我的问题是,当我通过连接点注册接收器时,Excel UI 冻结。更准确地说,当我在工作表上再次单击时,Excel 会冻结。如果没有注册的事件接收器,则不会发生此问题。这是接收器的代码。要将 Sink 注册到连接点,请调用 AttachToSource() 方法。我的代码是用 C++ 编写的,不使用 ATL 或 MFC。任何帮助表示赞赏!
编辑: Word 2010 中也出现同样的问题。那里显示了等待圈。我从“Ocidl.h”中得到 COM 定义。
#include "AppEventListener.h"
#include <iostream>
using namespace std;
//Constructor.
CAppEventListener::CAppEventListener() :
m_pConnectionPoint(NULL),
m_dwConnection(0)
{
m_refCount = 0;
}
//Destructor.
CAppEventListener::~CAppEventListener()
{}
/******************************************************************************
* IUnknown Interfaces -- All COM objects must implement, either
* directly or indirectly, the IUnknown interface.
******************************************************************************/
/******************************************************************************
* QueryInterface -- Determines if this component supports the
* requested interface, places a pointer to that interface in ppvObj if it is
* available, and returns S_OK. If not, sets ppvObj to NULL and returns
* E_NOINTERFACE.
******************************************************************************/
STDMETHODIMP CAppEventListener::QueryInterface(REFIID riid, void ** ppvObj)
{
if (riid == IID_IUnknown){
*ppvObj = static_cast<IUnknown*>(this);
}
else if (riid == IID_IDispatch){
*ppvObj = static_cast<IDispatch*>(this);
}
else if (riid == IID_ApplicationEvents){
*ppvObj = static_cast<IDispatch*>(this);
}
else{
*ppvObj = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppvObj)->AddRef();
return S_OK;
}
/******************************************************************************
* AddRef() -- In order to allow an object to delete itself when
* it is no longer needed, it is necessary to maintain a count of all
* references to this object. When a new reference is created, this function
* increments the count.
******************************************************************************/
STDMETHODIMP_(ULONG) CAppEventListener::AddRef()
{
return ++m_refCount;
}
/******************************************************************************
* Release() -- When a reference to this object is removed, this
* function decrements the reference count. If the reference count is 0, then
* this function deletes this object and returns 0.
******************************************************************************/
STDMETHODIMP_(ULONG) CAppEventListener::Release()
{
m_refCount--;
if (m_refCount == 0)
{
delete this;
return 0;
}
return m_refCount;
}
/******************************************************************************
* IDispatch Interface -- This interface allows this class to be used as an
* automation server, allowing its functions to be called by other COM
* objects.
******************************************************************************/
/******************************************************************************
* GetTypeInfoCount -- This function determines if the class supports type
* information interfaces or not. It places 1 in iTInfo if the class supports
* type information and 0 if it does not.
******************************************************************************/
STDMETHODIMP CAppEventListener::GetTypeInfoCount(UINT *iTInfo)
{
*iTInfo = 0;
return S_OK;
}
/******************************************************************************
* GetTypeInfo -- Returns the type information for the class. For classes
* that do not support type information, this function returns E_NOTIMPL;
******************************************************************************/
STDMETHODIMP CAppEventListener::GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo)
{
return E_NOTIMPL;
}
/******************************************************************************
* GetIDsOfNames -- Takes an array of strings and returns an array of DISPIDs
* that correspond to the methods or properties indicated. If the name is not
* recognized, returns DISP_E_UNKNOWNNAME.
******************************************************************************/
STDMETHODIMP CAppEventListener::GetIDsOfNames(REFIID riid,
OLECHAR **rgszNames,
UINT cNames, LCID lcid,
DISPID *rgDispId)
{
return E_NOTIMPL;
}
/******************************************************************************
* Invoke -- Takes a dispid and uses it to call another of this class's
* methods. Returns S_OK if the call was successful.
******************************************************************************/
STDMETHODIMP CAppEventListener::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{
switch(dispIdMember){
case 0x00622:
if(pDispParams->cArgs !=2)
return E_INVALIDARG;
else
{
if(pDispParams->rgvarg[1].vt & VT_BYREF)
{
HandleBeforeWorkbookClose( // Call the function.
*(pDispParams->rgvarg[1].ppdispVal),
pDispParams->rgvarg[0].pboolVal);
}
else
{
HandleBeforeWorkbookClose( // Call the function.
(pDispParams->rgvarg[1].pdispVal),
pDispParams->rgvarg[0].pboolVal);
}
}
case 0x0061c:
{
if(pDispParams->rgvarg[1].vt & VT_BYREF)
{
HandleSheetChange( // Call the function.
*(pDispParams->rgvarg[1].ppdispVal),
*(pDispParams->rgvarg[0].ppdispVal));
}
else
{
HandleSheetChange( // Call the function.
pDispParams->rgvarg[1].pdispVal,
pDispParams->rgvarg[0].pdispVal);
}
}
break;
}
return S_OK;
}
/******************************************************************************
* HandleBeforeWorkbookClose -- This method processes the BeforeWorkbookClose
* event for the application attached to this event handler.
******************************************************************************/
STDMETHODIMP CAppEventListener::HandleBeforeWorkbookClose( IDispatch* xlBook,
VARIANT_BOOL* fCancel )
{
cout << "HandleBeforeWorkbookClose\n" << endl;
HRESULT hr = S_OK;
return hr;
}
/******************************************************************************
* HandleSheetChange -- This method processes the SheetChange event for the
* application attached to this event handler.
******************************************************************************/
STDMETHODIMP CAppEventListener::HandleSheetChange( IDispatch* xlSheet,
IDispatch* xlRange)
{
cout << "HandleSheetChange\n" << endl;
HRESULT hr = S_OK;
return hr;
}
/******************************************************************************
* AttachToSource -- This method attaches to an event source.
******************************************************************************/
STDMETHODIMP CAppEventListener::AttachToSource( IUnknown* pEventSource )
{
HRESULT hr = S_OK;
IConnectionPointContainer* pCPC = NULL;
hr = pEventSource->QueryInterface( IID_IConnectionPointContainer,
(void**)&pCPC );
if (SUCCEEDED(hr)){
hr = pCPC->FindConnectionPoint( IID_ApplicationEvents,
&m_pConnectionPoint );
if (SUCCEEDED(hr)){
hr = m_pConnectionPoint->Advise( this, &m_dwConnection );
}
pCPC->Release();
}
return hr;
}
/******************************************************************************
* DetachFromSource -- This method detaches from an event source.
******************************************************************************/
STDMETHODIMP CAppEventListener::DetachFromSource()
{
HRESULT hr = S_OK;
if (m_pConnectionPoint != NULL){
m_pConnectionPoint->Unadvise( m_dwConnection );
m_pConnectionPoint = NULL;
}
return hr;
}