0

プログラムで Excel アプリケーションを起動しています。イベント リスナー (イベント シンク) を使用していない場合、すべて正常に動作します。私の問題は、接続ポイントを介してシンクを登録すると、Excel UI がフリーズすることです。より正確には、ワークシートを 2 回目にクリックすると、Excel がフリーズします。Event 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 に答える