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
66 /* RegGetValueW is supported by Win2k3 SP1 but headers need Win Vista */
68 #define _WIN32_WINNT 0x0600
78 #include "filedlgbrowser.h"
81 #include "wine/unicode.h"
82 #include "wine/debug.h"
83 #include "wine/heap.h"
85 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
87 #define UNIMPLEMENTED_FLAGS \
88 (OFN_DONTADDTORECENT |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex
; /* Index of picture in image list */
99 int m_iIndent
; /* Indentation index */
100 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
102 } SFOLDER
,*LPSFOLDER
;
104 typedef struct tagLookInInfo
111 /***********************************************************************
112 * Defines and global variables
115 /* Draw item constant */
116 #define XTEXTOFFSET 3
121 /* SearchItem methods */
122 #define SEARCH_PIDL 1
124 #define ITEM_NOTFOUND -1
126 /* Undefined windows message sent by CreateViewObject*/
127 #define WM_GETISHELLBROWSER WM_USER+7
129 #define TBPLACES_CMDID_PLACE0 0xa064
130 #define TBPLACES_CMDID_PLACE1 0xa065
131 #define TBPLACES_CMDID_PLACE2 0xa066
132 #define TBPLACES_CMDID_PLACE3 0xa067
133 #define TBPLACES_CMDID_PLACE4 0xa068
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBGetItemDataPtr(hwnd,iItemId) \
142 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
144 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
145 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
147 static const WCHAR LastVisitedMRUW
[] =
148 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
150 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
151 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
152 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
154 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
156 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
158 return GetPropW(hwnd
, filedlg_info_propnameW
);
161 static BOOL
is_dialog_hooked(const FileOpenDlgInfos
*info
)
163 return (info
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && info
->ofnInfos
->lpfnHook
;
166 static BOOL
filedialog_is_readonly_hidden(const FileOpenDlgInfos
*info
)
168 return (info
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) || (info
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
);
171 /***********************************************************************
175 /* Internal functions used by the dialog */
176 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
177 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
178 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
179 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
180 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
181 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
182 static void FILEDLG95_Clean(HWND hwnd
);
184 /* Functions used by the shell navigation */
185 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
186 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
187 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
188 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
190 /* Functions used by the EDIT box */
191 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
193 /* Functions used by the filetype combo box */
194 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
195 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
196 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
197 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
199 /* Functions used by the Look In combo box */
200 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
201 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
202 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
203 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
204 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
205 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
206 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
207 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
208 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
210 /* Functions for dealing with the most-recently-used registry keys */
211 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
212 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
213 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
215 static void FILEDLG95_MRU_load_ext(LPWSTR stored_path
, size_t cchMax
, LPCWSTR defext
);
216 static void FILEDLG95_MRU_save_ext(LPCWSTR filename
);
219 /* Miscellaneous tool functions */
220 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
221 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
222 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
223 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
224 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
225 static UINT
GetNumSelected( IDataObject
*doSelected
);
226 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
228 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
229 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
231 static BOOL
BrowseSelectedFolder(HWND hwnd
);
233 static BOOL
get_config_key_as_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
235 DWORD type
, data
, size
;
238 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
))
247 static BOOL
get_config_key_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
249 DWORD type
, data
, size
;
252 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
261 static BOOL
get_config_key_string(HKEY hkey
, const WCHAR
*name
, WCHAR
**value
)
266 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, NULL
, &size
))
268 if (type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
)
272 str
= heap_alloc(size
);
273 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)str
, &size
))
283 static BOOL
is_places_bar_enabled(const FileOpenDlgInfos
*fodInfos
)
285 static const WCHAR noplacesbarW
[] = {'N','o','P','l','a','c','e','s','B','a','r',0};
289 if (fodInfos
->ofnInfos
->lStructSize
!= sizeof(*fodInfos
->ofnInfos
) ||
290 (fodInfos
->ofnInfos
->FlagsEx
& OFN_EX_NOPLACESBAR
) ||
291 !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
))
296 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey
))
300 get_config_key_as_dword(hkey
, noplacesbarW
, &value
);
305 static void filedlg_collect_places_pidls(FileOpenDlgInfos
*fodInfos
)
307 static const int default_places
[] =
316 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
319 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
321 static const WCHAR placeW
[] = {'P','l','a','c','e','%','d',0};
327 sprintfW(nameW
, placeW
, i
);
328 if (get_config_key_dword(hkey
, nameW
, &value
))
330 hr
= SHGetSpecialFolderLocation(NULL
, value
, &fodInfos
->places
[i
]);
332 WARN("Unrecognized special folder %u.\n", value
);
334 else if (get_config_key_string(hkey
, nameW
, &str
))
336 hr
= SHParseDisplayName(str
, NULL
, &fodInfos
->places
[i
], 0, NULL
);
338 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str
));
343 /* FIXME: eliminate duplicates. */
349 for (i
= 0; i
< ARRAY_SIZE(default_places
); i
++)
350 SHGetSpecialFolderLocation(NULL
, default_places
[i
], &fodInfos
->places
[i
]);
353 /***********************************************************************
356 * Creates an Open common dialog box that lets the user select
357 * the drive, directory, and the name of a file or set of files to open.
359 * IN : The FileOpenDlgInfos structure associated with the dialog
360 * OUT : TRUE on success
361 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
363 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
371 /* test for missing functionality */
372 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
374 FIXME("Flags 0x%08x not yet implemented\n",
375 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
378 /* Create the dialog from a template */
380 if (is_places_bar_enabled(fodInfos
))
381 templateid
= NEWFILEOPENV2ORD
;
383 templateid
= NEWFILEOPENORD
;
385 if (!(hRes
= FindResourceW(COMDLG32_hInstance
, MAKEINTRESOURCEW(templateid
), (LPCWSTR
)RT_DIALOG
)))
387 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
390 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
391 !(template = LockResource( hDlgTmpl
)))
393 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
397 /* msdn: explorer style dialogs permit sizing by default.
398 * The OFN_ENABLESIZING flag is only needed when a hook or
399 * custom template is provided */
400 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
401 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
402 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
404 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
406 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
407 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
410 /* old style hook messages */
411 if (is_dialog_hooked(fodInfos
))
413 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
414 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
415 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
416 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
419 if (fodInfos
->unicode
)
420 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
422 fodInfos
->ofnInfos
->hwndOwner
,
426 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
428 fodInfos
->ofnInfos
->hwndOwner
,
431 if (fodInfos
->ole_initialized
)
434 /* Unable to create the dialog */
441 static WCHAR
*heap_strdupAtoW(const char *str
)
449 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
450 ret
= heap_alloc(len
* sizeof(WCHAR
));
451 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
456 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
458 INITCOMMONCONTROLSEX icc
;
460 /* Initialize ComboBoxEx32 */
461 icc
.dwSize
= sizeof(icc
);
462 icc
.dwICC
= ICC_USEREX_CLASSES
;
463 InitCommonControlsEx(&icc
);
465 /* Initialize CommDlgExtendedError() */
466 COMDLG32_SetCommDlgExtendedError(0);
468 memset(info
, 0, sizeof(*info
));
470 /* Pass in the original ofn */
471 info
->ofnInfos
= ofn
;
473 info
->title
= ofn
->lpstrTitle
;
474 info
->defext
= ofn
->lpstrDefExt
;
475 info
->filter
= ofn
->lpstrFilter
;
476 info
->customfilter
= ofn
->lpstrCustomFilter
;
480 info
->filename
= heap_alloc(ofn
->nMaxFile
* sizeof(WCHAR
));
481 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
484 if (ofn
->lpstrInitialDir
)
486 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
489 info
->initdir
= heap_alloc(len
* sizeof(WCHAR
));
490 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
494 info
->unicode
= TRUE
;
497 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
502 ofnW
= *(OPENFILENAMEW
*)ofn
;
504 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
505 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
506 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
510 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
511 ofnW
.lpstrFile
= heap_alloc(len
* sizeof(WCHAR
));
512 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
516 if (ofn
->lpstrFilter
)
521 /* filter is a list... title\0ext\0......\0\0 */
522 s
= ofn
->lpstrFilter
;
523 while (*s
) s
= s
+strlen(s
)+1;
525 n
= s
- ofn
->lpstrFilter
;
526 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
527 ofnW
.lpstrFilter
= heap_alloc(len
* sizeof(WCHAR
));
528 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
531 /* convert lpstrCustomFilter */
532 if (ofn
->lpstrCustomFilter
)
537 /* customfilter contains a pair of strings... title\0ext\0 */
538 s
= ofn
->lpstrCustomFilter
;
539 if (*s
) s
= s
+strlen(s
)+1;
540 if (*s
) s
= s
+strlen(s
)+1;
541 n
= s
- ofn
->lpstrCustomFilter
;
542 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
543 ofnW
.lpstrCustomFilter
= heap_alloc(len
* sizeof(WCHAR
));
544 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
547 init_filedlg_infoW(&ofnW
, info
);
549 /* fixup A-specific fields */
550 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
551 info
->unicode
= FALSE
;
553 /* free what was duplicated */
554 heap_free((void *)ofnW
.lpstrInitialDir
);
555 heap_free(ofnW
.lpstrFile
);
558 /***********************************************************************
561 * Call GetFileName95 with this structure and clean the memory.
563 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
565 WCHAR
*current_dir
= NULL
;
569 /* save current directory */
570 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
572 current_dir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
573 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
579 ret
= GetFileName95(info
);
582 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
583 ret
= GetFileName95(info
);
589 /* set the lpstrFileTitle */
590 if (ret
&& info
->ofnInfos
->lpstrFile
&& info
->ofnInfos
->lpstrFileTitle
)
594 LPOPENFILENAMEW ofn
= info
->ofnInfos
;
595 WCHAR
*file_title
= PathFindFileNameW(ofn
->lpstrFile
);
596 lstrcpynW(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
600 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)info
->ofnInfos
;
601 char *file_title
= PathFindFileNameA(ofn
->lpstrFile
);
602 lstrcpynA(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
608 SetCurrentDirectoryW(current_dir
);
609 heap_free(current_dir
);
614 heap_free((void *)info
->defext
);
615 heap_free((void *)info
->title
);
616 heap_free((void *)info
->filter
);
617 heap_free((void *)info
->customfilter
);
620 heap_free(info
->filename
);
621 heap_free(info
->initdir
);
623 for (i
= 0; i
< ARRAY_SIZE(info
->places
); i
++)
624 ILFree(info
->places
[i
]);
629 /******************************************************************************
630 * COMDLG32_GetDisplayNameOf [internal]
632 * Helper function to get the display name for a pidl.
634 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
635 LPSHELLFOLDER psfDesktop
;
638 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
641 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
642 IShellFolder_Release(psfDesktop
);
646 IShellFolder_Release(psfDesktop
);
647 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
650 /******************************************************************************
651 * COMDLG32_GetCanonicalPath [internal]
653 * Helper function to get the canonical path.
655 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
656 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
658 WCHAR lpstrTemp
[MAX_PATH
];
660 /* Get the current directory name */
661 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
664 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
666 PathAddBackslashW(lpstrPathAndFile
);
668 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile
), debugstr_w(lpstrFile
));
670 /* if the user specified a fully qualified path use it */
671 if(PathIsRelativeW(lpstrFile
))
673 lstrcatW(lpstrPathAndFile
, lpstrFile
);
677 /* does the path have a drive letter? */
678 if (PathGetDriveNumberW(lpstrFile
) == -1)
679 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
681 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
684 /* resolve "." and ".." */
685 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
686 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
687 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
690 /***********************************************************************
691 * COMDLG32_SplitFileNames [internal]
693 * Creates a delimited list of filenames.
695 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
697 UINT nStrCharCount
= 0; /* index in src buffer */
698 UINT nFileIndex
= 0; /* index in dest buffer */
699 UINT nFileCount
= 0; /* number of files */
701 /* we might get single filename without any '"',
702 * so we need nStrLen + terminating \0 + end-of-list \0 */
703 *lpstrFileList
= heap_alloc((nStrLen
+ 2) * sizeof(WCHAR
));
706 /* build delimited file list from filenames */
707 while ( nStrCharCount
<= nStrLen
)
709 if ( lpstrEdit
[nStrCharCount
]=='"' )
712 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
714 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
717 (*lpstrFileList
)[nFileIndex
++] = 0;
723 /* single, unquoted string */
724 if ((nStrLen
> 0) && (nFileIndex
== 0) )
726 lstrcpyW(*lpstrFileList
, lpstrEdit
);
727 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
732 (*lpstrFileList
)[nFileIndex
++] = '\0';
734 *sizeUsed
= nFileIndex
;
738 /***********************************************************************
739 * ArrangeCtrlPositions [internal]
741 * NOTE: Make sure to add testcases for any changes made here.
743 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
745 HWND hwndChild
, hwndStc32
;
746 RECT rectParent
, rectChild
, rectStc32
;
750 /* Take into account if open as read only checkbox and help button
755 RECT rectHelp
, rectCancel
;
756 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
757 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
758 /* subtract the height of the help button plus the space between
759 * the help button and the cancel button to the height of the dialog
761 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
765 There are two possibilities to add components to the default file dialog box.
767 By default, all the new components are added below the standard dialog box (the else case).
769 However, if there is a static text component with the stc32 id, a special case happens.
770 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
771 in the window and the cx and cy indicate how to size the window.
772 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
773 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
777 GetClientRect(hwndParentDlg
, &rectParent
);
779 /* when arranging controls we have to use fixed parent size */
780 rectParent
.bottom
-= help_fixup
;
782 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
785 GetWindowRect(hwndStc32
, &rectStc32
);
786 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
788 /* set the size of the stc32 control according to the size of
789 * client area of the parent dialog
791 SetWindowPos(hwndStc32
, 0,
793 rectParent
.right
, rectParent
.bottom
,
794 SWP_NOMOVE
| SWP_NOZORDER
);
797 SetRectEmpty(&rectStc32
);
799 /* this part moves controls of the child dialog */
800 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
803 if (hwndChild
!= hwndStc32
)
805 GetWindowRect(hwndChild
, &rectChild
);
806 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
808 /* move only if stc32 exist */
809 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
811 /* move to the right of visible controls of the parent dialog */
812 rectChild
.left
+= rectParent
.right
;
813 rectChild
.left
-= rectStc32
.right
;
815 /* move even if stc32 doesn't exist */
816 if (rectChild
.top
>= rectStc32
.bottom
)
818 /* move below visible controls of the parent dialog */
819 rectChild
.top
+= rectParent
.bottom
;
820 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
823 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
824 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
826 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
829 /* this part moves controls of the parent dialog */
830 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
833 if (hwndChild
!= hwndChildDlg
)
835 GetWindowRect(hwndChild
, &rectChild
);
836 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
838 /* left,top of stc32 marks the position of controls
839 * from the parent dialog
841 rectChild
.left
+= rectStc32
.left
;
842 rectChild
.top
+= rectStc32
.top
;
844 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
845 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
847 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
850 /* calculate the size of the resulting dialog */
852 /* here we have to use original parent size */
853 GetClientRect(hwndParentDlg
, &rectParent
);
854 GetClientRect(hwndChildDlg
, &rectChild
);
855 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
856 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
861 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
862 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
864 chgx
= rectChild
.right
- rectParent
.right
;
866 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
867 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
869 /* Unconditionally set new dialog
870 * height to that of the child
872 chgy
= rectChild
.bottom
- rectParent
.bottom
;
877 chgy
= rectChild
.bottom
- help_fixup
;
879 /* set the size of the parent dialog */
880 GetWindowRect(hwndParentDlg
, &rectParent
);
881 SetWindowPos(hwndParentDlg
, 0,
883 rectParent
.right
- rectParent
.left
+ chgx
,
884 rectParent
.bottom
- rectParent
.top
+ chgy
,
885 SWP_NOMOVE
| SWP_NOZORDER
);
888 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
897 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
904 TRACE("%p, %p\n", fodInfos
, hwnd
);
907 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
908 * structure's hInstance parameter is not a HINSTANCE, but
909 * instead a pointer to a template resource to use.
911 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
914 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
916 hinst
= COMDLG32_hInstance
;
917 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
919 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
925 hinst
= fodInfos
->ofnInfos
->hInstance
;
926 if(fodInfos
->unicode
)
928 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
929 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
933 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
934 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
938 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
941 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
942 !(template = LockResource( hDlgTmpl
)))
944 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
948 if (fodInfos
->unicode
)
949 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
950 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
951 (LPARAM
)fodInfos
->ofnInfos
);
953 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
954 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
955 (LPARAM
)fodInfos
->ofnInfos
);
958 else if (is_dialog_hooked(fodInfos
))
963 WORD menu
,class,title
;
965 GetClientRect(hwnd
,&rectHwnd
);
966 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
967 temp
.tmplate
.dwExtendedStyle
= 0;
968 temp
.tmplate
.cdit
= 0;
973 temp
.menu
= temp
.class = temp
.title
= 0;
975 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
976 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
983 /***********************************************************************
984 * SendCustomDlgNotificationMessage
986 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
989 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
991 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
995 TRACE("%p %d\n", hwndParentDlg
, uCode
);
997 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
1000 TRACE("CALL NOTIFY for %d\n", uCode
);
1002 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
1003 ofnNotify
.hdr
.idFrom
= 0;
1004 ofnNotify
.hdr
.code
= uCode
;
1005 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
1006 ofnNotify
.pszFile
= NULL
;
1008 if (fodInfos
->unicode
)
1009 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
1011 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
1013 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
1018 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
1022 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1024 TRACE("CDM_GETFILEPATH:\n");
1026 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1029 /* get path and filenames */
1030 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
1031 buffer
= heap_alloc( (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
1032 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
1035 p
= buffer
+ strlenW(buffer
);
1037 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
1039 if (fodInfos
->unicode
)
1041 total
= strlenW( buffer
) + 1;
1042 if (result
) lstrcpynW( result
, buffer
, size
);
1043 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
1047 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
1048 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
1049 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1051 heap_free( buffer
);
1055 /***********************************************************************
1056 * FILEDLG95_HandleCustomDialogMessages
1058 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1060 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1062 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1063 WCHAR lpstrPath
[MAX_PATH
];
1066 if(!fodInfos
) return FALSE
;
1070 case CDM_GETFILEPATH
:
1071 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1074 case CDM_GETFOLDERPATH
:
1075 TRACE("CDM_GETFOLDERPATH:\n");
1076 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1079 if (fodInfos
->unicode
)
1080 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1082 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1083 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1085 retval
= lstrlenW(lpstrPath
) + 1;
1088 case CDM_GETFOLDERIDLIST
:
1089 retval
= ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1090 if (retval
<= wParam
)
1091 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1095 TRACE("CDM_GETSPEC:\n");
1096 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1099 if (fodInfos
->unicode
)
1100 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1102 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1106 case CDM_SETCONTROLTEXT
:
1107 TRACE("CDM_SETCONTROLTEXT:\n");
1110 if( fodInfos
->unicode
)
1111 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1113 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1118 case CDM_HIDECONTROL
:
1119 /* MSDN states that it should fail for not OFN_EXPLORER case */
1120 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1122 HWND control
= GetDlgItem( hwnd
, wParam
);
1123 if (control
) ShowWindow( control
, SW_HIDE
);
1126 else retval
= FALSE
;
1130 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1131 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1134 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1138 /***********************************************************************
1139 * FILEDLG95_OnWMGetMMI
1141 * WM_GETMINMAXINFO message handler for resizable dialogs
1143 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1145 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1146 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1147 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1149 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1154 /***********************************************************************
1155 * FILEDLG95_OnWMSize
1157 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1159 * FIXME: this could be made more elaborate. Now use a simple scheme
1160 * where the file view is enlarged and the controls are either moved
1161 * vertically or horizontally to get out of the way. Only the "grip"
1162 * is moved in both directions to stay in the corner.
1164 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1170 FileOpenDlgInfos
*fodInfos
;
1172 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1173 fodInfos
= get_filedlg_infoptr(hwnd
);
1174 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1175 /* get the new dialog rectangle */
1176 GetWindowRect( hwnd
, &rc
);
1177 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1178 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1179 /* not initialized yet */
1180 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1181 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1182 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1184 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1185 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1186 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1187 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1188 /* change the size of the view window */
1189 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1190 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1191 hdwp
= BeginDeferWindowPos( 10);
1192 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1193 rcview
.right
- rcview
.left
+ chgx
,
1194 rcview
.bottom
- rcview
.top
+ chgy
,
1195 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1196 /* change position and sizes of the controls */
1197 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1199 int ctrlid
= GetDlgCtrlID( ctrl
);
1200 GetWindowRect( ctrl
, &rc
);
1201 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1202 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1204 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1206 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1208 else if( rc
.top
> rcview
.bottom
)
1210 /* if it was below the shell view
1214 /* file name (edit or comboboxex) and file types combo change also width */
1218 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1219 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1220 SWP_NOACTIVATE
| SWP_NOZORDER
);
1222 /* then these buttons must move out of the way */
1226 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1228 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1231 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1233 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1236 else if( rc
.left
> rcview
.right
)
1238 /* if it was to the right of the shell view
1240 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1242 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1249 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1251 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1252 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1253 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1255 case IDC_TOOLBARSTATIC
:
1257 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1259 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1262 /* not resized in windows. Since wine uses this invisible control
1263 * to size the browser view it needs to be resized */
1264 case IDC_SHELLSTATIC
:
1265 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1266 rc
.right
- rc
.left
+ chgx
,
1267 rc
.bottom
- rc
.top
+ chgy
,
1268 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1270 case IDC_TOOLBARPLACES
:
1271 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
+ chgy
,
1272 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1277 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1278 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1280 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1281 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1283 GetWindowRect( ctrl
, &rc
);
1284 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1285 if( rc
.top
> rcview
.bottom
)
1287 /* if it was below the shell view
1289 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1290 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1291 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1293 else if( rc
.left
> rcview
.right
)
1295 /* if it was to the right of the shell view
1297 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1298 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1299 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1302 /* size the custom dialog at the end: some applications do some
1303 * control re-arranging at this point */
1304 GetClientRect(hwnd
, &rc
);
1305 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1306 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1308 EndDeferWindowPos( hdwp
);
1309 /* should not be needed */
1310 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1314 /***********************************************************************
1317 * File open dialog procedure
1319 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1322 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1329 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1331 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1332 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1334 /* Some shell namespace extensions depend on COM being initialized. */
1335 if (SUCCEEDED(OleInitialize(NULL
)))
1336 fodInfos
->ole_initialized
= TRUE
;
1338 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1340 FILEDLG95_InitControls(hwnd
);
1342 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1344 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1345 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1346 RECT client
, client_adjusted
;
1348 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1350 style
|= WS_SIZEBOX
;
1351 ex_style
|= WS_EX_WINDOWEDGE
;
1354 style
&= ~WS_SIZEBOX
;
1355 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1356 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1358 GetClientRect( hwnd
, &client
);
1359 GetClientRect( hwnd
, &client_adjusted
);
1360 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1362 GetWindowRect( hwnd
, &rc
);
1363 rc
.right
+= client_adjusted
.right
- client
.right
;
1364 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1365 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1366 SWP_NOZORDER
| SWP_NOMOVE
);
1368 GetWindowRect( hwnd
, &rc
);
1369 fodInfos
->DlgInfos
.hwndGrip
=
1370 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1371 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1372 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1373 rc
.right
- gripx
, rc
.bottom
- gripy
,
1374 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1377 fodInfos
->DlgInfos
.hwndCustomDlg
=
1378 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1380 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1381 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1383 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1384 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1386 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1387 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1388 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1391 /* if the app has changed the position of the invisible listbox,
1392 * change that of the listview (browser) as well */
1393 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1394 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1395 if( !EqualRect( &rc
, &rcstc
))
1397 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1398 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1399 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1400 SWP_NOACTIVATE
| SWP_NOZORDER
);
1403 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1405 GetWindowRect( hwnd
, &rc
);
1406 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1407 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1408 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1409 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1410 GetClientRect( hwnd
, &rc
);
1411 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1412 rc
.right
- gripx
, rc
.bottom
- gripy
,
1413 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1414 /* resize the dialog to the previous invocation */
1415 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1416 SetWindowPos( hwnd
, NULL
,
1417 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1418 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1421 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1422 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1427 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1428 case WM_GETMINMAXINFO
:
1429 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1431 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1434 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1437 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1443 case WM_GETISHELLBROWSER
:
1444 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1448 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1449 HWND places_bar
= GetDlgItem(hwnd
, IDC_TOOLBARPLACES
);
1452 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1453 MemDialogSize
= fodInfos
->sizedlg
;
1457 himl
= (HIMAGELIST
)SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_GETIMAGELIST
, 0, 0);
1458 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, 0);
1459 ImageList_Destroy(himl
);
1465 RemovePropW(hwnd
, filedlg_info_propnameW
);
1470 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1473 /* set up the button tooltips strings */
1474 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1476 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1477 switch(lpnmh
->idFrom
)
1479 /* Up folder button */
1480 case FCIDM_TB_UPFOLDER
:
1481 stringId
= IDS_UPFOLDER
;
1483 /* New folder button */
1484 case FCIDM_TB_NEWFOLDER
:
1485 stringId
= IDS_NEWFOLDER
;
1487 /* List option button */
1488 case FCIDM_TB_SMALLICON
:
1489 stringId
= IDS_LISTVIEW
;
1491 /* Details option button */
1492 case FCIDM_TB_REPORTVIEW
:
1493 stringId
= IDS_REPORTVIEW
;
1495 /* Desktop button */
1496 case FCIDM_TB_DESKTOP
:
1497 stringId
= IDS_TODESKTOP
;
1502 lpdi
->hinst
= COMDLG32_hInstance
;
1503 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1508 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1509 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1514 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1516 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1517 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1520 /***********************************************************************
1521 * FILEDLG95_InitControls
1523 * WM_INITDIALOG message handler (before hook notification)
1525 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1527 BOOL win2000plus
= FALSE
;
1528 BOOL win98plus
= FALSE
;
1529 BOOL handledPath
= FALSE
;
1530 OSVERSIONINFOW osVi
;
1531 static const WCHAR szwSlash
[] = { '\\', 0 };
1532 static const WCHAR szwStar
[] = { '*',0 };
1534 static const TBBUTTON tbb
[] =
1536 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1537 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1538 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1539 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1540 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1541 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1542 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1543 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1544 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1546 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1551 HIMAGELIST toolbarImageList
;
1552 ITEMIDLIST
*desktopPidl
;
1553 SHFILEINFOW fileinfo
;
1555 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1557 TRACE("%p\n", fodInfos
);
1559 /* Get windows version emulating */
1560 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1561 GetVersionExW(&osVi
);
1562 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1563 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1564 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1565 win2000plus
= (osVi
.dwMajorVersion
> 4);
1566 if (win2000plus
) win98plus
= TRUE
;
1568 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1571 /* Use either the edit or the comboboxex for the filename control */
1572 if (filename_is_edit( fodInfos
))
1574 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1575 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1579 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1580 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1583 /* Get the hwnd of the controls */
1584 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1585 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1587 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1588 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1590 /* construct the toolbar */
1591 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1592 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1594 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1595 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1596 rectTB
.left
= rectlook
.right
;
1597 rectTB
.top
= rectlook
.top
-1;
1599 if (fodInfos
->unicode
)
1600 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1601 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1602 rectTB
.left
, rectTB
.top
,
1603 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1604 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1606 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1607 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1608 rectTB
.left
, rectTB
.top
,
1609 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1610 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1612 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1614 /* FIXME: use TB_LOADIMAGES when implemented */
1615 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1616 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1617 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1619 /* Retrieve and add desktop icon to the toolbar */
1620 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1621 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1622 SHGetFileInfoW((const WCHAR
*)desktopPidl
, 0, &fileinfo
, sizeof(fileinfo
),
1623 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1624 ImageList_AddIcon(toolbarImageList
, fileinfo
.hIcon
);
1626 DestroyIcon(fileinfo
.hIcon
);
1627 CoTaskMemFree(desktopPidl
);
1629 /* Finish Toolbar Construction */
1630 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1631 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1633 if (is_places_bar_enabled(fodInfos
))
1635 TBBUTTON tb
= { 0 };
1640 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_BUTTONSTRUCTSIZE
, 0, 0);
1641 GetClientRect(GetDlgItem(hwnd
, IDC_TOOLBARPLACES
), &rect
);
1642 cx
= rect
.right
- rect
.left
;
1644 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONWIDTH
, 0, MAKELPARAM(cx
, cx
));
1645 himl
= ImageList_Create(GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), ILC_COLOR32
, 4, 1);
1647 filedlg_collect_places_pidls(fodInfos
);
1648 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
1652 if (!fodInfos
->places
[i
])
1655 memset(&fileinfo
, 0, sizeof(fileinfo
));
1656 SHGetFileInfoW((const WCHAR
*)fodInfos
->places
[i
], 0, &fileinfo
, sizeof(fileinfo
),
1657 SHGFI_PIDL
| SHGFI_DISPLAYNAME
| SHGFI_ICON
);
1658 index
= ImageList_AddIcon(himl
, fileinfo
.hIcon
);
1661 tb
.iString
= (INT_PTR
)fileinfo
.szDisplayName
;
1662 tb
.fsState
= TBSTATE_ENABLED
| TBSTATE_WRAP
;
1663 tb
.idCommand
= TBPLACES_CMDID_PLACE0
+ i
;
1664 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tb
);
1666 DestroyIcon(fileinfo
.hIcon
);
1669 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, (LPARAM
)himl
);
1670 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, cx
* 3 / 4));
1673 /* Set the window text with the text specified in the OPENFILENAME structure */
1676 SetWindowTextW(hwnd
,fodInfos
->title
);
1678 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1681 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, ARRAY_SIZE(buf
));
1682 SetWindowTextW(hwnd
, buf
);
1685 /* Initialise the file name edit control */
1686 handledPath
= FALSE
;
1687 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1689 if(fodInfos
->filename
)
1691 /* 1. If win2000 or higher and filename contains a path, use it
1692 in preference over the lpstrInitialDir */
1693 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1694 WCHAR tmpBuf
[MAX_PATH
];
1698 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1701 /* nameBit is always shorter than the original filename. It may be NULL
1702 * when the filename contains only a drive name instead of file name */
1705 lstrcpyW(fodInfos
->filename
,nameBit
);
1709 *fodInfos
->filename
= '\0';
1711 heap_free(fodInfos
->initdir
);
1712 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1713 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1715 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1716 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1718 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1721 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1725 /* 2. (All platforms) If initdir is not null, then use it */
1726 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1728 /* Work out the proper path as supplied one might be relative */
1729 /* (Here because supplying '.' as dir browses to My Computer) */
1730 WCHAR tmpBuf
[MAX_PATH
];
1731 WCHAR tmpBuf2
[MAX_PATH
];
1735 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1736 if (PathFileExistsW(tmpBuf
)) {
1737 /* initdir does not have to be a directory. If a file is
1738 * specified, the dir part is taken */
1739 if (PathIsDirectoryW(tmpBuf
)) {
1740 PathAddBackslashW(tmpBuf
);
1741 lstrcatW(tmpBuf
, szwStar
);
1743 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1746 heap_free(fodInfos
->initdir
);
1747 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1748 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1750 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1753 else if (fodInfos
->initdir
)
1755 heap_free(fodInfos
->initdir
);
1756 fodInfos
->initdir
= NULL
;
1757 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1762 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1764 /* 2.5. Win2000+: Recently used defext */
1766 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1767 fodInfos
->initdir
[0] = '\0';
1769 FILEDLG95_MRU_load_ext(fodInfos
->initdir
, MAX_PATH
, fodInfos
->defext
);
1771 if (fodInfos
->initdir
[0] && PathIsDirectoryW(fodInfos
->initdir
)) {
1774 heap_free(fodInfos
->initdir
);
1775 fodInfos
->initdir
= NULL
;
1781 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1783 /* 3. All except w2k+: if filename contains a path use it */
1784 if (!win2000plus
&& fodInfos
->filename
&&
1785 *fodInfos
->filename
&&
1786 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1787 WCHAR tmpBuf
[MAX_PATH
];
1791 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1796 /* nameBit is always shorter than the original filename */
1797 lstrcpyW(fodInfos
->filename
, nameBit
);
1800 len
= lstrlenW(tmpBuf
);
1801 heap_free(fodInfos
->initdir
);
1802 fodInfos
->initdir
= heap_alloc((len
+1)*sizeof(WCHAR
));
1803 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1806 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1807 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1809 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1812 /* 4. Win2000+: Recently used */
1813 if (!handledPath
&& win2000plus
) {
1814 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1815 fodInfos
->initdir
[0] = '\0';
1817 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1819 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1822 heap_free(fodInfos
->initdir
);
1823 fodInfos
->initdir
= NULL
;
1827 /* 5. win98+ and win2000+ if any files of specified filter types in
1828 current directory, use it */
1829 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1831 LPCWSTR lpstrPos
= fodInfos
->filter
;
1832 WIN32_FIND_DATAW FindFileData
;
1837 /* filter is a list... title\0ext\0......\0\0 */
1839 /* Skip the title */
1840 if(! *lpstrPos
) break; /* end */
1841 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1843 /* See if any files exist in the current dir with this extension */
1844 if(! *lpstrPos
) break; /* end */
1846 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1848 if (hFind
== INVALID_HANDLE_VALUE
) {
1849 /* None found - continue search */
1850 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1854 heap_free(fodInfos
->initdir
);
1855 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1856 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1859 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1860 debugstr_w(lpstrPos
));
1867 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1868 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1869 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1871 if (SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
) == S_OK
)
1873 if (SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
) == S_OK
)
1876 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1877 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1880 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1883 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1886 } else if (!handledPath
) {
1887 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1888 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1890 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1893 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1894 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1896 /* Must the open as read only check box be checked ?*/
1897 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1899 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1902 /* Must the open as read only check box be hidden? */
1903 if (filedialog_is_readonly_hidden(fodInfos
))
1905 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1906 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1909 /* Must the help button be hidden? */
1910 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1912 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1913 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1916 /* change Open to Save */
1917 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1920 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, ARRAY_SIZE(buf
));
1921 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1922 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, ARRAY_SIZE(buf
));
1923 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1926 /* Initialize the filter combo box */
1927 FILEDLG95_FILETYPE_Init(hwnd
);
1932 /***********************************************************************
1933 * FILEDLG95_ResizeControls
1935 * WM_INITDIALOG message handler (after hook notification)
1937 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1939 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1941 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1944 UINT flags
= SWP_NOACTIVATE
;
1946 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1947 filedialog_is_readonly_hidden(fodInfos
) && !(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
));
1949 /* resize the custom dialog to the parent size */
1950 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1951 GetClientRect(hwnd
, &rc
);
1954 /* our own fake template is zero sized and doesn't have children, so
1955 * there is no need to resize it. Picasa depends on it.
1957 flags
|= SWP_NOSIZE
;
1960 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1961 0, 0, rc
.right
, rc
.bottom
, flags
);
1965 /* Resize the height; if opened as read-only, checkbox and help button are
1966 * hidden and we are not using a custom template nor a customDialog
1968 if (filedialog_is_readonly_hidden(fodInfos
) &&
1969 (!(fodInfos
->ofnInfos
->Flags
&
1970 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1972 RECT rectDlg
, rectHelp
, rectCancel
;
1973 GetWindowRect(hwnd
, &rectDlg
);
1974 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1975 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1976 /* subtract the height of the help button plus the space between the help
1977 * button and the cancel button to the height of the dialog
1979 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1980 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1981 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1987 /***********************************************************************
1988 * FILEDLG95_FillControls
1990 * WM_INITDIALOG message handler (after hook notification)
1992 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1994 LPITEMIDLIST pidlItemId
= NULL
;
1996 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1998 TRACE("dir=%s file=%s\n",
1999 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
2001 /* Get the initial directory pidl */
2003 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
2005 WCHAR path
[MAX_PATH
];
2007 GetCurrentDirectoryW(MAX_PATH
,path
);
2008 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
2011 /* Initialise shell objects */
2012 FILEDLG95_SHELL_Init(hwnd
);
2014 /* Initialize the Look In combo box */
2015 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
2017 /* Browse to the initial directory */
2018 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
2024 /***********************************************************************
2027 * Regroups all the cleaning functions of the filedlg
2029 void FILEDLG95_Clean(HWND hwnd
)
2031 FILEDLG95_FILETYPE_Clean(hwnd
);
2032 FILEDLG95_LOOKIN_Clean(hwnd
);
2033 FILEDLG95_SHELL_Clean(hwnd
);
2037 /***********************************************************************
2038 * Browse to arbitrary pidl
2040 static void filedlg_browse_to_pidl(const FileOpenDlgInfos
*info
, LPITEMIDLIST pidl
)
2042 TRACE("%p, %p\n", info
->ShellInfos
.hwndOwner
, pidl
);
2044 IShellBrowser_BrowseObject(info
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2045 if (info
->ofnInfos
->Flags
& OFN_EXPLORER
)
2046 SendCustomDlgNotificationMessage(info
->ShellInfos
.hwndOwner
, CDN_FOLDERCHANGE
);
2049 /***********************************************************************
2050 * FILEDLG95_OnWMCommand
2052 * WM_COMMAND message handler
2054 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
2056 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2057 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
2058 WORD id
= LOWORD(wParam
); /* item, control, or accelerator identifier */
2064 FILEDLG95_OnOpen(hwnd
);
2068 FILEDLG95_Clean(hwnd
);
2069 EndDialog(hwnd
, FALSE
);
2071 /* Filetype combo box */
2073 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
2075 /* LookIn combo box */
2077 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
2080 /* --- toolbar --- */
2081 /* Up folder button */
2082 case FCIDM_TB_UPFOLDER
:
2083 FILEDLG95_SHELL_UpFolder(hwnd
);
2085 /* New folder button */
2086 case FCIDM_TB_NEWFOLDER
:
2087 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
2089 /* List option button */
2090 case FCIDM_TB_SMALLICON
:
2091 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
2093 /* Details option button */
2094 case FCIDM_TB_REPORTVIEW
:
2095 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
2098 case FCIDM_TB_DESKTOP
:
2102 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP
, &pidl
);
2103 filedlg_browse_to_pidl(fodInfos
, pidl
);
2109 case TBPLACES_CMDID_PLACE0
:
2110 case TBPLACES_CMDID_PLACE1
:
2111 case TBPLACES_CMDID_PLACE2
:
2112 case TBPLACES_CMDID_PLACE3
:
2113 case TBPLACES_CMDID_PLACE4
:
2114 filedlg_browse_to_pidl(fodInfos
, fodInfos
->places
[id
- TBPLACES_CMDID_PLACE0
]);
2122 /* Do not use the listview selection anymore */
2123 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
2127 /***********************************************************************
2128 * FILEDLG95_OnWMGetIShellBrowser
2130 * WM_GETISHELLBROWSER message handler
2132 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
2134 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2138 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
2144 /***********************************************************************
2145 * FILEDLG95_SendFileOK
2147 * Sends the CDN_FILEOK notification if required
2150 * TRUE if the dialog should close
2151 * FALSE if the dialog should not be closed
2153 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
2155 /* ask the hook if we can close */
2156 if (is_dialog_hooked(fodInfos
))
2161 /* First send CDN_FILEOK as MSDN doc says */
2162 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2163 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
2166 TRACE("canceled\n");
2170 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2171 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
2172 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
2175 TRACE("canceled\n");
2182 /***********************************************************************
2183 * FILEDLG95_OnOpenMultipleFiles
2185 * Handles the opening of multiple files.
2188 * check destination buffer size
2190 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2192 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2193 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2194 UINT nCount
, nSizePath
;
2198 if(fodInfos
->unicode
)
2200 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2201 ofn
->lpstrFile
[0] = '\0';
2205 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2206 ofn
->lpstrFile
[0] = '\0';
2209 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2211 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2212 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2213 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2215 LPWSTR lpstrTemp
= lpstrFileList
;
2217 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2221 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2224 WCHAR lpstrNotFound
[100];
2225 WCHAR lpstrMsg
[100];
2227 static const WCHAR nl
[] = {'\n',0};
2229 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2230 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2232 lstrcpyW(tmp
, lpstrTemp
);
2234 lstrcatW(tmp
, lpstrNotFound
);
2236 lstrcatW(tmp
, lpstrMsg
);
2238 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2242 /* move to the next file in the list of files */
2243 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2248 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2249 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2251 /* For "oldstyle" dialog the components have to
2252 be separated by blanks (not '\0'!) and short
2253 filenames have to be used! */
2254 FIXME("Components have to be separated by blanks\n");
2256 if(fodInfos
->unicode
)
2258 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2259 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2260 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2264 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2266 if (ofn
->lpstrFile
!= NULL
)
2268 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2269 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2270 if (ofn
->nMaxFile
> nSizePath
)
2272 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2273 ofn
->lpstrFile
+ nSizePath
,
2274 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2279 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2280 fodInfos
->ofnInfos
->nFileExtension
= 0;
2282 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2285 /* clean and exit */
2286 FILEDLG95_Clean(hwnd
);
2287 return EndDialog(hwnd
,TRUE
);
2290 /* Returns the 'slot name' of the given module_name in the registry's
2291 * most-recently-used list. This will be an ASCII value in the
2292 * range ['a','z'). Returns zero on error.
2294 * The slot's value in the registry has the form:
2295 * module_name\0mru_path\0
2297 * If stored_path is given, then stored_path will contain the path name
2298 * stored in the registry's MRU list for the given module_name.
2300 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2301 * MRU list key for the given module_name.
2303 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2305 WCHAR mru_list
[32], *cur_mru_slot
;
2306 BOOL taken
[25] = {0};
2307 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2308 HKEY hkey_tmp
, *hkey
;
2317 *stored_path
= '\0';
2319 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2321 WARN("Unable to create MRU key: %d\n", ret
);
2325 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2326 (LPBYTE
)mru_list
, &mru_list_size
);
2327 if(ret
|| key_type
!= REG_SZ
){
2328 if(ret
== ERROR_FILE_NOT_FOUND
)
2331 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2336 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2337 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2338 DWORD value_data_size
= sizeof(value_data
);
2340 *value_name
= *cur_mru_slot
;
2342 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2343 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2344 if(ret
|| key_type
!= REG_BINARY
){
2345 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2349 if(!strcmpiW(module_name
, value_data
)){
2353 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2361 /* the module name isn't in the registry, so find the next open slot */
2362 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2363 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2364 for(i
= 0; i
< 25; ++i
){
2369 /* all slots are taken, so return the last one in MRUList */
2371 return *cur_mru_slot
;
2374 /* save the given filename as most-recently-used path for this module */
2375 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2377 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2381 /* get the current executable's name */
2382 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2384 WARN("GotModuleFileName failed: %d\n", GetLastError());
2387 module_name
= strrchrW(module_path
, '\\');
2389 module_name
= module_path
;
2393 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2398 { /* update the slot's info */
2399 WCHAR
*path_ends
, *final
;
2400 DWORD path_len
, final_len
;
2402 /* use only the path segment of `filename' */
2403 path_ends
= strrchrW(filename
, '\\');
2404 path_len
= path_ends
- filename
;
2406 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2408 final
= heap_alloc(final_len
* sizeof(WCHAR
));
2411 lstrcpyW(final
, module_name
);
2412 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2413 final
[final_len
-1] = '\0';
2415 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2416 final_len
* sizeof(WCHAR
));
2418 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2427 { /* update MRUList value */
2428 WCHAR old_mru_list
[32], new_mru_list
[32];
2429 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2430 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2432 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2433 (LPBYTE
)old_mru_list
, &mru_list_size
);
2434 if(ret
|| key_type
!= REG_SZ
){
2435 if(ret
== ERROR_FILE_NOT_FOUND
){
2436 new_mru_list
[0] = slot
;
2437 new_mru_list
[1] = '\0';
2439 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2444 /* copy old list data over so that the new slot is at the start
2446 *new_mru_slot
++ = slot
;
2447 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2448 if(*old_mru_slot
!= slot
)
2449 *new_mru_slot
++ = *old_mru_slot
;
2451 *new_mru_slot
= '\0';
2454 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2455 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2457 WARN("Error saving MRUList data: %d\n", ret
);
2464 /* load the most-recently-used path for this module */
2465 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2467 WCHAR module_path
[MAX_PATH
], *module_name
;
2469 /* get the current executable's name */
2470 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2472 WARN("GotModuleFileName failed: %d\n", GetLastError());
2475 module_name
= strrchrW(module_path
, '\\');
2477 module_name
= module_path
;
2481 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2482 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2485 static const WCHAR s_subkey
[] =
2487 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2488 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s',
2489 'i','o','n','\\','E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g',
2490 '3','2','\\','O','p','e','n','S','a','v','e','M','R','U',0
2492 static const WCHAR s_szAst
[] = { '*', 0 };
2494 typedef INT (CALLBACK
*MRUStringCmpFnW
)(LPCWSTR lhs
, LPCWSTR rhs
);
2495 typedef INT (CALLBACK
*MRUBinaryCmpFn
)(LPCVOID lhs
, LPCVOID rhs
, DWORD length
);
2497 /* https://docs.microsoft.com/en-us/windows/desktop/shell/mruinfo */
2498 typedef struct tagMRUINFOW
2507 MRUStringCmpFnW string_cmpfn
;
2508 MRUBinaryCmpFn binary_cmpfn
;
2510 } MRUINFOW
, *LPMRUINFOW
;
2512 /* flags for MRUINFOW.fFlags */
2513 #define MRU_STRING 0x0000
2514 #define MRU_BINARY 0x0001
2515 #define MRU_CACHEWRITE 0x0002
2517 static HINSTANCE s_hComCtl32
= NULL
;
2519 /* comctl32.400: CreateMRUListW */
2520 typedef HANDLE (WINAPI
*CREATEMRULISTW
)(const MRUINFOW
*);
2521 static CREATEMRULISTW s_pCreateMRUListW
= NULL
;
2523 /* comctl32.401: AddMRUStringW */
2524 typedef INT (WINAPI
*ADDMRUSTRINGW
)(HANDLE
, LPCWSTR
);
2525 static ADDMRUSTRINGW s_pAddMRUStringW
= NULL
;
2527 /* comctl32.402: FindMRUStringW */
2528 typedef INT (WINAPI
*FINDMRUSTRINGW
)(HANDLE
, LPCWSTR
, LPINT
);
2529 static FINDMRUSTRINGW s_pFindMRUStringW
= NULL
;
2531 /* comctl32.403: EnumMRUListW */
2532 typedef INT (WINAPI
*ENUMMRULISTW
)(HANDLE
, INT
, LPVOID
, DWORD
);
2533 static ENUMMRULISTW s_pEnumMRUListW
= NULL
;
2535 /* comctl32.152: FreeMRUList */
2536 typedef void (WINAPI
*FREEMRULIST
)(HANDLE
);
2537 static FREEMRULIST s_pFreeMRUList
= NULL
;
2539 static BOOL
FILEDLG_InitMRUList(void)
2544 s_hComCtl32
= GetModuleHandleA("comctl32");
2548 s_pCreateMRUListW
= (CREATEMRULISTW
)GetProcAddress(s_hComCtl32
, (LPCSTR
)400);
2549 s_pAddMRUStringW
= (ADDMRUSTRINGW
)GetProcAddress(s_hComCtl32
, (LPCSTR
)401);
2550 s_pFindMRUStringW
= (FINDMRUSTRINGW
)GetProcAddress(s_hComCtl32
, (LPCSTR
)402);
2551 s_pEnumMRUListW
= (ENUMMRULISTW
)GetProcAddress(s_hComCtl32
, (LPCSTR
)403);
2552 s_pFreeMRUList
= (FREEMRULIST
)GetProcAddress(s_hComCtl32
, (LPCSTR
)152);
2553 if (!s_pCreateMRUListW
||
2554 !s_pAddMRUStringW
||
2555 !s_pFindMRUStringW
||
2566 static BOOL
ExtIsPicture(LPCWSTR ext
)
2568 static const WCHAR s_image_exts
[][6] =
2573 { 'j','p','e','g',0 },
2575 { 'j','f','i','f',0 },
2579 { 't','i','f','f',0 }
2583 for (i
= 0; i
< ARRAY_SIZE(s_image_exts
); ++i
)
2585 if (lstrcmpiW(ext
, s_image_exts
[i
]) == 0)
2593 static void FILEDLG95_MRU_load_ext(LPWSTR stored_path
, size_t cchMax
, LPCWSTR defext
)
2595 HKEY hOpenSaveMRT
= NULL
;
2599 WCHAR szText
[MAX_PATH
];
2604 if (!defext
|| !*defext
|| !FILEDLG_InitMRUList())
2612 result
= RegOpenKeyW(HKEY_CURRENT_USER
, s_subkey
, &hOpenSaveMRT
);
2613 if (!result
&& hOpenSaveMRT
)
2615 ZeroMemory(&mi
, sizeof(mi
));
2616 mi
.cbSize
= sizeof(mi
);
2618 mi
.fFlags
= MRU_STRING
;
2619 mi
.hKey
= hOpenSaveMRT
;
2620 mi
.lpszSubKey
= defext
;
2621 mi
.u
.string_cmpfn
= lstrcmpiW
;
2622 hList
= (*s_pCreateMRUListW
)(&mi
);
2625 ret
= (*s_pEnumMRUListW
)(hList
, 0, szText
, sizeof(szText
));
2628 lstrcpynW(stored_path
, szText
, cchMax
);
2629 PathRemoveFileSpecW(stored_path
);
2631 (*s_pFreeMRUList
)(hList
);
2634 if (stored_path
[0] == 0)
2636 mi
.cbSize
= sizeof(mi
);
2638 mi
.fFlags
= MRU_STRING
;
2639 mi
.hKey
= hOpenSaveMRT
;
2640 mi
.lpszSubKey
= s_szAst
;
2641 mi
.u
.string_cmpfn
= lstrcmpiW
;
2642 hList
= (*s_pCreateMRUListW
)(&mi
);
2645 ret
= (*s_pEnumMRUListW
)(hList
, 0, szText
, sizeof(szText
));
2648 lstrcpynW(stored_path
, szText
, cchMax
);
2649 PathRemoveFileSpecW(stored_path
);
2651 (*s_pFreeMRUList
)(hList
);
2655 RegCloseKey(hOpenSaveMRT
);
2658 if (stored_path
[0] == 0)
2661 if (ExtIsPicture(defext
))
2663 SHGetSpecialFolderLocation(NULL
, CSIDL_MYPICTURES
, &pidl
);
2667 SHGetSpecialFolderLocation(NULL
, CSIDL_MYDOCUMENTS
, &pidl
);
2669 SHGetPathFromIDListW(pidl
, stored_path
);
2674 static void FILEDLG95_MRU_save_ext(LPCWSTR filename
)
2676 HKEY hOpenSaveMRT
= NULL
;
2680 LPCWSTR defext
= PathFindExtensionW(filename
);
2682 if (!defext
|| !*defext
|| !FILEDLG_InitMRUList())
2690 result
= RegOpenKeyW(HKEY_CURRENT_USER
, s_subkey
, &hOpenSaveMRT
);
2691 if (!result
&& hOpenSaveMRT
)
2693 ZeroMemory(&mi
, sizeof(mi
));
2694 mi
.cbSize
= sizeof(mi
);
2696 mi
.fFlags
= MRU_STRING
;
2697 mi
.hKey
= hOpenSaveMRT
;
2698 mi
.lpszSubKey
= defext
;
2699 mi
.u
.string_cmpfn
= lstrcmpiW
;
2700 hList
= (*s_pCreateMRUListW
)(&mi
);
2703 (*s_pAddMRUStringW
)(hList
, filename
);
2704 (*s_pFreeMRUList
)(hList
);
2707 mi
.cbSize
= sizeof(mi
);
2709 mi
.fFlags
= MRU_STRING
;
2710 mi
.hKey
= hOpenSaveMRT
;
2711 mi
.lpszSubKey
= s_szAst
;
2712 mi
.u
.string_cmpfn
= lstrcmpiW
;
2713 hList
= (*s_pCreateMRUListW
)(&mi
);
2716 (*s_pAddMRUStringW
)(hList
, filename
);
2717 (*s_pFreeMRUList
)(hList
);
2720 RegCloseKey(hOpenSaveMRT
);
2725 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2727 WCHAR strMsgTitle
[MAX_PATH
];
2728 WCHAR strMsgText
[MAX_PATH
];
2730 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, ARRAY_SIZE(strMsgTitle
));
2732 strMsgTitle
[0] = '\0';
2733 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, ARRAY_SIZE(strMsgText
));
2734 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2737 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2738 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2740 int nOpenAction
= defAction
;
2741 LPWSTR lpszTemp
, lpszTemp1
;
2742 LPITEMIDLIST pidl
= NULL
;
2743 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2745 /* check for invalid chars */
2746 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2748 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2752 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2754 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2757 LPSHELLFOLDER lpsfChild
;
2758 WCHAR lpwstrTemp
[MAX_PATH
];
2759 DWORD dwEaten
, dwAttributes
;
2762 lstrcpyW(lpwstrTemp
, lpszTemp
);
2763 p
= PathFindNextComponentW(lpwstrTemp
);
2765 if (!p
) break; /* end of path */
2768 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2770 /* There are no wildcards when OFN_NOVALIDATE is set */
2771 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2773 static const WCHAR wszWild
[] = { '*', '?', 0 };
2774 /* if the last element is a wildcard do a search */
2775 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2777 nOpenAction
= ONOPEN_SEARCH
;
2781 lpszTemp1
= lpszTemp
;
2783 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2785 /* append a backslash to drive letters */
2786 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2787 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2788 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2790 PathAddBackslashW(lpwstrTemp
);
2793 dwAttributes
= SFGAO_FOLDER
;
2794 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2796 /* the path component is valid, we have a pidl of the next path component */
2797 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2798 if(dwAttributes
& SFGAO_FOLDER
)
2800 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2802 ERR("bind to failed\n"); /* should not fail */
2805 IShellFolder_Release(*ppsf
);
2813 /* end dialog, return value */
2814 nOpenAction
= ONOPEN_OPEN
;
2820 else if (!(flags
& OFN_NOVALIDATE
))
2822 if(*lpszTemp
|| /* points to trailing null for last path element */
2823 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2825 if(flags
& OFN_PATHMUSTEXIST
)
2827 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2833 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2835 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2839 /* change to the current folder */
2840 nOpenAction
= ONOPEN_OPEN
;
2845 nOpenAction
= ONOPEN_OPEN
;
2854 /***********************************************************************
2857 * Ok button WM_COMMAND message handler
2859 * If the function succeeds, the return value is nonzero.
2861 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2863 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2864 LPWSTR lpstrFileList
;
2865 UINT nFileCount
= 0;
2868 WCHAR lpstrPathAndFile
[MAX_PATH
];
2869 LPSHELLFOLDER lpsf
= NULL
;
2872 TRACE("hwnd=%p\n", hwnd
);
2874 /* try to browse the selected item */
2875 if(BrowseSelectedFolder(hwnd
))
2878 /* get the files from the edit control */
2879 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2886 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2890 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2893 Step 1: Build a complete path name from the current folder and
2894 the filename or path in the edit box.
2896 - the path in the edit box is a root path
2897 (with or without drive letter)
2898 - the edit box contains ".." (or a path with ".." in it)
2901 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2902 heap_free(lpstrFileList
);
2905 Step 2: here we have a cleaned up path
2907 We have to parse the path step by step to see if we have to browse
2908 to a folder if the path points to a directory or the last
2909 valid element is a directory.
2912 lpstrPathAndFile: cleaned up path
2916 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2917 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2918 nOpenAction
= ONOPEN_OPEN
;
2920 nOpenAction
= ONOPEN_BROWSE
;
2922 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2923 fodInfos
->ofnInfos
->Flags
,
2924 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2930 Step 3: here we have a cleaned up and validated path
2933 lpsf: ShellFolder bound to the rightmost valid path component
2934 lpstrPathAndFile: cleaned up path
2935 nOpenAction: action to do
2937 TRACE("end validate sf=%p\n", lpsf
);
2941 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2942 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2945 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2948 /* replace the current filter */
2949 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2950 len
= lstrlenW(lpszTemp
)+1;
2951 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc(len
* sizeof(WCHAR
));
2952 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2954 /* set the filter cb to the extension when possible */
2955 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2956 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, iPos
, 0);
2959 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2960 TRACE("ONOPEN_BROWSE\n");
2962 IPersistFolder2
* ppf2
;
2963 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2965 LPITEMIDLIST pidlCurrent
;
2966 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2967 IPersistFolder2_Release(ppf2
);
2968 if (!ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2970 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2971 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2973 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2974 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2977 else if( nOpenAction
== ONOPEN_SEARCH
)
2979 if (fodInfos
->Shell
.FOIShellView
)
2980 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2982 ILFree(pidlCurrent
);
2983 if (filename_is_edit( fodInfos
))
2984 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2989 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2990 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2996 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2997 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
3001 /* update READONLY check box flag */
3002 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
3003 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
3005 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
3007 /* Attach the file extension with file name*/
3008 ext
= PathFindExtensionW(lpstrPathAndFile
);
3009 if (! *ext
&& fodInfos
->defext
)
3011 /* if no extension is specified with file name, then */
3012 /* attach the extension from file filter or default one */
3014 WCHAR
*filterExt
= NULL
;
3015 LPWSTR lpstrFilter
= NULL
;
3016 static const WCHAR szwDot
[] = {'.',0};
3017 int PathLength
= lstrlenW(lpstrPathAndFile
);
3019 /*Get the file extension from file type filter*/
3020 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3021 fodInfos
->ofnInfos
->nFilterIndex
-1);
3023 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
3025 WCHAR
* filterSearchIndex
;
3026 filterExt
= heap_alloc((lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
3027 strcpyW(filterExt
, lpstrFilter
);
3029 /* if a semicolon-separated list of file extensions was given, do not include the
3030 semicolon or anything after it in the extension.
3031 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
3032 filterSearchIndex
= strchrW(filterExt
, ';');
3033 if (filterSearchIndex
)
3035 filterSearchIndex
[0] = '\0';
3038 /* find the file extension by searching for the first dot in filterExt */
3039 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
3040 /* if the extension is invalid or contains a glob, ignore it */
3041 filterSearchIndex
= strchrW(filterExt
, '.');
3042 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
3044 strcpyW(filterExt
, filterSearchIndex
);
3048 heap_free(filterExt
);
3055 /* use the default file extension */
3056 filterExt
= heap_alloc((lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
3057 strcpyW(filterExt
, fodInfos
->defext
);
3060 if (*filterExt
) /* ignore filterExt="" */
3063 lstrcatW(lpstrPathAndFile
, szwDot
);
3064 /* Attach the extension */
3065 lstrcatW(lpstrPathAndFile
, filterExt
);
3068 heap_free(filterExt
);
3070 /* In Open dialog: if file does not exist try without extension */
3071 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
3072 lpstrPathAndFile
[PathLength
] = '\0';
3074 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
3077 if (!lstrcmpiW(fodInfos
->defext
, ext
))
3078 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
3080 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
3083 /* In Save dialog: check if the file already exists */
3084 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
3085 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
3086 && PathFileExistsW(lpstrPathAndFile
))
3088 WCHAR lpstrOverwrite
[100];
3091 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
3092 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
3093 MB_YESNO
| MB_ICONEXCLAMATION
);
3094 if (answer
== IDNO
|| answer
== IDCANCEL
)
3101 /* In Open dialog: check if it should be created if it doesn't exist */
3102 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
3103 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
3104 && !PathFileExistsW(lpstrPathAndFile
))
3106 WCHAR lpstrCreate
[100];
3109 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);