I came across a problem in my code today where an access violation was being caused, AFAICT, by casting a COM object of mine to an IUnknown**. The function it was passed into executed without a problem but when calling one of my object's functions it would execute some random function and corrupt the stack then die.
Indicative code (just ignore why it's done this way - I know it's bad and I know how to fix it but this is a question of why problems like this may occur):
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);
}
I have always been a bit suspicious of using C/C++ casts on COM objects but I've never encountered (possibly through undefined behaviour) any problems until now.
I had a quick look and from what I can tell casting to IUnknown is technically valid so long as there is no multiple interitance in the inheritance chain, however it is not considered best practice - I should really pass an IUnknown to MyClass::GetInternalObject(IUnknown** lpUnknown)
and then query the return value for the interface I want.
My question is, are there rules as to when C/C++ casts can be used on COM objects, and aside from multiple inheritance and the adjustor thunks they bring, how can casting COM objects result in surprises like access violations? Please be detailed.
Edit: They're all good examples of how it should be done properly but what I was hoping for was a technical explanation of why you shouldn't cast COM objects (assuming one exists) e.g. casting will return pMyObj2-4 in situation x but QueryInterface will return pMyObj2-8 because of y...or is casting COM objects simply a matter of bad practice/style?
TIA