我正在尝试在我的应用程序 (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 时需要特别小心。阅读为什么在具有多重继承的对象中实现 QueryInterface 时我需要显式向上转换,以获得很好的解释。
为什么我仍然不知道那个特定的运行时错误。