C++ 对于进程间COM对象,在不使用QueryInterface的情况下将IDispatch*强制转换为IUnknown*安全吗?

C++ 对于进程间COM对象,在不使用QueryInterface的情况下将IDispatch*强制转换为IUnknown*安全吗?,c++,com,atl,dcom,dangling-pointer,C++,Com,Atl,Dcom,Dangling Pointer,处理进程间COM对象时,将IDispatch*强制转换为IUnknown*,而不使用QueryInterface,安全吗 这里我们的IDispatch对象来自另一个进程OtherProcess.exe。 我的一位同事说我应该在IDispatch上调用QueryInterface,以获得IUnknown MIDL_INTERFACE("00020400-0000-0000-C000-000000000046") IDispatch : public IUnknown { public: v

处理进程间
COM
对象时,将
IDispatch*
强制转换为
IUnknown*
,而不使用
QueryInterface
,安全吗

这里我们的
IDispatch
对象来自另一个进程
OtherProcess.exe
。 我的一位同事说我应该在
IDispatch
上调用
QueryInterface
,以获得
IUnknown

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;
目前我正在做:

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
时,它会委托给这个对象。或者您可能有一个指向COM对象的指针,该COM对象委托给外部
IUnknown

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;

所以,基本上,永远不要直接投,即使你认为它会起作用,因为事情可能会随着时间的推移而改变。调用
QueryInterface
很少是性能瓶颈,因此不值得避免。

不,您应该始终使用
QueryInterface

仅仅因为你有一个
IUnknown
接口,并不意味着你可以直接将它转换到
IDispatch
。COM可能为您提供了底层对象的代理,这意味着指针与
IDispatch
无关

同样,一个实现可能会包装一个实现了
IDispatch
的对象,当您调用
QueryInterface
时,它会委托给这个对象。或者您可能有一个指向COM对象的指针,该COM对象委托给外部
IUnknown

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;

所以,基本上,永远不要直接投,即使你认为它会起作用,因为事情可能会随着时间的推移而改变。调用
QueryInterface
很少是一个性能瓶颈,因此不值得避免。

为了检测对象是否远程
coisHandlerConnection
无论如何都会
QueryInterface
参数(对于
IProxyManager
等),因此,不管您是提供已有的指针,还是另外查询
IUnknown
。您的
QueryInterface
调用对远程对象的状态没有影响:无论对象是否远程,远程对象是否已死亡-
CoIsHandlerConnected
对您都有相同的结果,而不管您是否有额外的
QueryInterface
。因此,没有必要这样做


另一个注意事项是,如果远程对象死了(进程外服务器崩溃等),调用
IDispatch::Invoke
仍然是安全的。代理只返回错误代码,没有未定义的行为。也就是说,看起来您根本不需要
CoIsHandlerConnected
,如果您在客户端进程上下文中遇到访问冲突,那么您可能需要首先解决其他问题。

为了检测对象是否远程
CoIsHandlerConnected
无论如何将
QueryInterface
参数(适用于
IProxyManager
etc),因此,无论您是提供已有的指针,还是另外查询
IUnknown
。您的
QueryInterface
调用对远程对象的状态没有影响:对象是否远程,远程对象是否已断开-
CoIsHandlerConnected
对于您可以不考虑额外的
查询接口
。因此,不需要这样做


另一个注意事项是,如果远程对象死了(进程外服务器崩溃等),调用
IDispatch::Invoke
仍然是安全的代理只返回没有定义行为的错误代码,也就是说,根本不需要< C++ > COSISANDLION连接/代码>,如果您在客户端进程上下文中遇到访问冲突,那么您可能首先需要解决其他问题。(如
static\u cast(pDispatch)
)产生完全相同的指针值,因为
IDispatch
派生自
IUnknown
。oth,在
pDispatch
上为
IID\u IUnknown
执行
QueryInterface
可以返回不同的指针,但这仍然是一个合法的操作。事实上,这就是如何获取COM的标识