From ac2063a418d5c198333188bd5e7e3c050037d838 Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Tue, 29 Mar 2011 21:13:23 +0200 Subject: [PATCH] comdlg32: Implement Advise/Unadvise for the Item Dialog. --- dlls/comdlg32/itemdlg.c | 54 ++++++++- dlls/comdlg32/tests/itemdlg.c | 201 ++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+), 4 deletions(-) diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 4cb6839e8de..61dcc99084b 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -35,6 +35,7 @@ #include "cdlg.h" #include "wine/debug.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(commdlg); @@ -43,6 +44,12 @@ enum ITEMDLG_TYPE { ITEMDLG_TYPE_SAVE }; +typedef struct { + struct list entry; + IFileDialogEvents *pfde; + DWORD cookie; +} events_client; + typedef struct FileDialogImpl { IFileDialog2 IFileDialog2_iface; union { @@ -57,6 +64,9 @@ typedef struct FileDialogImpl { UINT filterspec_count; UINT filetypeindex; + struct list events_clients; + DWORD events_next_cookie; + IShellItemArray *psia_selection; IShellItemArray *psia_results; IShellItem *psi_defaultfolder; @@ -209,15 +219,48 @@ static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie) { FileDialogImpl *This = impl_from_IFileDialog2(iface); - FIXME("stub - %p (%p, %p)\n", This, pfde, pdwCookie); - return E_NOTIMPL; + events_client *client; + TRACE("%p (%p, %p)\n", This, pfde, pdwCookie); + + if(!pfde || !pdwCookie) + return E_INVALIDARG; + + client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client)); + client->pfde = pfde; + client->cookie = ++This->events_next_cookie; + + IFileDialogEvents_AddRef(pfde); + *pdwCookie = client->cookie; + + list_add_tail(&This->events_clients, &client->entry); + + return S_OK; } static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie) { FileDialogImpl *This = impl_from_IFileDialog2(iface); - FIXME("stub - %p (%d)\n", This, dwCookie); - return E_NOTIMPL; + events_client *client, *found = NULL; + TRACE("%p (%d)\n", This, dwCookie); + + LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry) + { + if(client->cookie == dwCookie) + { + found = client; + break; + } + } + + if(found) + { + list_remove(&found->entry); + IFileDialogEvents_Release(found->pfde); + HeapFree(GetProcessHeap(), 0, found); + return S_OK; + } + + return E_INVALIDARG; } static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos) @@ -997,6 +1040,9 @@ static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **p fdimpl->psia_selection = fdimpl->psia_results = NULL; fdimpl->psi_setfolder = fdimpl->psi_folder = NULL; + list_init(&fdimpl->events_clients); + fdimpl->events_next_cookie = 0; + /* FIXME: The default folder setting should be restored for the * application if it was previously set. */ SHGetDesktopFolder(&psf); diff --git a/dlls/comdlg32/tests/itemdlg.c b/dlls/comdlg32/tests/itemdlg.c index e5f54392638..2e26186401c 100644 --- a/dlls/comdlg32/tests/itemdlg.c +++ b/dlls/comdlg32/tests/itemdlg.c @@ -20,6 +20,7 @@ */ #define COBJMACROS +#define CONST_VTABLE #include "shlobj.h" #include "wine/test.h" @@ -37,6 +38,117 @@ static void init_function_pointers(void) #undef MAKEFUNC } +/************************************************************************** + * IFileDialogEvents implementation + */ +typedef struct { + IFileDialogEvents IFileDialogEvents_iface; + LONG ref; +} IFileDialogEventsImpl; + +static inline IFileDialogEventsImpl *impl_from_IFileDialogEvents(IFileDialogEvents *iface) +{ + return CONTAINING_RECORD(iface, IFileDialogEventsImpl, IFileDialogEvents_iface); +} + +static HRESULT WINAPI IFileDialogEvents_fnQueryInterface(IFileDialogEvents *iface, REFIID riid, void **ppv) +{ + /* Not called. */ + ok(0, "Unexpectedly called.\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI IFileDialogEvents_fnAddRef(IFileDialogEvents *iface) +{ + IFileDialogEventsImpl *This = impl_from_IFileDialogEvents(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IFileDialogEvents_fnRelease(IFileDialogEvents *iface) +{ + IFileDialogEventsImpl *This = impl_from_IFileDialogEvents(iface); + LONG ref = InterlockedDecrement(&This->ref); + + if(!ref) + HeapFree(GetProcessHeap(), 0, This); + + return ref; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnFileOk(IFileDialogEvents *iface, IFileDialog *pfd) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnFolderChanging(IFileDialogEvents *iface, + IFileDialog *pfd, + IShellItem *psiFolder) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnFolderChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnSelectionChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnShareViolation(IFileDialogEvents *iface, + IFileDialog *pfd, + IShellItem *psi, + FDE_SHAREVIOLATION_RESPONSE *pResponse) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnTypeChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static HRESULT WINAPI IFileDialogEvents_fnOnOverwrite(IFileDialogEvents *iface, + IFileDialog *pfd, + IShellItem *psi, + FDE_OVERWRITE_RESPONSE *pResponse) +{ + ok(0, "Unexpectedly called.\n"); + return S_OK; +} + +static const IFileDialogEventsVtbl vt_IFileDialogEvents = { + IFileDialogEvents_fnQueryInterface, + IFileDialogEvents_fnAddRef, + IFileDialogEvents_fnRelease, + IFileDialogEvents_fnOnFileOk, + IFileDialogEvents_fnOnFolderChanging, + IFileDialogEvents_fnOnFolderChange, + IFileDialogEvents_fnOnSelectionChange, + IFileDialogEvents_fnOnShareViolation, + IFileDialogEvents_fnOnTypeChange, + IFileDialogEvents_fnOnOverwrite +}; + +static IFileDialogEvents *IFileDialogEvents_Constructor(void) +{ + IFileDialogEventsImpl *This; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(IFileDialogEventsImpl)); + This->IFileDialogEvents_iface.lpVtbl = &vt_IFileDialogEvents; + This->ref = 1; + + return &This->IFileDialogEvents_iface; +} + static BOOL test_instantiation(void) { IFileDialog *pfd; @@ -635,6 +747,94 @@ static void test_basics(void) IFileSaveDialog_Release(pfsd); } +static void test_advise_helper(IFileDialog *pfd) +{ + IFileDialogEventsImpl *pfdeimpl; + IFileDialogEvents *pfde; + DWORD cookie[10]; + UINT i; + HRESULT hr; + + pfde = IFileDialogEvents_Constructor(); + pfdeimpl = impl_from_IFileDialogEvents(pfde); + + hr = IFileDialog_Advise(pfd, NULL, NULL); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + hr = IFileDialog_Advise(pfd, pfde, NULL); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + hr = IFileDialog_Advise(pfd, NULL, &cookie[0]); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(pfdeimpl->ref == 1, "got ref %d\n", pfdeimpl->ref); + + hr = IFileDialog_Unadvise(pfd, 0); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + for(i = 0; i < 10; i++) { + hr = IFileDialog_Advise(pfd, pfde, &cookie[i]); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(cookie[i] == i+1, "Got cookie: %d\n", cookie[i]); + } + ok(pfdeimpl->ref == 10+1, "got ref %d\n", pfdeimpl->ref); + + for(i = 3; i < 7; i++) { + hr = IFileDialog_Unadvise(pfd, cookie[i]); + ok(hr == S_OK, "got 0x%08x\n", hr); + } + ok(pfdeimpl->ref == 6+1, "got ref %d\n", pfdeimpl->ref); + + for(i = 0; i < 3; i++) { + hr = IFileDialog_Unadvise(pfd, cookie[i]); + ok(hr == S_OK, "got 0x%08x\n", hr); + } + ok(pfdeimpl->ref == 3+1, "got ref %d\n", pfdeimpl->ref); + + for(i = 7; i < 10; i++) { + hr = IFileDialog_Unadvise(pfd, cookie[i]); + ok(hr == S_OK, "got 0x%08x\n", hr); + } + ok(pfdeimpl->ref == 1, "got ref %d\n", pfdeimpl->ref); + + hr = IFileDialog_Unadvise(pfd, cookie[9]+1); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(pfdeimpl->ref == 1, "got ref %d\n", pfdeimpl->ref); + + hr = IFileDialog_Advise(pfd, pfde, &cookie[0]); + ok(hr == S_OK, "got 0x%08x\n", hr); + todo_wine ok(cookie[0] == 1, "got cookie: %d\n", cookie[0]); + ok(pfdeimpl->ref == 1+1, "got ref %d\n", pfdeimpl->ref); + + hr = IFileDialog_Unadvise(pfd, cookie[0]); + + if(0) + { + /* Unadvising already unadvised cookies crashes on + Windows 7. */ + IFileDialog_Unadvise(pfd, cookie[0]); + } + + + IFileDialogEvents_Release(pfde); +} + +static void test_advise(void) +{ + IFileDialog *pfd; + HRESULT hr; + + trace("Testing FileOpenDialog (advise)\n"); + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "got 0x%08x.\n", hr); + test_advise_helper(pfd); + IFileDialog_Release(pfd); + + trace("Testing FileSaveDialog (advise)\n"); + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "got 0x%08x.\n", hr); + test_advise_helper(pfd); + IFileDialog_Release(pfd); +} + START_TEST(itemdlg) { OleInitialize(NULL); @@ -643,6 +843,7 @@ START_TEST(itemdlg) if(test_instantiation()) { test_basics(); + test_advise(); } else skip("Skipping all Item Dialog tests.\n");