示例代码(忽略为什么要这样做 - 我知道这样做很糟糕,也知道如何解决,但这是一个关于为什么会出现这种问题的问题):
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中,强制转换将返回pMyObj2-4,但QueryInterface将返回pMyObj2-8,因为y的原因......或者说,强制转换COM对象只是一种不良实践/风格吗?
TIA
IUnknown
接口地址传递给GetInternalObject()
,并查询所需的接口结果。破坏封送是不采用其他方式的许多原因之一。COM的规则很简单。您按IID查询接口,您会得到该IID的接口指针。如果它是从基础接口(如IUnknown)派生的,则可以使用这些方法。如果函数通过地址返回IUnknown,则不能安全地执行上述代码。 - WhozCraig