push 5aff8350ceade24f8243f07a9cf7ecb816236fb1
[wine/hacks.git] / dlls / comdlg32 / tests / filedlg.c
blobcb9508ea759a9e7073163295d928fc45944c75e6
1 /*
2 * Unit test suite for comdlg32 API functions: file dialogs
4 * Copyright 2007 Google (Lei Zhang)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <windows.h>
23 #include <wine/test.h>
25 #include "initguid.h"
26 #include "shlguid.h"
27 #define COBJMACROS
28 #include "shobjidl.h"
30 /* ##### */
32 static void toolbarcheck( HWND hDlg)
34 /* test toolbar properties */
35 /* bug #10532 */
36 int maxtextrows;
37 HWND ctrl;
38 DWORD ret;
39 char classname[20];
41 for( ctrl = GetWindow( hDlg, GW_CHILD);
42 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT)) {
43 GetClassName( ctrl, classname, 10);
44 classname[7] = '\0';
45 if( !strcmp( classname, "Toolbar")) break;
47 ok( ctrl != NULL, "could not get the toolbar control\n");
48 ret = SendMessage( ctrl, TB_ADDSTRING, 0, (LPARAM)"winetestwinetest\0\0");
49 ok( ret == 0, "addstring returned %d (expected 0)\n", ret);
50 maxtextrows = SendMessage( ctrl, TB_GETTEXTROWS, 0, 0);
51 ok( maxtextrows == 0 || broken(maxtextrows == 1), /* Win2k and below */
52 "Get(Max)TextRows returned %d (expected 0)\n", maxtextrows);
56 static UINT_PTR CALLBACK OFNHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
58 LPNMHDR nmh;
60 if( msg == WM_NOTIFY)
62 nmh = (LPNMHDR) lParam;
63 if( nmh->code == CDN_INITDONE)
65 PostMessage( GetParent(hDlg), WM_COMMAND, IDCANCEL, FALSE);
66 } else if (nmh->code == CDN_FOLDERCHANGE )
68 char buf[1024];
69 int ret;
71 memset(buf, 0x66, sizeof(buf));
72 ret = SendMessage( GetParent(hDlg), CDM_GETFOLDERIDLIST, 5, (LPARAM)buf);
73 ok(ret > 0, "CMD_GETFOLDERIDLIST not implemented\n");
74 if (ret > 5)
75 ok(buf[0] == 0x66 && buf[1] == 0x66, "CMD_GETFOLDERIDLIST: The buffer was touched on failure\n");
76 toolbarcheck( GetParent(hDlg));
80 return 0;
83 /* bug 6829 */
84 static void test_DialogCancel(void)
86 OPENFILENAMEA ofn;
87 BOOL result;
88 char szFileName[MAX_PATH] = "";
89 char szInitialDir[MAX_PATH];
91 GetWindowsDirectory(szInitialDir, MAX_PATH);
93 ZeroMemory(&ofn, sizeof(ofn));
95 ofn.lStructSize = sizeof(ofn);
96 ofn.hwndOwner = NULL;
97 ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
98 ofn.lpstrFile = szFileName;
99 ofn.nMaxFile = MAX_PATH;
100 ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLEHOOK;
101 ofn.lpstrDefExt = "txt";
102 ofn.lpfnHook = OFNHookProc;
103 ofn.lpstrInitialDir = szInitialDir;
105 PrintDlgA(NULL);
106 ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
107 "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
109 result = GetOpenFileNameA(&ofn);
110 ok(0 == result, "expected 0, got %d\n", result);
111 ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
112 CommDlgExtendedError());
114 PrintDlgA(NULL);
115 ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
116 "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
118 result = GetSaveFileNameA(&ofn);
119 ok(0 == result, "expected 0, got %d\n", result);
120 ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
121 CommDlgExtendedError());
123 PrintDlgA(NULL);
124 ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
125 "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
127 /* Before passing the ofn to Unicode functions, remove the ANSI strings */
128 ofn.lpstrFilter = NULL;
129 ofn.lpstrInitialDir = NULL;
130 ofn.lpstrDefExt = NULL;
132 PrintDlgA(NULL);
133 ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
134 "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
136 SetLastError(0xdeadbeef);
137 result = GetOpenFileNameW((LPOPENFILENAMEW) &ofn);
138 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
139 win_skip("GetOpenFileNameW is not implemented\n");
140 else
142 ok(0 == result, "expected 0, got %d\n", result);
143 ok(0 == CommDlgExtendedError() ||
144 broken(CDERR_INITIALIZATION == CommDlgExtendedError()), /* win9x */
145 "expected 0, got %d\n", CommDlgExtendedError());
148 SetLastError(0xdeadbeef);
149 result = GetSaveFileNameW((LPOPENFILENAMEW) &ofn);
150 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
151 win_skip("GetSaveFileNameW is not implemented\n");
152 else
154 ok(0 == result, "expected 0, got %d\n", result);
155 ok(0 == CommDlgExtendedError() ||
156 broken(CDERR_INITIALIZATION == CommDlgExtendedError()), /* win9x */
157 "expected 0, got %d\n", CommDlgExtendedError());
161 static UINT_PTR CALLBACK create_view_window2_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
163 if (msg == WM_NOTIFY)
165 if (((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE)
167 IShellBrowser *shell_browser = (IShellBrowser *)SendMessage(GetParent(dlg), WM_USER + 7 /* WM_GETISHELLBROWSER */, 0, 0);
168 IShellView *shell_view = NULL;
169 IShellView2 *shell_view2 = NULL;
170 SV2CVW2_PARAMS view_params;
171 FOLDERSETTINGS folder_settings;
172 HRESULT hr;
173 RECT rect = {0, 0, 0, 0};
175 hr = IShellBrowser_QueryActiveShellView(shell_browser, &shell_view);
176 ok(SUCCEEDED(hr), "QueryActiveShellView returned %#x\n", hr);
177 if (FAILED(hr)) goto cleanup;
179 hr = IShellView_QueryInterface(shell_view, &IID_IShellView2, (void **)&shell_view2);
180 if (hr == E_NOINTERFACE)
182 win_skip("IShellView2 not supported\n");
183 goto cleanup;
185 ok(SUCCEEDED(hr), "QueryInterface returned %#x\n", hr);
186 if (FAILED(hr)) goto cleanup;
188 hr = IShellView2_DestroyViewWindow(shell_view2);
189 ok(SUCCEEDED(hr), "DestroyViewWindow returned %#x\n", hr);
191 folder_settings.ViewMode = FVM_LIST;
192 folder_settings.fFlags = 0;
194 view_params.cbSize = sizeof(view_params);
195 view_params.psvPrev = NULL;
196 view_params.pfs = &folder_settings;
197 view_params.psbOwner = shell_browser;
198 view_params.prcView = &rect;
199 view_params.pvid = NULL;
200 view_params.hwndView = NULL;
202 hr = IShellView2_CreateViewWindow2(shell_view2, &view_params);
203 ok(SUCCEEDED(hr), "CreateViewWindow2 returned %#x\n", hr);
204 if (FAILED(hr)) goto cleanup;
206 hr = IShellView2_GetCurrentInfo(shell_view2, &folder_settings);
207 ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr);
208 ok(folder_settings.ViewMode == FVM_LIST,
209 "view mode is %d, expected FVM_LIST\n",
210 folder_settings.ViewMode);
212 hr = IShellView2_DestroyViewWindow(shell_view2);
213 ok(SUCCEEDED(hr), "DestroyViewWindow returned %#x\n", hr);
215 /* XP and W2K3 need this. On Win9x and W2K the call to DestroyWindow() fails and has
216 * no side effects. NT4 doesn't get here. (FIXME: Vista doesn't get here yet).
218 DestroyWindow(view_params.hwndView);
220 view_params.pvid = &VID_Details;
221 hr = IShellView2_CreateViewWindow2(shell_view2, &view_params);
222 ok(SUCCEEDED(hr), "CreateViewWindow2 returned %#x\n", hr);
223 if (FAILED(hr)) goto cleanup;
225 hr = IShellView2_GetCurrentInfo(shell_view2, &folder_settings);
226 ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr);
227 ok(folder_settings.ViewMode == FVM_DETAILS ||
228 broken(folder_settings.ViewMode == FVM_LIST), /* Win9x */
229 "view mode is %d, expected FVM_DETAILS\n",
230 folder_settings.ViewMode);
232 cleanup:
233 if (shell_view2) IShellView2_Release(shell_view2);
234 if (shell_view) IShellView_Release(shell_view);
235 PostMessage(GetParent(dlg), WM_COMMAND, IDCANCEL, 0);
238 return 0;
241 static LONG_PTR WINAPI template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
243 if (msg == WM_INITDIALOG)
245 HWND p,cb;
246 INT sel;
247 p = GetParent(dlg);
248 ok(p!=NULL, "Failed to get parent of template\n");
249 cb = GetDlgItem(p,0x470);
250 ok(cb!=NULL, "Failed to get filter combobox\n");
251 sel = SendMessage(cb, CB_GETCURSEL, 0, 0);
252 ok (sel != -1, "Failed to get selection from filter listbox\n");
254 if (msg == WM_NOTIFY)
256 if (((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE)
257 PostMessage(GetParent(dlg), WM_COMMAND, IDCANCEL, 0);
259 return 0;
262 static void test_create_view_window2(void)
264 OPENFILENAMEA ofn = {0};
265 char filename[1024] = {0};
266 DWORD ret;
268 ofn.lStructSize = sizeof(ofn);
269 ofn.lpstrFile = filename;
270 ofn.nMaxFile = 1024;
271 ofn.lpfnHook = create_view_window2_hook;
272 ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER;
273 ret = GetOpenFileNameA(&ofn);
274 ok(!ret, "GetOpenFileNameA returned %#x\n", ret);
275 ret = CommDlgExtendedError();
276 ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
279 static void test_create_view_template(void)
281 OPENFILENAMEA ofn = {0};
282 char filename[1024] = {0};
283 DWORD ret;
285 ofn.lStructSize = sizeof(ofn);
286 ofn.lpstrFile = filename;
287 ofn.nMaxFile = 1024;
288 ofn.lpfnHook = (LPOFNHOOKPROC)template_hook;
289 ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE;
290 ofn.hInstance = GetModuleHandleA(NULL);
291 ofn.lpTemplateName = "template1";
292 ofn.lpstrFilter="text\0*.txt\0All\0*\0\0";
293 ret = GetOpenFileNameA(&ofn);
294 ok(!ret, "GetOpenFileNameA returned %#x\n", ret);
295 ret = CommDlgExtendedError();
296 ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
299 /* test cases for resizing of the file dialog */
300 struct {
301 DWORD flags;
302 int resize_folderchange;/* change in CDN_FOLDERCHANGE handler */
303 int resize_timer1; /* change in first WM_TIMER handler */
304 int resize_check; /* expected change (in second WM_TIMER handler) */
305 BOOL todo; /* mark that test todo_wine */
306 BOOL testcontrols; /* test resizing and moving of the controls */
307 } resize_testcases[] = {
308 { 0 , 10, 10, 20,FALSE,FALSE}, /* 0 */
309 { 0 ,-10,-10,-20,FALSE,FALSE},
310 { OFN_ENABLESIZING , 0, 0, 0,FALSE,FALSE},
311 { OFN_ENABLESIZING , 0,-10, 0,FALSE,FALSE},
312 { OFN_ENABLESIZING , 0, 10, 10,FALSE, TRUE},
313 { OFN_ENABLESIZING ,-10, 0, 10,FALSE,FALSE}, /* 5 */
314 { OFN_ENABLESIZING , 10, 0, 10,FALSE,FALSE},
315 { OFN_ENABLESIZING , 0, 10, 20,FALSE,FALSE},
316 /* mark the end */
317 { 0xffffffff }
320 static LONG_PTR WINAPI resize_template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
322 static RECT initrc, rc;
323 static int index, count;
324 static int gotSWP_bottom, gotShowWindow;
325 HWND parent = GetParent( dlg);
326 int resize;
327 #define MAXNRCTRLS 30
328 static RECT ctrlrcs[MAXNRCTRLS];
329 static int ctrlids[MAXNRCTRLS];
330 static HWND ctrls[MAXNRCTRLS];
331 static int nrctrls;
333 switch( msg)
335 case WM_INITDIALOG:
337 DWORD style;
339 index = ((OPENFILENAME*)lParam)->lCustData;
340 count = 0;
341 gotSWP_bottom = gotShowWindow = 0;
342 /* test style */
343 style = GetWindowLong( parent, GWL_STYLE);
344 if( resize_testcases[index].flags & OFN_ENABLESIZING)
345 if( !(style & WS_SIZEBOX)) {
346 win_skip( "OFN_ENABLESIZING flag not supported.\n");
347 PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
348 } else
349 ok( style & WS_SIZEBOX,
350 "testid %d: dialog should have a WS_SIZEBOX style.\n", index);
351 else
352 ok( !(style & WS_SIZEBOX),
353 "testid %d: dialog should not have a WS_SIZEBOX style.\n", index);
354 break;
356 case WM_NOTIFY:
358 if(( (LPNMHDR)lParam)->code == CDN_FOLDERCHANGE){
359 GetWindowRect( parent, &initrc);
360 if( (resize = resize_testcases[index].resize_folderchange)){
361 MoveWindow( parent, initrc.left,initrc.top, initrc.right - initrc.left + resize,
362 initrc.bottom - initrc.top + resize, TRUE);
364 SetTimer( dlg, 0, 100, 0);
366 break;
368 case WM_TIMER:
370 if( count == 0){
371 /* store the control rectangles */
372 if( resize_testcases[index].testcontrols) {
373 HWND ctrl;
374 int i;
375 for( i = 0, ctrl = GetWindow( parent, GW_CHILD);
376 i < MAXNRCTRLS && ctrl;
377 i++, ctrl = GetWindow( ctrl, GW_HWNDNEXT)) {
378 ctrlids[i] = GetDlgCtrlID( ctrl);
379 GetWindowRect( ctrl, &ctrlrcs[i]);
380 MapWindowPoints( NULL, parent, (LPPOINT) &ctrlrcs[i], 2);
381 ctrls[i] = ctrl;
383 nrctrls = i;
385 if( (resize = resize_testcases[index].resize_timer1)){
386 GetWindowRect( parent, &rc);
387 MoveWindow( parent, rc.left,rc.top, rc.right - rc.left + resize,
388 rc.bottom - rc.top + resize, TRUE);
390 } else if( count == 1){
391 resize = resize_testcases[index].resize_check;
392 GetWindowRect( parent, &rc);
393 if( resize_testcases[index].todo){
394 todo_wine {
395 ok( resize == rc.right - rc.left - initrc.right + initrc.left,
396 "testid %d size-x change %d expected %d\n", index,
397 rc.right - rc.left - initrc.right + initrc.left, resize);
398 ok( resize == rc.bottom - rc.top - initrc.bottom + initrc.top,
399 "testid %d size-y change %d expected %d\n", index,
400 rc.bottom - rc.top - initrc.bottom + initrc.top, resize);
402 }else{
403 ok( resize == rc.right - rc.left - initrc.right + initrc.left,
404 "testid %d size-x change %d expected %d\n", index,
405 rc.right - rc.left - initrc.right + initrc.left, resize);
406 ok( resize == rc.bottom - rc.top - initrc.bottom + initrc.top,
407 "testid %d size-y change %d expected %d\n", index,
408 rc.bottom - rc.top - initrc.bottom + initrc.top, resize);
410 if( resize_testcases[index].testcontrols) {
411 int i;
412 RECT rc;
413 for( i = 0; i < nrctrls; i++) {
414 GetWindowRect( ctrls[i], &rc);
415 MapWindowPoints( NULL, parent, (LPPOINT) &rc, 2);
416 switch( ctrlids[i]){
418 /* test if RECT R1, moved and sized result in R2 */
419 #define TESTRECTS( R1, R2, Mx, My, Sx, Sy) \
420 ((R1).left + (Mx) ==(R2).left \
421 &&(R1).top + (My) ==(R2).top \
422 &&(R1).right + (Mx) + (Sx) == (R2).right \
423 &&(R1).bottom + (My) + (Sy) ==(R2).bottom)
425 /* sized horizontal and moved vertical */
426 case cmb1:
427 case edt1:
428 ok( TESTRECTS( ctrlrcs[i], rc, 0, 10, 10, 0) ||
429 broken(TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0)),/*win98*/
430 "control id %03x should have sized horizontally and moved vertically, before %d,%d-%d,%d after %d,%d-%d,%d\n",
431 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
432 ctrlrcs[i].right, ctrlrcs[i].bottom,
433 rc.left, rc.top, rc.right, rc.bottom);
434 break;
435 /* sized horizontal and vertical */
436 case lst2:
437 ok( TESTRECTS( ctrlrcs[i], rc, 0, 0, 10, 10),
438 "control id %03x should have sized horizontally and vertically, before %d,%d-%d,%d after %d,%d-%d,%d\n",
439 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
440 ctrlrcs[i].right, ctrlrcs[i].bottom,
441 rc.left, rc.top, rc.right, rc.bottom);
442 break;
443 /* moved horizontal and vertical */
444 case IDCANCEL:
445 case pshHelp:
446 ok( TESTRECTS( ctrlrcs[i], rc, 10, 10, 0, 0) ||
447 broken(TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0)),/*win98*/
448 "control id %03x should have moved horizontally and vertically, before %d,%d-%d,%d after %d,%d-%d,%d\n",
449 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
450 ctrlrcs[i].right, ctrlrcs[i].bottom,
451 rc.left, rc.top, rc.right, rc.bottom);
452 break;
453 /* moved vertically */
454 case chx1:
455 case stc2:
456 case stc3:
457 ok( TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0),
458 "control id %03x should have moved vertically, before %d,%d-%d,%d after %d,%d-%d,%d\n",
459 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
460 ctrlrcs[i].right, ctrlrcs[i].bottom,
461 rc.left, rc.top, rc.right, rc.bottom);
462 break;
463 /* resized horizontal */
464 case cmb2: /* aka IDC_LOOKIN */
465 ok( TESTRECTS( ctrlrcs[i], rc, 0, 0, 10, 0)||
466 TESTRECTS( ctrlrcs[i], rc, 0, 0, 0, 0), /* Vista and higher */
467 "control id %03x should have resized horizontally, before %d,%d-%d,%d after %d,%d-%d,%d\n",
468 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
469 ctrlrcs[i].right, ctrlrcs[i].bottom,
470 rc.left, rc.top, rc.right, rc.bottom);
471 break;
472 /* non moving non sizing controls */
473 case stc4:
474 ok( TESTRECTS( rc, ctrlrcs[i], 0, 0, 0, 0),
475 "control id %03x was moved/resized, before %d,%d-%d,%d after %d,%d-%d,%d\n",
476 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
477 ctrlrcs[i].right, ctrlrcs[i].bottom,
478 rc.left, rc.top, rc.right, rc.bottom);
479 break;
480 /* todo_wine: non moving non sizing controls */
481 case lst1:
482 todo_wine
483 ok( TESTRECTS( rc, ctrlrcs[i], 0, 0, 0, 0),
484 "control id %03x was moved/resized, before %d,%d-%d,%d after %d,%d-%d,%d\n",
485 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
486 ctrlrcs[i].right, ctrlrcs[i].bottom,
487 rc.left, rc.top, rc.right, rc.bottom);
488 break;
489 /* don't test: id is not unique */
490 case IDOK:
491 case stc1:
492 case 0:
493 case -1:
494 break;
495 default:
496 trace("untested control id %03x before %d,%d-%d,%d after %d,%d-%d,%d\n",
497 ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
498 ctrlrcs[i].right, ctrlrcs[i].bottom,
499 rc.left, rc.top, rc.right, rc.bottom);
500 #undef TESTRECTS
501 #undef MAXNRCTRLS
505 KillTimer( dlg, 0);
506 PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
508 count++;
510 break;
511 case WM_WINDOWPOSCHANGING:
513 WINDOWPOS *pwp = (WINDOWPOS *)lParam;
514 if( !index && pwp->hwndInsertAfter == HWND_BOTTOM){
515 gotSWP_bottom = 1;
516 ok( gotShowWindow == 0, "The WM_WINDOWPOSCHANGING message came after a WM_SHOWWINDOW message\n");
519 break;
520 case WM_SHOWWINDOW:
522 if( !index){
523 gotShowWindow = 1;
524 ok( gotSWP_bottom == 1, "No WM_WINDOWPOSCHANGING message came before a WM_SHOWWINDOW message\n");
527 break;
529 return 0;
532 static void test_resize(void)
534 OPENFILENAME ofn = { sizeof(OPENFILENAME)};
535 char filename[1024] = {0};
536 DWORD ret;
537 int i;
539 ofn.lpstrFile = filename;
540 ofn.nMaxFile = 1024;
541 ofn.lpfnHook = (LPOFNHOOKPROC) resize_template_hook;
542 ofn.hInstance = GetModuleHandle(NULL);
543 ofn.lpTemplateName = "template_sz";
544 for( i = 0; resize_testcases[i].flags != 0xffffffff; i++) {
545 ofn.lCustData = i;
546 ofn.Flags = resize_testcases[i].flags |
547 OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE | OFN_SHOWHELP ;
548 ret = GetOpenFileName(&ofn);
549 ok(!ret, "GetOpenFileName returned %#x\n", ret);
550 ret = CommDlgExtendedError();
551 ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
555 /* test cases for control message IDOK */
556 /* Show case for bug #19079 */
557 static struct {
558 int retval; /* return code of the message handler */
559 BOOL setmsgresult; /* set the result in the DWLP_MSGRESULT */
560 BOOL usemsgokstr; /* use the FILEOKSTRING message instead of WM_NOTIFY:CDN_FILEOK */
561 BOOL do_subclass; /* subclass the dialog hook procedure */
562 BOOL expclose; /* is the dialog expected to close ? */
563 BOOL actclose; /* has the dialog actually closed ? */
564 } ok_testcases[] = {
565 { 0, FALSE, FALSE, FALSE, TRUE},
566 { 0, TRUE, FALSE, FALSE, TRUE},
567 { 0, FALSE, FALSE, TRUE, TRUE},
568 { 0, TRUE, FALSE, TRUE, TRUE},
569 { 1, FALSE, FALSE, FALSE, TRUE},
570 { 1, TRUE, FALSE, FALSE, FALSE},
571 { 1, FALSE, FALSE, TRUE, FALSE},
572 { 1, TRUE, FALSE, TRUE, FALSE},
573 /* FILEOKSTRING tests */
574 { 1, TRUE, TRUE, FALSE, FALSE},
575 { 1, FALSE, TRUE, TRUE, FALSE},
576 /* mark the end */
577 { -1 }
580 /* test_ok_wndproc can be used as hook procedure or a subclass
581 * window proc for the file dialog */
582 static LONG_PTR WINAPI test_ok_wndproc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
584 HWND parent = GetParent( dlg);
585 static int index;
586 static UINT msgFILEOKSTRING;
587 if (msg == WM_INITDIALOG)
589 index = ((OPENFILENAME*)lParam)->lCustData;
590 ok_testcases[index].actclose = TRUE;
591 msgFILEOKSTRING = RegisterWindowMessageA( FILEOKSTRING);
593 if( msg == WM_NOTIFY) {
594 if(((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) {
595 SetTimer( dlg, 0, 100, 0);
596 PostMessage( parent, WM_COMMAND, IDOK, 0);
597 return FALSE;
598 } else if(((LPNMHDR)lParam)->code == CDN_FILEOK) {
599 if( ok_testcases[index].usemsgokstr)
600 return FALSE;
601 if( ok_testcases[index].setmsgresult)
602 SetWindowLongPtrA( dlg, DWLP_MSGRESULT, ok_testcases[index].retval);
603 return ok_testcases[index].retval;
606 if( msg == msgFILEOKSTRING) {
607 if( !ok_testcases[index].usemsgokstr)
608 return FALSE;
609 if( ok_testcases[index].setmsgresult)
610 SetWindowLongPtrA( dlg, DWLP_MSGRESULT, ok_testcases[index].retval);
611 return ok_testcases[index].retval;
613 if( msg == WM_TIMER) {
614 /* the dialog did not close automatically */
615 ok_testcases[index].actclose = FALSE;
616 KillTimer( dlg, 0);
617 PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
618 return FALSE;
620 if( ok_testcases[index].do_subclass)
621 return DefWindowProc( dlg, msg, wParam, lParam);
622 return FALSE;
625 static LONG_PTR WINAPI ok_template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
627 if (msg == WM_SETFONT)
628 SetWindowLongPtrA( dlg, GWLP_WNDPROC, (LONG_PTR) test_ok_wndproc);
629 return FALSE;
632 static void test_ok(void)
634 OPENFILENAME ofn = { sizeof(OPENFILENAME)};
635 char filename[1024] = {0};
636 char tmpfilename[ MAX_PATH];
637 int i;
638 DWORD ret;
640 if (!GetTempFileNameA(".", "txt", 0, tmpfilename)) {
641 skip("Failed to create a temporary file name\n");
642 return;
644 ofn.lpstrFile = filename;
645 ofn.nMaxFile = 1024;
646 ofn.hInstance = GetModuleHandle(NULL);
647 ofn.lpTemplateName = "template1";
648 ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE ;
649 for( i = 0; ok_testcases[i].retval != -1; i++) {
650 strcpy( filename, tmpfilename);
651 ofn.lCustData = i;
652 ofn.lpfnHook = ok_testcases[i].do_subclass
653 ? (LPOFNHOOKPROC) ok_template_hook
654 : (LPOFNHOOKPROC) test_ok_wndproc;
655 ret = GetOpenFileNameA(&ofn);
656 ok( ok_testcases[i].expclose == ok_testcases[i].actclose,
657 "testid %d: Open File dialog should %shave closed.\n", i,
658 ok_testcases[i].expclose ? "" : "NOT ");
659 ok(ret == ok_testcases[i].expclose, "testid %d: GetOpenFileName returned %#x\n", i, ret);
660 ret = CommDlgExtendedError();
661 ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
663 ret = DeleteFileA( tmpfilename);
664 ok( ret, "Failed to delete temporary file %s err %d\n", tmpfilename, GetLastError());
667 /* test arranging with a custom template */
668 typedef struct {
669 int x, y; /* left, top coordinates */
670 int cx, cy; /* width and height */
671 } posz;
672 static struct {
673 int nrcontrols; /* 0: no controls, 1: just the stc32 control 2: with button */
674 posz poszDlg;
675 posz poszStc32;
676 posz poszBtn;
677 DWORD ofnflags;
678 } arrange_tests[] = {
679 /* do not change the first two cases: used to get the uncustomized sizes */
680 { 0, {0},{0},{0},0 },
681 { 0, {0},{0},{0}, OFN_SHOWHELP},
682 /* two tests with just a subdialog, no controls */
683 { 0, {0, 0, 316, 76},{0},{0},0 },
684 { 0, {0, 0, 100, 76},{0},{0}, OFN_SHOWHELP},
685 /* now with a control with id stc32 */
686 { 1, {0, 0, 316, 76} ,{0, 0, 204, 76,},{0},0 }, /* bug #17748*/
687 { 1, {0, 0, 316, 76} ,{0, 0, 204, 76,},{0}, OFN_SHOWHELP}, /* bug #17748*/
688 /* tests with size of the stc32 control higher or wider then the standard dialog */
689 { 1, {0, 0, 316, 170} ,{0, 0, 204, 170,},{0},0 },
690 { 1, {0, 0, 316, 165} ,{0, 0, 411, 165,},{0}, OFN_SHOWHELP },
691 /* move the stc32 control around */
692 { 1, {0, 0, 300, 100} ,{73, 17, 50, 50,},{0},0 },
693 /* add control */
694 { 2, {0, 0, 280, 100} ,{0, 0, 50, 50,},{300,20,30,30},0 },
695 /* enable resizing should make the dialog bigger */
696 { 0, {0},{0},{0}, OFN_SHOWHELP|OFN_ENABLESIZING},
697 /* mark the end */
698 { -1 }
701 static LONG_PTR WINAPI template_hook_arrange(HWND dlgChild, UINT msg, WPARAM wParam, LPARAM lParam)
703 static int index, fixhelp;
704 static posz posz0[2];
705 static RECT clrcParent, clrcChild, rcStc32;
706 static HWND hwndStc32;
707 HWND dlgParent;
709 dlgParent = GetParent( dlgChild);
710 if (msg == WM_INITDIALOG) {
711 index = ((OPENFILENAME*)lParam)->lCustData;
712 /* get the positions before rearrangement */
713 GetClientRect( dlgParent, &clrcParent);
714 GetClientRect( dlgChild, &clrcChild);
715 hwndStc32 = GetDlgItem( dlgChild, stc32);
716 if( hwndStc32) GetWindowRect( hwndStc32, &rcStc32);
718 if (msg == WM_NOTIFY && ((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) {
719 RECT wrcParent;
721 GetWindowRect( dlgParent, &wrcParent);
722 /* the fist two "tests" just save the dialogs position, with and without
723 * help button */
724 if( index == 0) {
725 posz0[0].x = wrcParent.left;
726 posz0[0].y = wrcParent.top;
727 posz0[0].cx = wrcParent.right - wrcParent.left;
728 posz0[0].cy = wrcParent.bottom - wrcParent.top;
729 } else if( index == 1) {
730 posz0[1].x = wrcParent.left;
731 posz0[1].y = wrcParent.top;
732 posz0[1].cx = wrcParent.right - wrcParent.left;
733 posz0[1].cy = wrcParent.bottom - wrcParent.top;
734 fixhelp = posz0[1].cy - posz0[0].cy;
735 } else {
736 /* the real tests */
737 int withhelp;
738 int expectx, expecty;
740 withhelp = (arrange_tests[index].ofnflags & OFN_SHOWHELP) != 0;
741 GetWindowRect( dlgParent, &wrcParent);
742 if( !hwndStc32) {
743 /* case with no custom subitem with stc32:
744 * default to all custom controls below the standard */
745 expecty = posz0[withhelp].cy + clrcChild.bottom;
746 expectx = posz0[withhelp].cx;
747 } else {
748 /* special case: there is a control with id stc32 */
749 /* expected height */
750 expecty = posz0[withhelp].cy;
751 if( rcStc32.bottom - rcStc32.top > clrcParent.bottom) {
752 expecty += clrcChild.bottom - clrcParent.bottom;
753 if( !withhelp) expecty += fixhelp;
755 else
756 expecty += clrcChild.bottom - ( rcStc32.bottom - rcStc32.top) ;
757 /* expected width */
758 expectx = posz0[withhelp].cx;
759 if( rcStc32.right - rcStc32.left > clrcParent.right) {
760 expectx += clrcChild.right - clrcParent.right;
762 else
763 expectx += clrcChild.right - ( rcStc32.right - rcStc32.left) ;
765 if( !(arrange_tests[index].ofnflags & OFN_ENABLESIZING)) {
766 ok( wrcParent.bottom - wrcParent.top == expecty,
767 "Wrong height of dialog %d, expected %d\n",
768 wrcParent.bottom - wrcParent.top, expecty);
769 ok( wrcParent.right - wrcParent.left == expectx,
770 "Wrong width of dialog %d, expected %d\n",
771 wrcParent.right - wrcParent.left, expectx);
772 } else todo_wine {
773 ok( wrcParent.bottom - wrcParent.top > expecty,
774 "Wrong height of dialog %d, expected more than %d\n",
775 wrcParent.bottom - wrcParent.top, expecty);
776 ok( wrcParent.right - wrcParent.left > expectx,
777 "Wrong width of dialog %d, expected more than %d\n",
778 wrcParent.right - wrcParent.left, expectx);
782 PostMessage( dlgParent, WM_COMMAND, IDCANCEL, 0);
784 return 0;
787 static void test_arrange(void)
789 OPENFILENAMEA ofn = {0};
790 char filename[1024] = {0};
791 DWORD ret;
792 HRSRC hRes;
793 HANDLE hDlgTmpl;
794 LPBYTE pv;
795 DLGTEMPLATE *template;
796 DLGITEMTEMPLATE *itemtemplateStc32, *itemtemplateBtn;
797 int i;
799 /* load subdialog template into memory */
800 hRes = FindResource( GetModuleHandle(NULL), "template_stc32", (LPSTR)RT_DIALOG);
801 hDlgTmpl = LoadResource( GetModuleHandle(NULL), hRes );
802 /* get pointers to the structures for the dialog and the controls */
803 pv = LockResource( hDlgTmpl );
804 template = (DLGTEMPLATE*)pv;
805 if( template->x != 11111) {
806 win_skip("could not find the dialog template\n");
807 return;
809 /* skip dialog template, menu, class and title */
810 pv += sizeof(DLGTEMPLATE);
811 pv += 3 * sizeof(WORD);
812 /* skip font info */
813 while( *(WORD*)pv)
814 pv += sizeof(WORD);
815 pv += sizeof(WORD);
816 /* align on 32 bit boundaries */
817 pv = (LPBYTE)(((UINT_PTR)pv + 3 ) & ~3);
818 itemtemplateStc32 = (DLGITEMTEMPLATE*)pv;
819 if( itemtemplateStc32->x != 22222) {
820 win_skip("could not find the first item template\n");
821 return;
823 /* skip itemtemplate, class, title and creation data */
824 pv += sizeof(DLGITEMTEMPLATE);
825 pv += 4 * sizeof(WORD);
826 /* align on 32 bit boundaries */
827 pv = (LPBYTE)(((UINT_PTR)pv + 3 ) & ~3);
828 itemtemplateBtn = (DLGITEMTEMPLATE*)pv;
829 if( itemtemplateBtn->x != 12345) {
830 win_skip("could not find the second item template\n");
831 return;
834 ofn.lStructSize = sizeof(ofn);
835 ofn.lpstrFile = filename;
836 ofn.nMaxFile = 1024;
837 ofn.lpfnHook = (LPOFNHOOKPROC)template_hook_arrange;
838 ofn.hInstance = hDlgTmpl;
839 ofn.lpstrFilter="text\0*.txt\0All\0*\0\0";
840 for( i = 0; arrange_tests[i].nrcontrols != -1; i++) {
841 ofn.lCustData = i;
842 ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATEHANDLE | OFN_HIDEREADONLY |
843 arrange_tests[i].ofnflags;
844 template->cdit = arrange_tests[i].nrcontrols;
845 template->x = arrange_tests[i].poszDlg.x;
846 template->y = arrange_tests[i].poszDlg.y;
847 template->cx = arrange_tests[i].poszDlg.cx;
848 template->cy = arrange_tests[i].poszDlg.cy;
849 itemtemplateStc32->x = arrange_tests[i].poszStc32.x;
850 itemtemplateStc32->y = arrange_tests[i].poszStc32.y;
851 itemtemplateStc32->cx = arrange_tests[i].poszStc32.cx;
852 itemtemplateStc32->cy = arrange_tests[i].poszStc32.cy;
853 itemtemplateBtn->x = arrange_tests[i].poszBtn.x;
854 itemtemplateBtn->y = arrange_tests[i].poszBtn.y;
855 itemtemplateBtn->cx = arrange_tests[i].poszBtn.cx;
856 itemtemplateBtn->cy = arrange_tests[i].poszBtn.cy;
857 ret = GetOpenFileNameA(&ofn);
858 ok(!ret, "GetOpenFileNameA returned %#x\n", ret);
859 ret = CommDlgExtendedError();
860 ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
864 START_TEST(filedlg)
866 test_DialogCancel();
867 test_create_view_window2();
868 test_create_view_template();
869 test_arrange();
870 test_resize();
871 test_ok();