在处理进程间COM
对象时,将IDispatch*
转换为IUnknown*
而不使用QueryInterface
是否安全?
在这里,我们的IDispatch
对象来自另一个进程OtherProcess.exe
。
我的一位同事说,我应该在QueryInterface
上调用IDispatch
以获得IUnknown
。
目前我正在做:
void CComThrowDispatch::CheckCOMAvailabilty() const
{
IUnknown * pIUnknown = m_spDispatchDriver.p;
// is this line above a problem ?
// m_spDispatchDriver is an ATL CComDispatchDriver
// it handles an object instanciated in another process.
// m_spDispatchDriver.p is of type IDispatch*
if (pIUnknown == nullptr) return;
bool bComObjectReachable = ::CoIsHandlerConnected(pIUnknown) == TRUE;
if (bComObjectReachable == false)
{
throw MyException;
}
}
我的建议是我的问题:我正在处理OtherProcess.exe崩溃或被杀死的情况(访问冲突)。似乎在
Invoke
上调用诸如IDispatch
之类的函数来封装此对象,而不再存在OtherProcess.exe会引发这些访问冲突(编辑:注释和答案表明此最新假设完全是错误的!)。这就是为什么我要保护以
::CoIsHandlerConnected(pIUnknown);
作为参数的应用程序测试IUnknown
的原因。但是,就像我的同事建议的那样,通过在
QueryInterface
上调用IDispatch
,我恐怕又陷入了我要解决的相同问题:此IDispatch
处理不再存在的对象,而将QueryInterface
转换为IUnknown
只是未定义的行为都相同(再次 EDIT ,这个假设也是错误的)。我刚做 Actor 时真的错了吗?
处理失效的进程间
COM
对象的常用方法是什么?这是OAIdl.h中
IDispatch
定义的开始,该声明被声明为源自IUnknown
。MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
/* [out] */ __RPC__out UINT *pctinfo) = 0;
最佳答案
在C++中将IDispatch
转换为IUnknown
(类似于static_cast<IUnknown*>(pDispatch)
)会产生完全相同的指针值,因为IDispatch
源自IUnknown
。 OTOH,对QueryInterface
上的IID_IUnknown
执行pDispatch
可能会返回不同的指针,但这仍然是合法操作。实际上,这就是获取COM对象身份的方法,例如,检查两个接口(interface)是否由同一个COM对象实现(硬COM规则始终在同一个COM单元内工作)。
就是说,由COM编码器实现的代理COM对象可能是缓存接口(interface),因此,尽管远程服务器已经关闭,对IDispatch::QueryInterface
的调用仍可能返回S_OK
和代理的有效IUnknown
身份。也就是说,这种操作可能不会引起即时IPC call 。
在您的情况下,要测试COM服务器是否仍然正常运行,我只需要对已经拥有的代理对象调用IDispatch::GetTypeInfoCount
。实际上,这将导致IPC call (如果服务器在其他主机上运行,则可能导致有线往返)。
万一远程服务器崩溃或不可用,您可能会收到CO_E_OBJNOTCONNECTED
错误(可能是不同的错误代码,但肯定不是S_OK
)。
但是请注意,根据您的方案,仅检查服务器是否可用可能需要执行额外的IPC调用,这可能是一项昂贵的操作。