COM 自动化 Excel 2010 冻结
Posted
技术标签:
【中文标题】COM 自动化 Excel 2010 冻结【英文标题】:COM Automation Excel 2010 freezes 【发布时间】:2013-01-02 14:03:08 【问题描述】:我正在以编程方式启动 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;
【问题讨论】:
【参考方案1】:使用 CoInitializeEx(NULL, COINIT_MULTITHREADED) 并添加 _WIN32_DCOM 作为预处理器指令解决了问题。
【讨论】:
以上是关于COM 自动化 Excel 2010 冻结的主要内容,如果未能解决你的问题,请参考以下文章