shell32: Implement IExplorerBrowser::Advise and IExplorerBrowser::Unadvise.
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 @@
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 @@
This->hwnd_sv = NULL;
}
+ events_unadvise_all(This);
+
DestroyWindow(This->hwnd_main);
This->destroyed = TRUE;
@@ -314,18 +343,40 @@
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 @@
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..2d90d06 100644
--- a/dlls/shell32/tests/ebrowser.c
+++ b/dlls/shell32/tests/ebrowser.c
@@ -44,6 +44,77 @@
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;
+
+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)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ return InterlockedDecrement(&This->ref);
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
+ PCIDLIST_ABSOLUTE pidlFolder)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ This->pending++;
+ return S_OK;
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
+ PCIDLIST_ABSOLUTE pidlFolder)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ This->completed++;
+ return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
+ PCIDLIST_ABSOLUTE pidlFolder)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ This->failed++;
+ return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
+ IShellView *psv)
+{
+ IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
+ This->created++;
+ return S_OK;
+}
+
+static const IExplorerBrowserEventsVtbl ebevents =
+{
+ IExplorerBrowserEvents_fnQueryInterface,
+ IExplorerBrowserEvents_fnAddRef,
+ IExplorerBrowserEvents_fnRelease,
+ IExplorerBrowserEvents_fnOnNavigationPending,
+ IExplorerBrowserEvents_fnOnViewCreated,
+ IExplorerBrowserEvents_fnOnNavigationComplete,
+ IExplorerBrowserEvents_fnOnNavigationFailed
+};
+
static void test_QueryInterface(void)
{
IExplorerBrowser *peb;
@@ -378,6 +449,89 @@
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 +578,7 @@
test_SB_misc();
test_initialization();
test_basics();
+ test_Advise();
DestroyWindow(hwnd);
OleUninitialize();