c++ - 转换 COM 接口(interface)

标签 c++ com casting

我今天在我的代码中遇到了一个问题,AFAICT,通过将我的 COM 对象强制转换为 IUnknown** 导致访问冲突。它被传递到的函数执行时没有问题,但是当调用我的对象的函数之一时,它会执行一些随机函数并破坏堆栈然后死掉。

指示性代码(只是忽略为什么这样做 - 我知道它很糟糕并且我知道如何修复它但这是一个问题,为什么会出现这样的问题):

void MyClass2::func(IMyInterface* pMyObj)
{
    CComPtr<IMyInterface2> pMyObj2;
    HRESULT hRes = pMyObj->GetInternalObject((IUnknown**)&pMyObj2);

    if (SUCCEEDED(hRes))
        pMyObj2->Function(); // corrupt stack
}

void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
    pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}

我一直有点怀疑在 COM 对象上使用 C/C++ 强制转换,但直到现在我从未遇到过(可能是通过未定义的行为)任何问题。

我快速浏览了一下,据我所知,只要继承链中没有多重中断,转换为 IUnknown 在技术上是有效的,但它不被认为是最佳实践 - 我真的应该将 IUnknown 传递给 MyClass::GetInternalObject(IUnknown** lpUnknown)然后查询我想要的接口(interface)的返回值。

我的问题是,是否存在关于何时可以在 COM 对象上使用 C/C++ 强制转换的规则,除了多重继承和它们带来的调整器 thunk 之外,强制转换 COM 对象如何导致访问冲突等意外情况?请详细点。

编辑:它们都是应该如何正确完成的好例子,但我希望的是对为什么不应该转换 COM 对象(假设存在)的技术解释,例如转换将在 x 情况下返回 pMyObj2-4 但 QueryInterface 将返回 pMyObj2-8 因为 y ...或者转换 COM 对象只是一个不良实践/风格的问题?

TIA

最佳答案

我只使用 CComPtrCComQIPtr 来管理 COM 接口(interface),而不是使用 C 风格的转换编写代码,在我看来,这在 COM 上下文中是不合适的:

void MyClass2::Func(IMyInterface* pMyObj)
{
    // Assuming:
    //   HRESULT IMyInterface::GetInternalObject( /* [out] */ IUnknown** )
    CComPtr<IUnknown> spUnk;       
    HRESULT hr = pMyObj->GetInternalObject(&spUnk);
    if (SUCCEEDED(hr))
    {
        // Get IMyInterface2 via proper QueryInterface() call.
        CComQIPtr<IMyInterface2> spMyObj2( spUnk );
        if ( spMyObj2 )
        {
            // QueryInterface() succeeded

            spMyObj2->Function();
        }
    }
}

此外,我不是 COM 专家,但我怀疑您的代码:

void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
    pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}

如果您正在QueryInterface()'ing IID_MyInterface2,您应该将其存储在IMyInterface2* 中,而不是IUnknown *。 如果您的方法返回一个 IUnknown*,那么我将 QueryInterface() 一个 IID_IUnknown:

// NOTE on naming convention: your "lpUnknown" is confusing.
// Since it's a double indirection pointer, you may want to use "ppUnknown".
//
void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
    pInternalObject->QueryInterface(IID_IUnknown, (void**)ppUnknown);
}

或者更好地使用 IID_PPV_ARGS 宏:

void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
    IUnknown* pUnk = NULL;
    HRESULT hr = pInternalObject->QueryInterface(IID_PPV_ARGS(&pUnk));
    // Check hr...

    // Write output parameter
    *ppUnknown = pUnk;
}

COM 样式转换有一个特定的名称:QueryInterface()

关于c++ - 转换 COM 接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13395442/

相关文章:

java - 如果只使用两次,创建一个新的对象引用会不会更快?

C++如何检测空格

c++ - std::atomic 是否防止非原子变量在原子变量上的重新排序

c# - .NET Framework (v 4.0) 从 Win32 C++ 应用程序免费调用 COM 注册

java - (String)value 和 value.toString() , new Long(value) 和 (Long)value 之间的区别

c++ - "ask which exact type an object has"是否总是表明设计不好?

c++ - 使用类型谓词执行重载决议?

c++ - 如何隐藏或禁用 WIX 安装程序中的取消按钮?

c# - 无法创建具有复杂编程链的 ADODB.Connection

vb.net - 关闭 Windows 窗体应用程序和 excel.exe 进程如何交互(可能通过垃圾收集器)?