在处理进程间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
只会是未定义的行为(编辑再次,这个假设也是假的)。
当我做演员表演时我真的错了吗?
处理死时进程间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;
答案 0 :(得分:2)
为了检测对象是否是远程CoIsHandlerConnected
无论如何QueryInterface
参数(对于IProxyManager
等),所以无论你是否提供已有的指针都没关系,或者你另外查询IUnknown
。您的QueryInterface
调用对远程对象的状态没有影响:对象是否是远程对象,远程对象是否已经死亡 - CoIsHandlerConnected
对您有相同的结果,无论您是多少{ {1}}。因此,没有必要这样做。
然后另一个注意事项是,如果远程对象死了(进程外服务器崩溃等),则调用QueryInterface
仍然是安全的。代理只返回错误代码而没有未定义的行为。也就是说,看起来您根本不需要IDispatch::Invoke
,如果您在客户端进程的上下文中遇到访问冲突,那么您可能首先要解决其他问题。
答案 1 :(得分:2)
在C ++中将IDispatch
转换为IUnknown
(如static_cast<IUnknown*>(pDispatch)
)会产生完全相同的指针值,因为IDispatch
派生自IUnknown
。 OTOH,对QueryInterface
IID_IUnknown
执行pDispatch
可能会返回不同的指针,但它仍然是合法的操作。实际上,这是如何获取COM对象的标识,比如检查两个接口是否由同一个COM对象实现(一个硬COM规则总是在同一个COM公寓内工作)。
也就是说,COM编组器实现的代理COM对象可以缓存接口,因此对IDispatch::QueryInterface
的调用可能会返回S_OK
和有效IUnknown
尽管远程服务器已经关闭,但代理的身份仍然存在。也就是说,此类操作可能不会导致即时IPC调用。
在您的情况下,为了测试COM服务器是否还活着,我只需在您已有的代理对象上调用IDispatch::GetTypeInfoCount
。这实际上会导致IPC调用(或者如果服务器在不同的主机上运行则通过线路往返)。
如果远程服务器崩溃或不可用,您可能会收到CO_E_OBJNOTCONNECTED
错误(可能是不同的错误代码,但肯定不是S_OK
)。
请注意,根据您的情况,执行额外的IPC调用以检查服务器是否可用可能是一项代价高昂的操作。
答案 2 :(得分:1)
不,你应该总是rr-@burza:~$ cat /proc/29262/status | grep -i rss
VmRSS: 1736 kB
rr-@burza:~$ cat /proc/29262/status | grep -i vmsize
VmSize: 5980 kB
。
仅仅因为您使用了QueryInterface
界面,它并不代表您可以直接将其投放到IUnknown
。 COM可能已经为您提供了底层对象的代理,这意味着指针与IDispatch
无关。
同样,实现可以包装实现IDispatch
的对象,当您调用IDispatch
时,它会委托给该对象。或者,您可能有一个指向委托给外部QueryInterface
的COM对象的指针。
所以,基本上,即使你认为它会起作用,也绝不会直接投射,因为事情可能会随着时间的推移而改变。调用IUnknown
很少是性能瓶颈,因此不值得避免。