我今天在代码中遇到了一个问题,通过将我的COM对象强制转换为IUnknown**,导致了访问冲突AFAICT。它传递到的函数执行时没有问题,但当调用我的对象的函数时,它会执行一些随机函数,并损坏堆栈,然后死亡。
指示性代码(忽略为什么这样做-我知道这是坏的,我知道如何修复它,但这是一个问题,为什么像这样的问题可能会发生):
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)
,然后查询所需接口的返回值。
我的问题是,对于何时可以在COM对象上使用C/C强制转换,是否有规则?除了多重继承和它们带来的调整器thunk之外,强制转换COM对象如何会导致访问冲突之类的意外情况?请详细说明。
**编辑:**它们都是正确操作的好例子,但我希望得到的是一个技术解释,说明为什么不应该强制转换COM对象(假设存在一个),例如,在 x 情况下强制转换将返回pMyObj 2 -4,但QueryInterface将返回pMyObj 2 -8,因为 y......或者强制转换COM对象只是一个不好的做法/风格问题?
短暂性脑缺血
3条答案
按热度按时间kuhbmx9i1#
我只会使用
CComPtr
和CComQIPtr
来管理COM接口,而不是使用C风格的强制转换来编写代码,在我看来,C风格的强制转换在COM上下文中是不合适的:此外,我不是COMMaven,但我对您的代码表示怀疑:
如果你的方法返回一个
IUnknown*
,那么我会把QueryInterface()
和IID_IUnknown
存储在一个IMyInterface2*
中,而不是一个IUnknown*
中。或者最好使用
IID_PPV_ARGS
宏:COM样式转换具有特定的名称:
QueryInterface()
.v8wbuo2f2#
我认为问题在于,因为从
IMyInterface*
到IUnknown*
的转换是可以的(在COM中,一切都继承自IUknown
,对吗?),所以您认为从IMyInterface**
到IUnknown**
的转换也是可以的。但在C++中这是不正确的,我怀疑在COM中也是如此。对我来说,下面看起来更合乎逻辑,如果这不是严格正确的道歉,我的COM是非常生 rust ,但希望你得到的想法。
也就是说,首先获取一个IUnknown对象,然后将其向下转换为实际类型。
vxqlmq5t3#
我没有看到任何问题,在您的代码片段,堆栈腐败也许有它的原因,但它的其他地方。
我不认为这是你的实际代码,因为
GetInternalObject
应该是HRESULT
类型,而你的不是,所以你在复制/粘贴过程中丢失了一些东西。为了更安全,避免直接调用
QueryInterface
,因为与强制转换一起使用时,它们可能会误解接口。但与IUnknown*
之间的强制转换可能是不可避免的。如果不能信任被调用方返回正确的接口,则在调用方端,您可能更愿意再次使用QI,以确保保留您感兴趣的接口。如果GetInternalObject本身是COM接口方法,则可以如下所示:
PS如果GetInternalObject是一个本机方法,而不是COM,您将完全避免强制转换为
IUnknown*
。