[PATCH 4/6] shell32: Implement IExplorerBrowser::Advise and IExplorerBrowser::Unadvise.

David Hedberg david.hedberg at gmail.com
Mon Aug 23 05:55:20 CDT 2010


---
 dlls/shell32/ebrowser.c       |   61 +++++++++++++++-
 dlls/shell32/tests/ebrowser.c |  154 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 211 insertions(+), 4 deletions(-)

diff --git a/dlls/shell32/ebrowser.c b/dlls/shell32/ebrowser.c
index e4e132b..3e56ce0 100644
--- a/dlls/shell32/ebrowser.c
+++ b/dlls/shell32/ebrowser.c
@@ -28,6 +28,7 @@
 #include "windef.h"
 #include "winbase.h"
 
+#include "wine/list.h"
 #include "wine/debug.h"
 #include "debughlp.h"
 
@@ -35,6 +36,12 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
+typedef struct _event_client {
+    struct list entry;
+    IExplorerBrowserEvents *pebe;
+    DWORD cookie;
+} event_client;
+
 typedef struct _ExplorerBrowserImpl {
     const IExplorerBrowserVtbl *lpVtbl;
     const IShellBrowserVtbl *lpsbVtbl;
@@ -47,11 +54,31 @@ typedef struct _ExplorerBrowserImpl {
     EXPLORER_BROWSER_OPTIONS eb_options;
     FOLDERSETTINGS fs;
 
+    struct list event_clients;
+    DWORD events_next_cookie;
+
     IShellView *psv;
     RECT sv_rc;
 } ExplorerBrowserImpl;
 
 /**************************************************************************
+ * Event functions.
+ */
+static void events_unadvise_all(ExplorerBrowserImpl *This)
+{
+    event_client *client, *curs;
+    TRACE("%p\n", This);
+
+    LIST_FOR_EACH_ENTRY_SAFE(client, curs, &This->event_clients, event_client, entry)
+    {
+        TRACE("Removing %p\n", client);
+        list_remove(&client->entry);
+        IExplorerBrowserEvents_Release(client->pebe);
+        HeapFree(GetProcessHeap(), 0, client);
+    }
+}
+
+/**************************************************************************
  * Helper functions
  */
 static void update_layout(ExplorerBrowserImpl *This)
@@ -248,6 +275,8 @@ static HRESULT WINAPI IExplorerBrowser_fnDestroy(IExplorerBrowser *iface)
         This->hwnd_sv = NULL;
     }
 
+    events_unadvise_all(This);
+
     DestroyWindow(This->hwnd_main);
     This->destroyed = TRUE;
 
