对于进程间 COM 对象,在不使用 QueryInterface 的情况下将 IDispatch* 转换为 IUnknown* 是否安全?
Is it safe to cast a IDispatch* into an IUnknown*, without using QueryInterface, for interprocess COM objects?
处理进程间 COM
对象时,在不使用 QueryInterface
的情况下将 IDispatch*
转换为 IUnknown*
是否安全?
这里我们的 IDispatch
对象来自另一个进程 OtherProcess.exe
。
我的一位同事说我应该在 IDispatch
上调用 QueryInterface
以获得 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 崩溃或被杀死的情况(访问冲突)。似乎在 IDispatch
上调用 Invoke
之类的任何函数封装了不再存在的 OtherProcess.exe 中的任何对象会引发这些访问冲突(EDIT: 评论答案表明这个最新的假设是完全错误的!)。
这就是我试图保护应用程序测试 ::CoIsHandlerConnected(pIUnknown);
的原因,它采用 IUnknown
作为参数。
但是通过在 IDispatch
上调用 QueryInterface
,就像我的同事建议我做的那样,我害怕回到我试图解决的同一个问题:这个 IDispatch
处理一个不再存在的对象,并且 QueryInterface
到 IUnknown
将只是未定义的行为都是一样的(再次 EDIT,这个假设也是错误的) .
当我只是做演员时,我真的错了吗?
处理死进程间 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;
不,你应该总是 QueryInterface
。
仅仅因为您使用了 IUnknown
接口并不意味着您可以直接将其转换为 IDispatch
。 COM 可能给了你底层对象的代理,这意味着指针与 IDispatch
.
无关
同样,一个实现可能会包装一个实现 IDispatch
的对象,当您调用 QueryInterface
时,它会委托给该对象。或者您可能有一个指向委托给外部 IUnknown
.
的 COM 对象的指针
所以,基本上,永远不要直接投射,即使你认为它会起作用,因为事情可能会随着时间而改变。调用 QueryInterface
很少会成为性能瓶颈,因此不值得避免。
为了检测对象是否远程 CoIsHandlerConnected
无论如何都会 QueryInterface
参数(对于 IProxyManager
等),所以你是否提供指针并不重要有,或者您另外查询 IUnknown
。您的 QueryInterface
调用对远程对象的状态没有影响:对象是否远程,远程对象是否已死 - CoIsHandlerConnected
对您的结果相同,无论您的附加 QueryInterface
。因此,没有必要这样做。
然后另一个注意事项是,如果远程对象已死(进程外服务器崩溃等),调用 IDispatch::Invoke
仍然是安全的。代理只是 returns 没有未定义行为的错误代码。也就是说,看起来您根本不需要 CoIsHandlerConnected
,如果您在客户端进程的上下文中遇到访问冲突,那么您可能还有其他问题需要先解决。
在 C++ 中将 IDispatch
转换为 IUnknown
(如 static_cast<IUnknown*>(pDispatch)
)会产生完全相同的指针值,因为 IDispatch
派生自 IUnknown
。 OTOH,在 pDispatch
上为 IID_IUnknown
做 QueryInterface
可能 return 一个不同的指针,但它仍然是一个合法的操作。事实上,这就是如何获取 COM 对象的身份,比如说,检查两个接口是否由同一个 COM 对象实现(一个硬 COM 规则,它总是在同一个 COM 单元内工作)。
也就是说,由 COM 编组器 实现的代理 COM 对象可能 是缓存接口,因此对 IDispatch::QueryInterface
的调用可能 return S_OK
和代理的有效 IUnknown
身份,尽管远程服务器已经关闭。也就是说,这样的操作可能不会导致即时 IPC 调用。
在您的情况下,为了测试 COM 服务器是否仍然存在并且运行良好,我只需在您已有的代理对象上调用 IDispatch::GetTypeInfoCount
。这实际上会导致 IPC 调用(或者如果服务器在不同的主机上运行,则通过线路进行往返)。
如果远程服务器崩溃或不可用,您可能会收到 CO_E_OBJNOTCONNECTED
错误(可能是不同的错误代码,但肯定不是 S_OK
)。
不过请注意,执行额外的 IPC 调用只是为了检查服务器是否可用可能是一项代价高昂的操作,具体取决于您的情况。
处理进程间 COM
对象时,在不使用 QueryInterface
的情况下将 IDispatch*
转换为 IUnknown*
是否安全?
这里我们的 IDispatch
对象来自另一个进程 OtherProcess.exe
。
我的一位同事说我应该在 IDispatch
上调用 QueryInterface
以获得 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 崩溃或被杀死的情况(访问冲突)。似乎在 IDispatch
上调用 Invoke
之类的任何函数封装了不再存在的 OtherProcess.exe 中的任何对象会引发这些访问冲突(EDIT: 评论答案表明这个最新的假设是完全错误的!)。
这就是我试图保护应用程序测试 ::CoIsHandlerConnected(pIUnknown);
的原因,它采用 IUnknown
作为参数。
但是通过在 IDispatch
上调用 QueryInterface
,就像我的同事建议我做的那样,我害怕回到我试图解决的同一个问题:这个 IDispatch
处理一个不再存在的对象,并且 QueryInterface
到 IUnknown
将只是未定义的行为都是一样的(再次 EDIT,这个假设也是错误的) .
当我只是做演员时,我真的错了吗?
处理死进程间 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;
不,你应该总是 QueryInterface
。
仅仅因为您使用了 IUnknown
接口并不意味着您可以直接将其转换为 IDispatch
。 COM 可能给了你底层对象的代理,这意味着指针与 IDispatch
.
同样,一个实现可能会包装一个实现 IDispatch
的对象,当您调用 QueryInterface
时,它会委托给该对象。或者您可能有一个指向委托给外部 IUnknown
.
所以,基本上,永远不要直接投射,即使你认为它会起作用,因为事情可能会随着时间而改变。调用 QueryInterface
很少会成为性能瓶颈,因此不值得避免。
为了检测对象是否远程 CoIsHandlerConnected
无论如何都会 QueryInterface
参数(对于 IProxyManager
等),所以你是否提供指针并不重要有,或者您另外查询 IUnknown
。您的 QueryInterface
调用对远程对象的状态没有影响:对象是否远程,远程对象是否已死 - CoIsHandlerConnected
对您的结果相同,无论您的附加 QueryInterface
。因此,没有必要这样做。
然后另一个注意事项是,如果远程对象已死(进程外服务器崩溃等),调用 IDispatch::Invoke
仍然是安全的。代理只是 returns 没有未定义行为的错误代码。也就是说,看起来您根本不需要 CoIsHandlerConnected
,如果您在客户端进程的上下文中遇到访问冲突,那么您可能还有其他问题需要先解决。
在 C++ 中将 IDispatch
转换为 IUnknown
(如 static_cast<IUnknown*>(pDispatch)
)会产生完全相同的指针值,因为 IDispatch
派生自 IUnknown
。 OTOH,在 pDispatch
上为 IID_IUnknown
做 QueryInterface
可能 return 一个不同的指针,但它仍然是一个合法的操作。事实上,这就是如何获取 COM 对象的身份,比如说,检查两个接口是否由同一个 COM 对象实现(一个硬 COM 规则,它总是在同一个 COM 单元内工作)。
也就是说,由 COM 编组器 实现的代理 COM 对象可能 是缓存接口,因此对 IDispatch::QueryInterface
的调用可能 return S_OK
和代理的有效 IUnknown
身份,尽管远程服务器已经关闭。也就是说,这样的操作可能不会导致即时 IPC 调用。
在您的情况下,为了测试 COM 服务器是否仍然存在并且运行良好,我只需在您已有的代理对象上调用 IDispatch::GetTypeInfoCount
。这实际上会导致 IPC 调用(或者如果服务器在不同的主机上运行,则通过线路进行往返)。
如果远程服务器崩溃或不可用,您可能会收到 CO_E_OBJNOTCONNECTED
错误(可能是不同的错误代码,但肯定不是 S_OK
)。
不过请注意,执行额外的 IPC 调用只是为了检查服务器是否可用可能是一项代价高昂的操作,具体取决于您的情况。