shell32: Implement IExplorerBrowser::Advise and IExplorerBrowser::Unadvise.
This commit is contained in:
parent
2ca5513a62
commit
b88c3e2ecb
|
@ -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,10 +54,30 @@ 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue