1

首先让我说我对 COM 的工作非常缺乏经验,但我的任务是为其他人调试问题

我有两个名为 pvTaskCOM 和 pvFormsCOM 的 COM 项目,每个项目都有很多接口,但我关心的两个是:

pvTaskCOM 中的 ITaskActPtr

pvFormsCOM 中的 IChartingObjectPtr

导致我的问题的代码行是:

ITaskActPtr pTaskAct = m_pChartObj;

其中 m_pChartObj 是 IChartingObjectPtr。我遇到的问题是 pTaskAct 在一个工作流程中分配后为 NULL,但在大多数其他工作流程中都很好。我使用调试器深入研究了这里发生的事情,发现它在 QueryInterface 期间查看了错误的 COM 条目。在工作正常的工作流中,QueryInterface 从 pvTaskCOM/pvTaskAct.h 中获取条目:

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

其中包含我要转换到的接口,QueryInterface 返回 S_OK。

但在这个其他工作流程中,m_pChartObj 以相同的方式实例化,但 QueryInterface 出于某种奇怪的原因在 pvFormsCOM/ChartingObject.h

BEGIN_COM_MAP(CChartingObject)
  COM_INTERFACE_ENTRY(IChartingObject)
  .
  .
  .
END_COM_MAP()

它不包含我们尝试转换到的 ITaskAct,因此 QueryInterface 返回 E_NOINTERFACE。

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

4

2 回答 2

2

您可能在管道中迷路了。这是 C++ 代码,旨在让 COM 变得不那么苛刻。COM 的一个重要方面是客户端代码只能与接口一起使用。它对对象一无所知。接口是一个简单的合约,是你可以调用的函数列表。IChartingObject 会有一个 Paint() 函数。ITaskAct 将有,没有真正的想法,一些“任务”,一个 Schedule() 函数。

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

所以 ITaskActPtr pTaskAct = m_pChartObj; 基本上宣布,“我有一个图表,我想接下来调用任务函数”。像 Schedule()。这就需要 COM 询问图表对象的实现“你对任务接口契约有什么了解吗?”。不可避免地,它必须在 IChartingObject 来自的 CChartingObject 的接口映射中向服务器咨询,以查看它是否也实现了 ITaskAct。

所以你看到发生的事情是完全正常的。答案是不”。

于 2017-04-28T21:32:22.933 回答
2

在工作正常的工作流中,QueryInterface从 pvTaskCOM/pvTaskAct.h 中获取条目

不应该。

这一行:

ITaskActPtr pTaskAct = m_pChartObj;

在引擎盖下这样做:

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

它询问IChartingObject' 的实现对象是否支持该ITaskAct接口,如果支持则返回指向该实现的指针。所以这段代码应该只查看类的COM_MAP条目CChartingObject。它根本不应该在看CTaskAct课。

但是在这个其他工作流m_pChartObj中以相同的方式实例化,但QueryInterface出于某种奇怪的原因,请查看 pvFormsCOM/ChartingObject.h

这是正确的行为,因为这CChartingObject是实际实施的地方。如果ofITaskAct中没有 for 条目,则正确的行为是 for失败并出现错误。COM_MAPCChartingObjectCChartingObject::QueryInterface()E_NOINTERFACE

所以,真正的问题是你的“工作”工作流程实际上是有缺陷的,而你的“非工作”工作流程正在做正确的事情。

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

不,“工作”的工作流程被破坏了,简单明了。调用QueryInterface()接口IChartingObject应该是调用CChartingObject::QueryInterface(),但显然是调用CTaskAct::QueryInterface()。所以要么

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

  • 有些东西损坏了内存,而IChartingObject's vtable 是毫无戒心的受害者。

我会怀疑前者。因此,在“工作”工作流中,确保IChartingObject*指针实际上指向正确的对象。听起来有人在没有使用的情况下ITaskAct*将 a 类型转换为 a 。或者他们调用了某个对象并要求它而不是但随后将返回的指针保存在指针而不是指针中。IChartingObject*QueryInterface()QueryInterface()IID_ITaskActIID_IChartingObjectIChartingObject*ITaskAct*

于 2017-04-28T20:48:52.950 回答