@@ -314,18 +343,40 @@ static HRESULT WINAPI IExplorerBrowser_fnAdvise(IExplorerBrowser *iface,
                                                 DWORD *pdwCookie)
 {
     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
-    FIXME("stub, %p (%p, %p)\n", This, psbe, pdwCookie);
+    event_client *client;
+    TRACE("%p (%p, %p)\n", This, psbe, pdwCookie);
 
-    return E_NOTIMPL;
+    client = HeapAlloc(GetProcessHeap(), 0, sizeof(event_client));
+    client->pebe = psbe;
+    client->cookie = ++This->events_next_cookie;
+
+    IExplorerBrowserEvents_AddRef(psbe);
+    *pdwCookie = client->cookie;
+
+    list_add_tail(&This->event_clients, &client->entry);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IExplorerBrowser_fnUnadvise(IExplorerBrowser *iface,
                                                   DWORD dwCookie)
 {
     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
-    FIXME("stub, %p (0x%x)\n", This, dwCookie);
+    event_client *client;
+    TRACE("%p (0x%x)\n", This, dwCookie);
 
-    return E_NOTIMPL;
+    LIST_FOR_EACH_ENTRY(client, &This->event_clients, event_client, entry)
+    {
+        if(client->cookie == dwCookie)
+        {
+            list_remove(&client->entry);
+            IExplorerBrowserEvents_Release(client->pebe);
+            HeapFree(GetProcessHeap(), 0, client);
+            return S_OK;
+        }
+    }
+
+    return E_INVALIDARG;
 }
 
 static HRESULT WINAPI IExplorerBrowser_fnSetOptions(IExplorerBrowser *iface,
@@ -652,6 +703,8 @@ HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, voi
     eb->lpVtbl = &vt_IExplorerBrowser;
     eb->lpsbVtbl = &vt_IShellBrowser;
 
+    list_init(&eb->event_clients);
+
     ret = IExplorerBrowser_QueryInterface((IExplorerBrowser*)eb, riid, ppv);
     IExplorerBrowser_Release((IExplorerBrowser*)eb);
 
diff --git a/dlls/shell32/tests/ebrowser.c b/dlls/shell32/tests/ebrowser.c
index 3397eb7..203f04d 100644
--- a/dlls/shell32/tests/ebrowser.c
+++ b/dlls/shell32/tests/ebrowser.c
@@ -44,6 +44,76 @@ static HRESULT ebrowser_initialize(IExplorerBrowser *peb)
     return IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
 }
 
+/*********************************************************************
+ * IExplorerBrowserEvents implementation
+ */
+typedef struct {
+    const IExplorerBrowserEventsVtbl *lpVtbl;
+    LONG ref;
+    UINT pending, created, completed, failed;
+} IExplorerBrowserEventsImpl;
+
+static IExplorerBrowserEventsImpl ebev;
+
+#define EBE_IMPL(iface)                         \
+    ((IExplorerBrowserEventsImpl*)iface)
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
+                                                              REFIID riid, void **ppvObj)
+{
+    ok(0, "Never called.\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
+{
+    return InterlockedIncrement(&(EBE_IMPL(iface)->ref));
+}
+
+static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
+{
+    return InterlockedDecrement(&(EBE_IMPL(iface)->ref));
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
+                                                                   PCIDLIST_ABSOLUTE pidlFolder)
+{
+    EBE_IMPL(iface)->pending++;
+    return S_OK;
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
+                                                                    PCIDLIST_ABSOLUTE pidlFolder)
+{
+    EBE_IMPL(iface)->completed++;
+    return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
+                                                                  PCIDLIST_ABSOLUTE pidlFolder)
+{
+    EBE_IMPL(iface)->failed++;
+    return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
+                                                             IShellView *psv)
+{
+    EBE_IMPL(iface)->created++;
+    return S_OK;
+}
+
+static const IExplorerBrowserEventsVtbl ebevents =
+{
+    IExplorerBrowserEvents_fnQueryInterface,
+    IExplorerBrowserEvents_fnAddRef,
+    IExplorerBrowserEvents_fnRelease,
+    IExplorerBrowserEvents_fnOnNavigationPending,
+    IExplorerBrowserEvents_fnOnViewCreated,
+    IExplorerBrowserEvents_fnOnNavigationComplete,
+    IExplorerBrowserEvents_fnOnNavigationFailed
+};
+
+#undef EBE_IMPL
+
 static void test_QueryInterface(void)
 {
     IExplorerBrowser *peb;
@@ -378,6 +448,89 @@ static void test_basics(void)
     ok(lres == 0, "Got %d\n", lres);
 }
 
+static void test_Advise(void)
+{
+    IExplorerBrowser *peb;
+    IExplorerBrowserEvents *pebe;
+    DWORD cookies[10];
+    HRESULT hr;
+    UINT i, ref;
+
+    /* Set up our IExplorerBrowserEvents implementation */
+    ebev.lpVtbl = &ebevents;
+    pebe = (IExplorerBrowserEvents*) &ebev;
+
+    ebrowser_instantiate(&peb);
+
+    if(0)
+    {
+        /* Crashes on Windows 7 */
+        IExplorerBrowser_Advise(peb, pebe, NULL);
+        IExplorerBrowser_Advise(peb, NULL, &cookies[0]);
+    }
+
+    /* Using Unadvise with a cookie that has yet to be given out
+     * results in E_INVALIDARG */
+    hr = IExplorerBrowser_Unadvise(peb, 11);
+    ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
+
+    /* Add some before initialization */
+    for(i = 0; i < 5; i++)
+    {
+        hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    ebrowser_initialize(peb);
+
+    /* Add some after initialization */
+    for(i = 5; i < 10; i++)
+    {
+        hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    ok(ebev.ref == 10, "Got %d\n", ebev.ref);
+
+    /* Remove a bunch somewhere in the middle */
+    for(i = 4; i < 8; i++)
+    {
+        hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    if(0)
+    {
+        /* Using unadvise with a previously unadvised cookie results
+         * in a crash. */
+        hr = IExplorerBrowser_Unadvise(peb, cookies[5]);
+    }
+
+    /* Remove the rest. */
+    for(i = 0; i < 10; i++)
+    {
+        if(i<4||i>7)
+        {
+            hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
+            ok(hr == S_OK, "%d: got (0x%08x)\n", i, hr);
+        }
+    }
+
+    ok(ebev.ref == 0, "Got %d\n", ebev.ref);
+
+    /* ::Destroy implies ::Unadvise. */
+    hr = IExplorerBrowser_Advise(peb, pebe, &cookies[0]);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(ebev.ref == 1, "Got %d\n", ebev.ref);
+
+    hr = IExplorerBrowser_Destroy(peb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(ebev.ref == 0, "Got %d\n", ebev.ref);
+
+    ref = IExplorerBrowser_Release(peb);
+    ok(!ref, "Got %d", ref);
+}
+
 static BOOL test_instantiate_control(void)
 {
     IExplorerBrowser *peb;
@@ -424,6 +577,7 @@ START_TEST(ebrowser)
     test_SB_misc();
     test_initialization();
     test_basics();
+    test_Advise();
 
     DestroyWindow(hwnd);
     OleUninitialize();
-- 
1.7.2




More information about the wine-patches mailing list