我今天在我的代码中遇到了一个问题,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
最佳答案
我只使用 CComPtr
和 CComQIPtr
来管理 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/