Module: wine Branch: master Commit: b88c3e2ecbf72a3a785b8846ebd630dd6bfcca3e URL: http://source.winehq.org/git/wine.git/?a=commit;h=b88c3e2ecbf72a3a785b8846eb...
Author: David Hedberg david.hedberg@gmail.com Date: Tue Aug 24 10:56:19 2010 +0200
shell32: Implement IExplorerBrowser::Advise and IExplorerBrowser::Unadvise.
---
dlls/shell32/ebrowser.c | 61 +++++++++++++++- dlls/shell32/tests/ebrowser.c | 155 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 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..2d90d06 100644 --- a/dlls/shell32/tests/ebrowser.c +++ b/dlls/shell32/tests/ebrowser.c @@ -44,6 +44,77 @@ 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; + +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 @@ 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 +578,7 @@ START_TEST(ebrowser) test_SB_misc(); test_initialization(); test_basics(); + test_Advise();
DestroyWindow(hwnd); OleUninitialize();