为什么QueryInterface查看两个不同的com项目的同一代码行

Why is QueryInterface looking at two different COM projects for the same line of code?

本文关键字:com 项目 代码 两个 QueryInterface 为什么      更新时间:2023-10-16

让我开始说我对com的运作非常没有经验,但是我的任务是为别人调试一个问题

我有两个名为PVTASKCOM和PVFORMSCOM的com项目,每个项目都有许多接口,但是我关注的两个项目是:

在pvtaskcom中的itaskActptr

iChartingObjectptr,在pvformscom中

引起我问题的代码行是:

ITaskActPtr pTaskAct = m_pChartObj;

其中m_pchartobj是iChartingObjectptr。我遇到的问题是,在一个工作流程中,Ptaskact在此作业之后是无效的,但在大多数其他工作流程中都很好。我使用调试器潜入这里,发现它正在查看查询方面的错误com条目。在正常工作的工作流程中,查询因面从pvtaskcom/pvtaskact.h获取条目:

BEGIN_COM_MAP(CTaskAct)
  COM_INTERFACE_ENTRY(ITaskAct)
  .
  .
  .
END_COM_MAP()

包含我要铸造的界面,然后查询以返回s_ok。

但是,在其他工作流中,m_pchartobj的实例化是相同的,但是出于某些奇怪的原因查看pvformscom/chartingingobject.h

出于某些奇怪的原因。
BEGIN_COM_MAP(CChartingObject)
  COM_INTERFACE_ENTRY(IChartingObject)
  .
  .
  .
END_COM_MAP()

不包含我们试图施放的itaskact,因此查询返回e_nointerface。

我有什么问题是什么可能导致它在相同的代码中查看两个不同的com?这是某种继承问题吗?我只需要朝正确的方向迈出一步。

在工作流正常工作的工作流中,QueryInterface从pvtaskcom/pvtaskact.h抓取条目。H

不应该是。

这一行:

ITaskActPtr pTaskAct = m_pChartObj;

在引擎盖下这样做:

ITaskAct *pTaskAct = NULL;
m_pChartObj->QueryInterface(IID_ITaskAct, (void*)&pTaskAct);

如果它支持ITaskAct接口,则询问IChartingObject的实现对象,如果是这样,则要求将指针返回到该实现的指针。因此,此代码应仅查看COM_MAP类的CC_4条目。它根本不应该看CTaskAct类。

但是,在其他工作流中, m_pChartObj是相同的,但是QueryInterface出于某些奇怪的原因,pvformscom/chartingObject.h

外观

这是正确的行为,因为那是实际实现CChartingObject的地方。如果CChartingObjectCOM_MAP中没有ITaskAct的条目,则正确的行为是CChartingObject::QueryInterface()E_NOINTERFACE错误中失败。

因此,真正的问题是您的"工作"工作流程实际上是有缺陷的,而您的"非工作"工作流正在做正确的事情。

是什么可能导致它在同一行代码中查看两个不同的com?这是某种继承问题吗?

否。"工作"工作流程被损坏,简单明了。在IChartingObject接口上调用QueryInterface()应调用CChartingObject::QueryInterface(),但显然是在调用CTaskAct::QueryInterface()。所以要么

  • IChartingObject*指针实际上指向CTaskAct对象,而不是CChartingObject对象

  • 某些东西损坏了内存,IChartingObject的VTable是毫无戒心的受害者。

我会怀疑前者。因此,在"工作"工作流程中,请确保IChartingObject*指针实际上指向正确的对象。听起来好像有人服用了ITaskAct*并将其类型化为IChartingObject*,而无需使用QueryInterface()。或者他们在某些对象上打电话给QueryInterface(),并要求它用于IID_ITaskAct,而不是IID_IChartingObject,但随后将返回的指针保存在IChartingObject*指针中,而不是ITaskAct*指针中。

您可能会在管道中丢失一点。这是C 代码,旨在使COM变得更加严厉。COM的一个重要方面是客户端代码仅与接口一起使用。它对对象一无所知。接口是一个简单的合同,您可以调用的功能列表。iChartingObject将具有paint((函数。iTaskact不会有一个"任务"," Tasky",Schedule((函数。

注意m_pchartobj是一个非常误导的名称。它存储一个接口指针,而不是对象。但是并不少见,如果对象仅实现一个接口或具有您一直使用的"主导"接口,则很容易将接口指针视为对象指针。在服务器代码内隐藏对象是一个非常强大的目标,您只能进行接口调用。

所以itaskActptr ptaskact = m_pchartobj;基本上宣布:"我有一个图表,我想下一个任务函数调用"。喜欢schepen((。这要求com询问图表对象实现"您对任务接口合同有什么了解吗?"。不可避免地,它必须回到服务器,在cChartingObject的接口图中,以查看它是否也实现了itaskact。

因此,您看到的事情完全正常。答案是"否"。