#include "cdlg.h"
#include "wine/debug.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
ITEMDLG_TYPE_SAVE
};
+typedef struct {
+ struct list entry;
+ IFileDialogEvents *pfde;
+ DWORD cookie;
+} events_client;
+
typedef struct FileDialogImpl {
IFileDialog2 IFileDialog2_iface;
union {
UINT filterspec_count;
UINT filetypeindex;
+ struct list events_clients;
+ DWORD events_next_cookie;
+
IShellItemArray *psia_selection;
IShellItemArray *psia_results;
IShellItem *psi_defaultfolder;
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)
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);
*/
#define COBJMACROS
+#define CONST_VTABLE
#include "shlobj.h"
#include "wine/test.h"
#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;
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);
if(test_instantiation())
{
test_basics();
+ test_advise();
}
else
skip("Skipping all Item Dialog tests.\n");