我试图在我的应用程序(IWebBrowser2)中嵌入浏览器控件。我需要实现IDispatch,IDocHostShowUI,IDocHostUIHandler等以使其工作。我在纯C++/Win32 api中执行此操作。我没有使用ATL,MFC或任何其他框架。
我有一个名为TWebf的主类,它创建一个Win32窗口来放置浏览器控件,并进行使其工作所需的所有OLE调用。它还通过Refresh(),Back(),Forward()等方法用于控制浏览器控件。
现在,这是通过组合实现的。 TWebf具有将所有不同接口(interface)(IDispatch,IDocHostShowUI ...)实现为(堆栈分配的)成员的类。 TWebf在其构造函数中所做的第一件事是为所有这些成员提供一个指向其自身的指针(dispatch.webf = this;等)。 QueryInterface,AddRef和Release作为TWebf中所有接口(interface)实现的那些方法的调用而实现(例如,通过调用return webf->QueryInterface(riid, ppv);)
我不喜欢TWebf和实现接口(interface)的类之间的这种循环依赖关系。 TWebf的TDispatch成员的TWebf成员的...
所以我当时正在考虑使用多重继承来解决这个问题。这也将简化QueryInterface使其始终能够仅返回this
我想要的UMLish草图如下所示:
(点击查看大图)
c++ - C++ COM设计。合成与多重继承-LMLPHP

从uml中可以看出,我想提供所有接口(interface)的最小实现,因此我只需要重写接口(interface)中的那些方法,而实际上我想在TWebf中做一些实质性的事情。
我的“多继承实现”是否可能?这是个好主意吗?这是最好的解决方案吗?
编辑:
为了将来的讨论,这是TWebf中QueryInterface的当前实现

HRESULT STDMETHODCALLTYPE TWebf::QueryInterface(REFIID riid, void **ppv)
{
    *ppv = NULL;

    if (riid == IID_IUnknown) {
        *ppv = this;
    } else if (riid == IID_IOleClientSite) {
        *ppv = &clientsite;
    } else if (riid == IID_IOleWindow || riid == IID_IOleInPlaceSite) {
        *ppv = &site;
    } else if (riid == IID_IOleInPlaceUIWindow || riid == IID_IOleInPlaceFrame) {
        *ppv = &frame;
    } else if (riid == IID_IDispatch) {
        *ppv = &dispatch;
    } else if (riid == IID_IDocHostUIHandler) {
        *ppv = &uihandler;
    }

    if (*ppv != NULL) {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}
编辑2:
我尝试仅通过几个接口(interface)实现该功能。从IUnknown和TOleClientSite继承TWebf似乎很好,但是当我将TDispatch添加到继承列表时,它停止工作。
除了warning C4584: 'TWebf' : base-class 'IUnknown' is already a base-class of 'TDispatch'警告之外,我还遇到运行时错误。运行时错误为“访问冲突读取位置0x00000000”
由于某些原因,运行时错误发生在处理IOleClientSite的行上,而不是IDispatch。我不知道为什么会这样,或者是否确实与多重继承有关。有任何线索吗?
编辑3:
QueryInterface的错误实现似乎是运行时异常的原因。正如Mark Ransom正确指出的那样,此指针需要在分配给* ppv之前进行强制转换,并且在请求IUnknown时需要特别注意。阅读Why exactly do I need an explicit upcast when implementing QueryInterface in an object with multiple inheritance可以得到很好的解释。
为什么我仍然不知道确切地得到了那个特定的运行时错误。

最佳答案

多重继承是建立COM接口(interface)的一种非常常见的方式,因此是可能的。

但是QueryInterface仍然必须为每个接口(interface)强制转换指针。多重继承的一个有趣的特性是,可以针对每种类类型调整指针-指向IDispatch的指针与指向IDocHostUIHandler的指针不会具有相同的值,即使它们都指向同一个对象。还请确保IUnknown的QueryInterface始终返回相同的指针;由于所有接口(interface)都是从IUnknown派生的,因此,如果尝试直接将其强制转换为IUnknown,则会得到模棱两可的转换,但这也意味着您可以将任何接口(interface)用作IUnknown,只需在父列表中选择第一个即可。

关于c++ - C++ COM设计。合成与多重继承,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3613491/

10-10 03:45