[PATCH v2] ieframe: implement COM aggregation in WebBrowser

Damjan Jovanovic damjan.jov at gmail.com
Sat Dec 7 17:43:49 CST 2019


Wine's WebBrowser currently just ignores the "outer" it is passed.
Support COM aggregation like Windows does instead.

Try 2 renames the internal IUnknown functions, uses the
hlink_frame to store the outer, and beefs up the unit tests.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=12406
Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/ieframe/classinfo.c        |   6 +-
 dlls/ieframe/ieframe.h          |   1 +
 dlls/ieframe/oleobject.c        |  30 +--
 dlls/ieframe/persist.c          |  18 +-
 dlls/ieframe/tests/webbrowser.c |  60 ++++++
 dlls/ieframe/view.c             |  12 +-
 dlls/ieframe/webbrowser.c       | 325 ++++++++++++++++++--------------
 7 files changed, 277 insertions(+), 175 deletions(-)
-------------- next part --------------
diff --git a/dlls/ieframe/classinfo.c b/dlls/ieframe/classinfo.c
index 3fa77bb6ce..c6698af890 100644
--- a/dlls/ieframe/classinfo.c
+++ b/dlls/ieframe/classinfo.c
@@ -37,19 +37,19 @@ static HRESULT WINAPI ProvideClassInfo_QueryInterface(IProvideClassInfo2 *iface,
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IProvideClassInfo2(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI ProvideClassInfo_AddRef(IProvideClassInfo2 *iface)
 {
     WebBrowser *This = impl_from_IProvideClassInfo2(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI ProvideClassInfo_Release(IProvideClassInfo2 *iface)
 {
     WebBrowser *This = impl_from_IProvideClassInfo2(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI ProvideClassInfo_GetClassInfo(IProvideClassInfo2 *iface, ITypeInfo **ppTI)
diff --git a/dlls/ieframe/ieframe.h b/dlls/ieframe/ieframe.h
index 2b4861d79b..8d238863be 100644
--- a/dlls/ieframe/ieframe.h
+++ b/dlls/ieframe/ieframe.h
@@ -170,6 +170,7 @@ struct DocHost {
 };
 
 struct WebBrowser {
+    IUnknown                 IUnknown_inner;
     IWebBrowser2             IWebBrowser2_iface;
     IOleObject               IOleObject_iface;
     IOleInPlaceObject        IOleInPlaceObject_iface;
diff --git a/dlls/ieframe/oleobject.c b/dlls/ieframe/oleobject.c
index 22fe4b1848..5c49845aa7 100644
--- a/dlls/ieframe/oleobject.c
+++ b/dlls/ieframe/oleobject.c
@@ -439,19 +439,19 @@ static inline WebBrowser *impl_from_IOleObject(IOleObject *iface)
 static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv)
 {
     WebBrowser *This = impl_from_IOleObject(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI OleObject_AddRef(IOleObject *iface)
 {
     WebBrowser *This = impl_from_IOleObject(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI OleObject_Release(IOleObject *iface)
 {
     WebBrowser *This = impl_from_IOleObject(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, LPOLECLIENTSITE pClientSite)
@@ -838,19 +838,19 @@ static HRESULT WINAPI OleInPlaceObject_QueryInterface(IOleInPlaceObject *iface,
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IOleInPlaceObject(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI OleInPlaceObject_AddRef(IOleInPlaceObject *iface)
 {
     WebBrowser *This = impl_from_IOleInPlaceObject(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI OleInPlaceObject_Release(IOleInPlaceObject *iface)
 {
     WebBrowser *This = impl_from_IOleInPlaceObject(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI OleInPlaceObject_GetWindow(IOleInPlaceObject *iface, HWND* phwnd)
@@ -947,19 +947,19 @@ static HRESULT WINAPI OleControl_QueryInterface(IOleControl *iface,
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IOleControl(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI OleControl_AddRef(IOleControl *iface)
 {
     WebBrowser *This = impl_from_IOleControl(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI OleControl_Release(IOleControl *iface)
 {
     WebBrowser *This = impl_from_IOleControl(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI OleControl_GetControlInfo(IOleControl *iface, LPCONTROLINFO pCI)
@@ -1030,19 +1030,19 @@ static HRESULT WINAPI InPlaceActiveObject_QueryInterface(IOleInPlaceActiveObject
         REFIID riid, void **ppv)
 {
     WebBrowser *This = impl_from_IOleInPlaceActiveObject(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI InPlaceActiveObject_AddRef(IOleInPlaceActiveObject *iface)
 {
     WebBrowser *This = impl_from_IOleInPlaceActiveObject(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI InPlaceActiveObject_Release(IOleInPlaceActiveObject *iface)
 {
     WebBrowser *This = impl_from_IOleInPlaceActiveObject(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI InPlaceActiveObject_GetWindow(IOleInPlaceActiveObject *iface,
@@ -1137,19 +1137,19 @@ static HRESULT WINAPI WBOleCommandTarget_QueryInterface(IOleCommandTarget *iface
         REFIID riid, void **ppv)
 {
     WebBrowser *This = impl_from_IOleCommandTarget(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI WBOleCommandTarget_AddRef(IOleCommandTarget *iface)
 {
     WebBrowser *This = impl_from_IOleCommandTarget(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI WBOleCommandTarget_Release(IOleCommandTarget *iface)
 {
     WebBrowser *This = impl_from_IOleCommandTarget(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI WBOleCommandTarget_QueryStatus(IOleCommandTarget *iface,
diff --git a/dlls/ieframe/persist.c b/dlls/ieframe/persist.c
index 4c890d7ebf..bef5ef7344 100644
--- a/dlls/ieframe/persist.c
+++ b/dlls/ieframe/persist.c
@@ -38,19 +38,19 @@ static HRESULT WINAPI PersistStorage_QueryInterface(IPersistStorage *iface,
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IPersistStorage(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI PersistStorage_AddRef(IPersistStorage *iface)
 {
     WebBrowser *This = impl_from_IPersistStorage(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI PersistStorage_Release(IPersistStorage *iface)
 {
     WebBrowser *This = impl_from_IPersistStorage(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI PersistStorage_GetClassID(IPersistStorage *iface, CLSID *pClassID)
@@ -122,19 +122,19 @@ static HRESULT WINAPI PersistMemory_QueryInterface(IPersistMemory *iface,
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IPersistMemory(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI PersistMemory_AddRef(IPersistMemory *iface)
 {
     WebBrowser *This = impl_from_IPersistMemory(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI PersistMemory_Release(IPersistMemory *iface)
 {
     WebBrowser *This = impl_from_IPersistMemory(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI PersistMemory_GetClassID(IPersistMemory *iface, CLSID *pClassID)
@@ -206,19 +206,19 @@ static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface
         REFIID riid, LPVOID *ppobj)
 {
     WebBrowser *This = impl_from_IPersistStreamInit(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppobj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppobj);
 }
 
 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
 {
     WebBrowser *This = impl_from_IPersistStreamInit(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
 {
     WebBrowser *This = impl_from_IPersistStreamInit(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c
index a99c68ac5e..d8e157f489 100644
--- a/dlls/ieframe/tests/webbrowser.c
+++ b/dlls/ieframe/tests/webbrowser.c
@@ -45,6 +45,7 @@
 #include "docobjectservice.h"
 
 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+DEFINE_GUID(outer_test_iid,0x06d4cd6c,0x18dd,0x11ea,0x8e,0x76,0xfc,0xaa,0x14,0x72,0x2d,0xac);
 DEFINE_OLEGUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0);
 
 #define DEFINE_EXPECT(func) \
@@ -155,6 +156,7 @@ DEFINE_EXPECT(ControlSite_TranslateAccelerator);
 DEFINE_EXPECT(OnFocus_TRUE);
 DEFINE_EXPECT(OnFocus_FALSE);
 DEFINE_EXPECT(GetExternal);
+DEFINE_EXPECT(outer_QI_test);
 
 static const WCHAR wszItem[] = {'i','t','e','m',0};
 
@@ -4136,6 +4138,63 @@ static void test_SetAdvise(void)
     IWebBrowser2_Release(browser);
 }
 
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(riid, &outer_test_iid)) {
+        CHECK_EXPECT(outer_QI_test);
+        *ppv = (IUnknown*)0xdeadbeef;
+        return S_OK;
+    }
+    ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI outer_AddRef(IUnknown *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI outer_Release(IUnknown *iface)
+{
+    return 1;
+}
+
+static IUnknownVtbl outer_vtbl = {
+    outer_QueryInterface,
+    outer_AddRef,
+    outer_Release
+};
+
+static void test_Aggregation(void)
+{
+    HRESULT hr;
+    IClassFactory *class_factory;
+    IUnknown outer = { &outer_vtbl };
+    IUnknown *unk = NULL;
+    IWebBrowser *web_browser = NULL;
+    IUnknown *unk2 = NULL;
+
+    hr = CoGetClassObject(&CLSID_WebBrowser, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&class_factory);
+    ok(hr == S_OK, "CoGetClassObject failed: %08x\n", hr);
+
+    hr = IClassFactory_CreateInstance(class_factory, &outer, &IID_IUnknown, (void**)&unk);
+    ok(hr == S_OK, "CreateInstance returned hr = %08x\n", hr);
+    ok(unk != NULL, "result NULL, hr = %08x\n", hr);
+
+    hr = IUnknown_QueryInterface(unk, &IID_IWebBrowser, (void**)&web_browser);
+    ok(hr == S_OK, "QI to IWebBrowser failed, hr=%08x\n", hr);
+
+    SET_EXPECT(outer_QI_test);
+    hr = IWebBrowser_QueryInterface(web_browser, &outer_test_iid, (void**)&unk2);
+    CHECK_CALLED(outer_QI_test);
+    ok(hr == S_OK, "Could not get test iface: %08x\n", hr);
+    ok(unk2 == (IUnknown*)0xdeadbeef, "unexpected unk2\n");
+
+    IWebBrowser_Release(web_browser);
+    IUnknown_Release(unk);
+    IClassFactory_Release(class_factory);
+}
+
 START_TEST(webbrowser)
 {
     OleInitialize(NULL);
@@ -4167,6 +4226,7 @@ START_TEST(webbrowser)
     test_FileProtocol();
     trace("Testing SetAdvise...\n");
     test_SetAdvise();
+    test_Aggregation();
 
     OleUninitialize();
 }
diff --git a/dlls/ieframe/view.c b/dlls/ieframe/view.c
index 546e2511a3..d307bb5a00 100644
--- a/dlls/ieframe/view.c
+++ b/dlls/ieframe/view.c
@@ -35,19 +35,19 @@ static inline WebBrowser *impl_from_IViewObject2(IViewObject2 *iface)
 static HRESULT WINAPI ViewObject_QueryInterface(IViewObject2 *iface, REFIID riid, void **ppv)
 {
     WebBrowser *This = impl_from_IViewObject2(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI ViewObject_AddRef(IViewObject2 *iface)
 {
     WebBrowser *This = impl_from_IViewObject2(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI ViewObject_Release(IViewObject2 *iface)
 {
     WebBrowser *This = impl_from_IViewObject2(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI ViewObject_Draw(IViewObject2 *iface, DWORD dwDrawAspect,
@@ -157,19 +157,19 @@ static inline WebBrowser *impl_from_IDataObject(IDataObject *iface)
 static HRESULT WINAPI DataObject_QueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
 {
     WebBrowser *This = impl_from_IDataObject(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppvObj);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppvObj);
 }
 
 static ULONG WINAPI DataObject_AddRef(LPDATAOBJECT iface)
 {
     WebBrowser *This = impl_from_IDataObject(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI DataObject_Release(LPDATAOBJECT iface)
 {
     WebBrowser *This = impl_from_IDataObject(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT WINAPI DataObject_GetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
diff --git a/dlls/ieframe/webbrowser.c b/dlls/ieframe/webbrowser.c
index 03acf38869..5f12318bc4 100644
--- a/dlls/ieframe/webbrowser.c
+++ b/dlls/ieframe/webbrowser.c
@@ -37,151 +37,21 @@ static HRESULT WINAPI WebBrowser_QueryInterface(IWebBrowser2 *iface, REFIID riid
 {
     WebBrowser *This = impl_from_IWebBrowser2(iface);
 
-    if (ppv == NULL)
-        return E_POINTER;
-    *ppv = NULL;
-
-    if(IsEqualGUID(&IID_IUnknown, riid)) {
-        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = &This->IWebBrowser2_iface;
-    }else if(IsEqualGUID(&IID_IDispatch, riid)) {
-        TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
-        *ppv = &This->IWebBrowser2_iface;
-    }else if(IsEqualGUID(&IID_IWebBrowser, riid)) {
-        TRACE("(%p)->(IID_IWebBrowser %p)\n", This, ppv);
-        *ppv = &This->IWebBrowser2_iface;
-    }else if(IsEqualGUID(&IID_IWebBrowserApp, riid)) {
-        TRACE("(%p)->(IID_IWebBrowserApp %p)\n", This, ppv);
-        *ppv = &This->IWebBrowser2_iface;
-    }else if(IsEqualGUID(&IID_IWebBrowser2, riid)) {
-        TRACE("(%p)->(IID_IWebBrowser2 %p)\n", This, ppv);
-        *ppv = &This->IWebBrowser2_iface;
-    }else if(IsEqualGUID(&IID_IOleObject, riid)) {
-        TRACE("(%p)->(IID_IOleObject %p)\n", This, ppv);
-        *ppv = &This->IOleObject_iface;
-    }else if(IsEqualGUID(&IID_IOleWindow, riid)) {
-        TRACE("(%p)->(IID_IOleWindow %p)\n", This, ppv);
-        *ppv = &This->IOleInPlaceObject_iface;
-    }else if(IsEqualGUID (&IID_IOleInPlaceObject, riid)) {
-        TRACE("(%p)->(IID_IOleInPlaceObject %p)\n", This, ppv);
-        *ppv = &This->IOleInPlaceObject_iface;
-    }else if(IsEqualGUID(&IID_IOleControl, riid)) {
-        TRACE("(%p)->(IID_IOleControl %p)\n", This, ppv);
-        *ppv = &This->IOleControl_iface;
-    }else if(IsEqualGUID(&IID_IPersist, riid)) {
-        TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
-        *ppv = &This->IPersistStorage_iface;
-    }else if(IsEqualGUID(&IID_IPersistStorage, riid)) {
-        TRACE("(%p)->(IID_IPersistStorage %p)\n", This, ppv);
-        *ppv = &This->IPersistStorage_iface;
-    }else if(IsEqualGUID(&IID_IPersistMemory, riid)) {
-        TRACE("(%p)->(IID_IPersistStorage %p)\n", This, ppv);
-        *ppv = &This->IPersistMemory_iface;
-    }else if(IsEqualGUID (&IID_IPersistStreamInit, riid)) {
-        TRACE("(%p)->(IID_IPersistStreamInit %p)\n", This, ppv);
-        *ppv = &This->IPersistStreamInit_iface;
-    }else if(IsEqualGUID(&IID_IProvideClassInfo, riid)) {
-        TRACE("(%p)->(IID_IProvideClassInfo %p)\n", This, ppv);
-        *ppv = &This->IProvideClassInfo2_iface;
-    }else if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) {
-        TRACE("(%p)->(IID_IProvideClassInfo2 %p)\n", This, ppv);
-        *ppv = &This->IProvideClassInfo2_iface;
-    }else if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) {
-        TRACE("(%p)->(IID_IConnectionPointContainer %p)\n", This, ppv);
-        *ppv = &This->doc_host.cps.IConnectionPointContainer_iface;
-    }else if(IsEqualGUID(&IID_IViewObject, riid)) {
-        TRACE("(%p)->(IID_IViewObject %p)\n", This, ppv);
-        *ppv = &This->IViewObject2_iface;
-    }else if(IsEqualGUID(&IID_IViewObject2, riid)) {
-        TRACE("(%p)->(IID_IViewObject2 %p)\n", This, ppv);
-        *ppv = &This->IViewObject2_iface;
-    }else if(IsEqualGUID(&IID_IOleInPlaceActiveObject, riid)) {
-        TRACE("(%p)->(IID_IOleInPlaceActiveObject %p)\n", This, ppv);
-        *ppv = &This->IOleInPlaceActiveObject_iface;
-    }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) {
-        TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv);
-        *ppv = &This->IOleCommandTarget_iface;
-    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
-        *ppv = &This->IServiceProvider_iface;
-        TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
-    }else if(IsEqualGUID(&IID_IDataObject, riid)) {
-        *ppv = &This->IDataObject_iface;
-        TRACE("(%p)->(IID_IDataObject %p)\n", This, ppv);
-    }else if(IsEqualGUID(&IID_IQuickActivate, riid)) {
-        TRACE("(%p)->(IID_IQuickActivate %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IRunnableObject, riid)) {
-        TRACE("(%p)->(IID_IRunnableObject %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IPerPropertyBrowsing, riid)) {
-        TRACE("(%p)->(IID_IPerPropertyBrowsing %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IOleCache, riid)) {
-        TRACE("(%p)->(IID_IOleCache %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IOleInPlaceSite, riid)) {
-        TRACE("(%p)->(IID_IOleInPlaceSite %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IObjectWithSite, riid)) {
-        TRACE("(%p)->(IID_IObjectWithSite %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IViewObjectEx, riid)) {
-        TRACE("(%p)->(IID_IViewObjectEx %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IOleLink, riid)) {
-        TRACE("(%p)->(IID_IOleLink %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IMarshal, riid)) {
-        TRACE("(%p)->(IID_IMarshal %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(IsEqualGUID(&IID_IStdMarshalInfo, riid)) {
-        /* This is implemented since IE10 */
-        WARN("(%p)->(IID_IStdMarshalInfo %p) returning NULL\n", This, ppv);
-        return E_NOINTERFACE;
-    }else if(HlinkFrame_QI(&This->hlink_frame, riid, ppv)) {
-        return S_OK;
-    }
-
-    if(*ppv) {
-        IUnknown_AddRef((IUnknown*)*ppv);
-        return S_OK;
-    }
-
-    FIXME("(%p)->(%s %p) interface not supported\n", This, debugstr_guid(riid), ppv);
-    return E_NOINTERFACE;
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI WebBrowser_AddRef(IWebBrowser2 *iface)
 {
     WebBrowser *This = impl_from_IWebBrowser2(iface);
-    LONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p) ref=%d\n", This, ref);
-    return ref;
+
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI WebBrowser_Release(IWebBrowser2 *iface)
 {
     WebBrowser *This = impl_from_IWebBrowser2(iface);
-    LONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    if(!ref) {
-        if(This->sink)
-            IAdviseSink_Release(This->sink);
-
-        if(This->doc_host.document)
-            IUnknown_Release(This->doc_host.document);
 
-        DocHost_Release(&This->doc_host);
-
-        WebBrowser_OleObject_Destroy(This);
-
-        heap_free(This);
-        unlock_module();
-    }
-
-    return ref;
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 /* IDispatch methods */
@@ -1136,19 +1006,19 @@ static HRESULT WINAPI WBServiceProvider_QueryInterface(IServiceProvider *iface,
             REFIID riid, LPVOID *ppv)
 {
     WebBrowser *This = impl_from_IServiceProvider(iface);
-    return IWebBrowser2_QueryInterface(&This->IWebBrowser2_iface, riid, ppv);
+    return IUnknown_QueryInterface(This->hlink_frame.outer, riid, ppv);
 }
 
 static ULONG WINAPI WBServiceProvider_AddRef(IServiceProvider *iface)
 {
     WebBrowser *This = impl_from_IServiceProvider(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WINAPI WBServiceProvider_Release(IServiceProvider *iface)
 {
     WebBrowser *This = impl_from_IServiceProvider(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static HRESULT STDMETHODCALLTYPE WBServiceProvider_QueryService(IServiceProvider *iface,
@@ -1188,13 +1058,13 @@ static inline WebBrowser *impl_from_DocHost(DocHost *iface)
 static ULONG WebBrowser_addref(DocHost *iface)
 {
     WebBrowser *This = impl_from_DocHost(iface);
-    return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
+    return IUnknown_AddRef(This->hlink_frame.outer);
 }
 
 static ULONG WebBrowser_release(DocHost *iface)
 {
     WebBrowser *This = impl_from_DocHost(iface);
-    return IWebBrowser2_Release(&This->IWebBrowser2_iface);
+    return IUnknown_Release(This->hlink_frame.outer);
 }
 
 static void DocHostContainer_get_docobj_rect(DocHost *This, RECT *rc)
@@ -1224,6 +1094,169 @@ static const IDocHostContainerVtbl DocHostContainerVtbl = {
     DocHostContainer_set_url
 };
 
+static inline WebBrowser *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, WebBrowser, IUnknown_inner);
+}
+
+static HRESULT WINAPI WebBrowser_Internal_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    WebBrowser *This = impl_from_IUnknown(iface);
+
+    if (ppv == NULL)
+        return E_POINTER;
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = &This->IUnknown_inner;
+    }else if(IsEqualGUID(&IID_IDispatch, riid)) {
+        TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
+        *ppv = &This->IWebBrowser2_iface;
+    }else if(IsEqualGUID(&IID_IWebBrowser, riid)) {
+        TRACE("(%p)->(IID_IWebBrowser %p)\n", This, ppv);
+        *ppv = &This->IWebBrowser2_iface;
+    }else if(IsEqualGUID(&IID_IWebBrowserApp, riid)) {
+        TRACE("(%p)->(IID_IWebBrowserApp %p)\n", This, ppv);
+        *ppv = &This->IWebBrowser2_iface;
+    }else if(IsEqualGUID(&IID_IWebBrowser2, riid)) {
+        TRACE("(%p)->(IID_IWebBrowser2 %p)\n", This, ppv);
+        *ppv = &This->IWebBrowser2_iface;
+    }else if(IsEqualGUID(&IID_IOleObject, riid)) {
+        TRACE("(%p)->(IID_IOleObject %p)\n", This, ppv);
+        *ppv = &This->IOleObject_iface;
+    }else if(IsEqualGUID(&IID_IOleWindow, riid)) {
+        TRACE("(%p)->(IID_IOleWindow %p)\n", This, ppv);
+        *ppv = &This->IOleInPlaceObject_iface;
+    }else if(IsEqualGUID (&IID_IOleInPlaceObject, riid)) {
+        TRACE("(%p)->(IID_IOleInPlaceObject %p)\n", This, ppv);
+        *ppv = &This->IOleInPlaceObject_iface;
+    }else if(IsEqualGUID(&IID_IOleControl, riid)) {
+        TRACE("(%p)->(IID_IOleControl %p)\n", This, ppv);
+        *ppv = &This->IOleControl_iface;
+    }else if(IsEqualGUID(&IID_IPersist, riid)) {
+        TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
+        *ppv = &This->IPersistStorage_iface;
+    }else if(IsEqualGUID(&IID_IPersistStorage, riid)) {
+        TRACE("(%p)->(IID_IPersistStorage %p)\n", This, ppv);
+        *ppv = &This->IPersistStorage_iface;
+    }else if(IsEqualGUID(&IID_IPersistMemory, riid)) {
+        TRACE("(%p)->(IID_IPersistStorage %p)\n", This, ppv);
+        *ppv = &This->IPersistMemory_iface;
+    }else if(IsEqualGUID (&IID_IPersistStreamInit, riid)) {
+        TRACE("(%p)->(IID_IPersistStreamInit %p)\n", This, ppv);
+        *ppv = &This->IPersistStreamInit_iface;
+    }else if(IsEqualGUID(&IID_IProvideClassInfo, riid)) {
+        TRACE("(%p)->(IID_IProvideClassInfo %p)\n", This, ppv);
+        *ppv = &This->IProvideClassInfo2_iface;
+    }else if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) {
+        TRACE("(%p)->(IID_IProvideClassInfo2 %p)\n", This, ppv);
+        *ppv = &This->IProvideClassInfo2_iface;
+    }else if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) {
+        TRACE("(%p)->(IID_IConnectionPointContainer %p)\n", This, ppv);
+        *ppv = &This->doc_host.cps.IConnectionPointContainer_iface;
+    }else if(IsEqualGUID(&IID_IViewObject, riid)) {
+        TRACE("(%p)->(IID_IViewObject %p)\n", This, ppv);
+        *ppv = &This->IViewObject2_iface;
+    }else if(IsEqualGUID(&IID_IViewObject2, riid)) {
+        TRACE("(%p)->(IID_IViewObject2 %p)\n", This, ppv);
+        *ppv = &This->IViewObject2_iface;
+    }else if(IsEqualGUID(&IID_IOleInPlaceActiveObject, riid)) {
+        TRACE("(%p)->(IID_IOleInPlaceActiveObject %p)\n", This, ppv);
+        *ppv = &This->IOleInPlaceActiveObject_iface;
+    }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) {
+        TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv);
+        *ppv = &This->IOleCommandTarget_iface;
+    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
+        *ppv = &This->IServiceProvider_iface;
+        TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
+    }else if(IsEqualGUID(&IID_IDataObject, riid)) {
+        *ppv = &This->IDataObject_iface;
+        TRACE("(%p)->(IID_IDataObject %p)\n", This, ppv);
+    }else if(IsEqualGUID(&IID_IQuickActivate, riid)) {
+        TRACE("(%p)->(IID_IQuickActivate %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IRunnableObject, riid)) {
+        TRACE("(%p)->(IID_IRunnableObject %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IPerPropertyBrowsing, riid)) {
+        TRACE("(%p)->(IID_IPerPropertyBrowsing %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IOleCache, riid)) {
+        TRACE("(%p)->(IID_IOleCache %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IOleInPlaceSite, riid)) {
+        TRACE("(%p)->(IID_IOleInPlaceSite %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IObjectWithSite, riid)) {
+        TRACE("(%p)->(IID_IObjectWithSite %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IViewObjectEx, riid)) {
+        TRACE("(%p)->(IID_IViewObjectEx %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IOleLink, riid)) {
+        TRACE("(%p)->(IID_IOleLink %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IMarshal, riid)) {
+        TRACE("(%p)->(IID_IMarshal %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IStdMarshalInfo, riid)) {
+        /* This is implemented since IE10 */
+        WARN("(%p)->(IID_IStdMarshalInfo %p) returning NULL\n", This, ppv);
+        return E_NOINTERFACE;
+    }else if(HlinkFrame_QI(&This->hlink_frame, riid, ppv)) {
+        return S_OK;
+    }
+
+    if(*ppv) {
+        IUnknown_AddRef((IUnknown*)*ppv);
+        return S_OK;
+    }
+
+    FIXME("(%p)->(%s %p) interface not supported\n", This, debugstr_guid(riid), ppv);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI WebBrowser_Internal_AddRef(IUnknown *iface)
+{
+    WebBrowser *This = impl_from_IUnknown(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p) ref=%d\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI WebBrowser_Internal_Release(IUnknown *iface)
+{
+    WebBrowser *This = impl_from_IUnknown(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if(!ref) {
+        if(This->sink)
+            IAdviseSink_Release(This->sink);
+
+        if(This->doc_host.document)
+            IUnknown_Release(This->doc_host.document);
+
+        DocHost_Release(&This->doc_host);
+
+        WebBrowser_OleObject_Destroy(This);
+
+        heap_free(This);
+        unlock_module();
+    }
+
+    return ref;
+}
+
+static const struct IUnknownVtbl internal_unk_vtbl =
+{
+    WebBrowser_Internal_QueryInterface,
+    WebBrowser_Internal_AddRef,
+    WebBrowser_Internal_Release
+};
+
 static HRESULT create_webbrowser(int version, IUnknown *outer, REFIID riid, void **ppv)
 {
     WebBrowser *ret;
@@ -1231,8 +1264,16 @@ static HRESULT create_webbrowser(int version, IUnknown *outer, REFIID riid, void
 
     TRACE("(%p %s %p) version=%d\n", outer, debugstr_guid(riid), ppv, version);
 
+    if (outer && !IsEqualIID(riid, &IID_IUnknown))
+        return CLASS_E_NOAGGREGATION;
+
     ret = heap_alloc_zero(sizeof(WebBrowser));
 
+    ret->IUnknown_inner.lpVtbl = &internal_unk_vtbl;
+    if (outer)
+        ret->hlink_frame.outer = outer;
+    else
+        ret->hlink_frame.outer = &ret->IUnknown_inner;
     ret->IWebBrowser2_iface.lpVtbl = &WebBrowser2Vtbl;
     ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
     ret->ref = 1;
@@ -1251,13 +1292,13 @@ static HRESULT create_webbrowser(int version, IUnknown *outer, REFIID riid, void
     WebBrowser_Persist_Init(ret);
     WebBrowser_ClassInfo_Init(ret);
 
-    HlinkFrame_Init(&ret->hlink_frame, (IUnknown*)&ret->IWebBrowser2_iface, &ret->doc_host);
+    HlinkFrame_Init(&ret->hlink_frame, ret->hlink_frame.outer, &ret->doc_host);
 
     lock_module();
 
-    hres = IWebBrowser2_QueryInterface(&ret->IWebBrowser2_iface, riid, ppv);
+    hres = IUnknown_QueryInterface(&ret->IUnknown_inner, riid, ppv);
 
-    IWebBrowser2_Release(&ret->IWebBrowser2_iface);
+    IUnknown_Release(&ret->IUnknown_inner);
     return hres;
 }
 


More information about the wine-devel mailing list