2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
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.
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.
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
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).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
74 #include "filedlgbrowser.h"
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_DONTADDTORECENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex
; /* Index of picture in image list */
96 int m_iIndent
; /* Indentation index */
97 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
101 typedef struct tagLookInInfo
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define XTEXTOFFSET 3
118 /* SearchItem methods */
119 #define SEARCH_PIDL 1
121 #define ITEM_NOTFOUND -1
123 /* Undefined windows message sent by CreateViewObject*/
124 #define WM_GETISHELLBROWSER WM_USER+7
127 * Those macros exist in windowsx.h. However, you can't really use them since
128 * they rely on the UNICODE defines and can't be used inside Wine itself.
131 /* Combo box macros */
132 #define CBAddString(hwnd,str) \
133 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
135 #define CBInsertString(hwnd,str,pos) \
136 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
138 #define CBDeleteString(hwnd,pos) \
139 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
141 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
142 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
144 #define CBGetItemDataPtr(hwnd,iItemId) \
145 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
147 #define CBGetLBText(hwnd,iItemId,str) \
148 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
150 #define CBGetCurSel(hwnd) \
151 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
153 #define CBSetCurSel(hwnd,pos) \
154 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
156 #define CBGetCount(hwnd) \
157 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
158 #define CBShowDropDown(hwnd,show) \
159 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
160 #define CBSetItemHeight(hwnd,index,height) \
161 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
163 #define CBSetExtendedUI(hwnd,flag) \
164 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
166 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
167 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
168 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
170 static const WCHAR LastVisitedMRUW
[] =
171 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
172 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
173 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
174 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
175 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
177 /***********************************************************************
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
);
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
);
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
);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
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
);
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
);
217 /* Functions for dealing with the most-recently-used registry keys */
218 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
219 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
220 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
222 /* Miscellaneous tool functions */
223 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
224 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
225 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
226 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
227 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
228 static UINT
GetNumSelected( IDataObject
*doSelected
);
230 /* Shell memory allocation */
231 static void *MemAlloc(UINT size
);
232 static void MemFree(void *mem
);
234 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
235 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
236 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
237 static BOOL
BrowseSelectedFolder(HWND hwnd
);
239 /***********************************************************************
242 * Creates an Open common dialog box that lets the user select
243 * the drive, directory, and the name of a file or set of files to open.
245 * IN : The FileOpenDlgInfos structure associated with the dialog
246 * OUT : TRUE on success
247 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
249 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
253 LPCVOID origTemplate
;
255 LPDLGTEMPLATEW
template;
260 /* test for missing functionality */
261 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
263 FIXME("Flags 0x%08x not yet implemented\n",
264 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
267 /* Create the dialog from a template */
269 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
271 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
274 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
275 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
276 !(origTemplate
= LockResource(hDlgTmpl
)))
278 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
281 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
283 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
286 memcpy(template, origTemplate
, dwSize
);
288 /* msdn: explorer style dialogs permit sizing by default.
289 * The OFN_ENABLESIZING flag is only needed when a hook or
290 * custom tmeplate is provided */
291 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
292 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
293 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
295 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
297 template->style
|= WS_SIZEBOX
;
298 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
299 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
302 template->style
&= ~WS_SIZEBOX
;
305 /* old style hook messages */
306 if (IsHooked(fodInfos
))
308 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
309 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
310 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
311 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
314 /* Some shell namespace extensions depend on COM being initialized. */
315 hr
= OleInitialize(NULL
);
317 if (fodInfos
->unicode
)
318 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
320 fodInfos
->ofnInfos
->hwndOwner
,
324 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
326 fodInfos
->ofnInfos
->hwndOwner
,
332 HeapFree(GetProcessHeap(), 0, template);
334 /* Unable to create the dialog */
341 /***********************************************************************
344 * Call GetFileName95 with this structure and clean the memory.
346 * IN : The OPENFILENAMEA initialisation structure passed to
347 * GetOpenFileNameA win api function (see filedlg.c)
349 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
352 FileOpenDlgInfos fodInfos
;
353 LPSTR lpstrSavDir
= NULL
;
355 LPWSTR defext
= NULL
;
356 LPWSTR filter
= NULL
;
357 LPWSTR customfilter
= NULL
;
358 INITCOMMONCONTROLSEX icc
;
360 /* Initialize ComboBoxEx32 */
361 icc
.dwSize
= sizeof(icc
);
362 icc
.dwICC
= ICC_USEREX_CLASSES
;
363 InitCommonControlsEx(&icc
);
365 /* Initialize CommDlgExtendedError() */
366 COMDLG32_SetCommDlgExtendedError(0);
368 /* Initialize FileOpenDlgInfos structure */
369 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
371 /* Pass in the original ofn */
372 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
374 /* save current directory */
375 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
377 lpstrSavDir
= MemAlloc(MAX_PATH
);
378 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
381 fodInfos
.unicode
= FALSE
;
383 /* convert all the input strings to unicode */
384 if(ofn
->lpstrInitialDir
)
386 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
387 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
388 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
391 fodInfos
.initdir
= NULL
;
395 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
396 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
399 fodInfos
.filename
= NULL
;
403 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
404 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
405 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
407 fodInfos
.defext
= defext
;
411 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
412 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
413 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
415 fodInfos
.title
= title
;
417 if (ofn
->lpstrFilter
)
422 /* filter is a list... title\0ext\0......\0\0 */
423 s
= ofn
->lpstrFilter
;
424 while (*s
) s
= s
+strlen(s
)+1;
426 n
= s
- ofn
->lpstrFilter
;
427 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
428 filter
= MemAlloc(len
*sizeof(WCHAR
));
429 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
431 fodInfos
.filter
= filter
;
433 /* convert lpstrCustomFilter */
434 if (ofn
->lpstrCustomFilter
)
439 /* customfilter contains a pair of strings... title\0ext\0 */
440 s
= ofn
->lpstrCustomFilter
;
441 if (*s
) s
= s
+strlen(s
)+1;
442 if (*s
) s
= s
+strlen(s
)+1;
443 n
= s
- ofn
->lpstrCustomFilter
;
444 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
445 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
446 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
448 fodInfos
.customfilter
= customfilter
;
450 /* Initialize the dialog property */
451 fodInfos
.DlgInfos
.dwDlgProp
= 0;
452 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
457 ret
= GetFileName95(&fodInfos
);
460 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
461 ret
= GetFileName95(&fodInfos
);
469 SetCurrentDirectoryA(lpstrSavDir
);
470 MemFree(lpstrSavDir
);
476 MemFree(customfilter
);
477 MemFree(fodInfos
.initdir
);
478 MemFree(fodInfos
.filename
);
480 TRACE("selected file: %s\n",ofn
->lpstrFile
);
485 /***********************************************************************
488 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
489 * Call GetFileName95 with this structure and clean the memory.
492 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
495 FileOpenDlgInfos fodInfos
;
496 LPWSTR lpstrSavDir
= NULL
;
497 INITCOMMONCONTROLSEX icc
;
499 /* Initialize ComboBoxEx32 */
500 icc
.dwSize
= sizeof(icc
);
501 icc
.dwICC
= ICC_USEREX_CLASSES
;
502 InitCommonControlsEx(&icc
);
504 /* Initialize CommDlgExtendedError() */
505 COMDLG32_SetCommDlgExtendedError(0);
507 /* Initialize FileOpenDlgInfos structure */
508 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
510 /* Pass in the original ofn */
511 fodInfos
.ofnInfos
= ofn
;
513 fodInfos
.title
= ofn
->lpstrTitle
;
514 fodInfos
.defext
= ofn
->lpstrDefExt
;
515 fodInfos
.filter
= ofn
->lpstrFilter
;
516 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
518 /* convert string arguments, save others */
521 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
522 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
525 fodInfos
.filename
= NULL
;
527 if(ofn
->lpstrInitialDir
)
529 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
530 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
531 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
532 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
535 fodInfos
.initdir
= NULL
;
537 /* save current directory */
538 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
540 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
541 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
544 fodInfos
.unicode
= TRUE
;
549 ret
= GetFileName95(&fodInfos
);
552 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
553 ret
= GetFileName95(&fodInfos
);
561 SetCurrentDirectoryW(lpstrSavDir
);
562 MemFree(lpstrSavDir
);
565 /* restore saved IN arguments and convert OUT arguments back */
566 MemFree(fodInfos
.filename
);
567 MemFree(fodInfos
.initdir
);
571 /******************************************************************************
572 * COMDLG32_GetDisplayNameOf [internal]
574 * Helper function to get the display name for a pidl.
576 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
577 LPSHELLFOLDER psfDesktop
;
580 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
583 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
584 IShellFolder_Release(psfDesktop
);
588 IShellFolder_Release(psfDesktop
);
589 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
592 /******************************************************************************
593 * COMDLG32_GetCanonicalPath [internal]
595 * Helper function to get the canonical path.
597 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
598 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
600 WCHAR lpstrTemp
[MAX_PATH
];
602 /* Get the current directory name */
603 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
606 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
608 PathAddBackslashW(lpstrPathAndFile
);
610 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
612 /* if the user specified a fully qualified path use it */
613 if(PathIsRelativeW(lpstrFile
))
615 lstrcatW(lpstrPathAndFile
, lpstrFile
);
619 /* does the path have a drive letter? */
620 if (PathGetDriveNumberW(lpstrFile
) == -1)
621 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
623 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
626 /* resolve "." and ".." */
627 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
628 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
629 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
632 /***********************************************************************
633 * COMDLG32_SplitFileNames [internal]
635 * Creates a delimited list of filenames.
637 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
639 UINT nStrCharCount
= 0; /* index in src buffer */
640 UINT nFileIndex
= 0; /* index in dest buffer */
641 UINT nFileCount
= 0; /* number of files */
643 /* we might get single filename without any '"',
644 * so we need nStrLen + terminating \0 + end-of-list \0 */
645 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
648 /* build delimited file list from filenames */
649 while ( nStrCharCount
<= nStrLen
)
651 if ( lpstrEdit
[nStrCharCount
]=='"' )
654 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
656 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
659 (*lpstrFileList
)[nFileIndex
++] = 0;
665 /* single, unquoted string */
666 if ((nStrLen
> 0) && (nFileIndex
== 0) )
668 lstrcpyW(*lpstrFileList
, lpstrEdit
);
669 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
674 (*lpstrFileList
)[nFileIndex
++] = '\0';
676 *sizeUsed
= nFileIndex
;
680 /***********************************************************************
681 * ArrangeCtrlPositions [internal]
683 * NOTE: Make sure to add testcases for any changes made here.
685 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
687 HWND hwndChild
, hwndStc32
;
688 RECT rectParent
, rectChild
, rectStc32
;
692 /* Take into account if open as read only checkbox and help button
697 RECT rectHelp
, rectCancel
;
698 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
699 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
700 /* subtract the height of the help button plus the space between
701 * the help button and the cancel button to the height of the dialog
703 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
707 There are two possibilities to add components to the default file dialog box.
709 By default, all the new components are added below the standard dialog box (the else case).
711 However, if there is a static text component with the stc32 id, a special case happens.
712 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
713 in the window and the cx and cy indicate how to size the window.
714 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
715 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
719 GetClientRect(hwndParentDlg
, &rectParent
);
721 /* when arranging controls we have to use fixed parent size */
722 rectParent
.bottom
-= help_fixup
;
724 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
727 GetWindowRect(hwndStc32
, &rectStc32
);
728 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
730 /* set the size of the stc32 control according to the size of
731 * client area of the parent dialog
733 SetWindowPos(hwndStc32
, 0,
735 rectParent
.right
, rectParent
.bottom
,
736 SWP_NOMOVE
| SWP_NOZORDER
);
739 SetRectEmpty(&rectStc32
);
741 /* this part moves controls of the child dialog */
742 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
745 if (hwndChild
!= hwndStc32
)
747 GetWindowRect(hwndChild
, &rectChild
);
748 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
750 /* move only if stc32 exist */
751 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
753 /* move to the right of visible controls of the parent dialog */
754 rectChild
.left
+= rectParent
.right
;
755 rectChild
.left
-= rectStc32
.right
;
757 /* move even if stc32 doesn't exist */
758 if (rectChild
.top
>= rectStc32
.bottom
)
760 /* move below visible controls of the parent dialog */
761 rectChild
.top
+= rectParent
.bottom
;
762 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
765 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
766 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
768 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
771 /* this part moves controls of the parent dialog */
772 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
775 if (hwndChild
!= hwndChildDlg
)
777 GetWindowRect(hwndChild
, &rectChild
);
778 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
780 /* left,top of stc32 marks the position of controls
781 * from the parent dialog
783 rectChild
.left
+= rectStc32
.left
;
784 rectChild
.top
+= rectStc32
.top
;
786 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
787 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
789 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
792 /* calculate the size of the resulting dialog */
794 /* here we have to use original parent size */
795 GetClientRect(hwndParentDlg
, &rectParent
);
796 GetClientRect(hwndChildDlg
, &rectChild
);
797 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
798 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
803 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
804 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
806 chgx
= rectChild
.right
- rectParent
.right
;
808 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
809 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
811 /* Unconditionally set new dialog
812 * height to that of the child
814 chgy
= rectChild
.bottom
- rectParent
.bottom
;
819 chgy
= rectChild
.bottom
- help_fixup
;
821 /* set the size of the parent dialog */
822 GetWindowRect(hwndParentDlg
, &rectParent
);
823 SetWindowPos(hwndParentDlg
, 0,
825 rectParent
.right
- rectParent
.left
+ chgx
,
826 rectParent
.bottom
- rectParent
.top
+ chgy
,
827 SWP_NOMOVE
| SWP_NOZORDER
);
830 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
839 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
849 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
850 * structure's hInstance parameter is not a HINSTANCE, but
851 * instead a pointer to a template resource to use.
853 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
856 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
858 hinst
= COMDLG32_hInstance
;
859 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
861 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
867 hinst
= fodInfos
->ofnInfos
->hInstance
;
868 if(fodInfos
->unicode
)
870 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
871 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
875 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
876 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
880 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
883 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
884 !(template = LockResource( hDlgTmpl
)))
886 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
890 if (fodInfos
->unicode
)
891 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
892 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
893 (LPARAM
)fodInfos
->ofnInfos
);
895 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
896 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
897 (LPARAM
)fodInfos
->ofnInfos
);
900 else if( IsHooked(fodInfos
))
905 WORD menu
,class,title
;
907 GetClientRect(hwnd
,&rectHwnd
);
908 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
909 temp
.tmplate
.dwExtendedStyle
= 0;
910 temp
.tmplate
.cdit
= 0;
915 temp
.menu
= temp
.class = temp
.title
= 0;
917 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
918 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
925 /***********************************************************************
926 * SendCustomDlgNotificationMessage
928 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
931 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
933 LRESULT hook_result
= 0;
934 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
936 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
938 if(!fodInfos
) return 0;
940 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
942 TRACE("CALL NOTIFY for %x\n", uCode
);
943 if(fodInfos
->unicode
)
946 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
947 ofnNotify
.hdr
.idFrom
=0;
948 ofnNotify
.hdr
.code
= uCode
;
949 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
950 ofnNotify
.pszFile
= NULL
;
951 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
956 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
957 ofnNotify
.hdr
.idFrom
=0;
958 ofnNotify
.hdr
.code
= uCode
;
959 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
960 ofnNotify
.pszFile
= NULL
;
961 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
963 TRACE("RET NOTIFY\n");
965 TRACE("Retval: 0x%08lx\n", hook_result
);
969 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
973 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
975 TRACE("CDM_GETFILEPATH:\n");
977 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
980 /* get path and filenames */
981 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
982 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
983 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
986 p
= buffer
+ strlenW(buffer
);
988 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
990 if (fodInfos
->unicode
)
992 total
= strlenW( buffer
) + 1;
993 if (result
) lstrcpynW( result
, buffer
, size
);
994 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
998 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
999 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
1000 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1002 HeapFree( GetProcessHeap(), 0, buffer
);
1006 /***********************************************************************
1007 * FILEDLG95_HandleCustomDialogMessages
1009 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1011 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1013 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1014 WCHAR lpstrPath
[MAX_PATH
];
1017 if(!fodInfos
) return FALSE
;
1021 case CDM_GETFILEPATH
:
1022 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1025 case CDM_GETFOLDERPATH
:
1026 TRACE("CDM_GETFOLDERPATH:\n");
1027 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1030 if (fodInfos
->unicode
)
1031 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1033 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1034 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1036 retval
= lstrlenW(lpstrPath
) + 1;
1039 case CDM_GETFOLDERIDLIST
:
1040 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1041 if (retval
<= wParam
)
1042 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1046 TRACE("CDM_GETSPEC:\n");
1047 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1050 if (fodInfos
->unicode
)
1051 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1053 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1057 case CDM_SETCONTROLTEXT
:
1058 TRACE("CDM_SETCONTROLTEXT:\n");
1061 if( fodInfos
->unicode
)
1062 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1064 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1069 case CDM_HIDECONTROL
:
1070 /* MSDN states that it should fail for not OFN_EXPLORER case */
1071 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1073 HWND control
= GetDlgItem( hwnd
, wParam
);
1074 if (control
) ShowWindow( control
, SW_HIDE
);
1077 else retval
= FALSE
;
1081 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1082 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1085 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1089 /***********************************************************************
1090 * FILEDLG95_OnWMGetMMI
1092 * WM_GETMINMAXINFO message handler for resizable dialogs
1094 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1096 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1097 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1098 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1100 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1105 /***********************************************************************
1106 * FILEDLG95_OnWMSize
1108 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1110 * FIXME: this could be made more elaborate. Now use a simple scheme
1111 * where the file view is enlarged and the controls are either moved
1112 * vertically or horizontally to get out of the way. Only the "grip"
1113 * is moved in both directions to stay in the corner.
1115 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1121 FileOpenDlgInfos
*fodInfos
;
1123 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1124 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1125 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1126 /* get the new dialog rectangle */
1127 GetWindowRect( hwnd
, &rc
);
1128 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1129 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1130 /* not initialized yet */
1131 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1132 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1133 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1135 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1136 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1137 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1138 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1139 /* change the size of the view window */
1140 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1141 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1142 hdwp
= BeginDeferWindowPos( 10);
1143 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1144 rcview
.right
- rcview
.left
+ chgx
,
1145 rcview
.bottom
- rcview
.top
+ chgy
,
1146 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1147 /* change position and sizes of the controls */
1148 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1150 int ctrlid
= GetDlgCtrlID( ctrl
);
1151 GetWindowRect( ctrl
, &rc
);
1152 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1153 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1155 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1157 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1159 else if( rc
.top
> rcview
.bottom
)
1161 /* if it was below the shell view
1165 /* file name (edit or comboboxex) and file types combo change also width */
1169 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1170 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1171 SWP_NOACTIVATE
| SWP_NOZORDER
);
1173 /* then these buttons must move out of the way */
1177 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1179 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1182 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1184 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1187 else if( rc
.left
> rcview
.right
)
1189 /* if it was to the right of the shell view
1191 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1193 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1200 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1202 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1203 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1204 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1206 case IDC_TOOLBARSTATIC
:
1208 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1210 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1213 /* not resized in windows. Since wine uses this invisible control
1214 * to size the browser view it needs to be resized */
1215 case IDC_SHELLSTATIC
:
1216 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1217 rc
.right
- rc
.left
+ chgx
,
1218 rc
.bottom
- rc
.top
+ chgy
,
1219 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1224 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1225 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1227 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1228 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1230 GetWindowRect( ctrl
, &rc
);
1231 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1232 if( rc
.top
> rcview
.bottom
)
1234 /* if it was below the shell view
1236 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1237 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1238 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1240 else if( rc
.left
> rcview
.right
)
1242 /* if it was to the right of the shell view
1244 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1245 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1246 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1249 /* size the custom dialog at the end: some applications do some
1250 * control re-arranging at this point */
1251 GetClientRect(hwnd
, &rc
);
1252 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1253 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1255 EndDeferWindowPos( hdwp
);
1256 /* should not be needed */
1257 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1261 /***********************************************************************
1264 * File open dialog procedure
1266 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1269 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1276 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1278 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1279 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1281 /* Adds the FileOpenDlgInfos in the property list of the dialog
1282 so it will be easily accessible through a GetPropA(...) */
1283 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1285 FILEDLG95_InitControls(hwnd
);
1287 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1289 GetWindowRect( hwnd
, &rc
);
1290 fodInfos
->DlgInfos
.hwndGrip
=
1291 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1292 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1293 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1294 rc
.right
- gripx
, rc
.bottom
- gripy
,
1295 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1298 fodInfos
->DlgInfos
.hwndCustomDlg
=
1299 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1301 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1302 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1304 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1305 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1307 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1308 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1309 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1312 /* if the app has changed the position of the invisible listbox,
1313 * change that of the listview (browser) as well */
1314 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1315 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1316 if( !EqualRect( &rc
, &rcstc
))
1318 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1319 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1320 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1321 SWP_NOACTIVATE
| SWP_NOZORDER
);
1324 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1326 GetWindowRect( hwnd
, &rc
);
1327 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1328 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1329 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1330 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1331 GetClientRect( hwnd
, &rc
);
1332 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1333 rc
.right
- gripx
, rc
.bottom
- gripy
,
1334 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1335 /* resize the dialog to the previous invocation */
1336 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1337 SetWindowPos( hwnd
, NULL
,
1338 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1339 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1342 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1343 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1348 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1349 case WM_GETMINMAXINFO
:
1350 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1352 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1355 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1358 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1364 case WM_GETISHELLBROWSER
:
1365 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1369 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1370 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1371 MemDialogSize
= fodInfos
->sizedlg
;
1372 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1377 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1380 /* set up the button tooltips strings */
1381 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1383 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1384 switch(lpnmh
->idFrom
)
1386 /* Up folder button */
1387 case FCIDM_TB_UPFOLDER
:
1388 stringId
= IDS_UPFOLDER
;
1390 /* New folder button */
1391 case FCIDM_TB_NEWFOLDER
:
1392 stringId
= IDS_NEWFOLDER
;
1394 /* List option button */
1395 case FCIDM_TB_SMALLICON
:
1396 stringId
= IDS_LISTVIEW
;
1398 /* Details option button */
1399 case FCIDM_TB_REPORTVIEW
:
1400 stringId
= IDS_REPORTVIEW
;
1402 /* Desktop button */
1403 case FCIDM_TB_DESKTOP
:
1404 stringId
= IDS_TODESKTOP
;
1409 lpdi
->hinst
= COMDLG32_hInstance
;
1410 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1415 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1416 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1421 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1423 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1424 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1427 /***********************************************************************
1428 * FILEDLG95_InitControls
1430 * WM_INITDIALOG message handler (before hook notification)
1432 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1434 BOOL win2000plus
= FALSE
;
1435 BOOL win98plus
= FALSE
;
1436 BOOL handledPath
= FALSE
;
1437 OSVERSIONINFOW osVi
;
1438 static const WCHAR szwSlash
[] = { '\\', 0 };
1439 static const WCHAR szwStar
[] = { '*',0 };
1441 static const TBBUTTON tbb
[] =
1443 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1444 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1445 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1446 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1447 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1448 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1449 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1450 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1451 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1453 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1458 HIMAGELIST toolbarImageList
;
1459 SHFILEINFOA shFileInfo
;
1460 ITEMIDLIST
*desktopPidl
;
1462 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1464 TRACE("%p\n", fodInfos
);
1466 /* Get windows version emulating */
1467 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1468 GetVersionExW(&osVi
);
1469 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1470 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1471 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1472 win2000plus
= (osVi
.dwMajorVersion
> 4);
1473 if (win2000plus
) win98plus
= TRUE
;
1475 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1478 /* Use either the edit or the comboboxex for the filename control */
1479 if (filename_is_edit( fodInfos
))
1481 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1482 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1486 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1487 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1490 /* Get the hwnd of the controls */
1491 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1492 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1494 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1495 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1497 /* construct the toolbar */
1498 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1499 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1501 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1502 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1503 rectTB
.left
= rectlook
.right
;
1504 rectTB
.top
= rectlook
.top
-1;
1506 if (fodInfos
->unicode
)
1507 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1508 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1509 rectTB
.left
, rectTB
.top
,
1510 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1511 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1513 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1514 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1515 rectTB
.left
, rectTB
.top
,
1516 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1517 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1519 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1521 /* FIXME: use TB_LOADIMAGES when implemented */
1522 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1523 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1524 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1526 /* Retrieve and add desktop icon to the toolbar */
1527 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1528 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1529 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1530 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1531 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1533 DestroyIcon(shFileInfo
.hIcon
);
1534 CoTaskMemFree(desktopPidl
);
1536 /* Finish Toolbar Construction */
1537 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1538 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1540 /* Set the window text with the text specified in the OPENFILENAME structure */
1543 SetWindowTextW(hwnd
,fodInfos
->title
);
1545 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1548 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1549 SetWindowTextW(hwnd
, buf
);
1552 /* Initialise the file name edit control */
1553 handledPath
= FALSE
;
1554 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1556 if(fodInfos
->filename
)
1558 /* 1. If win2000 or higher and filename contains a path, use it
1559 in preference over the lpstrInitialDir */
1560 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1561 WCHAR tmpBuf
[MAX_PATH
];
1565 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1568 /* nameBit is always shorter than the original filename */
1569 lstrcpyW(fodInfos
->filename
,nameBit
);
1572 MemFree(fodInfos
->initdir
);
1573 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1574 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1576 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1577 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1579 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1582 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1586 /* 2. (All platforms) If initdir is not null, then use it */
1587 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1589 /* Work out the proper path as supplied one might be relative */
1590 /* (Here because supplying '.' as dir browses to My Computer) */
1591 WCHAR tmpBuf
[MAX_PATH
];
1592 WCHAR tmpBuf2
[MAX_PATH
];
1596 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1597 if (PathFileExistsW(tmpBuf
)) {
1598 /* initdir does not have to be a directory. If a file is
1599 * specified, the dir part is taken */
1600 if (PathIsDirectoryW(tmpBuf
)) {
1601 PathAddBackslashW(tmpBuf
);
1602 lstrcatW(tmpBuf
, szwStar
);
1604 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1607 MemFree(fodInfos
->initdir
);
1608 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1609 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1611 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1614 else if (fodInfos
->initdir
)
1616 MemFree(fodInfos
->initdir
);
1617 fodInfos
->initdir
= NULL
;
1618 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1622 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1624 /* 3. All except w2k+: if filename contains a path use it */
1625 if (!win2000plus
&& fodInfos
->filename
&&
1626 *fodInfos
->filename
&&
1627 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1628 WCHAR tmpBuf
[MAX_PATH
];
1632 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1637 /* nameBit is always shorter than the original filename */
1638 lstrcpyW(fodInfos
->filename
, nameBit
);
1641 len
= lstrlenW(tmpBuf
);
1642 MemFree(fodInfos
->initdir
);
1643 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1644 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1647 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1648 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1650 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1653 /* 4. Win2000+: Recently used */
1654 if (!handledPath
&& win2000plus
) {
1655 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1656 fodInfos
->initdir
[0] = '\0';
1658 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1660 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1663 MemFree(fodInfos
->initdir
);
1664 fodInfos
->initdir
= NULL
;
1668 /* 5. win98+ and win2000+ if any files of specified filter types in
1669 current directory, use it */
1670 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1672 LPCWSTR lpstrPos
= fodInfos
->filter
;
1673 WIN32_FIND_DATAW FindFileData
;
1678 /* filter is a list... title\0ext\0......\0\0 */
1680 /* Skip the title */
1681 if(! *lpstrPos
) break; /* end */
1682 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1684 /* See if any files exist in the current dir with this extension */
1685 if(! *lpstrPos
) break; /* end */
1687 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1689 if (hFind
== INVALID_HANDLE_VALUE
) {
1690 /* None found - continue search */
1691 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1695 MemFree(fodInfos
->initdir
);
1696 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1697 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1700 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1701 debugstr_w(lpstrPos
));
1708 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1709 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1710 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1712 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1714 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1717 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1718 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1720 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1723 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1726 } else if (!handledPath
) {
1727 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1728 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1730 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1733 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1734 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1736 /* Must the open as read only check box be checked ?*/
1737 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1739 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1742 /* Must the open as read only check box be hidden? */
1743 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1745 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1746 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1749 /* Must the help button be hidden? */
1750 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1752 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1753 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1756 /* change Open to Save */
1757 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1760 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1761 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1762 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1763 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1766 /* Initialize the filter combo box */
1767 FILEDLG95_FILETYPE_Init(hwnd
);
1772 /***********************************************************************
1773 * FILEDLG95_ResizeControls
1775 * WM_INITDIALOG message handler (after hook notification)
1777 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1779 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1781 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1784 UINT flags
= SWP_NOACTIVATE
;
1786 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1787 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1789 /* resize the custom dialog to the parent size */
1790 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1791 GetClientRect(hwnd
, &rc
);
1794 /* our own fake template is zero sized and doesn't have children, so
1795 * there is no need to resize it. Picasa depends on it.
1797 flags
|= SWP_NOSIZE
;
1800 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1801 0, 0, rc
.right
, rc
.bottom
, flags
);
1805 /* Resize the height; if opened as read-only, checkbox and help button are
1806 * hidden and we are not using a custom template nor a customDialog
1808 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1809 (!(fodInfos
->ofnInfos
->Flags
&
1810 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1812 RECT rectDlg
, rectHelp
, rectCancel
;
1813 GetWindowRect(hwnd
, &rectDlg
);
1814 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1815 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1816 /* subtract the height of the help button plus the space between the help
1817 * button and the cancel button to the height of the dialog
1819 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1820 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1821 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1827 /***********************************************************************
1828 * FILEDLG95_FillControls
1830 * WM_INITDIALOG message handler (after hook notification)
1832 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1834 LPITEMIDLIST pidlItemId
= NULL
;
1836 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1838 TRACE("dir=%s file=%s\n",
1839 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1841 /* Get the initial directory pidl */
1843 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1845 WCHAR path
[MAX_PATH
];
1847 GetCurrentDirectoryW(MAX_PATH
,path
);
1848 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1851 /* Initialise shell objects */
1852 FILEDLG95_SHELL_Init(hwnd
);
1854 /* Initialize the Look In combo box */
1855 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1857 /* Browse to the initial directory */
1858 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1860 /* Free pidlItem memory */
1861 COMDLG32_SHFree(pidlItemId
);
1865 /***********************************************************************
1868 * Regroups all the cleaning functions of the filedlg
1870 void FILEDLG95_Clean(HWND hwnd
)
1872 FILEDLG95_FILETYPE_Clean(hwnd
);
1873 FILEDLG95_LOOKIN_Clean(hwnd
);
1874 FILEDLG95_SHELL_Clean(hwnd
);
1876 /***********************************************************************
1877 * FILEDLG95_OnWMCommand
1879 * WM_COMMAND message handler
1881 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1883 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1884 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1885 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1891 FILEDLG95_OnOpen(hwnd
);
1895 FILEDLG95_Clean(hwnd
);
1896 EndDialog(hwnd
, FALSE
);
1898 /* Filetype combo box */
1900 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1902 /* LookIn combo box */
1904 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1907 /* --- toolbar --- */
1908 /* Up folder button */
1909 case FCIDM_TB_UPFOLDER
:
1910 FILEDLG95_SHELL_UpFolder(hwnd
);
1912 /* New folder button */
1913 case FCIDM_TB_NEWFOLDER
:
1914 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1916 /* List option button */
1917 case FCIDM_TB_SMALLICON
:
1918 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1920 /* Details option button */
1921 case FCIDM_TB_REPORTVIEW
:
1922 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1924 /* Details option button */
1925 case FCIDM_TB_DESKTOP
:
1926 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1934 /* Do not use the listview selection anymore */
1935 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1939 /***********************************************************************
1940 * FILEDLG95_OnWMGetIShellBrowser
1942 * WM_GETISHELLBROWSER message handler
1944 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1946 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1950 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1956 /***********************************************************************
1957 * FILEDLG95_SendFileOK
1959 * Sends the CDN_FILEOK notification if required
1962 * TRUE if the dialog should close
1963 * FALSE if the dialog should not be closed
1965 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1967 /* ask the hook if we can close */
1968 if(IsHooked(fodInfos
))
1973 /* First send CDN_FILEOK as MSDN doc says */
1974 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1975 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1978 TRACE("canceled\n");
1982 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1983 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1984 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1987 TRACE("canceled\n");
1994 /***********************************************************************
1995 * FILEDLG95_OnOpenMultipleFiles
1997 * Handles the opening of multiple files.
2000 * check destination buffer size
2002 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2004 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2005 UINT nCount
, nSizePath
;
2006 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2010 if(fodInfos
->unicode
)
2012 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2013 ofn
->lpstrFile
[0] = '\0';
2017 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2018 ofn
->lpstrFile
[0] = '\0';
2021 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2023 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2024 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2025 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2027 LPWSTR lpstrTemp
= lpstrFileList
;
2029 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2033 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2036 WCHAR lpstrNotFound
[100];
2037 WCHAR lpstrMsg
[100];
2039 static const WCHAR nl
[] = {'\n',0};
2041 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2042 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2044 lstrcpyW(tmp
, lpstrTemp
);
2046 lstrcatW(tmp
, lpstrNotFound
);
2048 lstrcatW(tmp
, lpstrMsg
);
2050 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2054 /* move to the next file in the list of files */
2055 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2056 COMDLG32_SHFree(pidl
);
2060 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2061 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2063 /* For "oldstyle" dialog the components have to
2064 be separated by blanks (not '\0'!) and short
2065 filenames have to be used! */
2066 FIXME("Components have to be separated by blanks\n");
2068 if(fodInfos
->unicode
)
2070 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2071 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2072 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2076 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2078 if (ofn
->lpstrFile
!= NULL
)
2080 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2081 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2082 if (ofn
->nMaxFile
> nSizePath
)
2084 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2085 ofn
->lpstrFile
+ nSizePath
,
2086 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2091 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2092 fodInfos
->ofnInfos
->nFileExtension
= 0;
2094 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2097 /* clean and exit */
2098 FILEDLG95_Clean(hwnd
);
2099 return EndDialog(hwnd
,TRUE
);
2102 /* Returns the 'slot name' of the given module_name in the registry's
2103 * most-recently-used list. This will be an ASCII value in the
2104 * range ['a','z'). Returns zero on error.
2106 * The slot's value in the registry has the form:
2107 * module_name\0mru_path\0
2109 * If stored_path is given, then stored_path will contain the path name
2110 * stored in the registry's MRU list for the given module_name.
2112 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2113 * MRU list key for the given module_name.
2115 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2117 WCHAR mru_list
[32], *cur_mru_slot
;
2118 BOOL taken
[25] = {0};
2119 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2120 HKEY hkey_tmp
, *hkey
;
2129 *stored_path
= '\0';
2131 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2133 WARN("Unable to create MRU key: %d\n", ret
);
2137 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2138 (LPBYTE
)mru_list
, &mru_list_size
);
2139 if(ret
|| key_type
!= REG_SZ
){
2140 if(ret
== ERROR_FILE_NOT_FOUND
)
2143 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2148 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2149 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2150 DWORD value_data_size
= sizeof(value_data
);
2152 *value_name
= *cur_mru_slot
;
2154 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2155 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2156 if(ret
|| key_type
!= REG_BINARY
){
2157 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2161 if(!strcmpiW(module_name
, value_data
)){
2165 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2173 /* the module name isn't in the registry, so find the next open slot */
2174 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2175 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2176 for(i
= 0; i
< 25; ++i
){
2181 /* all slots are taken, so return the last one in MRUList */
2183 return *cur_mru_slot
;
2186 /* save the given filename as most-recently-used path for this module */
2187 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2189 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2193 /* get the current executable's name */
2194 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2195 WARN("GotModuleFileName failed: %d\n", GetLastError());
2198 module_name
= strrchrW(module_path
, '\\');
2200 module_name
= module_path
;
2204 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2209 { /* update the slot's info */
2210 WCHAR
*path_ends
, *final
;
2211 DWORD path_len
, final_len
;
2213 /* use only the path segment of `filename' */
2214 path_ends
= strrchrW(filename
, '\\');
2215 path_len
= path_ends
- filename
;
2217 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2219 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2222 lstrcpyW(final
, module_name
);
2223 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2224 final
[final_len
-1] = '\0';
2226 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2227 final_len
* sizeof(WCHAR
));
2229 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2238 { /* update MRUList value */
2239 WCHAR old_mru_list
[32], new_mru_list
[32];
2240 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2241 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2243 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2244 (LPBYTE
)old_mru_list
, &mru_list_size
);
2245 if(ret
|| key_type
!= REG_SZ
){
2246 if(ret
== ERROR_FILE_NOT_FOUND
){
2247 new_mru_list
[0] = slot
;
2248 new_mru_list
[1] = '\0';
2250 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2255 /* copy old list data over so that the new slot is at the start
2257 *new_mru_slot
++ = slot
;
2258 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2259 if(*old_mru_slot
!= slot
)
2260 *new_mru_slot
++ = *old_mru_slot
;
2262 *new_mru_slot
= '\0';
2265 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2266 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2268 WARN("Error saving MRUList data: %d\n", ret
);
2275 /* load the most-recently-used path for this module */
2276 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2278 WCHAR module_path
[MAX_PATH
], *module_name
;
2280 /* get the current executable's name */
2281 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2282 WARN("GotModuleFileName failed: %d\n", GetLastError());
2285 module_name
= strrchrW(module_path
, '\\');
2287 module_name
= module_path
;
2291 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2292 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2295 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2297 WCHAR strMsgTitle
[MAX_PATH
];
2298 WCHAR strMsgText
[MAX_PATH
];
2300 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2302 strMsgTitle
[0] = '\0';
2303 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2304 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2307 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2308 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2310 int nOpenAction
= defAction
;
2311 LPWSTR lpszTemp
, lpszTemp1
;
2312 LPITEMIDLIST pidl
= NULL
;
2313 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2315 /* check for invalid chars */
2316 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2318 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2322 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2324 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2327 LPSHELLFOLDER lpsfChild
;
2328 WCHAR lpwstrTemp
[MAX_PATH
];
2329 DWORD dwEaten
, dwAttributes
;
2332 lstrcpyW(lpwstrTemp
, lpszTemp
);
2333 p
= PathFindNextComponentW(lpwstrTemp
);
2335 if (!p
) break; /* end of path */
2338 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2340 /* There are no wildcards when OFN_NOVALIDATE is set */
2341 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2343 static const WCHAR wszWild
[] = { '*', '?', 0 };
2344 /* if the last element is a wildcard do a search */
2345 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2347 nOpenAction
= ONOPEN_SEARCH
;
2351 lpszTemp1
= lpszTemp
;
2353 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2355 /* append a backslash to drive letters */
2356 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2357 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2358 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2360 PathAddBackslashW(lpwstrTemp
);
2363 dwAttributes
= SFGAO_FOLDER
;
2364 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2366 /* the path component is valid, we have a pidl of the next path component */
2367 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2368 if(dwAttributes
& SFGAO_FOLDER
)
2370 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2372 ERR("bind to failed\n"); /* should not fail */
2375 IShellFolder_Release(*ppsf
);
2383 /* end dialog, return value */
2384 nOpenAction
= ONOPEN_OPEN
;
2387 COMDLG32_SHFree(pidl
);
2390 else if (!(flags
& OFN_NOVALIDATE
))
2392 if(*lpszTemp
|| /* points to trailing null for last path element */
2393 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2395 if(flags
& OFN_PATHMUSTEXIST
)
2397 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2403 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2405 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2409 /* change to the current folder */
2410 nOpenAction
= ONOPEN_OPEN
;
2415 nOpenAction
= ONOPEN_OPEN
;
2419 if(pidl
) COMDLG32_SHFree(pidl
);
2424 /***********************************************************************
2427 * Ok button WM_COMMAND message handler
2429 * If the function succeeds, the return value is nonzero.
2431 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2433 LPWSTR lpstrFileList
;
2434 UINT nFileCount
= 0;
2437 WCHAR lpstrPathAndFile
[MAX_PATH
];
2438 LPSHELLFOLDER lpsf
= NULL
;
2440 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2442 TRACE("hwnd=%p\n", hwnd
);
2444 /* try to browse the selected item */
2445 if(BrowseSelectedFolder(hwnd
))
2448 /* get the files from the edit control */
2449 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2456 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2460 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2463 Step 1: Build a complete path name from the current folder and
2464 the filename or path in the edit box.
2466 - the path in the edit box is a root path
2467 (with or without drive letter)
2468 - the edit box contains ".." (or a path with ".." in it)
2471 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2472 MemFree(lpstrFileList
);
2475 Step 2: here we have a cleaned up path
2477 We have to parse the path step by step to see if we have to browse
2478 to a folder if the path points to a directory or the last
2479 valid element is a directory.
2482 lpstrPathAndFile: cleaned up path
2486 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2487 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2488 nOpenAction
= ONOPEN_OPEN
;
2490 nOpenAction
= ONOPEN_BROWSE
;
2492 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2493 fodInfos
->ofnInfos
->Flags
,
2494 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2500 Step 3: here we have a cleaned up and validated path
2503 lpsf: ShellFolder bound to the rightmost valid path component
2504 lpstrPathAndFile: cleaned up path
2505 nOpenAction: action to do
2507 TRACE("end validate sf=%p\n", lpsf
);
2511 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2512 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2515 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2518 /* replace the current filter */
2519 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2520 len
= lstrlenW(lpszTemp
)+1;
2521 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2522 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2524 /* set the filter cb to the extension when possible */
2525 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2526 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2529 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2530 TRACE("ONOPEN_BROWSE\n");
2532 IPersistFolder2
* ppf2
;
2533 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2535 LPITEMIDLIST pidlCurrent
;
2536 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2537 IPersistFolder2_Release(ppf2
);
2538 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2540 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2541 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2543 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2546 else if( nOpenAction
== ONOPEN_SEARCH
)
2548 if (fodInfos
->Shell
.FOIShellView
)
2549 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2551 COMDLG32_SHFree(pidlCurrent
);
2552 if (filename_is_edit( fodInfos
))
2553 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2558 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2559 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2563 /* update READONLY check box flag */
2564 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2565 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2567 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2569 /* Attach the file extension with file name*/
2570 ext
= PathFindExtensionW(lpstrPathAndFile
);
2571 if (! *ext
&& fodInfos
->defext
)
2573 /* if no extension is specified with file name, then */
2574 /* attach the extension from file filter or default one */
2576 WCHAR
*filterExt
= NULL
;
2577 LPWSTR lpstrFilter
= NULL
;
2578 static const WCHAR szwDot
[] = {'.',0};
2579 int PathLength
= lstrlenW(lpstrPathAndFile
);
2581 /*Get the file extension from file type filter*/
2582 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2583 fodInfos
->ofnInfos
->nFilterIndex
-1);
2585 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2587 WCHAR
* filterSearchIndex
;
2588 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2589 strcpyW(filterExt
, lpstrFilter
);
2591 /* if a semicolon-separated list of file extensions was given, do not include the
2592 semicolon or anything after it in the extension.
2593 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2594 filterSearchIndex
= strchrW(filterExt
, ';');
2595 if (filterSearchIndex
)
2597 filterSearchIndex
[0] = '\0';
2600 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2601 /* if the extension is invalid or contains a glob, ignore it */
2602 filterSearchIndex
= PathFindExtensionW(filterExt
);
2603 if (*filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2605 strcpyW(filterExt
, filterSearchIndex
);
2609 HeapFree(GetProcessHeap(), 0, filterExt
);
2616 /* use the default file extension */
2617 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2618 strcpyW(filterExt
, fodInfos
->defext
);
2621 if (*filterExt
) /* ignore filterExt="" */
2624 lstrcatW(lpstrPathAndFile
, szwDot
);
2625 /* Attach the extension */
2626 lstrcatW(lpstrPathAndFile
, filterExt
);
2629 HeapFree(GetProcessHeap(), 0, filterExt
);
2631 /* In Open dialog: if file does not exist try without extension */
2632 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2633 lpstrPathAndFile
[PathLength
] = '\0';
2635 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2638 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2639 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2641 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2644 /* In Save dialog: check if the file already exists */
2645 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2646 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2647 && PathFileExistsW(lpstrPathAndFile
))
2649 WCHAR lpstrOverwrite
[100];
2652 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2653 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2654 MB_YESNO
| MB_ICONEXCLAMATION
);
2655 if (answer
== IDNO
|| answer
== IDCANCEL
)
2662 /* In Open dialog: check if it should be created if it doesn't exist */
2663 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2664 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2665 && !PathFileExistsW(lpstrPathAndFile
))
2667 WCHAR lpstrCreate
[100];
2670 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2671 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2672 MB_YESNO
| MB_ICONEXCLAMATION
);
2673 if (answer
== IDNO
|| answer
== IDCANCEL
)
2680 /* Check that the size of the file does not exceed buffer size.
2681 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2682 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2683 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2686 /* fill destination buffer */
2687 if (fodInfos
->ofnInfos
->lpstrFile
)
2689 if(fodInfos
->unicode
)
2691 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2693 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2694 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2695 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2699 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2701 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2702 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2703 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2704 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2708 if(fodInfos
->unicode
)
2712 /* set filename offset */
2713 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2714 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2716 /* set extension offset */
2717 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2718 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2723 CHAR tempFileA
[MAX_PATH
];
2725 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2726 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2727 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2729 /* set filename offset */
2730 lpszTemp
= PathFindFileNameA(tempFileA
);
2731 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2733 /* set extension offset */
2734 lpszTemp
= PathFindExtensionA(tempFileA
);
2735 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2738 /* set the lpstrFileTitle */
2739 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2741 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2742 if(fodInfos
->unicode
)
2744 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2745 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2749 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2750 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2751 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2755 /* copy currently selected filter to lpstrCustomFilter */
2756 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2758 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2759 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2760 NULL
, 0, NULL
, NULL
);
2761 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2763 LPSTR s
= ofn
->lpstrCustomFilter
;
2764 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2765 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2766 s
, len
, NULL
, NULL
);
2771 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2774 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2777 FILEDLG95_Clean(hwnd
);
2778 ret
= EndDialog(hwnd
, TRUE
);
2784 size
= lstrlenW(lpstrPathAndFile
) + 1;
2785 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2787 /* return needed size in first two bytes of lpstrFile */
2788 if(fodInfos
->ofnInfos
->lpstrFile
)
2789 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2790 FILEDLG95_Clean(hwnd
);
2791 ret
= EndDialog(hwnd
, FALSE
);
2792 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2799 if(lpsf
) IShellFolder_Release(lpsf
);
2803 /***********************************************************************
2804 * FILEDLG95_SHELL_Init
2806 * Initialisation of the shell objects
2808 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2810 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2815 * Initialisation of the FileOpenDialogInfos structure
2821 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2823 /* Disable multi-select if flag not set */
2824 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2826 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2828 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2829 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2831 /* Construct the IShellBrowser interface */
2832 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2837 /***********************************************************************
2838 * FILEDLG95_SHELL_ExecuteCommand
2840 * Change the folder option and refresh the view
2841 * If the function succeeds, the return value is nonzero.
2843 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2845 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2848 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2850 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2855 CMINVOKECOMMANDINFO ci
;
2856 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2857 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2861 IContextMenu_InvokeCommand(pcm
, &ci
);
2862 IContextMenu_Release(pcm
);
2868 /***********************************************************************
2869 * FILEDLG95_SHELL_UpFolder
2871 * Browse to the specified object
2872 * If the function succeeds, the return value is nonzero.
2874 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2876 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2880 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2884 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2885 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2891 /***********************************************************************
2892 * FILEDLG95_SHELL_BrowseToDesktop
2894 * Browse to the Desktop
2895 * If the function succeeds, the return value is nonzero.
2897 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2899 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2905 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2906 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2907 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2908 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2909 COMDLG32_SHFree(pidl
);
2910 return SUCCEEDED(hres
);
2912 /***********************************************************************
2913 * FILEDLG95_SHELL_Clean
2915 * Cleans the memory used by shell objects
2917 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2919 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2923 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2925 /* clean Shell interfaces */
2926 if (fodInfos
->Shell
.FOIShellView
)
2928 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2929 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2931 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2932 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2933 if (fodInfos
->Shell
.FOIDataObject
)
2934 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2937 /***********************************************************************
2938 * FILEDLG95_FILETYPE_Init
2940 * Initialisation of the file type combo box
2942 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2944 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2945 int nFilters
= 0; /* number of filters */
2950 if(fodInfos
->customfilter
)
2952 /* customfilter has one entry... title\0ext\0
2953 * Set first entry of combo box item with customfilter
2956 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2959 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2961 /* Copy the extensions */
2962 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2963 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2964 lstrcpyW(lpstrExt
,lpstrPos
);
2966 /* Add the item at the end of the combo */
2967 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2968 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2971 if(fodInfos
->filter
)
2973 LPCWSTR lpstrPos
= fodInfos
->filter
;
2977 /* filter is a list... title\0ext\0......\0\0
2978 * Set the combo item text to the title and the item data
2981 LPCWSTR lpstrDisplay
;
2985 if(! *lpstrPos
) break; /* end */
2986 lpstrDisplay
= lpstrPos
;
2987 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2989 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2993 /* Copy the extensions */
2994 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2995 lstrcpyW(lpstrExt
,lpstrPos
);
2996 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2998 /* Add the item at the end of the combo */
2999 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
3001 /* malformed filters are added anyway... */
3002 if (!*lpstrExt
) break;
3007 * Set the current filter to the one specified
3008 * in the initialisation structure
3010 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3014 /* Check to make sure our index isn't out of bounds. */
3015 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3016 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3017 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3019 /* set default filter index */
3020 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3021 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3023 /* calculate index of Combo Box item */
3024 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3025 if (fodInfos
->customfilter
== NULL
)
3028 /* Set the current index selection. */
3029 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3031 /* Get the corresponding text string from the combo box. */
3032 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3035 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3041 CharLowerW(lpstrFilter
); /* lowercase */
3042 len
= lstrlenW(lpstrFilter
)+1;
3043 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3044 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3047 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3051 /***********************************************************************
3052 * FILEDLG95_FILETYPE_OnCommand
3054 * WM_COMMAND of the file type combo box
3055 * If the function succeeds, the return value is nonzero.
3057 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3059 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3067 /* Get the current item of the filetype combo box */
3068 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3070 /* set the current filter index */
3071 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3072 (fodInfos
->customfilter
== NULL
? 1 : 0);
3074 /* Set the current filter with the current selection */
3075 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3077 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3079 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3082 CharLowerW(lpstrFilter
); /* lowercase */
3083 len
= lstrlenW(lpstrFilter
)+1;
3084 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3085 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3086 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3087 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3090 /* Refresh the actual view to display the included items*/
3091 if (fodInfos
->Shell
.FOIShellView
)
3092 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3097 /***********************************************************************
3098 * FILEDLG95_FILETYPE_SearchExt
3100 * searches for an extension in the filetype box
3102 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3104 int i
, iCount
= CBGetCount(hwnd
);
3106 TRACE("%s\n", debugstr_w(lpstrExt
));
3108 if(iCount
!= CB_ERR
)
3110 for(i
=0;i
<iCount
;i
++)
3112 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3119 /***********************************************************************
3120 * FILEDLG95_FILETYPE_Clean
3122 * Clean the memory used by the filetype combo box
3124 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3126 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3128 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3132 /* Delete each string of the combo and their associated data */
3133 if(iCount
!= CB_ERR
)
3135 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3137 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3138 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3141 /* Current filter */
3142 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3146 /***********************************************************************
3147 * FILEDLG95_LOOKIN_Init
3149 * Initialisation of the look in combo box
3152 /* Small helper function, to determine if the unixfs shell extension is rooted
3153 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3155 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3157 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3158 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3160 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3161 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3162 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3163 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3165 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3172 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3174 IShellFolder
*psfRoot
, *psfDrives
;
3175 IEnumIDList
*lpeRoot
, *lpeDrives
;
3176 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3179 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3183 liInfos
->iMaxIndentation
= 0;
3185 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3187 hdc
= GetDC( hwndCombo
);
3188 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3189 GetTextMetricsW( hdc
, &tm
);
3190 ReleaseDC( hwndCombo
, hdc
);
3192 /* set item height for both text field and listbox */
3193 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3194 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3196 /* Turn on the extended UI for the combo box like Windows does */
3197 CBSetExtendedUI(hwndCombo
, TRUE
);
3199 /* Initialise data of Desktop folder */
3200 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3201 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3202 COMDLG32_SHFree(pidlTmp
);
3204 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3206 SHGetDesktopFolder(&psfRoot
);
3210 /* enumerate the contents of the desktop */
3211 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3213 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3215 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3217 /* If the unixfs extension is rooted, we don't expand the drives by default */
3218 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3220 /* special handling for CSIDL_DRIVES */
3221 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3223 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3225 /* enumerate the drives */
3226 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3228 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3230 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3231 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3232 COMDLG32_SHFree(pidlAbsTmp
);
3233 COMDLG32_SHFree(pidlTmp1
);
3235 IEnumIDList_Release(lpeDrives
);
3237 IShellFolder_Release(psfDrives
);
3242 COMDLG32_SHFree(pidlTmp
);
3244 IEnumIDList_Release(lpeRoot
);
3246 IShellFolder_Release(psfRoot
);
3249 COMDLG32_SHFree(pidlDrives
);
3252 /***********************************************************************
3253 * FILEDLG95_LOOKIN_DrawItem
3255 * WM_DRAWITEM message handler
3257 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3259 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3260 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3261 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3265 HIMAGELIST ilItemImage
;
3268 LPSFOLDER tmpFolder
;
3269 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3270 UINT icon_width
, icon_height
;
3274 if(pDIStruct
->itemID
== -1)
3277 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3278 pDIStruct
->itemID
)))
3282 icon_width
= GetSystemMetrics(SM_CXICON
);
3283 icon_height
= GetSystemMetrics(SM_CYICON
);
3284 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3286 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3287 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3288 shgfi_flags
|= SHGFI_SMALLICON
;
3291 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3292 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3294 /* Is this item selected ? */
3295 if(pDIStruct
->itemState
& ODS_SELECTED
)
3297 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3298 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3299 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3303 SetTextColor(pDIStruct
->hDC
,crText
);
3304 SetBkColor(pDIStruct
->hDC
,crWin
);
3305 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3308 /* Do not indent item if drawing in the edit of the combo */
3309 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3312 iIndentation
= tmpFolder
->m_iIndent
;
3314 /* Draw text and icon */
3316 /* Initialise the icon display area */
3317 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3318 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3319 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3320 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3322 /* Initialise the text display area */
3323 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3324 rectText
.left
= rectIcon
.right
;
3326 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3327 rectText
.right
= pDIStruct
->rcItem
.right
;
3329 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3331 /* Draw the icon from the image list */
3332 ImageList_Draw(ilItemImage
,
3339 /* Draw the associated text */
3340 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3344 /***********************************************************************
3345 * FILEDLG95_LOOKIN_OnCommand
3347 * LookIn combo box WM_COMMAND message handler
3348 * If the function succeeds, the return value is nonzero.
3350 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3352 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3354 TRACE("%p\n", fodInfos
);
3360 LPSFOLDER tmpFolder
;
3363 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3365 if( iItem
== CB_ERR
) return FALSE
;
3367 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3372 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3373 tmpFolder
->pidlItem
,
3376 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3377 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3387 /***********************************************************************
3388 * FILEDLG95_LOOKIN_AddItem
3390 * Adds an absolute pidl item to the lookin combo box
3391 * returns the index of the inserted item
3393 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3395 LPITEMIDLIST pidlNext
;
3398 LookInInfos
*liInfos
;
3400 TRACE("%08x\n", iInsertId
);
3405 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3408 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3409 tmpFolder
->m_iIndent
= 0;
3411 /* Calculate the indentation of the item in the lookin*/
3413 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3415 tmpFolder
->m_iIndent
++;
3418 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3420 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3421 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3423 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3424 SHGetFileInfoW((LPCWSTR
)pidl
,
3428 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3429 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3431 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3433 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3437 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3439 /* Add the item at the end of the list */
3442 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3444 /* Insert the item at the iInsertId position*/
3447 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3450 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3454 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3455 MemFree( tmpFolder
);
3460 /***********************************************************************
3461 * FILEDLG95_LOOKIN_InsertItemAfterParent
3463 * Insert an item below its parent
3465 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3468 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3473 if (pidl
== pidlParent
)
3476 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3480 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3483 /* Free pidlParent memory */
3484 COMDLG32_SHFree(pidlParent
);
3486 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3489 /***********************************************************************
3490 * FILEDLG95_LOOKIN_SelectItem
3492 * Adds an absolute pidl item to the lookin combo box
3493 * returns the index of the inserted item
3495 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3498 LookInInfos
*liInfos
;
3502 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3504 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3508 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3509 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3514 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3515 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3519 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3521 if(iRemovedItem
< iItemPos
)
3526 CBSetCurSel(hwnd
,iItemPos
);
3527 liInfos
->uSelectedItem
= iItemPos
;
3533 /***********************************************************************
3534 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3536 * Remove the item with an expansion level over iExpansionLevel
3538 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3541 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3545 if(liInfos
->iMaxIndentation
<= 2)
3548 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3550 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3551 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3553 CBDeleteString(hwnd
,iItemPos
);
3554 liInfos
->iMaxIndentation
--;
3562 /***********************************************************************
3563 * FILEDLG95_LOOKIN_SearchItem
3565 * Search for pidl in the lookin combo box
3566 * returns the index of the found item
3568 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3571 int iCount
= CBGetCount(hwnd
);
3573 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3575 if (iCount
!= CB_ERR
)
3579 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3581 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3583 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3591 /***********************************************************************
3592 * FILEDLG95_LOOKIN_Clean
3594 * Clean the memory used by the lookin combo box
3596 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3598 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3599 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3601 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3605 /* Delete each string of the combo and their associated data */
3606 if (iCount
!= CB_ERR
)
3608 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3610 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3611 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3613 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3617 /* LookInInfos structure */
3619 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3622 /***********************************************************************
3623 * FILEDLG95_FILENAME_FillFromSelection
3625 * fills the edit box from the cached DataObject
3627 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3629 FileOpenDlgInfos
*fodInfos
;
3631 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3632 WCHAR lpstrTemp
[MAX_PATH
];
3633 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3636 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3638 /* Count how many files we have */
3639 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3641 /* calculate the string length, count files */
3642 if (nFileSelected
>= 1)
3644 nLength
+= 3; /* first and last quotes, trailing \0 */
3645 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3647 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3651 /* get the total length of the selected file names */
3652 lpstrTemp
[0] = '\0';
3653 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3655 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3657 nLength
+= lstrlenW( lpstrTemp
) + 3;
3660 COMDLG32_SHFree( pidl
);
3665 /* allocate the buffer */
3666 if (nFiles
<= 1) nLength
= MAX_PATH
;
3667 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3669 /* Generate the string for the edit control */
3672 lpstrCurrFile
= lpstrAllFile
;
3673 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3675 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3679 /* get the file name */
3680 lpstrTemp
[0] = '\0';
3681 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3683 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3687 *lpstrCurrFile
++ = '\"';
3688 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3689 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3690 *lpstrCurrFile
++ = '\"';
3691 *lpstrCurrFile
++ = ' ';
3696 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3699 COMDLG32_SHFree( pidl
);
3702 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3704 /* Select the file name like Windows does */
3705 if (filename_is_edit( fodInfos
))
3706 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3708 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3712 /* copied from shell32 to avoid linking to it
3713 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3714 * is dependent on whether emulated OS is unicode or not.
3716 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3721 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3722 COMDLG32_SHFree(src
->u
.pOleStr
);
3726 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3731 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3736 FIXME("unknown type %x!\n", src
->uType
);
3737 if (len
) *dest
= '\0';
3743 /***********************************************************************
3744 * FILEDLG95_FILENAME_GetFileNames
3746 * Copies the filenames to a delimited string list.
3748 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3750 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3751 UINT nFileCount
= 0; /* number of files */
3752 UINT nStrLen
= 0; /* length of string in edit control */
3753 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3757 /* get the filenames from the filename control */
3758 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3759 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3760 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3762 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3764 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3769 #define SETDefFormatEtc(fe,cf,med) \
3771 (fe).cfFormat = cf;\
3772 (fe).dwAspect = DVASPECT_CONTENT; \
3779 * DATAOBJECT Helper functions
3782 /***********************************************************************
3783 * COMCTL32_ReleaseStgMedium
3785 * like ReleaseStgMedium from ole32
3787 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3789 if(medium
.pUnkForRelease
)
3791 IUnknown_Release(medium
.pUnkForRelease
);
3795 GlobalUnlock(medium
.u
.hGlobal
);
3796 GlobalFree(medium
.u
.hGlobal
);
3800 /***********************************************************************
3801 * GetPidlFromDataObject
3803 * Return pidl(s) by number from the cached DataObject
3805 * nPidlIndex=0 gets the fully qualified root path
3807 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3811 FORMATETC formatetc
;
3812 LPITEMIDLIST pidl
= NULL
;
3814 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3819 /* Set the FORMATETC structure*/
3820 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3822 /* Get the pidls from IDataObject */
3823 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3825 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3826 if(nPidlIndex
<= cida
->cidl
)
3828 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3830 COMCTL32_ReleaseStgMedium(medium
);
3835 /***********************************************************************
3838 * Return the number of selected items in the DataObject.
3841 static UINT
GetNumSelected( IDataObject
*doSelected
)
3845 FORMATETC formatetc
;
3847 TRACE("sv=%p\n", doSelected
);
3849 if (!doSelected
) return 0;
3851 /* Set the FORMATETC structure*/
3852 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3854 /* Get the pidls from IDataObject */
3855 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3857 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3858 retVal
= cida
->cidl
;
3859 COMCTL32_ReleaseStgMedium(medium
);
3869 /***********************************************************************
3872 * Get the pidl's display name (relative to folder) and
3873 * put it in lpstrFileName.
3875 * Return NOERROR on success,
3879 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3884 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3888 SHGetDesktopFolder(&lpsf
);
3889 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3890 IShellFolder_Release(lpsf
);
3894 /* Get the display name of the pidl relative to the folder */
3895 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3897 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3902 /***********************************************************************
3903 * GetShellFolderFromPidl
3905 * pidlRel is the item pidl relative
3906 * Return the IShellFolder of the absolute pidl
3908 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3910 IShellFolder
*psf
= NULL
,*psfParent
;
3912 TRACE("%p\n", pidlAbs
);
3914 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3917 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3919 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3921 IShellFolder_Release(psfParent
);
3925 /* return the desktop */
3931 /***********************************************************************
3934 * Return the LPITEMIDLIST to the parent of the pidl in the list
3936 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3938 LPITEMIDLIST pidlParent
;
3940 TRACE("%p\n", pidl
);
3942 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3943 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3948 /***********************************************************************
3951 * returns the pidl of the file name relative to folder
3952 * NULL if an error occurred
3954 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3956 LPITEMIDLIST pidl
= NULL
;
3959 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3961 if(!lpcstrFileName
) return NULL
;
3962 if(!*lpcstrFileName
) return NULL
;
3966 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3967 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3968 IShellFolder_Release(lpsf
);
3973 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3980 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3982 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3985 TRACE("%p, %p\n", psf
, pidl
);
3987 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3989 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3990 /* see documentation shell 4.1*/
3991 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3994 /***********************************************************************
3995 * BrowseSelectedFolder
3997 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3999 BOOL bBrowseSelFolder
= FALSE
;
4000 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
4004 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4006 LPITEMIDLIST pidlSelection
;
4008 /* get the file selected */
4009 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4010 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4012 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4013 pidlSelection
, SBSP_RELATIVE
) ) )
4015 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
4016 ' ','n','o','t',' ','e','x','i','s','t',0};
4017 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4019 bBrowseSelFolder
= TRUE
;
4020 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4021 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4023 COMDLG32_SHFree( pidlSelection
);
4026 return bBrowseSelFolder
;
4030 * Memory allocation methods */
4031 static void *MemAlloc(UINT size
)
4033 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4036 static void MemFree(void *mem
)
4038 HeapFree(GetProcessHeap(),0,mem
);
4041 static inline BOOL
valid_struct_size( DWORD size
)
4043 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4044 (size
== sizeof( OPENFILENAMEW
));
4047 static inline BOOL
is_win16_looks(DWORD flags
)
4049 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4050 !(flags
& OFN_EXPLORER
));
4053 /* ------------------ APIs ---------------------- */
4055 /***********************************************************************
4056 * GetOpenFileNameA (COMDLG32.@)
4058 * Creates a dialog box for the user to select a file to open.
4061 * TRUE on success: user enters a valid file
4062 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4065 BOOL WINAPI
GetOpenFileNameA(
4066 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4068 TRACE("flags %08x\n", ofn
->Flags
);
4070 if (!valid_struct_size( ofn
->lStructSize
))
4072 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4076 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4077 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4078 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4080 if (is_win16_looks(ofn
->Flags
))
4081 return GetFileName31A(ofn
, OPEN_DIALOG
);
4083 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4086 /***********************************************************************
4087 * GetOpenFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to open.
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI
GetOpenFileNameW(
4097 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4099 TRACE("flags %08x\n", ofn
->Flags
);
4101 if (!valid_struct_size( ofn
->lStructSize
))
4103 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4107 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4108 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4109 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4111 if (is_win16_looks(ofn
->Flags
))
4112 return GetFileName31W(ofn
, OPEN_DIALOG
);
4114 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4118 /***********************************************************************
4119 * GetSaveFileNameA (COMDLG32.@)
4121 * Creates a dialog box for the user to select a file to save.
4124 * TRUE on success: user enters a valid file
4125 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4128 BOOL WINAPI
GetSaveFileNameA(
4129 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4131 if (!valid_struct_size( ofn
->lStructSize
))
4133 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4137 if (is_win16_looks(ofn
->Flags
))
4138 return GetFileName31A(ofn
, SAVE_DIALOG
);
4140 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4143 /***********************************************************************
4144 * GetSaveFileNameW (COMDLG32.@)
4146 * Creates a dialog box for the user to select a file to save.
4149 * TRUE on success: user enters a valid file
4150 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4153 BOOL WINAPI
GetSaveFileNameW(
4154 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4156 if (!valid_struct_size( ofn
->lStructSize
))
4158 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4162 if (is_win16_looks(ofn
->Flags
))
4163 return GetFileName31W(ofn
, SAVE_DIALOG
);
4165 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4168 /***********************************************************************
4169 * GetFileTitleA (COMDLG32.@)
4171 * See GetFileTitleW.
4173 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4176 UNICODE_STRING strWFile
;
4179 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4180 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4181 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4182 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4183 RtlFreeUnicodeString( &strWFile
);
4184 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4189 /***********************************************************************
4190 * GetFileTitleW (COMDLG32.@)
4192 * Get the name of a file.
4195 * lpFile [I] name and location of file
4196 * lpTitle [O] returned file name
4197 * cbBuf [I] buffer size of lpTitle
4201 * Failure: negative number.
4203 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4206 static const WCHAR brkpoint
[] = {'*','[',']',0};
4207 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4209 if(lpFile
== NULL
|| lpTitle
== NULL
)
4212 len
= lstrlenW(lpFile
);
4217 if(strpbrkW(lpFile
, brkpoint
))
4222 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4225 for(i
= len
; i
>= 0; i
--)
4227 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4237 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4239 len
= lstrlenW(lpFile
+i
)+1;
4243 lstrcpyW(lpTitle
, &lpFile
[i
]);