0

我正在以编程方式启动 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;
}
4

1 回答 1

0

使用CoInitializeEx(NULL, COINIT_MULTITHREADED)并添加_WIN32_DCOM作为预处理器指令解决了这个问题。

于 2013-01-03T09:14:57.853 回答