我今天在我的代碼中遇到了一個問題,在我的代碼中導致了一個訪問衝突,AFAICT,通過將我的COM對象強制轉換爲IUnknown **。它被傳入的函數沒有問題,但是當調用我的對象函數之一時,它會執行一些隨機函數並破壞堆棧然後死掉。Casting COM接口
指示代碼(只是忽略它爲什麼做這樣 - 我知道這是不好的,我知道如何解決它,但是這是一個瞭解爲什麼會出現這樣的問題,一個問題):
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對象(假設存在)的技術解釋,例如,鑄造將返回pMyObj2-4的情況x但QueryInterface將返回pMyObj2-8,因爲y ...或正在投射COM對象只是一個不好的練習/風格問題?
TIA
您正在追逐錯誤的問題。這種問題是版本問題的經典結果,有人在更改其定義後沒有更新接口的IID。所以你要調用完全錯誤的方法或用錯誤的參數調用它。聯繫這個組件的作者來解決這個問題。 –
下面有幾個答案說明了這樣做的正確方法。將一個'IUnknown'接口地址傳遞給你的GetInternalObject(),然後查詢你需要的接口的結果。打破編組是許多不以其他方式做的原因之一。 COM的規則很簡單。您通過IID查詢接口,您將返回該IID的接口指針。如果它是從基本接口(如IUnknown)派生的,則可以使用這些方法。如果一個函數通過地址返回一個IUnknown,那麼你不能做你上面的代碼安全地做的事情。 – WhozCraig
@Hans我不認爲這是一個版本控制問題 - 我遇到的問題非常具體,否則我可以使用相同的COM接口而不會出現問題。 – Sparkles