【发布时间】:2011-04-06 12:33:32
【问题描述】:
我正在尝试在我的应用程序 (IWebBrowser2) 中嵌入浏览器控件。我需要实现 IDispatch、IDocHostShowUI、IDocHostUIHandler 等来完成这项工作。我在纯 C++/Win32 api 中执行此操作。我没有使用 ATL、MFC 或任何其他框架。
我有一个名为 TWebf 的主类,它创建一个 Win32 窗口以将浏览器控件放入其中并进行使其工作所需的所有 OLE 调用。它还用于控制浏览器控件,例如 Refresh()、Back()、Forward() 等方法。
现在这是通过组合实现的。 TWebf 具有将所有不同接口(IDispatch、IDocHostShowUI ...)实现为(堆栈分配的)成员的类。 TWebf 在其构造函数中所做的第一件事是给所有这些成员一个指向自身的指针(dispatch.webf = this; 等)。 QueryInterface、AddRef 和 Release 被实现为对 TWebf 中所有接口实现的这些方法的调用(例如,通过调用 return webf->QueryInterface(riid, ppv);)
我不喜欢 TWebf 和实现接口的类之间的这种循环依赖。 TWebf 有一个 TDispatch 成员,该成员有一个 TWebf 成员,该成员有一个...
所以我正在考虑用多重继承来解决这个问题。这也将简化 QueryInterface 以始终能够只返回 this。
我想要的 UMLish 草图是这样的: (点击查看大图)
从 uml 中可以看出,我想提供所有接口的最低限度的实现,所以我只需要覆盖接口中的那些方法,我实际上想在 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:
我尝试仅针对几个接口实现此功能。让 TWebf 从 IUnknown 和 TOleClientSite 继承似乎工作正常,但是当我将 TDispatch 添加到继承列表时它停止工作。
除了warning C4584: 'TWebf' : base-class 'IUnknown' is already a base-class of 'TDispatch' 警告之外,我还会遇到运行时错误。运行时错误是“访问冲突读取位置0x00000000”
由于某种原因,运行时错误发生在处理 IOleClientSite 而不是 IDispatch 的行上。我不知道为什么会这样,或者它是否真的与多重继承有关。有什么线索吗?
编辑 3:
QueryInterface 的错误实现似乎是运行时异常的原因。正如Mark Ransom 正确指出的那样, this 指针需要在分配给 *ppv 之前进行强制转换,并且在请求 IUnknown 时需要特别小心。阅读 Why exactly do I need an explicit upcast when implementing QueryInterface in an object with multiple inheritance 以获得很好的解释。
为什么我仍然不知道具体的运行时错误。
【问题讨论】:
-
这是一个骗子,我知道这是因为我向另一个人提出了答案。去寻找它。
-
@Ben Voigt:谢谢,我在问这个问题之前阅读了他们两个,但觉得他们没有回答我的特定问题。如果他们这样做,我对此没有足够好的理解来实现它。
-
它应该(显然)是
static_cast<IMumble*>(this)。
标签: c++ com winapi multiple-inheritance iwebbrowser2