From: David Hedberg Subject: [PATCH 1/5] comdlg32/tests: Add some IFileDialogEvents tests. Message-Id: <1409490485-12961-1-git-send-email-david.hedberg@gmail.com> Date: Sun, 31 Aug 2014 15:08:01 +0200 This way of triggering the combobox sadly doesn't work in wine, but I couldn't come up with any other way. Hopefully it's enough to demonstrate that the behavior of wine in the next patch is correct (= sending OnTypeChange also when changing the filetype in the dialog). --- dlls/comdlg32/tests/itemdlg.c | 340 +++++++++++++++++++++++++++++++++--------- 1 file changed, 272 insertions(+), 68 deletions(-) diff --git a/dlls/comdlg32/tests/itemdlg.c b/dlls/comdlg32/tests/itemdlg.c index 5974362..3dcdf73 100644 --- a/dlls/comdlg32/tests/itemdlg.c +++ b/dlls/comdlg32/tests/itemdlg.c @@ -25,6 +25,16 @@ #include "shlobj.h" #include "wine/test.h" +#define IDT_CHANGEFILETYPE 500 +#define IDT_CLOSEDIALOG 501 + +typedef enum { + IFDEVENT_TEST_NONE = 0, + IFDEVENT_TEST1 = 0x1, + IFDEVENT_TEST2 = 0x2, + IFDEVENT_TEST3 = 0x3 +} FileDialogEventsTest; + static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**); static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*); static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**); @@ -43,6 +53,62 @@ static void init_function_pointers(void) #include DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F); +struct fw_arg { + LPCWSTR class, text; + HWND hwnd_res; +}; + +static BOOL CALLBACK find_window_callback(HWND hwnd, LPARAM lparam) +{ + struct fw_arg *arg = (struct fw_arg*)lparam; + WCHAR buf[1024]; + + if(arg->class) + { + GetClassNameW(hwnd, buf, 1024); + if(lstrcmpW(buf, arg->class)) + return TRUE; + } + + if(arg->text) + { + GetWindowTextW(hwnd, buf, 1024); + if(lstrcmpW(buf, arg->text)) + return TRUE; + } + + arg->hwnd_res = hwnd; + return FALSE; +} + +static HWND find_window(HWND parent, LPCWSTR class, LPCWSTR text) +{ + struct fw_arg arg = {class, text, NULL}; + + EnumChildWindows(parent, find_window_callback, (LPARAM)&arg); + return arg.hwnd_res; +} + +static HWND get_hwnd_from_ifiledialog(IFileDialog *pfd) +{ + IOleWindow *pow; + HWND dlg_hwnd; + HRESULT hr; + + hr = IFileDialog_QueryInterface(pfd, &IID_IOleWindow, (void**)&pow); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + hr = IOleWindow_GetWindow(pow, &dlg_hwnd); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + IOleWindow_Release(pow); + + return dlg_hwnd; +} + +static void test_customize_onfolderchange(IFileDialog *pfd); +static void filedialog_change_filetype(IFileDialog *pfd, HWND dlg_hwnd); + /************************************************************************** * IFileDialogEvents implementation */ @@ -55,7 +121,7 @@ typedef struct { LONG OnOverwrite; LPCWSTR set_filename; BOOL set_filename_tried; - BOOL cfd_test1; + FileDialogEventsTest events_test; } IFileDialogEventsImpl; static inline IFileDialogEventsImpl *impl_from_IFileDialogEvents(IFileDialogEvents *iface) @@ -103,25 +169,39 @@ static HRESULT WINAPI IFileDialogEvents_fnOnFolderChanging(IFileDialogEvents *if return S_OK; } -static void test_customize_onfolderchange(IFileDialog *pfd); - -static LRESULT CALLBACK test_customize_dlgproc(HWND hwnd, UINT message, LPARAM lparam, WPARAM wparam) +static LRESULT CALLBACK test_customize_dlgproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { WNDPROC oldwndproc = GetPropA(hwnd, "WT_OLDWC"); + IFileDialog *pfd = GetPropA(hwnd, "WT_PFD"); + BOOL br; - if(message == WM_USER+0x1234) + switch(message) { - IFileDialog *pfd = (IFileDialog*)lparam; + case WM_USER+0x1234: test_customize_onfolderchange(pfd); + break; + case WM_TIMER: + switch(wparam) + { + case IDT_CHANGEFILETYPE: + filedialog_change_filetype(pfd, hwnd); + KillTimer(hwnd, IDT_CHANGEFILETYPE); + SetTimer(hwnd, IDT_CLOSEDIALOG, 100, 0); + return TRUE; + case IDT_CLOSEDIALOG: + /* Calling IFileDialog_Close here does not work */ + br = PostMessageW(hwnd, WM_COMMAND, IDCANCEL, 0); + ok(br, "Failed"); + return TRUE; + } } - return CallWindowProcW(oldwndproc, hwnd, message, lparam, wparam); + return CallWindowProcW(oldwndproc, hwnd, message, wparam, lparam); } static HRESULT WINAPI IFileDialogEvents_fnOnFolderChange(IFileDialogEvents *iface, IFileDialog *pfd) { IFileDialogEventsImpl *This = impl_from_IFileDialogEvents(iface); - IOleWindow *pow; HWND dlg_hwnd; HRESULT hr; BOOL br; @@ -129,15 +209,9 @@ static HRESULT WINAPI IFileDialogEvents_fnOnFolderChange(IFileDialogEvents *ifac if(This->set_filename) { - hr = IFileDialog_QueryInterface(pfd, &IID_IOleWindow, (void**)&pow); - ok(hr == S_OK, "Got 0x%08x\n", hr); - - hr = IOleWindow_GetWindow(pow, &dlg_hwnd); - ok(hr == S_OK, "Got 0x%08x\n", hr); + dlg_hwnd = get_hwnd_from_ifiledialog(pfd); ok(dlg_hwnd != NULL, "Got NULL.\n"); - IOleWindow_Release(pow); - hr = IFileDialog_SetFileName(pfd, This->set_filename); ok(hr == S_OK, "Got 0x%08x\n", hr); @@ -149,27 +223,35 @@ static HRESULT WINAPI IFileDialogEvents_fnOnFolderChange(IFileDialogEvents *ifac } } - if(This->cfd_test1) + if(This->events_test) { WNDPROC oldwndproc; - hr = IFileDialog_QueryInterface(pfd, &IID_IOleWindow, (void**)&pow); - ok(hr == S_OK, "Got 0x%08x\n", hr); - hr = IOleWindow_GetWindow(pow, &dlg_hwnd); - ok(hr == S_OK, "Got 0x%08x\n", hr); - ok(dlg_hwnd != NULL, "Got NULL.\n"); - - IOleWindow_Release(pow); + dlg_hwnd = get_hwnd_from_ifiledialog(pfd); /* On Vista, the custom control area of the dialog is not * fully set up when the first OnFolderChange event is * issued. */ oldwndproc = (WNDPROC)GetWindowLongPtrW(dlg_hwnd, GWLP_WNDPROC); SetPropA(dlg_hwnd, "WT_OLDWC", (HANDLE)oldwndproc); + SetPropA(dlg_hwnd, "WT_PFD", (HANDLE)pfd); SetWindowLongPtrW(dlg_hwnd, GWLP_WNDPROC, (LPARAM)test_customize_dlgproc); - br = PostMessageW(dlg_hwnd, WM_USER+0x1234, (LPARAM)pfd, 0); - ok(br, "Failed\n"); + switch(This->events_test) + { + case IFDEVENT_TEST1: + br = PostMessageW(dlg_hwnd, WM_USER+0x1234, 0, 0); + ok(br, "Failed\n"); + break; + case IFDEVENT_TEST2: + SetTimer(dlg_hwnd, IDT_CLOSEDIALOG, 100, 0); + break; + case IFDEVENT_TEST3: + SetTimer(dlg_hwnd, IDT_CHANGEFILETYPE, 100, 0); + break; + default: + ok(FALSE, "Should not happen (%d)\n", This->events_test); + } } return S_OK; @@ -1008,6 +1090,168 @@ static void test_advise(void) ok(!ref, "Got refcount %d, should have been released.\n", ref); } +static void filedialog_change_filetype(IFileDialog *pfd, HWND dlg_hwnd) +{ + HWND cb_filetype; + const WCHAR filetype1[] = {'f','n','a','m','e','1',0}; + const WCHAR filetype1_broken[] = {'f','n','a','m','e','1',' ', '(','*','.','t','x','t',')',0}; + + cb_filetype = find_window(dlg_hwnd, NULL, filetype1); + ok(cb_filetype != NULL || broken(cb_filetype == NULL), "Could not find combobox on first attempt\n"); + + if(!cb_filetype) + { + /* Not sure when this happens. Some specific version? + * Seen on 32-bit English Vista */ + trace("Didn't find combobox on first attempt, trying broken string..\n"); + cb_filetype = find_window(dlg_hwnd, NULL, filetype1_broken); + ok(broken(cb_filetype != NULL), "Failed to find combobox on second attempt\n"); + if(!cb_filetype) + return; + } + + /* Making the combobox send a CBN_SELCHANGE */ + SendMessageW( cb_filetype, CB_SHOWDROPDOWN, 1, 0 ); + SendMessageW( cb_filetype, CB_SETCURSEL, 1, 0 ); + SendMessageW( cb_filetype, WM_LBUTTONDOWN, 0, -1 ); + SendMessageW( cb_filetype, WM_LBUTTONUP, 0, -1 ); +} + +static void test_events(void) +{ + IFileDialog *pfd; + IFileDialogEventsImpl *pfdeimpl; + IFileDialogEvents *pfde; + DWORD cookie; + ULONG ref; + HRESULT hr; + const WCHAR fname1[] = {'f','n','a','m','e','1', 0}; + const WCHAR fspec1[] = {'*','.','t','x','t',0}; + const WCHAR fname2[] = {'f','n','a','m','e','2', 0}; + const WCHAR fspec2[] = {'*','.','e','x','e',0}; + COMDLG_FILTERSPEC filterspec[3] = {{fname1, fspec1}, {fname2, fspec2}}; + + + /* + * 1. Show the dialog with no filetypes added + */ + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + pfde = IFileDialogEvents_Constructor(); + pfdeimpl = impl_from_IFileDialogEvents(pfde); + pfdeimpl->events_test = IFDEVENT_TEST2; + + hr = IFileDialog_Advise(pfd, pfde, &cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + hr = IFileDialog_Show(pfd, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "got 0x%08x.\n", hr); + + ok(pfdeimpl->OnFolderChanging == 1, "Got %d\n", pfdeimpl->OnFolderChanging); + pfdeimpl->OnFolderChanging = 0; + ok(pfdeimpl->OnFolderChange == 1, "Got %d\n", pfdeimpl->OnFolderChange); + pfdeimpl->OnFolderChange = 0; + /* pfdeimpl->OnSelectionChange too unreliable to test. Can be 0, 1 or even 2. */ + pfdeimpl->OnSelectionChange = 0; + ok(pfdeimpl->OnTypeChange == 0, "Got %d\n", pfdeimpl->OnTypeChange); + pfdeimpl->OnTypeChange = 0; + + ensure_zero_events(pfdeimpl); + + hr = IFileDialog_Unadvise(pfd, cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + IFileDialogEvents_Release(pfde); + ref = IFileDialog_Release(pfd); + ok(!ref || broken(ref == 3 /* win2008_64 */), "Got %d\n", ref); + + + /* + * 2. Show the dialog with filetypes added + */ + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + pfde = IFileDialogEvents_Constructor(); + pfdeimpl = impl_from_IFileDialogEvents(pfde); + pfdeimpl->events_test = IFDEVENT_TEST2; + + hr = IFileDialog_Advise(pfd, pfde, &cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + hr = IFileDialog_SetFileTypes(pfd, 2, filterspec); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + ensure_zero_events(pfdeimpl); + + hr = IFileDialog_Show(pfd, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "got 0x%08x.\n", hr); + + ok(pfdeimpl->OnFolderChanging == 1, "Got %d\n", pfdeimpl->OnFolderChanging); + pfdeimpl->OnFolderChanging = 0; + ok(pfdeimpl->OnFolderChange == 1, "Got %d\n", pfdeimpl->OnFolderChange); + pfdeimpl->OnFolderChange = 0; + /* pfdeimpl->OnSelectionChange too unreliable to test. Can be 0, 1 or even 2. */ + pfdeimpl->OnSelectionChange = 0; + /* Called once just by showing the dialog */ + todo_wine ok(pfdeimpl->OnTypeChange == 1, "Got %d\n", pfdeimpl->OnTypeChange); + pfdeimpl->OnTypeChange = 0; + + ensure_zero_events(pfdeimpl); + + hr = IFileDialog_Unadvise(pfd, cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + IFileDialogEvents_Release(pfde); + ref = IFileDialog_Release(pfd); + ok(!ref, "Got %d\n", ref); + + + /* + * 3. Show the dialog with filetypes added and simulate manual change of filetype + */ + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + pfde = IFileDialogEvents_Constructor(); + pfdeimpl = impl_from_IFileDialogEvents(pfde); + pfdeimpl->events_test = IFDEVENT_TEST3; + + hr = IFileDialog_Advise(pfd, pfde, &cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + hr = IFileDialog_SetFileTypes(pfd, 2, filterspec); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + ensure_zero_events(pfdeimpl); + + hr = IFileDialog_Show(pfd, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "got 0x%08x.\n", hr); + + ok(pfdeimpl->OnFolderChanging == 1, "Got %d\n", pfdeimpl->OnFolderChanging); + pfdeimpl->OnFolderChanging = 0; + ok(pfdeimpl->OnFolderChange == 1, "Got %d\n", pfdeimpl->OnFolderChange); + pfdeimpl->OnFolderChange = 0; + /* pfdeimpl->OnSelectionChange too unreliable to test. Can be 0, 1 or even 2. */ + pfdeimpl->OnSelectionChange = 0; + /* Called once by showing the dialog and once again when changing the filetype */ + todo_wine ok(pfdeimpl->OnTypeChange == 2, "Got %d\n", pfdeimpl->OnTypeChange); + pfdeimpl->OnTypeChange = 0; + + ensure_zero_events(pfdeimpl); + + hr = IFileDialog_Unadvise(pfd, cookie); + ok(hr == S_OK, "got 0x%08x.\n", hr); + + IFileDialogEvents_Release(pfde); + ref = IFileDialog_Release(pfd); + ok(!ref, "Got %d\n", ref); +} + static void touch_file(LPCWSTR filename) { HANDLE file; @@ -1269,57 +1513,16 @@ static const WCHAR visualgroup2W[] = {'v','i','s','u','a','l','g','r','o','u','p static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0}; static const WCHAR RadioButtonListW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0}; -struct fw_arg { - LPCWSTR class, text; - HWND hwnd_res; -}; -static BOOL CALLBACK find_window_callback(HWND hwnd, LPARAM lparam) -{ - struct fw_arg *arg = (struct fw_arg*)lparam; - WCHAR buf[1024]; - - if(arg->class) - { - GetClassNameW(hwnd, buf, 1024); - if(lstrcmpW(buf, arg->class)) - return TRUE; - } - - if(arg->text) - { - GetWindowTextW(hwnd, buf, 1024); - if(lstrcmpW(buf, arg->text)) - return TRUE; - } - - arg->hwnd_res = hwnd; - return FALSE; -} - -static HWND find_window(HWND parent, LPCWSTR class, LPCWSTR text) -{ - struct fw_arg arg = {class, text, NULL}; - - EnumChildWindows(parent, find_window_callback, (LPARAM)&arg); - return arg.hwnd_res; -} - static void test_customize_onfolderchange(IFileDialog *pfd) { - IOleWindow *pow; HWND dlg_hwnd, item, item_parent; - HRESULT hr; BOOL br; WCHAR buf[1024]; buf[0] = '\0'; - hr = IFileDialog_QueryInterface(pfd, &IID_IOleWindow, (void**)&pow); - ok(hr == S_OK, "Got 0x%08x\n", hr); - hr = IOleWindow_GetWindow(pow, &dlg_hwnd); - ok(hr == S_OK, "Got 0x%08x\n", hr); + dlg_hwnd = get_hwnd_from_ifiledialog(pfd); ok(dlg_hwnd != NULL, "Got NULL.\n"); - IOleWindow_Release(pow); item = find_window(dlg_hwnd, NULL, checkbutton2W); ok(item != NULL, "Failed to find item.\n"); @@ -1665,7 +1868,7 @@ static void test_customize(void) pfde = IFileDialogEvents_Constructor(); pfdeimpl = impl_from_IFileDialogEvents(pfde); - pfdeimpl->cfd_test1 = TRUE; + pfdeimpl->events_test = IFDEVENT_TEST1; hr = IFileDialog_Advise(pfod, pfde, &cookie); ok(hr == S_OK, "Got 0x%08x\n", hr); @@ -2053,6 +2256,7 @@ START_TEST(itemdlg) { test_basics(); test_advise(); + test_events(); test_filename(); test_customize(); test_persistent_state(); -- 1.9.1