[COMDLG32]
[reactos.git] / reactos / dll / win32 / comdlg32 / filedlg.c
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
3 *
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
28 *
29 * FIXME: any hook gets a OPENFILENAMEA structure
30 *
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
32 *
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
34 *
35 * FIXME: algorithm for selecting the initial directory is too simple
36 *
37 * FIXME: add to recent docs
38 *
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
42 *
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
44 *
45 *
46 */
47
48 #include "config.h"
49 #include "wine/port.h"
50
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
56
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlobj.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
77
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
80
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
92 */
93 typedef struct SFolder
94 {
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99
100 } SFOLDER,*LPSFOLDER;
101
102 typedef struct tagLookInInfo
103 {
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
107
108
109 /***********************************************************************
110 * Defines and global variables
111 */
112
113 /* Draw item constant */
114 #define ICONWIDTH 18
115 #define XTEXTOFFSET 3
116
117 /* AddItem flags*/
118 #define LISTEND -1
119
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
122 #define SEARCH_EXP 2
123 #define ITEM_NOTFOUND -1
124
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
127
128 /* NOTE
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
131 */
132
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
136
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
139
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
142
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
145
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
148
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
151
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
154
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
157
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
164
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
167
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
171
172 /***********************************************************************
173 * Prototypes
174 */
175
176 /* Internal functions used by the dialog */
177 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
178 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
179 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
180 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
181 static BOOL FILEDLG95_OnOpen(HWND hwnd);
182 static LRESULT FILEDLG95_InitControls(HWND hwnd);
183 static void FILEDLG95_Clean(HWND hwnd);
184
185 /* Functions used by the shell navigation */
186 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
188 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
189 static void FILEDLG95_SHELL_Clean(HWND hwnd);
190 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
191
192 /* Functions used by the EDIT box */
193 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
194
195 /* Functions used by the filetype combo box */
196 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
197 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
198 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
199 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
200
201 /* Functions used by the Look In combo box */
202 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
203 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
204 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
206 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
207 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
208 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
209 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
210 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
211
212 /* Miscellaneous tool functions */
213 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
214 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
215 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
216 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
217 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
218 static UINT GetNumSelected( IDataObject *doSelected );
219
220 /* Shell memory allocation */
221 static void *MemAlloc(UINT size);
222 static void MemFree(void *mem);
223
224 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
227 static BOOL BrowseSelectedFolder(HWND hwnd);
228
229 /***********************************************************************
230 * GetFileName95
231 *
232 * Creates an Open common dialog box that lets the user select
233 * the drive, directory, and the name of a file or set of files to open.
234 *
235 * IN : The FileOpenDlgInfos structure associated with the dialog
236 * OUT : TRUE on success
237 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
238 */
239 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
240 {
241
242 LRESULT lRes;
243 LPCVOID template;
244 HRSRC hRes;
245 HANDLE hDlgTmpl = 0;
246 HRESULT hr;
247
248 /* test for missing functionality */
249 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
250 {
251 FIXME("Flags 0x%08x not yet implemented\n",
252 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
253 }
254
255 /* Create the dialog from a template */
256
257 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
258 {
259 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
260 return FALSE;
261 }
262 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
263 !(template = LockResource( hDlgTmpl )))
264 {
265 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
266 return FALSE;
267 }
268
269 /* msdn: explorer style dialogs permit sizing by default.
270 * The OFN_ENABLESIZING flag is only needed when a hook or
271 * custom tmeplate is provided */
272 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
273 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
274 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
275
276 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
277 {
278 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
279 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
280 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
281 }
282 else
283 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
284
285
286 /* old style hook messages */
287 if (IsHooked(fodInfos))
288 {
289 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
290 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
291 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
292 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
293 }
294
295 /* Some shell namespace extensions depend on COM being initialized. */
296 hr = OleInitialize(NULL);
297
298 if (fodInfos->unicode)
299 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
300 template,
301 fodInfos->ofnInfos->hwndOwner,
302 FileOpenDlgProc95,
303 (LPARAM) fodInfos);
304 else
305 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
306 template,
307 fodInfos->ofnInfos->hwndOwner,
308 FileOpenDlgProc95,
309 (LPARAM) fodInfos);
310 if (SUCCEEDED(hr))
311 OleUninitialize();
312
313 /* Unable to create the dialog */
314 if( lRes == -1)
315 return FALSE;
316
317 return lRes;
318 }
319
320 /***********************************************************************
321 * GetFileDialog95A
322 *
323 * Call GetFileName95 with this structure and clean the memory.
324 *
325 * IN : The OPENFILENAMEA initialisation structure passed to
326 * GetOpenFileNameA win api function (see filedlg.c)
327 */
328 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
329 {
330 BOOL ret;
331 FileOpenDlgInfos fodInfos;
332 LPSTR lpstrSavDir = NULL;
333 LPWSTR title = NULL;
334 LPWSTR defext = NULL;
335 LPWSTR filter = NULL;
336 LPWSTR customfilter = NULL;
337
338 /* Initialize CommDlgExtendedError() */
339 COMDLG32_SetCommDlgExtendedError(0);
340
341 /* Initialize FileOpenDlgInfos structure */
342 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
343
344 /* Pass in the original ofn */
345 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
346
347 /* save current directory */
348 if (ofn->Flags & OFN_NOCHANGEDIR)
349 {
350 lpstrSavDir = MemAlloc(MAX_PATH);
351 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
352 }
353
354 fodInfos.unicode = FALSE;
355
356 /* convert all the input strings to unicode */
357 if(ofn->lpstrInitialDir)
358 {
359 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
360 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
361 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
362 }
363 else
364 fodInfos.initdir = NULL;
365
366 if(ofn->lpstrFile)
367 {
368 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
369 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
370 }
371 else
372 fodInfos.filename = NULL;
373
374 if(ofn->lpstrDefExt)
375 {
376 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
377 defext = MemAlloc((len+1)*sizeof(WCHAR));
378 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
379 }
380 fodInfos.defext = defext;
381
382 if(ofn->lpstrTitle)
383 {
384 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
385 title = MemAlloc((len+1)*sizeof(WCHAR));
386 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
387 }
388 fodInfos.title = title;
389
390 if (ofn->lpstrFilter)
391 {
392 LPCSTR s;
393 int n, len;
394
395 /* filter is a list... title\0ext\0......\0\0 */
396 s = ofn->lpstrFilter;
397 while (*s) s = s+strlen(s)+1;
398 s++;
399 n = s - ofn->lpstrFilter;
400 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
401 filter = MemAlloc(len*sizeof(WCHAR));
402 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
403 }
404 fodInfos.filter = filter;
405
406 /* convert lpstrCustomFilter */
407 if (ofn->lpstrCustomFilter)
408 {
409 LPCSTR s;
410 int n, len;
411
412 /* customfilter contains a pair of strings... title\0ext\0 */
413 s = ofn->lpstrCustomFilter;
414 if (*s) s = s+strlen(s)+1;
415 if (*s) s = s+strlen(s)+1;
416 n = s - ofn->lpstrCustomFilter;
417 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
418 customfilter = MemAlloc(len*sizeof(WCHAR));
419 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
420 }
421 fodInfos.customfilter = customfilter;
422
423 /* Initialize the dialog property */
424 fodInfos.DlgInfos.dwDlgProp = 0;
425 fodInfos.DlgInfos.hwndCustomDlg = NULL;
426
427 switch(iDlgType)
428 {
429 case OPEN_DIALOG :
430 ret = GetFileName95(&fodInfos);
431 break;
432 case SAVE_DIALOG :
433 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
434 ret = GetFileName95(&fodInfos);
435 break;
436 default :
437 ret = 0;
438 }
439
440 if (lpstrSavDir)
441 {
442 SetCurrentDirectoryA(lpstrSavDir);
443 MemFree(lpstrSavDir);
444 }
445
446 MemFree(title);
447 MemFree(defext);
448 MemFree(filter);
449 MemFree(customfilter);
450 MemFree(fodInfos.initdir);
451 MemFree(fodInfos.filename);
452
453 TRACE("selected file: %s\n",ofn->lpstrFile);
454
455 return ret;
456 }
457
458 /***********************************************************************
459 * GetFileDialog95W
460 *
461 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
462 * Call GetFileName95 with this structure and clean the memory.
463 *
464 */
465 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
466 {
467 BOOL ret;
468 FileOpenDlgInfos fodInfos;
469 LPWSTR lpstrSavDir = NULL;
470
471 /* Initialize CommDlgExtendedError() */
472 COMDLG32_SetCommDlgExtendedError(0);
473
474 /* Initialize FileOpenDlgInfos structure */
475 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
476
477 /* Pass in the original ofn */
478 fodInfos.ofnInfos = ofn;
479
480 fodInfos.title = ofn->lpstrTitle;
481 fodInfos.defext = ofn->lpstrDefExt;
482 fodInfos.filter = ofn->lpstrFilter;
483 fodInfos.customfilter = ofn->lpstrCustomFilter;
484
485 /* convert string arguments, save others */
486 if(ofn->lpstrFile)
487 {
488 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
489 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
490 }
491 else
492 fodInfos.filename = NULL;
493
494 if(ofn->lpstrInitialDir)
495 {
496 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
497 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
498 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
499 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
500 }
501 else
502 fodInfos.initdir = NULL;
503
504 /* save current directory */
505 if (ofn->Flags & OFN_NOCHANGEDIR)
506 {
507 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
508 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
509 }
510
511 fodInfos.unicode = TRUE;
512
513 switch(iDlgType)
514 {
515 case OPEN_DIALOG :
516 ret = GetFileName95(&fodInfos);
517 break;
518 case SAVE_DIALOG :
519 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
520 ret = GetFileName95(&fodInfos);
521 break;
522 default :
523 ret = 0;
524 }
525
526 if (lpstrSavDir)
527 {
528 SetCurrentDirectoryW(lpstrSavDir);
529 MemFree(lpstrSavDir);
530 }
531
532 /* restore saved IN arguments and convert OUT arguments back */
533 MemFree(fodInfos.filename);
534 MemFree(fodInfos.initdir);
535 return ret;
536 }
537
538 /******************************************************************************
539 * COMDLG32_GetDisplayNameOf [internal]
540 *
541 * Helper function to get the display name for a pidl.
542 */
543 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
544 LPSHELLFOLDER psfDesktop;
545 STRRET strret;
546
547 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
548 return FALSE;
549
550 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
551 IShellFolder_Release(psfDesktop);
552 return FALSE;
553 }
554
555 IShellFolder_Release(psfDesktop);
556 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
557 }
558
559 /***********************************************************************
560 * ArrangeCtrlPositions [internal]
561 *
562 * NOTE: Make sure to add testcases for any changes made here.
563 */
564 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
565 {
566 HWND hwndChild, hwndStc32;
567 RECT rectParent, rectChild, rectStc32;
568 INT help_fixup = 0;
569 int chgx, chgy;
570
571 /* Take into account if open as read only checkbox and help button
572 * are hidden
573 */
574 if (hide_help)
575 {
576 RECT rectHelp, rectCancel;
577 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
578 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
579 /* subtract the height of the help button plus the space between
580 * the help button and the cancel button to the height of the dialog
581 */
582 help_fixup = rectHelp.bottom - rectCancel.bottom;
583 }
584
585 /*
586 There are two possibilities to add components to the default file dialog box.
587
588 By default, all the new components are added below the standard dialog box (the else case).
589
590 However, if there is a static text component with the stc32 id, a special case happens.
591 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
592 in the window and the cx and cy indicate how to size the window.
593 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
594 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
595
596 */
597
598 GetClientRect(hwndParentDlg, &rectParent);
599
600 /* when arranging controls we have to use fixed parent size */
601 rectParent.bottom -= help_fixup;
602
603 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
604 if (hwndStc32)
605 {
606 GetWindowRect(hwndStc32, &rectStc32);
607 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
608
609 /* set the size of the stc32 control according to the size of
610 * client area of the parent dialog
611 */
612 SetWindowPos(hwndStc32, 0,
613 0, 0,
614 rectParent.right, rectParent.bottom,
615 SWP_NOMOVE | SWP_NOZORDER);
616 }
617 else
618 SetRectEmpty(&rectStc32);
619
620 /* this part moves controls of the child dialog */
621 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
622 while (hwndChild)
623 {
624 if (hwndChild != hwndStc32)
625 {
626 GetWindowRect(hwndChild, &rectChild);
627 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
628
629 /* move only if stc32 exist */
630 if (hwndStc32 && rectChild.left > rectStc32.right)
631 {
632 /* move to the right of visible controls of the parent dialog */
633 rectChild.left += rectParent.right;
634 rectChild.left -= rectStc32.right;
635 }
636 /* move even if stc32 doesn't exist */
637 if (rectChild.top >= rectStc32.bottom)
638 {
639 /* move below visible controls of the parent dialog */
640 rectChild.top += rectParent.bottom;
641 rectChild.top -= rectStc32.bottom - rectStc32.top;
642 }
643
644 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
645 0, 0, SWP_NOSIZE | SWP_NOZORDER);
646 }
647 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
648 }
649
650 /* this part moves controls of the parent dialog */
651 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
652 while (hwndChild)
653 {
654 if (hwndChild != hwndChildDlg)
655 {
656 GetWindowRect(hwndChild, &rectChild);
657 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
658
659 /* left,top of stc32 marks the position of controls
660 * from the parent dialog
661 */
662 rectChild.left += rectStc32.left;
663 rectChild.top += rectStc32.top;
664
665 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
666 0, 0, SWP_NOSIZE | SWP_NOZORDER);
667 }
668 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
669 }
670
671 /* calculate the size of the resulting dialog */
672
673 /* here we have to use original parent size */
674 GetClientRect(hwndParentDlg, &rectParent);
675 GetClientRect(hwndChildDlg, &rectChild);
676 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
677 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
678
679 if (hwndStc32)
680 {
681 /* width */
682 if (rectParent.right > rectStc32.right - rectStc32.left)
683 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
684 else
685 chgx = rectChild.right - rectParent.right;
686 /* height */
687 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
688 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
689 else
690 /* Unconditionally set new dialog
691 * height to that of the child
692 */
693 chgy = rectChild.bottom - rectParent.bottom;
694 }
695 else
696 {
697 chgx = 0;
698 chgy = rectChild.bottom - help_fixup;
699 }
700 /* set the size of the parent dialog */
701 GetWindowRect(hwndParentDlg, &rectParent);
702 SetWindowPos(hwndParentDlg, 0,
703 0, 0,
704 rectParent.right - rectParent.left + chgx,
705 rectParent.bottom - rectParent.top + chgy,
706 SWP_NOMOVE | SWP_NOZORDER);
707 }
708
709 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
710 {
711 switch(uMsg) {
712 case WM_INITDIALOG:
713 return TRUE;
714 }
715 return FALSE;
716 }
717
718 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
719 {
720 LPCVOID template;
721 HRSRC hRes;
722 HANDLE hDlgTmpl = 0;
723 HWND hChildDlg = 0;
724
725 TRACE("\n");
726
727 /*
728 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
729 * structure's hInstance parameter is not a HINSTANCE, but
730 * instead a pointer to a template resource to use.
731 */
732 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
733 {
734 HINSTANCE hinst;
735 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
736 {
737 hinst = COMDLG32_hInstance;
738 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
739 {
740 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
741 return NULL;
742 }
743 }
744 else
745 {
746 hinst = fodInfos->ofnInfos->hInstance;
747 if(fodInfos->unicode)
748 {
749 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
750 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
751 }
752 else
753 {
754 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
755 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
756 }
757 if (!hRes)
758 {
759 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
760 return NULL;
761 }
762 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
763 !(template = LockResource( hDlgTmpl )))
764 {
765 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
766 return NULL;
767 }
768 }
769 if (fodInfos->unicode)
770 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
771 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
772 (LPARAM)fodInfos->ofnInfos);
773 else
774 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
777 return hChildDlg;
778 }
779 else if( IsHooked(fodInfos))
780 {
781 RECT rectHwnd;
782 struct {
783 DLGTEMPLATE tmplate;
784 WORD menu,class,title;
785 } temp;
786 GetClientRect(hwnd,&rectHwnd);
787 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
788 temp.tmplate.dwExtendedStyle = 0;
789 temp.tmplate.cdit = 0;
790 temp.tmplate.x = 0;
791 temp.tmplate.y = 0;
792 temp.tmplate.cx = 0;
793 temp.tmplate.cy = 0;
794 temp.menu = temp.class = temp.title = 0;
795
796 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
797 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
798
799 return hChildDlg;
800 }
801 return NULL;
802 }
803
804 /***********************************************************************
805 * SendCustomDlgNotificationMessage
806 *
807 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
808 */
809
810 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
811 {
812 LRESULT hook_result = 0;
813 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
814
815 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
816
817 if(!fodInfos) return 0;
818
819 if(fodInfos->DlgInfos.hwndCustomDlg)
820 {
821 TRACE("CALL NOTIFY for %x\n", uCode);
822 if(fodInfos->unicode)
823 {
824 OFNOTIFYW ofnNotify;
825 ofnNotify.hdr.hwndFrom=hwndParentDlg;
826 ofnNotify.hdr.idFrom=0;
827 ofnNotify.hdr.code = uCode;
828 ofnNotify.lpOFN = fodInfos->ofnInfos;
829 ofnNotify.pszFile = NULL;
830 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
831 }
832 else
833 {
834 OFNOTIFYA ofnNotify;
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
841 }
842 TRACE("RET NOTIFY\n");
843 }
844 TRACE("Retval: 0x%08lx\n", hook_result);
845 return hook_result;
846 }
847
848 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
849 {
850 UINT len, total;
851 WCHAR *p, *buffer;
852 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
853
854 TRACE("CDM_GETFILEPATH:\n");
855
856 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
857 return -1;
858
859 /* get path and filenames */
860 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
861 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
862 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
863 if (len)
864 {
865 p = buffer + strlenW(buffer);
866 *p++ = '\\';
867 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
868 }
869 if (fodInfos->unicode)
870 {
871 total = strlenW( buffer) + 1;
872 if (result) lstrcpynW( result, buffer, size );
873 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
874 }
875 else
876 {
877 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
878 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
879 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
880 }
881 HeapFree( GetProcessHeap(), 0, buffer );
882 return total;
883 }
884
885 /***********************************************************************
886 * FILEDLG95_HandleCustomDialogMessages
887 *
888 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
889 */
890 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
891 {
892 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
893 WCHAR lpstrPath[MAX_PATH];
894 INT_PTR retval;
895
896 if(!fodInfos) return FALSE;
897
898 switch(uMsg)
899 {
900 case CDM_GETFILEPATH:
901 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
902 break;
903
904 case CDM_GETFOLDERPATH:
905 TRACE("CDM_GETFOLDERPATH:\n");
906 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
907 if (lParam)
908 {
909 if (fodInfos->unicode)
910 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
911 else
912 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
913 (LPSTR)lParam, (int)wParam, NULL, NULL);
914 }
915 retval = lstrlenW(lpstrPath) + 1;
916 break;
917
918 case CDM_GETFOLDERIDLIST:
919 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
920 if (retval <= wParam)
921 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
922 break;
923
924 case CDM_GETSPEC:
925 TRACE("CDM_GETSPEC:\n");
926 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
927 if (lParam)
928 {
929 if (fodInfos->unicode)
930 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
931 else
932 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
933 }
934 break;
935
936 case CDM_SETCONTROLTEXT:
937 TRACE("CDM_SETCONTROLTEXT:\n");
938 if ( lParam )
939 {
940 if( fodInfos->unicode )
941 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
942 else
943 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
944 }
945 retval = TRUE;
946 break;
947
948 case CDM_HIDECONTROL:
949 /* MSDN states that it should fail for not OFN_EXPLORER case */
950 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
951 {
952 HWND control = GetDlgItem( hwnd, wParam );
953 if (control) ShowWindow( control, SW_HIDE );
954 retval = TRUE;
955 }
956 else retval = FALSE;
957 break;
958
959 default:
960 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
961 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
962 return FALSE;
963 }
964 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
965 return TRUE;
966 }
967
968 /***********************************************************************
969 * FILEDLG95_OnWMGetMMI
970 *
971 * WM_GETMINMAXINFO message handler for resizable dialogs
972 */
973 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
974 {
975 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
976 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
977 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
978 {
979 mmiptr->ptMinTrackSize = fodInfos->initial_size;
980 }
981 return TRUE;
982 }
983
984 /***********************************************************************
985 * FILEDLG95_OnWMSize
986 *
987 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
988 *
989 * FIXME: this could be made more elaborate. Now use a simple scheme
990 * where the file view is enlarged and the controls are either moved
991 * vertically or horizontally to get out of the way. Only the "grip"
992 * is moved in both directions to stay in the corner.
993 */
994 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
995 {
996 RECT rc, rcview;
997 int chgx, chgy;
998 HWND ctrl;
999 HDWP hdwp;
1000 FileOpenDlgInfos *fodInfos;
1001
1002 if( wParam != SIZE_RESTORED) return FALSE;
1003 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1004 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1005 /* get the new dialog rectangle */
1006 GetWindowRect( hwnd, &rc);
1007 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1008 rc.right -rc.left, rc.bottom -rc.top);
1009 /* not initialized yet */
1010 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1011 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1012 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1013 return FALSE;
1014 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1015 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1016 fodInfos->sizedlg.cx = rc.right - rc.left;
1017 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1018 /* change the size of the view window */
1019 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1020 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1021 hdwp = BeginDeferWindowPos( 10);
1022 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1023 rcview.right - rcview.left + chgx,
1024 rcview.bottom - rcview.top + chgy,
1025 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1026 /* change position and sizes of the controls */
1027 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1028 {
1029 int ctrlid = GetDlgCtrlID( ctrl);
1030 GetWindowRect( ctrl, &rc);
1031 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1032 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1033 {
1034 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1035 0, 0,
1036 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1037 }
1038 else if( rc.top > rcview.bottom)
1039 {
1040 /* if it was below the shell view
1041 * move to bottom */
1042 switch( ctrlid)
1043 {
1044 /* file name box and file types combo change also width */
1045 case edt1:
1046 case cmb1:
1047 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1048 rc.right - rc.left + chgx, rc.bottom - rc.top,
1049 SWP_NOACTIVATE | SWP_NOZORDER);
1050 break;
1051 /* then these buttons must move out of the way */
1052 case IDOK:
1053 case IDCANCEL:
1054 case pshHelp:
1055 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1056 0, 0,
1057 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1058 break;
1059 default:
1060 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1061 0, 0,
1062 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1063 }
1064 }
1065 else if( rc.left > rcview.right)
1066 {
1067 /* if it was to the right of the shell view
1068 * move to right */
1069 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1070 0, 0,
1071 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1072 }
1073 else
1074 /* special cases */
1075 {
1076 switch( ctrlid)
1077 {
1078 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1079 case IDC_LOOKIN:
1080 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1081 rc.right - rc.left + chgx, rc.bottom - rc.top,
1082 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1083 break;
1084 case IDC_TOOLBARSTATIC:
1085 case IDC_TOOLBAR:
1086 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1087 0, 0,
1088 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1089 break;
1090 #endif
1091 /* not resized in windows. Since wine uses this invisible control
1092 * to size the browser view it needs to be resized */
1093 case IDC_SHELLSTATIC:
1094 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1095 rc.right - rc.left + chgx,
1096 rc.bottom - rc.top + chgy,
1097 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1098 break;
1099 }
1100 }
1101 }
1102 if(fodInfos->DlgInfos.hwndCustomDlg &&
1103 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1104 {
1105 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1106 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1107 {
1108 GetWindowRect( ctrl, &rc);
1109 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1110 if( rc.top > rcview.bottom)
1111 {
1112 /* if it was below the shell view
1113 * move to bottom */
1114 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1115 rc.right - rc.left, rc.bottom - rc.top,
1116 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1117 }
1118 else if( rc.left > rcview.right)
1119 {
1120 /* if it was to the right of the shell view
1121 * move to right */
1122 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1123 rc.right - rc.left, rc.bottom - rc.top,
1124 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1125 }
1126 }
1127 /* size the custom dialog at the end: some applications do some
1128 * control re-arranging at this point */
1129 GetClientRect(hwnd, &rc);
1130 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1131 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1132 }
1133 EndDeferWindowPos( hdwp);
1134 /* should not be needed */
1135 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1136 return TRUE;
1137 }
1138
1139 /***********************************************************************
1140 * FileOpenDlgProc95
1141 *
1142 * File open dialog procedure
1143 */
1144 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1145 {
1146 #if 0
1147 TRACE("%p 0x%04x\n", hwnd, uMsg);
1148 #endif
1149
1150 switch(uMsg)
1151 {
1152 case WM_INITDIALOG:
1153 {
1154 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1155 RECT rc, rcstc;
1156 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1157 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1158
1159 /* Adds the FileOpenDlgInfos in the property list of the dialog
1160 so it will be easily accessible through a GetPropA(...) */
1161 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1162
1163 FILEDLG95_InitControls(hwnd);
1164
1165 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1166 {
1167 GetWindowRect( hwnd, &rc);
1168 fodInfos->DlgInfos.hwndGrip =
1169 CreateWindowExA( 0, "SCROLLBAR", NULL,
1170 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1171 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1172 rc.right - gripx, rc.bottom - gripy,
1173 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1174 }
1175
1176 fodInfos->DlgInfos.hwndCustomDlg =
1177 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1178
1179 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1180 FILEDLG95_FillControls(hwnd, wParam, lParam);
1181
1182 if( fodInfos->DlgInfos.hwndCustomDlg)
1183 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1184
1185 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1186 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1187 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1188 }
1189
1190 /* if the app has changed the position of the invisible listbox,
1191 * change that of the listview (browser) as well */
1192 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1193 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1194 if( !EqualRect( &rc, &rcstc))
1195 {
1196 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1197 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1198 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1199 SWP_NOACTIVATE | SWP_NOZORDER);
1200 }
1201
1202 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1203 {
1204 GetWindowRect( hwnd, &rc);
1205 fodInfos->sizedlg.cx = rc.right - rc.left;
1206 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1207 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1208 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1209 GetClientRect( hwnd, &rc);
1210 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1211 rc.right - gripx, rc.bottom - gripy,
1212 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1213 /* resize the dialog to the previous invocation */
1214 if( MemDialogSize.cx && MemDialogSize.cy)
1215 SetWindowPos( hwnd, NULL,
1216 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1217 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 }
1219
1220 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1221 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1222
1223 return 0;
1224 }
1225 case WM_SIZE:
1226 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1227 case WM_GETMINMAXINFO:
1228 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1229 case WM_COMMAND:
1230 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1231 case WM_DRAWITEM:
1232 {
1233 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1234 {
1235 case IDC_LOOKIN:
1236 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1237 return TRUE;
1238 }
1239 }
1240 return FALSE;
1241
1242 case WM_GETISHELLBROWSER:
1243 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1244
1245 case WM_DESTROY:
1246 {
1247 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1248 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1249 MemDialogSize = fodInfos->sizedlg;
1250 RemovePropA(hwnd, FileOpenDlgInfosStr);
1251 return FALSE;
1252 }
1253 case WM_NOTIFY:
1254 {
1255 LPNMHDR lpnmh = (LPNMHDR)lParam;
1256 UINT stringId = -1;
1257
1258 /* set up the button tooltips strings */
1259 if(TTN_GETDISPINFOA == lpnmh->code )
1260 {
1261 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1262 switch(lpnmh->idFrom )
1263 {
1264 /* Up folder button */
1265 case FCIDM_TB_UPFOLDER:
1266 stringId = IDS_UPFOLDER;
1267 break;
1268 /* New folder button */
1269 case FCIDM_TB_NEWFOLDER:
1270 stringId = IDS_NEWFOLDER;
1271 break;
1272 /* List option button */
1273 case FCIDM_TB_SMALLICON:
1274 stringId = IDS_LISTVIEW;
1275 break;
1276 /* Details option button */
1277 case FCIDM_TB_REPORTVIEW:
1278 stringId = IDS_REPORTVIEW;
1279 break;
1280 /* Desktop button */
1281 case FCIDM_TB_DESKTOP:
1282 stringId = IDS_TODESKTOP;
1283 break;
1284 default:
1285 stringId = 0;
1286 }
1287 lpdi->hinst = COMDLG32_hInstance;
1288 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1289 }
1290 return FALSE;
1291 }
1292 default :
1293 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1294 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1295 return FALSE;
1296 }
1297 }
1298
1299 /***********************************************************************
1300 * FILEDLG95_InitControls
1301 *
1302 * WM_INITDIALOG message handler (before hook notification)
1303 */
1304 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1305 {
1306 int win2000plus = 0;
1307 int win98plus = 0;
1308 int handledPath = FALSE;
1309 OSVERSIONINFOW osVi;
1310 static const WCHAR szwSlash[] = { '\\', 0 };
1311 static const WCHAR szwStar[] = { '*',0 };
1312
1313 static const TBBUTTON tbb[] =
1314 {
1315 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1316 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1317 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1318 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1322 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1324 };
1325 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1326
1327 RECT rectTB;
1328 RECT rectlook;
1329
1330 HIMAGELIST toolbarImageList;
1331 SHFILEINFOA shFileInfo;
1332 ITEMIDLIST *desktopPidl;
1333
1334 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1335
1336 TRACE("%p\n", fodInfos);
1337
1338 /* Get windows version emulating */
1339 osVi.dwOSVersionInfoSize = sizeof(osVi);
1340 GetVersionExW(&osVi);
1341 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1342 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1343 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1344 win2000plus = (osVi.dwMajorVersion > 4);
1345 if (win2000plus) win98plus = TRUE;
1346 }
1347 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1348
1349 /* Get the hwnd of the controls */
1350 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1351 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1352 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1353
1354 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1355 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1356
1357 /* construct the toolbar */
1358 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1359 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1360
1361 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1362 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1363 rectTB.left = rectlook.right;
1364 rectTB.top = rectlook.top-1;
1365
1366 if (fodInfos->unicode)
1367 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1368 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1369 rectTB.left, rectTB.top,
1370 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1371 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1372 else
1373 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1374 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1375 rectTB.left, rectTB.top,
1376 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1377 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1378
1379 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1380
1381 /* FIXME: use TB_LOADIMAGES when implemented */
1382 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1383 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1385
1386 /* Retrieve and add desktop icon to the toolbar */
1387 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1388 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1389 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1390 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1391 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1392
1393 DestroyIcon(shFileInfo.hIcon);
1394 CoTaskMemFree(desktopPidl);
1395
1396 /* Finish Toolbar Construction */
1397 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1398 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1399
1400 /* Set the window text with the text specified in the OPENFILENAME structure */
1401 if(fodInfos->title)
1402 {
1403 SetWindowTextW(hwnd,fodInfos->title);
1404 }
1405 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1406 {
1407 WCHAR buf[16];
1408 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1409 SetWindowTextW(hwnd, buf);
1410 }
1411
1412 /* Initialise the file name edit control */
1413 handledPath = FALSE;
1414 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1415
1416 if(fodInfos->filename)
1417 {
1418 /* 1. If win2000 or higher and filename contains a path, use it
1419 in preference over the lpstrInitialDir */
1420 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1421 WCHAR tmpBuf[MAX_PATH];
1422 WCHAR *nameBit;
1423 DWORD result;
1424
1425 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1426 if (result) {
1427
1428 /* nameBit is always shorter than the original filename */
1429 lstrcpyW(fodInfos->filename,nameBit);
1430
1431 *nameBit = 0x00;
1432 if (fodInfos->initdir == NULL)
1433 MemFree(fodInfos->initdir);
1434 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1435 lstrcpyW(fodInfos->initdir, tmpBuf);
1436 handledPath = TRUE;
1437 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1438 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1439 }
1440 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1441
1442 } else {
1443 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1444 }
1445 }
1446
1447 /* 2. (All platforms) If initdir is not null, then use it */
1448 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1449 (*fodInfos->initdir!=0x00))
1450 {
1451 /* Work out the proper path as supplied one might be relative */
1452 /* (Here because supplying '.' as dir browses to My Computer) */
1453 if (handledPath==FALSE) {
1454 WCHAR tmpBuf[MAX_PATH];
1455 WCHAR tmpBuf2[MAX_PATH];
1456 WCHAR *nameBit;
1457 DWORD result;
1458
1459 lstrcpyW(tmpBuf, fodInfos->initdir);
1460 if( PathFileExistsW(tmpBuf) ) {
1461 /* initdir does not have to be a directory. If a file is
1462 * specified, the dir part is taken */
1463 if( PathIsDirectoryW(tmpBuf)) {
1464 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1465 lstrcatW(tmpBuf, szwSlash);
1466 }
1467 lstrcatW(tmpBuf, szwStar);
1468 }
1469 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1470 if (result) {
1471 *nameBit = 0x00;
1472 MemFree(fodInfos->initdir);
1473 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1474 lstrcpyW(fodInfos->initdir, tmpBuf2);
1475 handledPath = TRUE;
1476 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1477 }
1478 }
1479 else if (fodInfos->initdir)
1480 {
1481 MemFree(fodInfos->initdir);
1482 fodInfos->initdir = NULL;
1483 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1484 }
1485 }
1486 }
1487
1488 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1489 (*fodInfos->initdir==0x00)))
1490 {
1491 /* 3. All except w2k+: if filename contains a path use it */
1492 if (!win2000plus && fodInfos->filename &&
1493 *fodInfos->filename &&
1494 strpbrkW(fodInfos->filename, szwSlash)) {
1495 WCHAR tmpBuf[MAX_PATH];
1496 WCHAR *nameBit;
1497 DWORD result;
1498
1499 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1500 tmpBuf, &nameBit);
1501 if (result) {
1502 int len;
1503
1504 /* nameBit is always shorter than the original filename */
1505 lstrcpyW(fodInfos->filename, nameBit);
1506 *nameBit = 0x00;
1507
1508 len = lstrlenW(tmpBuf);
1509 MemFree(fodInfos->initdir);
1510 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1511 lstrcpyW(fodInfos->initdir, tmpBuf);
1512
1513 handledPath = TRUE;
1514 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1515 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1516 }
1517 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1518 }
1519
1520 /* 4. win98+ and win2000+ if any files of specified filter types in
1521 current directory, use it */
1522 if ( win98plus && handledPath == FALSE &&
1523 fodInfos->filter && *fodInfos->filter) {
1524
1525 LPCWSTR lpstrPos = fodInfos->filter;
1526 WIN32_FIND_DATAW FindFileData;
1527 HANDLE hFind;
1528
1529 while (1)
1530 {
1531 /* filter is a list... title\0ext\0......\0\0 */
1532
1533 /* Skip the title */
1534 if(! *lpstrPos) break; /* end */
1535 lpstrPos += lstrlenW(lpstrPos) + 1;
1536
1537 /* See if any files exist in the current dir with this extension */
1538 if(! *lpstrPos) break; /* end */
1539
1540 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1541
1542 if (hFind == INVALID_HANDLE_VALUE) {
1543 /* None found - continue search */
1544 lpstrPos += lstrlenW(lpstrPos) + 1;
1545
1546 } else {
1547
1548 MemFree(fodInfos->initdir);
1549 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1550 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1551
1552 handledPath = TRUE;
1553 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1554 debugstr_w(lpstrPos));
1555 FindClose(hFind);
1556 break;
1557 }
1558 }
1559 }
1560
1561 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1562
1563 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1564 if (handledPath == FALSE && (win2000plus || win98plus)) {
1565 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1566
1567 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1568 {
1569 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1570 {
1571 /* last fallback */
1572 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1573 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1574 } else {
1575 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1576 }
1577 } else {
1578 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1579 }
1580 handledPath = TRUE;
1581 } else if (handledPath==FALSE) {
1582 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1583 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1584 handledPath = TRUE;
1585 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1586 }
1587 }
1588 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1589 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1590
1591 /* Must the open as read only check box be checked ?*/
1592 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1593 {
1594 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1595 }
1596
1597 /* Must the open as read only check box be hidden? */
1598 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1599 {
1600 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1601 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1602 }
1603
1604 /* Must the help button be hidden? */
1605 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1606 {
1607 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1608 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1609 }
1610
1611 /* change Open to Save */
1612 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1613 {
1614 WCHAR buf[16];
1615 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1616 SetDlgItemTextW(hwnd, IDOK, buf);
1617 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1618 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1619 }
1620
1621 /* Initialize the filter combo box */
1622 FILEDLG95_FILETYPE_Init(hwnd);
1623
1624 return 0;
1625 }
1626
1627 /***********************************************************************
1628 * FILEDLG95_ResizeControls
1629 *
1630 * WM_INITDIALOG message handler (after hook notification)
1631 */
1632 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1633 {
1634 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1635
1636 if (fodInfos->DlgInfos.hwndCustomDlg)
1637 {
1638 RECT rc;
1639 UINT flags = SWP_NOACTIVATE;
1640
1641 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1642 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1643
1644 /* resize the custom dialog to the parent size */
1645 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1646 GetClientRect(hwnd, &rc);
1647 else
1648 {
1649 /* our own fake template is zero sized and doesn't have children, so
1650 * there is no need to resize it. Picasa depends on it.
1651 */
1652 flags |= SWP_NOSIZE;
1653 SetRectEmpty(&rc);
1654 }
1655 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1656 0, 0, rc.right, rc.bottom, flags);
1657 }
1658 else
1659 {
1660 /* Resize the height, if open as read only checkbox ad help button are
1661 * hidden and we are not using a custom template nor a customDialog
1662 */
1663 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1664 (!(fodInfos->ofnInfos->Flags &
1665 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1666 {
1667 RECT rectDlg, rectHelp, rectCancel;
1668 GetWindowRect(hwnd, &rectDlg);
1669 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1670 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1671 /* subtract the height of the help button plus the space between the help
1672 * button and the cancel button to the height of the dialog
1673 */
1674 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1675 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1676 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1677 }
1678 }
1679 return TRUE;
1680 }
1681
1682 /***********************************************************************
1683 * FILEDLG95_FillControls
1684 *
1685 * WM_INITDIALOG message handler (after hook notification)
1686 */
1687 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1688 {
1689 LPITEMIDLIST pidlItemId = NULL;
1690
1691 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1692
1693 TRACE("dir=%s file=%s\n",
1694 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1695
1696 /* Get the initial directory pidl */
1697
1698 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1699 {
1700 WCHAR path[MAX_PATH];
1701
1702 GetCurrentDirectoryW(MAX_PATH,path);
1703 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1704 }
1705
1706 /* Initialise shell objects */
1707 FILEDLG95_SHELL_Init(hwnd);
1708
1709 /* Initialize the Look In combo box */
1710 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1711
1712 /* Browse to the initial directory */
1713 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1714
1715 /* Free pidlItem memory */
1716 COMDLG32_SHFree(pidlItemId);
1717
1718 return TRUE;
1719 }
1720 /***********************************************************************
1721 * FILEDLG95_Clean
1722 *
1723 * Regroups all the cleaning functions of the filedlg
1724 */
1725 void FILEDLG95_Clean(HWND hwnd)
1726 {
1727 FILEDLG95_FILETYPE_Clean(hwnd);
1728 FILEDLG95_LOOKIN_Clean(hwnd);
1729 FILEDLG95_SHELL_Clean(hwnd);
1730 }
1731 /***********************************************************************
1732 * FILEDLG95_OnWMCommand
1733 *
1734 * WM_COMMAND message handler
1735 */
1736 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1737 {
1738 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1739 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1740 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1741
1742 switch(wID)
1743 {
1744 /* OK button */
1745 case IDOK:
1746 FILEDLG95_OnOpen(hwnd);
1747 break;
1748 /* Cancel button */
1749 case IDCANCEL:
1750 FILEDLG95_Clean(hwnd);
1751 EndDialog(hwnd, FALSE);
1752 break;
1753 /* Filetype combo box */
1754 case IDC_FILETYPE:
1755 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1756 break;
1757 /* LookIn combo box */
1758 case IDC_LOOKIN:
1759 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1760 break;
1761
1762 /* --- toolbar --- */
1763 /* Up folder button */
1764 case FCIDM_TB_UPFOLDER:
1765 FILEDLG95_SHELL_UpFolder(hwnd);
1766 break;
1767 /* New folder button */
1768 case FCIDM_TB_NEWFOLDER:
1769 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1770 break;
1771 /* List option button */
1772 case FCIDM_TB_SMALLICON:
1773 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1774 break;
1775 /* Details option button */
1776 case FCIDM_TB_REPORTVIEW:
1777 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1778 break;
1779 /* Details option button */
1780 case FCIDM_TB_DESKTOP:
1781 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1782 break;
1783
1784 case IDC_FILENAME:
1785 break;
1786
1787 }
1788 /* Do not use the listview selection anymore */
1789 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1790 return 0;
1791 }
1792
1793 /***********************************************************************
1794 * FILEDLG95_OnWMGetIShellBrowser
1795 *
1796 * WM_GETISHELLBROWSER message handler
1797 */
1798 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1799 {
1800 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1801
1802 TRACE("\n");
1803
1804 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1805
1806 return TRUE;
1807 }
1808
1809
1810 /***********************************************************************
1811 * FILEDLG95_SendFileOK
1812 *
1813 * Sends the CDN_FILEOK notification if required
1814 *
1815 * RETURNS
1816 * TRUE if the dialog should close
1817 * FALSE if the dialog should not be closed
1818 */
1819 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1820 {
1821 /* ask the hook if we can close */
1822 if(IsHooked(fodInfos))
1823 {
1824 LRESULT retval = 0;
1825
1826 TRACE("---\n");
1827 /* First send CDN_FILEOK as MSDN doc says */
1828 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1829 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1830 if( retval)
1831 {
1832 TRACE("canceled\n");
1833 return FALSE;
1834 }
1835
1836 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1837 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1838 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1839 if( retval)
1840 {
1841 TRACE("canceled\n");
1842 return FALSE;
1843 }
1844 }
1845 return TRUE;
1846 }
1847
1848 /***********************************************************************
1849 * FILEDLG95_OnOpenMultipleFiles
1850 *
1851 * Handles the opening of multiple files.
1852 *
1853 * FIXME
1854 * check destination buffer size
1855 */
1856 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1857 {
1858 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1859 UINT nCount, nSizePath;
1860 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1861
1862 TRACE("\n");
1863
1864 if(fodInfos->unicode)
1865 {
1866 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1867 ofn->lpstrFile[0] = '\0';
1868 }
1869 else
1870 {
1871 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1872 ofn->lpstrFile[0] = '\0';
1873 }
1874
1875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1876
1877 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1878 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1879 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1880 {
1881 LPWSTR lpstrTemp = lpstrFileList;
1882
1883 for ( nCount = 0; nCount < nFileCount; nCount++ )
1884 {
1885 LPITEMIDLIST pidl;
1886
1887 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1888 if (!pidl)
1889 {
1890 WCHAR lpstrNotFound[100];
1891 WCHAR lpstrMsg[100];
1892 WCHAR tmp[400];
1893 static const WCHAR nl[] = {'\n',0};
1894
1895 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1896 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1897
1898 lstrcpyW(tmp, lpstrTemp);
1899 lstrcatW(tmp, nl);
1900 lstrcatW(tmp, lpstrNotFound);
1901 lstrcatW(tmp, nl);
1902 lstrcatW(tmp, lpstrMsg);
1903
1904 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1905 return FALSE;
1906 }
1907
1908 /* move to the next file in the list of files */
1909 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1910 COMDLG32_SHFree(pidl);
1911 }
1912 }
1913
1914 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1915 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1916 {
1917 /* For "oldstyle" dialog the components have to
1918 be separated by blanks (not '\0'!) and short
1919 filenames have to be used! */
1920 FIXME("Components have to be separated by blanks\n");
1921 }
1922 if(fodInfos->unicode)
1923 {
1924 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1925 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1926 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1927 }
1928 else
1929 {
1930 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1931
1932 if (ofn->lpstrFile != NULL)
1933 {
1934 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1935 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1936 if (ofn->nMaxFile > nSizePath)
1937 {
1938 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1939 ofn->lpstrFile + nSizePath,
1940 ofn->nMaxFile - nSizePath, NULL, NULL);
1941 }
1942 }
1943 }
1944
1945 fodInfos->ofnInfos->nFileOffset = nSizePath;
1946 fodInfos->ofnInfos->nFileExtension = 0;
1947
1948 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1949 return FALSE;
1950
1951 /* clean and exit */
1952 FILEDLG95_Clean(hwnd);
1953 return EndDialog(hwnd,TRUE);
1954 }
1955
1956 /***********************************************************************
1957 * FILEDLG95_OnOpen
1958 *
1959 * Ok button WM_COMMAND message handler
1960 *
1961 * If the function succeeds, the return value is nonzero.
1962 */
1963 #define ONOPEN_BROWSE 1
1964 #define ONOPEN_OPEN 2
1965 #define ONOPEN_SEARCH 3
1966 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1967 {
1968 WCHAR strMsgTitle[MAX_PATH];
1969 WCHAR strMsgText [MAX_PATH];
1970 if (idCaption)
1971 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1972 else
1973 strMsgTitle[0] = '\0';
1974 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1975 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1976 }
1977
1978 BOOL FILEDLG95_OnOpen(HWND hwnd)
1979 {
1980 LPWSTR lpstrFileList;
1981 UINT nFileCount = 0;
1982 UINT sizeUsed = 0;
1983 BOOL ret = TRUE;
1984 WCHAR lpstrPathAndFile[MAX_PATH];
1985 WCHAR lpstrTemp[MAX_PATH];
1986 LPSHELLFOLDER lpsf = NULL;
1987 int nOpenAction;
1988 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1989
1990 TRACE("hwnd=%p\n", hwnd);
1991
1992 /* try to browse the selected item */
1993 if(BrowseSelectedFolder(hwnd))
1994 return FALSE;
1995
1996 /* get the files from the edit control */
1997 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1998
1999 if(nFileCount == 0)
2000 return FALSE;
2001
2002 if(nFileCount > 1)
2003 {
2004 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2005 goto ret;
2006 }
2007
2008 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2009
2010 /*
2011 Step 1: Build a complete path name from the current folder and
2012 the filename or path in the edit box.
2013 Special cases:
2014 - the path in the edit box is a root path
2015 (with or without drive letter)
2016 - the edit box contains ".." (or a path with ".." in it)
2017 */
2018
2019 /* Get the current directory name */
2020 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2021 {
2022 /* last fallback */
2023 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2024 }
2025 PathAddBackslashW(lpstrPathAndFile);
2026
2027 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2028
2029 /* if the user specified a fully qualified path use it */
2030 if(PathIsRelativeW(lpstrFileList))
2031 {
2032 lstrcatW(lpstrPathAndFile, lpstrFileList);
2033 }
2034 else
2035 {
2036 /* does the path have a drive letter? */
2037 if (PathGetDriveNumberW(lpstrFileList) == -1)
2038 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2039 else
2040 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2041 }
2042
2043 /* resolve "." and ".." */
2044 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2045 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2046 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2047
2048 MemFree(lpstrFileList);
2049
2050 /*
2051 Step 2: here we have a cleaned up path
2052
2053 We have to parse the path step by step to see if we have to browse
2054 to a folder if the path points to a directory or the last
2055 valid element is a directory.
2056
2057 valid variables:
2058 lpstrPathAndFile: cleaned up path
2059 */
2060
2061 if (nFileCount &&
2062 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2063 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2064 nOpenAction = ONOPEN_OPEN;
2065 else
2066 nOpenAction = ONOPEN_BROWSE;
2067
2068 /* don't apply any checks with OFN_NOVALIDATE */
2069 {
2070 LPWSTR lpszTemp, lpszTemp1;
2071 LPITEMIDLIST pidl = NULL;
2072 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2073
2074 /* check for invalid chars */
2075 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2076 {
2077 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2078 ret = FALSE;
2079 goto ret;
2080 }
2081
2082 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2083
2084 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2085 while (lpszTemp1)
2086 {
2087 LPSHELLFOLDER lpsfChild;
2088 WCHAR lpwstrTemp[MAX_PATH];
2089 DWORD dwEaten, dwAttributes;
2090 LPWSTR p;
2091
2092 lstrcpyW(lpwstrTemp, lpszTemp);
2093 p = PathFindNextComponentW(lpwstrTemp);
2094
2095 if (!p) break; /* end of path */
2096
2097 *p = 0;
2098 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2099
2100 /* There are no wildcards when OFN_NOVALIDATE is set */
2101 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2102 {
2103 static const WCHAR wszWild[] = { '*', '?', 0 };
2104 /* if the last element is a wildcard do a search */
2105 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2106 {
2107 nOpenAction = ONOPEN_SEARCH;
2108 break;
2109 }
2110 }
2111 lpszTemp1 = lpszTemp;
2112
2113 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2114
2115 /* append a backslash to drive letters */
2116 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2117 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2118 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2119 {
2120 PathAddBackslashW(lpwstrTemp);
2121 }
2122
2123 dwAttributes = SFGAO_FOLDER;
2124 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2125 {
2126 /* the path component is valid, we have a pidl of the next path component */
2127 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2128 if(dwAttributes & SFGAO_FOLDER)
2129 {
2130 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2131 {
2132 ERR("bind to failed\n"); /* should not fail */
2133 break;
2134 }
2135 IShellFolder_Release(lpsf);
2136 lpsf = lpsfChild;
2137 lpsfChild = NULL;
2138 }
2139 else
2140 {
2141 TRACE("value\n");
2142
2143 /* end dialog, return value */
2144 nOpenAction = ONOPEN_OPEN;
2145 break;
2146 }
2147 COMDLG32_SHFree(pidl);
2148 pidl = NULL;
2149 }
2150 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2151 {
2152 if(*lpszTemp || /* points to trailing null for last path element */
2153 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2154 {
2155 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2156 {
2157 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2158 break;
2159 }
2160 }
2161 else
2162 {
2163 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2164 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2165 {
2166 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2167 break;
2168 }
2169 }
2170 /* change to the current folder */
2171 nOpenAction = ONOPEN_OPEN;
2172 break;
2173 }
2174 else
2175 {
2176 nOpenAction = ONOPEN_OPEN;
2177 break;
2178 }
2179 }
2180 if(pidl) COMDLG32_SHFree(pidl);
2181 }
2182
2183 /*
2184 Step 3: here we have a cleaned up and validated path
2185
2186 valid variables:
2187 lpsf: ShellFolder bound to the rightmost valid path component
2188 lpstrPathAndFile: cleaned up path
2189 nOpenAction: action to do
2190 */
2191 TRACE("end validate sf=%p\n", lpsf);
2192
2193 switch(nOpenAction)
2194 {
2195 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2196 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2197 {
2198 int iPos;
2199 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2200 DWORD len;
2201
2202 /* replace the current filter */
2203 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2204 len = lstrlenW(lpszTemp)+1;
2205 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2206 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2207
2208 /* set the filter cb to the extension when possible */
2209 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2210 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2211 }
2212 /* fall through */
2213 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2214 TRACE("ONOPEN_BROWSE\n");
2215 {
2216 IPersistFolder2 * ppf2;
2217 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2218 {
2219 LPITEMIDLIST pidlCurrent;
2220 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2221 IPersistFolder2_Release(ppf2);
2222 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2223 {
2224 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2225 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2226 {
2227 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2228 }
2229 }
2230 else if( nOpenAction == ONOPEN_SEARCH )
2231 {
2232 if (fodInfos->Shell.FOIShellView)
2233 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2234 }
2235 COMDLG32_SHFree(pidlCurrent);
2236 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2237 }
2238 }
2239 ret = FALSE;
2240 break;
2241 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2242 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2243 {
2244 WCHAR *ext = NULL;
2245
2246 /* update READONLY check box flag */
2247 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2248 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2249 else
2250 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2251
2252 /* Attach the file extension with file name*/
2253 ext = PathFindExtensionW(lpstrPathAndFile);
2254 if (! *ext)
2255 {
2256 /* if no extension is specified with file name, then */
2257 /* attach the extension from file filter or default one */
2258
2259 WCHAR *filterExt = NULL;
2260 LPWSTR lpstrFilter = NULL;
2261 static const WCHAR szwDot[] = {'.',0};
2262 int PathLength = lstrlenW(lpstrPathAndFile);
2263
2264 /* Attach the dot*/
2265 lstrcatW(lpstrPathAndFile, szwDot);
2266
2267 /*Get the file extension from file type filter*/
2268 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2269 fodInfos->ofnInfos->nFilterIndex-1);
2270
2271 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2272 filterExt = PathFindExtensionW(lpstrFilter);
2273
2274 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2275 lstrcatW(lpstrPathAndFile, filterExt + 1);
2276 else if ( fodInfos->defext ) /* attach the default file extension*/
2277 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2278
2279 /* In Open dialog: if file does not exist try without extension */
2280 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2281 lpstrPathAndFile[PathLength] = '\0';
2282 }
2283
2284 if (fodInfos->defext) /* add default extension */
2285 {
2286 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2287 if (*ext)
2288 ext++;
2289 if (!lstrcmpiW(fodInfos->defext, ext))
2290 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2291 else
2292 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2293 }
2294
2295 /* In Save dialog: check if the file already exists */
2296 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2297 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2298 && PathFileExistsW(lpstrPathAndFile))
2299 {
2300 WCHAR lpstrOverwrite[100];
2301 int answer;
2302
2303 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2304 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2305 MB_YESNO | MB_ICONEXCLAMATION);
2306 if (answer == IDNO)
2307 {
2308 ret = FALSE;
2309 goto ret;
2310 }
2311 }
2312
2313 /* In Open dialog: check if it should be created if it doesn't exist */
2314 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2315 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2316 && !PathFileExistsW(lpstrPathAndFile))
2317 {
2318 WCHAR lpstrCreate[100];
2319 int answer;
2320
2321 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2322 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2323 MB_YESNO | MB_ICONEXCLAMATION);
2324 if (answer == IDNO)
2325 {
2326 ret = FALSE;
2327 goto ret;
2328 }
2329 }
2330
2331 /* Check that the size of the file does not exceed buffer size.
2332 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2333 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2334 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2335 {
2336
2337 /* fill destination buffer */
2338 if (fodInfos->ofnInfos->lpstrFile)
2339 {
2340 if(fodInfos->unicode)
2341 {
2342 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2343
2344 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2345 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2346 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2347 }
2348 else
2349 {
2350 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2351
2352 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2353 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2354 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2355 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2356 }
2357 }
2358
2359 if(fodInfos->unicode)
2360 {
2361 LPWSTR lpszTemp;
2362
2363 /* set filename offset */
2364 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2365 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2366
2367 /* set extension offset */
2368 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2369 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2370 }
2371 else
2372 {
2373 LPSTR lpszTemp;
2374 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2375
2376 /* set filename offset */
2377 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2378 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2379
2380 /* set extension offset */
2381 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2382 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2383 }
2384
2385 /* set the lpstrFileTitle */
2386 if(fodInfos->ofnInfos->lpstrFileTitle)
2387 {
2388 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2389 if(fodInfos->unicode)
2390 {
2391 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2392 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2393 }
2394 else
2395 {
2396 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2397 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2398 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2399 }
2400 }
2401
2402 /* copy currently selected filter to lpstrCustomFilter */
2403 if (fodInfos->ofnInfos->lpstrCustomFilter)
2404 {
2405 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2406 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2407 NULL, 0, NULL, NULL);
2408 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2409 {
2410 LPSTR s = ofn->lpstrCustomFilter;
2411 s += strlen(ofn->lpstrCustomFilter)+1;
2412 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2413 s, len, NULL, NULL);
2414 }
2415 }
2416
2417
2418 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2419 goto ret;
2420
2421 TRACE("close\n");
2422 FILEDLG95_Clean(hwnd);
2423 ret = EndDialog(hwnd, TRUE);
2424 }
2425 else
2426 {
2427 WORD size;
2428
2429 size = lstrlenW(lpstrPathAndFile) + 1;
2430 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2431 size += 1;
2432 /* return needed size in first two bytes of lpstrFile */
2433 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2434 FILEDLG95_Clean(hwnd);
2435 ret = EndDialog(hwnd, FALSE);
2436 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2437 }
2438 }
2439 break;
2440 }
2441
2442 ret:
2443 if(lpsf) IShellFolder_Release(lpsf);
2444 return ret;
2445 }
2446
2447 /***********************************************************************
2448 * FILEDLG95_SHELL_Init
2449 *
2450 * Initialisation of the shell objects
2451 */
2452 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2453 {
2454 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2455
2456 TRACE("\n");
2457
2458 /*
2459 * Initialisation of the FileOpenDialogInfos structure
2460 */
2461
2462 /* Shell */
2463
2464 /*ShellInfos */
2465 fodInfos->ShellInfos.hwndOwner = hwnd;
2466
2467 /* Disable multi-select if flag not set */
2468 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2469 {
2470 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2471 }
2472 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2473 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2474
2475 /* Construct the IShellBrowser interface */
2476 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2477
2478 return NOERROR;
2479 }
2480
2481 /***********************************************************************
2482 * FILEDLG95_SHELL_ExecuteCommand
2483 *
2484 * Change the folder option and refresh the view
2485 * If the function succeeds, the return value is nonzero.
2486 */
2487 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2488 {
2489 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2490 IContextMenu * pcm;
2491
2492 TRACE("(%p,%p)\n", hwnd, lpVerb);
2493
2494 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2495 SVGIO_BACKGROUND,
2496 &IID_IContextMenu,
2497 (LPVOID*)&pcm)))
2498 {
2499 CMINVOKECOMMANDINFO ci;
2500 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2501 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2502 ci.lpVerb = lpVerb;
2503 ci.hwnd = hwnd;
2504
2505 IContextMenu_InvokeCommand(pcm, &ci);
2506 IContextMenu_Release(pcm);
2507 }
2508
2509 return FALSE;
2510 }
2511
2512 /***********************************************************************
2513 * FILEDLG95_SHELL_UpFolder
2514 *
2515 * Browse to the specified object
2516 * If the function succeeds, the return value is nonzero.
2517 */
2518 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2519 {
2520 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2521
2522 TRACE("\n");
2523
2524 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2525 NULL,
2526 SBSP_PARENT)))
2527 {
2528 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2529 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2530 return TRUE;
2531 }
2532 return FALSE;
2533 }
2534
2535 /***********************************************************************
2536 * FILEDLG95_SHELL_BrowseToDesktop
2537 *
2538 * Browse to the Desktop
2539 * If the function succeeds, the return value is nonzero.
2540 */
2541 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2542 {
2543 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2544 LPITEMIDLIST pidl;
2545 HRESULT hres;
2546
2547 TRACE("\n");
2548
2549 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2550 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2551 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2552 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2553 COMDLG32_SHFree(pidl);
2554 return SUCCEEDED(hres);
2555 }
2556 /***********************************************************************
2557 * FILEDLG95_SHELL_Clean
2558 *
2559 * Cleans the memory used by shell objects
2560 */
2561 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2562 {
2563 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2564
2565 TRACE("\n");
2566
2567 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2568
2569 /* clean Shell interfaces */
2570 if (fodInfos->Shell.FOIShellView)
2571 {
2572 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2573 IShellView_Release(fodInfos->Shell.FOIShellView);
2574 }
2575 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2576 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2577 if (fodInfos->Shell.FOIDataObject)
2578 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2579 }
2580
2581 /***********************************************************************
2582 * FILEDLG95_FILETYPE_Init
2583 *
2584 * Initialisation of the file type combo box
2585 */
2586 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2587 {
2588 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2589 int nFilters = 0; /* number of filters */
2590 int nFilterIndexCB;
2591
2592 TRACE("\n");
2593
2594 if(fodInfos->customfilter)
2595 {
2596 /* customfilter has one entry... title\0ext\0
2597 * Set first entry of combo box item with customfilter
2598 */
2599 LPWSTR lpstrExt;
2600 LPCWSTR lpstrPos = fodInfos->customfilter;
2601
2602 /* Get the title */
2603 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2604
2605 /* Copy the extensions */
2606 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2607 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2608 lstrcpyW(lpstrExt,lpstrPos);
2609
2610 /* Add the item at the end of the combo */
2611 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2612 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2613 nFilters++;
2614 }
2615 if(fodInfos->filter)
2616 {
2617 LPCWSTR lpstrPos = fodInfos->filter;
2618
2619 for(;;)
2620 {
2621 /* filter is a list... title\0ext\0......\0\0
2622 * Set the combo item text to the title and the item data
2623 * to the ext
2624 */
2625 LPCWSTR lpstrDisplay;
2626 LPWSTR lpstrExt;
2627
2628 /* Get the title */
2629 if(! *lpstrPos) break; /* end */
2630 lpstrDisplay = lpstrPos;
2631 lpstrPos += lstrlenW(lpstrPos) + 1;
2632
2633 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2634
2635 nFilters++;
2636
2637 /* Copy the extensions */
2638 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2639 lstrcpyW(lpstrExt,lpstrPos);
2640 lpstrPos += lstrlenW(lpstrPos) + 1;
2641
2642 /* Add the item at the end of the combo */
2643 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2644
2645 /* malformed filters are added anyway... */
2646 if (!*lpstrExt) break;
2647 }
2648 }
2649
2650 /*
2651 * Set the current filter to the one specified
2652 * in the initialisation structure
2653 */
2654 if (fodInfos->filter || fodInfos->customfilter)
2655 {
2656 LPWSTR lpstrFilter;
2657
2658 /* Check to make sure our index isn't out of bounds. */
2659 if ( fodInfos->ofnInfos->nFilterIndex >
2660 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2661 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2662
2663 /* set default filter index */
2664 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2665 fodInfos->ofnInfos->nFilterIndex = 1;
2666
2667 /* calculate index of Combo Box item */
2668 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2669 if (fodInfos->customfilter == NULL)
2670 nFilterIndexCB--;
2671
2672 /* Set the current index selection. */
2673 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2674
2675 /* Get the corresponding text string from the combo box. */
2676 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2677 nFilterIndexCB);
2678
2679 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2680 lpstrFilter = NULL;
2681
2682 if(lpstrFilter)
2683 {
2684 DWORD len;
2685 CharLowerW(lpstrFilter); /* lowercase */
2686 len = lstrlenW(lpstrFilter)+1;
2687 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2688 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2689 }
2690 } else
2691 fodInfos->ofnInfos->nFilterIndex = 0;
2692 return S_OK;
2693 }
2694
2695 /***********************************************************************
2696 * FILEDLG95_FILETYPE_OnCommand
2697 *
2698 * WM_COMMAND of the file type combo box
2699 * If the function succeeds, the return value is nonzero.
2700 */
2701 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2702 {
2703 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2704
2705 switch(wNotifyCode)
2706 {
2707 case CBN_SELENDOK:
2708 {
2709 LPWSTR lpstrFilter;
2710
2711 /* Get the current item of the filetype combo box */
2712 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2713
2714 /* set the current filter index */
2715 fodInfos->ofnInfos->nFilterIndex = iItem +
2716 (fodInfos->customfilter == NULL ? 1 : 0);
2717
2718 /* Set the current filter with the current selection */
2719 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2720
2721 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2722 iItem);
2723 if((INT_PTR)lpstrFilter != CB_ERR)
2724 {
2725 DWORD len;
2726 CharLowerW(lpstrFilter); /* lowercase */
2727 len = lstrlenW(lpstrFilter)+1;
2728 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2729 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2730 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2731 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2732 }
2733
2734 /* Refresh the actual view to display the included items*/
2735 if (fodInfos->Shell.FOIShellView)
2736 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2737 }
2738 }
2739 return FALSE;
2740 }
2741 /***********************************************************************
2742 * FILEDLG95_FILETYPE_SearchExt
2743 *
2744 * searches for an extension in the filetype box
2745 */
2746 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2747 {
2748 int i, iCount = CBGetCount(hwnd);
2749
2750 TRACE("%s\n", debugstr_w(lpstrExt));
2751
2752 if(iCount != CB_ERR)
2753 {
2754 for(i=0;i<iCount;i++)
2755 {
2756 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2757 return i;
2758 }
2759 }
2760 return -1;
2761 }
2762
2763 /***********************************************************************
2764 * FILEDLG95_FILETYPE_Clean
2765 *
2766 * Clean the memory used by the filetype combo box
2767 */
2768 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2769 {
2770 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2771 int iPos;
2772 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2773
2774 TRACE("\n");
2775
2776 /* Delete each string of the combo and their associated data */
2777 if(iCount != CB_ERR)
2778 {
2779 for(iPos = iCount-1;iPos>=0;iPos--)
2780 {
2781 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2782 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2783 }
2784 }
2785 /* Current filter */
2786 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2787
2788 }
2789
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_Init
2792 *
2793 * Initialisation of the look in combo box
2794 */
2795
2796 /* Small helper function, to determine if the unixfs shell extension is rooted
2797 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2798 */
2799 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2800 HKEY hKey;
2801 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2802 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2803 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2804 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2805 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2806 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2807 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2808
2809 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2810 return FALSE;
2811
2812 RegCloseKey(hKey);
2813 return TRUE;
2814 }
2815
2816 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2817 {
2818 IShellFolder *psfRoot, *psfDrives;
2819 IEnumIDList *lpeRoot, *lpeDrives;
2820 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2821
2822 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2823
2824 TRACE("\n");
2825
2826 liInfos->iMaxIndentation = 0;
2827
2828 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2829
2830 /* set item height for both text field and listbox */
2831 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2832 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2833
2834 /* Turn on the extended UI for the combo box like Windows does */
2835 CBSetExtendedUI(hwndCombo, TRUE);
2836
2837 /* Initialise data of Desktop folder */
2838 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2839 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2840 COMDLG32_SHFree(pidlTmp);
2841
2842 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2843
2844 SHGetDesktopFolder(&psfRoot);
2845
2846 if (psfRoot)
2847 {
2848 /* enumerate the contents of the desktop */
2849 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2850 {
2851 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2852 {
2853 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2854
2855 /* If the unixfs extension is rooted, we don't expand the drives by default */
2856 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2857 {
2858 /* special handling for CSIDL_DRIVES */
2859 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2860 {
2861 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2862 {
2863 /* enumerate the drives */
2864 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2865 {
2866 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2867 {
2868 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2869 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2870 COMDLG32_SHFree(pidlAbsTmp);
2871 COMDLG32_SHFree(pidlTmp1);
2872 }
2873 IEnumIDList_Release(lpeDrives);
2874 }
2875 IShellFolder_Release(psfDrives);
2876 }
2877 }
2878 }
2879
2880 COMDLG32_SHFree(pidlTmp);
2881 }
2882 IEnumIDList_Release(lpeRoot);
2883 }
2884 IShellFolder_Release(psfRoot);
2885 }
2886
2887 COMDLG32_SHFree(pidlDrives);
2888 }
2889
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_DrawItem
2892 *
2893 * WM_DRAWITEM message handler
2894 */
2895 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2896 {
2897 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2898 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2899 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2900 RECT rectText;
2901 RECT rectIcon;
2902 SHFILEINFOW sfi;
2903 HIMAGELIST ilItemImage;
2904 int iIndentation;
2905 TEXTMETRICW tm;
2906 LPSFOLDER tmpFolder;
2907 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2908
2909 TRACE("\n");
2910
2911 if(pDIStruct->itemID == -1)
2912 return 0;
2913
2914 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2915 pDIStruct->itemID)))
2916 return 0;
2917
2918
2919 if(pDIStruct->itemID == liInfos->uSelectedItem)
2920 {
2921 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2922 0,
2923 &sfi,
2924 sizeof (sfi),
2925 SHGFI_PIDL | SHGFI_SMALLICON |
2926 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2927 SHGFI_DISPLAYNAME );
2928 }
2929 else
2930 {
2931 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2932 0,
2933 &sfi,
2934 sizeof (sfi),
2935 SHGFI_PIDL | SHGFI_SMALLICON |
2936 SHGFI_SYSICONINDEX |
2937 SHGFI_DISPLAYNAME);
2938 }
2939
2940 /* Is this item selected ? */
2941 if(pDIStruct->itemState & ODS_SELECTED)
2942 {
2943 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2944 SetBkColor(pDIStruct->hDC,crHighLight);
2945 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2946 }
2947 else
2948 {
2949 SetTextColor(pDIStruct->hDC,crText);
2950 SetBkColor(pDIStruct->hDC,crWin);
2951 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2952 }
2953
2954 /* Do not indent item if drawing in the edit of the combo */
2955 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2956 {
2957 iIndentation = 0;
2958 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2959 0,
2960 &sfi,
2961 sizeof (sfi),
2962 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2963 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2964
2965 }
2966 else
2967 {
2968 iIndentation = tmpFolder->m_iIndent;
2969 }
2970 /* Draw text and icon */
2971
2972 /* Initialise the icon display area */
2973 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2974 rectIcon.top = pDIStruct->rcItem.top;
2975 rectIcon.right = rectIcon.left + ICONWIDTH;
2976 rectIcon.bottom = pDIStruct->rcItem.bottom;
2977
2978 /* Initialise the text display area */
2979 GetTextMetricsW(pDIStruct->hDC, &tm);
2980 rectText.left = rectIcon.right;
2981 rectText.top =
2982 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2983 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2984 rectText.bottom =
2985 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2986
2987 /* Draw the icon from the image list */
2988 ImageList_Draw(ilItemImage,
2989 sfi.iIcon,
2990 pDIStruct->hDC,
2991 rectIcon.left,
2992 rectIcon.top,
2993 ILD_TRANSPARENT );
2994
2995 /* Draw the associated text */
2996 if(sfi.szDisplayName)
2997 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2998
2999
3000 return NOERROR;
3001 }
3002
3003 /***********************************************************************
3004 * FILEDLG95_LOOKIN_OnCommand
3005 *
3006 * LookIn combo box WM_COMMAND message handler
3007 * If the function succeeds, the return value is nonzero.
3008 */
3009 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3010 {
3011 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3012
3013 TRACE("%p\n", fodInfos);
3014
3015 switch(wNotifyCode)
3016 {
3017 case CBN_SELENDOK:
3018 {
3019 LPSFOLDER tmpFolder;
3020 int iItem;
3021
3022 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3023
3024 if( iItem == CB_ERR) return FALSE;
3025
3026 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3027 iItem)))
3028 return FALSE;
3029
3030
3031 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3032 tmpFolder->pidlItem,
3033 SBSP_ABSOLUTE)))
3034 {
3035 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3036 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3037 return TRUE;
3038 }
3039 break;
3040 }
3041
3042 }
3043 return FALSE;
3044 }
3045
3046 /***********************************************************************
3047 * FILEDLG95_LOOKIN_AddItem
3048 *
3049 * Adds an absolute pidl item to the lookin combo box
3050 * returns the index of the inserted item
3051 */
3052 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3053 {
3054 LPITEMIDLIST pidlNext;
3055 SHFILEINFOW sfi;
3056 SFOLDER *tmpFolder;
3057 LookInInfos *liInfos;
3058
3059 TRACE("%08x\n", iInsertId);
3060
3061 if(!pidl)
3062 return -1;
3063
3064 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3065 return -1;
3066
3067 tmpFolder = MemAlloc(sizeof(SFOLDER));
3068 tmpFolder->m_iIndent = 0;
3069
3070 /* Calculate the indentation of the item in the lookin*/
3071 pidlNext = pidl;
3072 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3073 {
3074 tmpFolder->m_iIndent++;
3075 }
3076
3077 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3078
3079 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3080 liInfos->iMaxIndentation = tmpFolder->m_iIndent;