我读过有关各种 COM 设计模式的详细信息COM 程序员的食谱 http://msdn.microsoft.com/en-us/library/ms809982.aspx以及一些相关的 SO 线程,特别是讨论组合与多重继承的线程 https://stackoverflow.com/questions/3613491/c-com-design-composition-vs-multiple-inheritance。可能是因为我对 C++ 和 COM 都太陌生,所以我可能会错过各种来源中提出的观点,所以这是我用一句话表达的问题:
我可以扩展 MIDL 生成的接口以供 DLL 内部使用吗?如果可以,在给定 MIDL/COM 限制的情况下,如何正确处理钻石问题/并行层次结构?
肮脏的细节...
希望能帮助其他人找出我的困惑所在,以下是我的假设:
1)COM不支持虚拟继承,只允许通过接口进行多重继承。
2)即使COM看不到它,只要我不希望COM直接公开它,那么使用不受支持的C++继承就不应该是非法的。
3)因为MIDL只允许接口的单一继承,如果我有一个并行的层次结构,我需要将它们聚合到组件类中。
4) MIDL 似乎没有声明 coclass 本身,因此我需要编写一个 .h 文件来声明实际的类,在那里,我可以根据需要进行扩展,并理解 COM 使用者无法使用它(这没关系)。
我想要做的是拥有一个处理大部分实现细节并将某些特定功能委托给子类的基础对象(我尚未决定它是否是抽象的,但我认为现在会是抽象的)。客户端通常会使用子类。所以,
项目.idl
import "oaidl.idl"
import "ocidl.idl"
[
object,
uuid(...),
dual,
oleautomation
]
interface IBase : IDispatch {
//stuff I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild1 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild2 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
uuid(...),
version(...),
]
library myproject {
importlib("stdole32.tlb");
interface IBase;
interface IChild1;
interface IChild2;
[
uuid(...),
]
coclass Base {
[default]interface IBase;
interface IOle*; //include other IOle* interfaces required for the functionality
};
[
uuid(...),
]
coclass Child1 {
[default]interface IChild1;
interface IOle*; //those are delegated to the base members
};
[
uuid(...),
]
coclass Child2 {
[default]interface IChild2;
interface IOle*; //those are delegated to the base members
};
};
base.h
#include base_h.h //interfaces generated by MIDL
// I assume I need to re-include IOle* because IBase has no relationship
// and C++ wouldn't know that I want the object base to also have those
// interfaces...
class base : public IBase,
public IOle* {
//handle all IUnknown, IDispatch and other IOle* stuff here
//as well as the common implementations as appropriate
};
child1.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
//I also assume that by inheriting base, child1 also inherits its interface
class Child1 : public Base,
public IChild1 {
//specific details only, let base handle everything else.
};
child2.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
class Child2 : public Base,
public IChild2 {
//specific details only, let base handle everything else.
};
从概念上讲,创建一个新的 child* 对象总是意味着创建基对象,因为需要基对象来处理实现细节,所以我认为让基对象处理 QueryInterface 和引用计数也是合适的,但我很困惑分以下几点:
1) 编译器抱怨由于并行层次结构导致成员不明确; IUnknown 从我的自定义接口和附加 IOle* 接口中重新实现了多次。文档表明,预计每个对象实际上只需要一个实现,但我不清楚如何解决编译器的问题,并且我觉得进行强制转换在某种程度上是错误的?我还想知道我是否应该让所有接口都被虚拟继承seems对于 C++ 来说是有效的,尽管 COM 不会没有这样的理解,但它也不应该关心(?)。
2) However, if I do declare all of inherited interfaces as virtual in the .h files, compiler then complains that inherited members are not allowed when I try to implement QueryInterface in the Base class.cpp. I've googled on that error but am not clear what it is trying to tell me here.
编辑:我回答了我自己的问题。英特尔有文档 http://software.intel.com/en-us/articles/cdiag341/对于这个错误,我最初没有单击链接,假设它可能不适用于 Visual Studio。无论如何我希望我这样做,但现在我明白为什么我会收到此错误,因为我试图在 Base:: 中执行所有实现,而不是 IUnknown:: 或 IDispatch:: 。现在这就引出了一个新问题,它可能会澄清我最初的主要问题——如果可能的话,我如何将实现从 IUnknown (和其他)推迟到 Base 并仅从 Base 工作?看来,如果我只使用 IUnknown::xxx,它就不再可以访问 Base 的私有成员,这似乎是合理的预期,所以这可能不是我想要的。我尝试将除基础接口之外的所有其他接口声明为虚拟接口,但这并没有真正实现。 (同样,这可能是我的经验不足,没有看到明显的解决方案。)
3)Base的QueryInterface无法将base转换为子接口,这是一个合理的抱怨,所以我认为无论如何我都必须为所有子接口重新实现QI,但是一旦我确定请求的接口不是子接口,我就可以将其委托回base的QI。奇怪的是,编译器坚持认为 child* 类是抽象的,因为缺少 IUnknown 和 IDispatch 的成员,但基类是否已经实现了,因此子类也应该具有这些成员?
各种编译器错误让我担心,我对语言和框架中的任何一个或两者都缺乏经验,这导致我对如何设计 COM 对象和继承层次结构以及实现细节做出了有缺陷的假设,我在这里肯定遗漏了一些东西。任何指点,甚至是打在头上的一记耳光,都将不胜感激。
Thanks!