Let me start off by saying I am VERY inexperienced with the workings of COM, but I have been tasked with debugging an issue for someone else
I have two COM projects named pvTaskCOM and pvFormsCOM and each has many Interfaces, but the two I am concerned with are:
ITaskActPtr which is in pvTaskCOM
IChartingObjectPtr which is in pvFormsCOM
The line of code causing my problem is:
ITaskActPtr pTaskAct = m_pChartObj;
Where m_pChartObj is an IChartingObjectPtr. The problem I was encountering was that pTaskAct was NULL after this assignment in one workflow, but fine in most other workflows. I dived into what is happening here using the debugger and found it is looking at the wrong COM entries during the QueryInterface. In the workflows that work fine, QueryInterface grabs entries from pvTaskCOM/pvTaskAct.h:
BEGIN_COM_MAP(CTaskAct)
COM_INTERFACE_ENTRY(ITaskAct)
.
.
.
END_COM_MAP()
Which contains the Interface I'm trying to cast to, and QueryInterface returns S_OK.
But in this other workflow m_pChartObj is instantiated in the same way, but QueryInterface for some strange reason looks inside pvFormsCOM/ChartingObject.h
BEGIN_COM_MAP(CChartingObject)
COM_INTERFACE_ENTRY(IChartingObject)
.
.
.
END_COM_MAP()
which does NOT contain the ITaskAct we are trying to cast to, and so QueryInterface returns E_NOINTERFACE.
The question I have is what could cause it to be looking at two different COM's for the same line of code? Is it some sort of inheritance issue? I just need a step in the right direction.
It shouldn't be.
This line:
Is doing this under the hood:
It is asking the
IChartingObject's implementing object if it supports theITaskActinterface, and if so to return a pointer to that implementation. So this code should only be looking at the entries of theCOM_MAPfor theCChartingObjectclass. It should not be looking at theCTaskActclass at all.That is the correct behavior, since that is where
CChartingObjectis actually implemented. If there is no entry forITaskActin theCOM_MAPofCChartingObject, then the correct behavior is forCChartingObject::QueryInterface()to fail with anE_NOINTERFACEerror.So, the real problem is that your "working" workflows are actually flawed, and your "non working" workflow is doing the correct thing.
No. The "working" workflows are corrupted, plain and simple. Calling
QueryInterface()on anIChartingObjectinterface should be callingCChartingObject::QueryInterface(), but it is clearly callingCTaskAct::QueryInterface()instead. So eitherthe
IChartingObject*pointer is actually pointing at aCTaskActobject instead of aCChartingObjectobjectsomething has corrupted memory and the
IChartingObject's vtable is the unsuspecting victim.I would suspect the former. So, in the "working" workflows, make sure the
IChartingObject*pointer is actually pointing at the correct object. It sounds like someone took anITaskAct*and type-casted it to aIChartingObject*without usingQueryInterface(). Or they calledQueryInterface()on some object and asked it forIID_ITaskActinstead ofIID_IChartingObjectbut then saved the returned pointer in anIChartingObject*pointer instead of anITaskAct*pointer.