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