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)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
140 static const WCHAR LastVisitedMRUW
[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
147 /***********************************************************************
151 /* Internal functions used by the dialog */
152 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
153 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
154 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
155 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
156 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
157 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
158 static void FILEDLG95_Clean(HWND hwnd
);
160 /* Functions used by the shell navigation */
161 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
162 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
163 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
165 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
170 /* Functions used by the filetype combo box */
171 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
172 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
178 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
179 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
189 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
192 /* Miscellaneous tool functions */
193 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
194 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
195 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
196 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
197 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
198 static UINT
GetNumSelected( IDataObject
*doSelected
);
199 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
201 /* Shell memory allocation */
202 static void *MemAlloc(UINT size
);
203 static void MemFree(void *mem
);
205 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
207 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
208 static BOOL
BrowseSelectedFolder(HWND hwnd
);
210 /***********************************************************************
213 * Creates an Open common dialog box that lets the user select
214 * the drive, directory, and the name of a file or set of files to open.
216 * IN : The FileOpenDlgInfos structure associated with the dialog
217 * OUT : TRUE on success
218 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
220 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
224 LPCVOID origTemplate
;
226 LPDLGTEMPLATEW
template;
231 /* test for missing functionality */
232 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
234 FIXME("Flags 0x%08x not yet implemented\n",
235 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
238 /* Create the dialog from a template */
240 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
242 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
245 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
246 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
247 !(origTemplate
= LockResource(hDlgTmpl
)))
249 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
252 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
254 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
257 memcpy(template, origTemplate
, dwSize
);
259 /* msdn: explorer style dialogs permit sizing by default.
260 * The OFN_ENABLESIZING flag is only needed when a hook or
261 * custom tmeplate is provided */
262 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
263 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
264 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
266 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
268 template->style
|= WS_SIZEBOX
;
269 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
270 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
273 template->style
&= ~WS_SIZEBOX
;
276 /* old style hook messages */
277 if (IsHooked(fodInfos
))
279 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
280 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
281 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
282 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr
= OleInitialize(NULL
);
288 if (fodInfos
->unicode
)
289 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
291 fodInfos
->ofnInfos
->hwndOwner
,
295 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
297 fodInfos
->ofnInfos
->hwndOwner
,
303 HeapFree(GetProcessHeap(), 0, template);
305 /* Unable to create the dialog */
312 /***********************************************************************
315 * Call GetFileName95 with this structure and clean the memory.
317 * IN : The OPENFILENAMEA initialisation structure passed to
318 * GetOpenFileNameA win api function (see filedlg.c)
320 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
323 FileOpenDlgInfos fodInfos
;
324 LPSTR lpstrSavDir
= NULL
;
326 LPWSTR defext
= NULL
;
327 LPWSTR filter
= NULL
;
328 LPWSTR customfilter
= NULL
;
329 INITCOMMONCONTROLSEX icc
;
331 /* Initialize ComboBoxEx32 */
332 icc
.dwSize
= sizeof(icc
);
333 icc
.dwICC
= ICC_USEREX_CLASSES
;
334 InitCommonControlsEx(&icc
);
336 /* Initialize CommDlgExtendedError() */
337 COMDLG32_SetCommDlgExtendedError(0);
339 /* Initialize FileOpenDlgInfos structure */
340 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
342 /* Pass in the original ofn */
343 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
345 /* save current directory */
346 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
348 lpstrSavDir
= MemAlloc(MAX_PATH
);
349 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
352 fodInfos
.unicode
= FALSE
;
354 /* convert all the input strings to unicode */
355 if(ofn
->lpstrInitialDir
)
357 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
358 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
359 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
362 fodInfos
.initdir
= NULL
;
366 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
367 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
370 fodInfos
.filename
= NULL
;
374 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
375 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
378 fodInfos
.defext
= defext
;
382 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
383 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
384 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
386 fodInfos
.title
= title
;
388 if (ofn
->lpstrFilter
)
393 /* filter is a list... title\0ext\0......\0\0 */
394 s
= ofn
->lpstrFilter
;
395 while (*s
) s
= s
+strlen(s
)+1;
397 n
= s
- ofn
->lpstrFilter
;
398 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
399 filter
= MemAlloc(len
*sizeof(WCHAR
));
400 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
402 fodInfos
.filter
= filter
;
404 /* convert lpstrCustomFilter */
405 if (ofn
->lpstrCustomFilter
)
410 /* customfilter contains a pair of strings... title\0ext\0 */
411 s
= ofn
->lpstrCustomFilter
;
412 if (*s
) s
= s
+strlen(s
)+1;
413 if (*s
) s
= s
+strlen(s
)+1;
414 n
= s
- ofn
->lpstrCustomFilter
;
415 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
416 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
417 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
419 fodInfos
.customfilter
= customfilter
;
421 /* Initialize the dialog property */
422 fodInfos
.DlgInfos
.dwDlgProp
= 0;
423 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
428 ret
= GetFileName95(&fodInfos
);
431 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
432 ret
= GetFileName95(&fodInfos
);
438 /* set the lpstrFileTitle */
439 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
441 LPSTR lpstrFileTitle
= PathFindFileNameA(ofn
->lpstrFile
);
442 lstrcpynA(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
447 SetCurrentDirectoryA(lpstrSavDir
);
448 MemFree(lpstrSavDir
);
454 MemFree(customfilter
);
455 MemFree(fodInfos
.initdir
);
456 MemFree(fodInfos
.filename
);
458 TRACE("selected file: %s\n",ofn
->lpstrFile
);
463 /***********************************************************************
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
470 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
473 FileOpenDlgInfos fodInfos
;
474 LPWSTR lpstrSavDir
= NULL
;
475 INITCOMMONCONTROLSEX icc
;
477 /* Initialize ComboBoxEx32 */
478 icc
.dwSize
= sizeof(icc
);
479 icc
.dwICC
= ICC_USEREX_CLASSES
;
480 InitCommonControlsEx(&icc
);
482 /* Initialize CommDlgExtendedError() */
483 COMDLG32_SetCommDlgExtendedError(0);
485 /* Initialize FileOpenDlgInfos structure */
486 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
488 /* Pass in the original ofn */
489 fodInfos
.ofnInfos
= ofn
;
491 fodInfos
.title
= ofn
->lpstrTitle
;
492 fodInfos
.defext
= ofn
->lpstrDefExt
;
493 fodInfos
.filter
= ofn
->lpstrFilter
;
494 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
496 /* convert string arguments, save others */
499 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
500 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
503 fodInfos
.filename
= NULL
;
505 if(ofn
->lpstrInitialDir
)
507 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
508 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
509 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
510 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
513 fodInfos
.initdir
= NULL
;
515 /* save current directory */
516 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
518 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
519 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
522 fodInfos
.unicode
= TRUE
;
527 ret
= GetFileName95(&fodInfos
);
530 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
531 ret
= GetFileName95(&fodInfos
);
537 /* set the lpstrFileTitle */
538 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
540 LPWSTR lpstrFileTitle
= PathFindFileNameW(ofn
->lpstrFile
);
541 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
546 SetCurrentDirectoryW(lpstrSavDir
);
547 MemFree(lpstrSavDir
);
550 /* restore saved IN arguments and convert OUT arguments back */
551 MemFree(fodInfos
.filename
);
552 MemFree(fodInfos
.initdir
);
556 /******************************************************************************
557 * COMDLG32_GetDisplayNameOf [internal]
559 * Helper function to get the display name for a pidl.
561 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
562 LPSHELLFOLDER psfDesktop
;
565 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
568 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
569 IShellFolder_Release(psfDesktop
);
573 IShellFolder_Release(psfDesktop
);
574 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
577 /******************************************************************************
578 * COMDLG32_GetCanonicalPath [internal]
580 * Helper function to get the canonical path.
582 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
583 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
585 WCHAR lpstrTemp
[MAX_PATH
];
587 /* Get the current directory name */
588 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
591 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
593 PathAddBackslashW(lpstrPathAndFile
);
595 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
597 /* if the user specified a fully qualified path use it */
598 if(PathIsRelativeW(lpstrFile
))
600 lstrcatW(lpstrPathAndFile
, lpstrFile
);
604 /* does the path have a drive letter? */
605 if (PathGetDriveNumberW(lpstrFile
) == -1)
606 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
608 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
611 /* resolve "." and ".." */
612 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
613 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
614 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
617 /***********************************************************************
618 * COMDLG32_SplitFileNames [internal]
620 * Creates a delimited list of filenames.
622 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
624 UINT nStrCharCount
= 0; /* index in src buffer */
625 UINT nFileIndex
= 0; /* index in dest buffer */
626 UINT nFileCount
= 0; /* number of files */
628 /* we might get single filename without any '"',
629 * so we need nStrLen + terminating \0 + end-of-list \0 */
630 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
633 /* build delimited file list from filenames */
634 while ( nStrCharCount
<= nStrLen
)
636 if ( lpstrEdit
[nStrCharCount
]=='"' )
639 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
641 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
644 (*lpstrFileList
)[nFileIndex
++] = 0;
650 /* single, unquoted string */
651 if ((nStrLen
> 0) && (nFileIndex
== 0) )
653 lstrcpyW(*lpstrFileList
, lpstrEdit
);
654 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
659 (*lpstrFileList
)[nFileIndex
++] = '\0';
661 *sizeUsed
= nFileIndex
;
665 /***********************************************************************
666 * ArrangeCtrlPositions [internal]
668 * NOTE: Make sure to add testcases for any changes made here.
670 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
672 HWND hwndChild
, hwndStc32
;
673 RECT rectParent
, rectChild
, rectStc32
;
677 /* Take into account if open as read only checkbox and help button
682 RECT rectHelp
, rectCancel
;
683 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
684 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
685 /* subtract the height of the help button plus the space between
686 * the help button and the cancel button to the height of the dialog
688 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
692 There are two possibilities to add components to the default file dialog box.
694 By default, all the new components are added below the standard dialog box (the else case).
696 However, if there is a static text component with the stc32 id, a special case happens.
697 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
698 in the window and the cx and cy indicate how to size the window.
699 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
700 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
704 GetClientRect(hwndParentDlg
, &rectParent
);
706 /* when arranging controls we have to use fixed parent size */
707 rectParent
.bottom
-= help_fixup
;
709 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
712 GetWindowRect(hwndStc32
, &rectStc32
);
713 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
715 /* set the size of the stc32 control according to the size of
716 * client area of the parent dialog
718 SetWindowPos(hwndStc32
, 0,
720 rectParent
.right
, rectParent
.bottom
,
721 SWP_NOMOVE
| SWP_NOZORDER
);
724 SetRectEmpty(&rectStc32
);
726 /* this part moves controls of the child dialog */
727 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
730 if (hwndChild
!= hwndStc32
)
732 GetWindowRect(hwndChild
, &rectChild
);
733 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
735 /* move only if stc32 exist */
736 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
738 /* move to the right of visible controls of the parent dialog */
739 rectChild
.left
+= rectParent
.right
;
740 rectChild
.left
-= rectStc32
.right
;
742 /* move even if stc32 doesn't exist */
743 if (rectChild
.top
>= rectStc32
.bottom
)
745 /* move below visible controls of the parent dialog */
746 rectChild
.top
+= rectParent
.bottom
;
747 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
750 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
751 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
753 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
756 /* this part moves controls of the parent dialog */
757 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
760 if (hwndChild
!= hwndChildDlg
)
762 GetWindowRect(hwndChild
, &rectChild
);
763 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
765 /* left,top of stc32 marks the position of controls
766 * from the parent dialog
768 rectChild
.left
+= rectStc32
.left
;
769 rectChild
.top
+= rectStc32
.top
;
771 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
772 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
774 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
777 /* calculate the size of the resulting dialog */
779 /* here we have to use original parent size */
780 GetClientRect(hwndParentDlg
, &rectParent
);
781 GetClientRect(hwndChildDlg
, &rectChild
);
782 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
783 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
788 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
789 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
791 chgx
= rectChild
.right
- rectParent
.right
;
793 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
794 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
796 /* Unconditionally set new dialog
797 * height to that of the child
799 chgy
= rectChild
.bottom
- rectParent
.bottom
;
804 chgy
= rectChild
.bottom
- help_fixup
;
806 /* set the size of the parent dialog */
807 GetWindowRect(hwndParentDlg
, &rectParent
);
808 SetWindowPos(hwndParentDlg
, 0,
810 rectParent
.right
- rectParent
.left
+ chgx
,
811 rectParent
.bottom
- rectParent
.top
+ chgy
,
812 SWP_NOMOVE
| SWP_NOZORDER
);
815 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
824 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
834 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
835 * structure's hInstance parameter is not a HINSTANCE, but
836 * instead a pointer to a template resource to use.
838 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
841 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
843 hinst
= COMDLG32_hInstance
;
844 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
846 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
852 hinst
= fodInfos
->ofnInfos
->hInstance
;
853 if(fodInfos
->unicode
)
855 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
856 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
860 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
861 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
865 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
868 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
869 !(template = LockResource( hDlgTmpl
)))
871 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
875 if (fodInfos
->unicode
)
876 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
877 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
878 (LPARAM
)fodInfos
->ofnInfos
);
880 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
881 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
882 (LPARAM
)fodInfos
->ofnInfos
);
885 else if( IsHooked(fodInfos
))
890 WORD menu
,class,title
;
892 GetClientRect(hwnd
,&rectHwnd
);
893 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
894 temp
.tmplate
.dwExtendedStyle
= 0;
895 temp
.tmplate
.cdit
= 0;
900 temp
.menu
= temp
.class = temp
.title
= 0;
902 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
903 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
910 /***********************************************************************
911 * SendCustomDlgNotificationMessage
913 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
916 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
918 LRESULT hook_result
= 0;
919 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
921 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
923 if(!fodInfos
) return 0;
925 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
927 TRACE("CALL NOTIFY for %x\n", uCode
);
928 if(fodInfos
->unicode
)
931 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
932 ofnNotify
.hdr
.idFrom
=0;
933 ofnNotify
.hdr
.code
= uCode
;
934 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
935 ofnNotify
.pszFile
= NULL
;
936 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
941 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
942 ofnNotify
.hdr
.idFrom
=0;
943 ofnNotify
.hdr
.code
= uCode
;
944 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
945 ofnNotify
.pszFile
= NULL
;
946 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
948 TRACE("RET NOTIFY\n");
950 TRACE("Retval: 0x%08lx\n", hook_result
);
954 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
958 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
960 TRACE("CDM_GETFILEPATH:\n");
962 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
965 /* get path and filenames */
966 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
967 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
968 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
971 p
= buffer
+ strlenW(buffer
);
973 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
975 if (fodInfos
->unicode
)
977 total
= strlenW( buffer
) + 1;
978 if (result
) lstrcpynW( result
, buffer
, size
);
979 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
983 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
984 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
985 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
987 HeapFree( GetProcessHeap(), 0, buffer
);
991 /***********************************************************************
992 * FILEDLG95_HandleCustomDialogMessages
994 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
996 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
998 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
999 WCHAR lpstrPath
[MAX_PATH
];
1002 if(!fodInfos
) return FALSE
;
1006 case CDM_GETFILEPATH
:
1007 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1010 case CDM_GETFOLDERPATH
:
1011 TRACE("CDM_GETFOLDERPATH:\n");
1012 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1015 if (fodInfos
->unicode
)
1016 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1018 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1019 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1021 retval
= lstrlenW(lpstrPath
) + 1;
1024 case CDM_GETFOLDERIDLIST
:
1025 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1026 if (retval
<= wParam
)
1027 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1031 TRACE("CDM_GETSPEC:\n");
1032 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1035 if (fodInfos
->unicode
)
1036 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1038 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1042 case CDM_SETCONTROLTEXT
:
1043 TRACE("CDM_SETCONTROLTEXT:\n");
1046 if( fodInfos
->unicode
)
1047 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1049 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1054 case CDM_HIDECONTROL
:
1055 /* MSDN states that it should fail for not OFN_EXPLORER case */
1056 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1058 HWND control
= GetDlgItem( hwnd
, wParam
);
1059 if (control
) ShowWindow( control
, SW_HIDE
);
1062 else retval
= FALSE
;
1066 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1067 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1070 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1074 /***********************************************************************
1075 * FILEDLG95_OnWMGetMMI
1077 * WM_GETMINMAXINFO message handler for resizable dialogs
1079 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1081 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1082 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1083 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1085 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1090 /***********************************************************************
1091 * FILEDLG95_OnWMSize
1093 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1095 * FIXME: this could be made more elaborate. Now use a simple scheme
1096 * where the file view is enlarged and the controls are either moved
1097 * vertically or horizontally to get out of the way. Only the "grip"
1098 * is moved in both directions to stay in the corner.
1100 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1106 FileOpenDlgInfos
*fodInfos
;
1108 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1109 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1110 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1111 /* get the new dialog rectangle */
1112 GetWindowRect( hwnd
, &rc
);
1113 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1114 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1115 /* not initialized yet */
1116 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1117 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1118 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1120 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1121 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1122 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1123 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1124 /* change the size of the view window */
1125 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1126 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1127 hdwp
= BeginDeferWindowPos( 10);
1128 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1129 rcview
.right
- rcview
.left
+ chgx
,
1130 rcview
.bottom
- rcview
.top
+ chgy
,
1131 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1132 /* change position and sizes of the controls */
1133 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1135 int ctrlid
= GetDlgCtrlID( ctrl
);
1136 GetWindowRect( ctrl
, &rc
);
1137 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1138 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1140 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1142 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1144 else if( rc
.top
> rcview
.bottom
)
1146 /* if it was below the shell view
1150 /* file name (edit or comboboxex) and file types combo change also width */
1154 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1155 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1156 SWP_NOACTIVATE
| SWP_NOZORDER
);
1158 /* then these buttons must move out of the way */
1162 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1164 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1167 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1169 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1172 else if( rc
.left
> rcview
.right
)
1174 /* if it was to the right of the shell view
1176 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1178 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1185 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1187 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1188 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1189 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1191 case IDC_TOOLBARSTATIC
:
1193 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1195 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1198 /* not resized in windows. Since wine uses this invisible control
1199 * to size the browser view it needs to be resized */
1200 case IDC_SHELLSTATIC
:
1201 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1202 rc
.right
- rc
.left
+ chgx
,
1203 rc
.bottom
- rc
.top
+ chgy
,
1204 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1209 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1210 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1212 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1213 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1215 GetWindowRect( ctrl
, &rc
);
1216 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1217 if( rc
.top
> rcview
.bottom
)
1219 /* if it was below the shell view
1221 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1222 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1223 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1225 else if( rc
.left
> rcview
.right
)
1227 /* if it was to the right of the shell view
1229 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1230 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1231 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1234 /* size the custom dialog at the end: some applications do some
1235 * control re-arranging at this point */
1236 GetClientRect(hwnd
, &rc
);
1237 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1238 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1240 EndDeferWindowPos( hdwp
);
1241 /* should not be needed */
1242 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1246 /***********************************************************************
1249 * File open dialog procedure
1251 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1254 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1261 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1263 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1264 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1266 /* Adds the FileOpenDlgInfos in the property list of the dialog
1267 so it will be easily accessible through a GetPropA(...) */
1268 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1270 FILEDLG95_InitControls(hwnd
);
1272 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1274 GetWindowRect( hwnd
, &rc
);
1275 fodInfos
->DlgInfos
.hwndGrip
=
1276 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1277 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1278 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1279 rc
.right
- gripx
, rc
.bottom
- gripy
,
1280 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1283 fodInfos
->DlgInfos
.hwndCustomDlg
=
1284 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1286 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1287 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1289 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1290 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1292 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1293 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1294 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1297 /* if the app has changed the position of the invisible listbox,
1298 * change that of the listview (browser) as well */
1299 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1300 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1301 if( !EqualRect( &rc
, &rcstc
))
1303 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1304 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1305 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1306 SWP_NOACTIVATE
| SWP_NOZORDER
);
1309 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1311 GetWindowRect( hwnd
, &rc
);
1312 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1313 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1314 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1315 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1316 GetClientRect( hwnd
, &rc
);
1317 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1318 rc
.right
- gripx
, rc
.bottom
- gripy
,
1319 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1320 /* resize the dialog to the previous invocation */
1321 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1322 SetWindowPos( hwnd
, NULL
,
1323 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1324 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1327 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1328 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1333 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1334 case WM_GETMINMAXINFO
:
1335 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1337 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1340 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1343 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1349 case WM_GETISHELLBROWSER
:
1350 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1354 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1355 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1356 MemDialogSize
= fodInfos
->sizedlg
;
1357 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1362 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1365 /* set up the button tooltips strings */
1366 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1368 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1369 switch(lpnmh
->idFrom
)
1371 /* Up folder button */
1372 case FCIDM_TB_UPFOLDER
:
1373 stringId
= IDS_UPFOLDER
;
1375 /* New folder button */
1376 case FCIDM_TB_NEWFOLDER
:
1377 stringId
= IDS_NEWFOLDER
;
1379 /* List option button */
1380 case FCIDM_TB_SMALLICON
:
1381 stringId
= IDS_LISTVIEW
;
1383 /* Details option button */
1384 case FCIDM_TB_REPORTVIEW
:
1385 stringId
= IDS_REPORTVIEW
;
1387 /* Desktop button */
1388 case FCIDM_TB_DESKTOP
:
1389 stringId
= IDS_TODESKTOP
;
1394 lpdi
->hinst
= COMDLG32_hInstance
;
1395 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1400 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1401 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1406 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1408 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1409 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1412 /***********************************************************************
1413 * FILEDLG95_InitControls
1415 * WM_INITDIALOG message handler (before hook notification)
1417 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1419 BOOL win2000plus
= FALSE
;
1420 BOOL win98plus
= FALSE
;
1421 BOOL handledPath
= FALSE
;
1422 OSVERSIONINFOW osVi
;
1423 static const WCHAR szwSlash
[] = { '\\', 0 };
1424 static const WCHAR szwStar
[] = { '*',0 };
1426 static const TBBUTTON tbb
[] =
1428 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1429 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1430 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1431 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1432 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1433 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1434 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1435 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1436 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1438 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1443 HIMAGELIST toolbarImageList
;
1444 SHFILEINFOA shFileInfo
;
1445 ITEMIDLIST
*desktopPidl
;
1447 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1449 TRACE("%p\n", fodInfos
);
1451 /* Get windows version emulating */
1452 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1453 GetVersionExW(&osVi
);
1454 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1455 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1456 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1457 win2000plus
= (osVi
.dwMajorVersion
> 4);
1458 if (win2000plus
) win98plus
= TRUE
;
1460 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1463 /* Use either the edit or the comboboxex for the filename control */
1464 if (filename_is_edit( fodInfos
))
1466 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1467 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1471 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1472 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1475 /* Get the hwnd of the controls */
1476 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1477 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1479 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1480 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1482 /* construct the toolbar */
1483 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1484 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1486 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1487 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1488 rectTB
.left
= rectlook
.right
;
1489 rectTB
.top
= rectlook
.top
-1;
1491 if (fodInfos
->unicode
)
1492 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1493 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1494 rectTB
.left
, rectTB
.top
,
1495 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1496 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1498 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1499 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1500 rectTB
.left
, rectTB
.top
,
1501 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1502 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1504 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1506 /* FIXME: use TB_LOADIMAGES when implemented */
1507 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1508 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1509 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1511 /* Retrieve and add desktop icon to the toolbar */
1512 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1513 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1514 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1515 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1516 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1518 DestroyIcon(shFileInfo
.hIcon
);
1519 CoTaskMemFree(desktopPidl
);
1521 /* Finish Toolbar Construction */
1522 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1523 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1525 /* Set the window text with the text specified in the OPENFILENAME structure */
1528 SetWindowTextW(hwnd
,fodInfos
->title
);
1530 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1533 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1534 SetWindowTextW(hwnd
, buf
);
1537 /* Initialise the file name edit control */
1538 handledPath
= FALSE
;
1539 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1541 if(fodInfos
->filename
)
1543 /* 1. If win2000 or higher and filename contains a path, use it
1544 in preference over the lpstrInitialDir */
1545 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1546 WCHAR tmpBuf
[MAX_PATH
];
1550 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1553 /* nameBit is always shorter than the original filename */
1554 lstrcpyW(fodInfos
->filename
,nameBit
);
1557 MemFree(fodInfos
->initdir
);
1558 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1559 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1561 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1562 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1564 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1567 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1571 /* 2. (All platforms) If initdir is not null, then use it */
1572 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1574 /* Work out the proper path as supplied one might be relative */
1575 /* (Here because supplying '.' as dir browses to My Computer) */
1576 WCHAR tmpBuf
[MAX_PATH
];
1577 WCHAR tmpBuf2
[MAX_PATH
];
1581 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1582 if (PathFileExistsW(tmpBuf
)) {
1583 /* initdir does not have to be a directory. If a file is
1584 * specified, the dir part is taken */
1585 if (PathIsDirectoryW(tmpBuf
)) {
1586 PathAddBackslashW(tmpBuf
);
1587 lstrcatW(tmpBuf
, szwStar
);
1589 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1592 MemFree(fodInfos
->initdir
);
1593 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1594 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1596 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1599 else if (fodInfos
->initdir
)
1601 MemFree(fodInfos
->initdir
);
1602 fodInfos
->initdir
= NULL
;
1603 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1607 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1609 /* 3. All except w2k+: if filename contains a path use it */
1610 if (!win2000plus
&& fodInfos
->filename
&&
1611 *fodInfos
->filename
&&
1612 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1613 WCHAR tmpBuf
[MAX_PATH
];
1617 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1622 /* nameBit is always shorter than the original filename */
1623 lstrcpyW(fodInfos
->filename
, nameBit
);
1626 len
= lstrlenW(tmpBuf
);
1627 MemFree(fodInfos
->initdir
);
1628 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1629 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1632 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1633 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1635 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1638 /* 4. Win2000+: Recently used */
1639 if (!handledPath
&& win2000plus
) {
1640 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1641 fodInfos
->initdir
[0] = '\0';
1643 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1645 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1648 MemFree(fodInfos
->initdir
);
1649 fodInfos
->initdir
= NULL
;
1653 /* 5. win98+ and win2000+ if any files of specified filter types in
1654 current directory, use it */
1655 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1657 LPCWSTR lpstrPos
= fodInfos
->filter
;
1658 WIN32_FIND_DATAW FindFileData
;
1663 /* filter is a list... title\0ext\0......\0\0 */
1665 /* Skip the title */
1666 if(! *lpstrPos
) break; /* end */
1667 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1669 /* See if any files exist in the current dir with this extension */
1670 if(! *lpstrPos
) break; /* end */
1672 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1674 if (hFind
== INVALID_HANDLE_VALUE
) {
1675 /* None found - continue search */
1676 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1680 MemFree(fodInfos
->initdir
);
1681 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1682 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1685 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1686 debugstr_w(lpstrPos
));
1693 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1694 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1695 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1697 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1699 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1702 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1703 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1705 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1708 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1711 } else if (!handledPath
) {
1712 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1713 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1715 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1718 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1719 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1721 /* Must the open as read only check box be checked ?*/
1722 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1724 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1727 /* Must the open as read only check box be hidden? */
1728 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1730 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1731 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1734 /* Must the help button be hidden? */
1735 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1737 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1738 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1741 /* change Open to Save */
1742 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1745 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1746 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1747 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1748 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1751 /* Initialize the filter combo box */
1752 FILEDLG95_FILETYPE_Init(hwnd
);
1757 /***********************************************************************
1758 * FILEDLG95_ResizeControls
1760 * WM_INITDIALOG message handler (after hook notification)
1762 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1764 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1766 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1769 UINT flags
= SWP_NOACTIVATE
;
1771 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1772 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1774 /* resize the custom dialog to the parent size */
1775 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1776 GetClientRect(hwnd
, &rc
);
1779 /* our own fake template is zero sized and doesn't have children, so
1780 * there is no need to resize it. Picasa depends on it.
1782 flags
|= SWP_NOSIZE
;
1785 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1786 0, 0, rc
.right
, rc
.bottom
, flags
);
1790 /* Resize the height; if opened as read-only, checkbox and help button are
1791 * hidden and we are not using a custom template nor a customDialog
1793 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1794 (!(fodInfos
->ofnInfos
->Flags
&
1795 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1797 RECT rectDlg
, rectHelp
, rectCancel
;
1798 GetWindowRect(hwnd
, &rectDlg
);
1799 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1800 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1801 /* subtract the height of the help button plus the space between the help
1802 * button and the cancel button to the height of the dialog
1804 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1805 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1806 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1812 /***********************************************************************
1813 * FILEDLG95_FillControls
1815 * WM_INITDIALOG message handler (after hook notification)
1817 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1819 LPITEMIDLIST pidlItemId
= NULL
;
1821 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1823 TRACE("dir=%s file=%s\n",
1824 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1826 /* Get the initial directory pidl */
1828 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1830 WCHAR path
[MAX_PATH
];
1832 GetCurrentDirectoryW(MAX_PATH
,path
);
1833 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1836 /* Initialise shell objects */
1837 FILEDLG95_SHELL_Init(hwnd
);
1839 /* Initialize the Look In combo box */
1840 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1842 /* Browse to the initial directory */
1843 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1845 /* Free pidlItem memory */
1846 COMDLG32_SHFree(pidlItemId
);
1850 /***********************************************************************
1853 * Regroups all the cleaning functions of the filedlg
1855 void FILEDLG95_Clean(HWND hwnd
)
1857 FILEDLG95_FILETYPE_Clean(hwnd
);
1858 FILEDLG95_LOOKIN_Clean(hwnd
);
1859 FILEDLG95_SHELL_Clean(hwnd
);
1861 /***********************************************************************
1862 * FILEDLG95_OnWMCommand
1864 * WM_COMMAND message handler
1866 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1868 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1869 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1870 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1876 FILEDLG95_OnOpen(hwnd
);
1880 FILEDLG95_Clean(hwnd
);
1881 EndDialog(hwnd
, FALSE
);
1883 /* Filetype combo box */
1885 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1887 /* LookIn combo box */
1889 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1892 /* --- toolbar --- */
1893 /* Up folder button */
1894 case FCIDM_TB_UPFOLDER
:
1895 FILEDLG95_SHELL_UpFolder(hwnd
);
1897 /* New folder button */
1898 case FCIDM_TB_NEWFOLDER
:
1899 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1901 /* List option button */
1902 case FCIDM_TB_SMALLICON
:
1903 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1905 /* Details option button */
1906 case FCIDM_TB_REPORTVIEW
:
1907 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1909 /* Details option button */
1910 case FCIDM_TB_DESKTOP
:
1911 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1919 /* Do not use the listview selection anymore */
1920 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1924 /***********************************************************************
1925 * FILEDLG95_OnWMGetIShellBrowser
1927 * WM_GETISHELLBROWSER message handler
1929 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1931 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1935 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1941 /***********************************************************************
1942 * FILEDLG95_SendFileOK
1944 * Sends the CDN_FILEOK notification if required
1947 * TRUE if the dialog should close
1948 * FALSE if the dialog should not be closed
1950 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1952 /* ask the hook if we can close */
1953 if(IsHooked(fodInfos
))
1958 /* First send CDN_FILEOK as MSDN doc says */
1959 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1960 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1963 TRACE("canceled\n");
1967 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1968 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1969 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1972 TRACE("canceled\n");
1979 /***********************************************************************
1980 * FILEDLG95_OnOpenMultipleFiles
1982 * Handles the opening of multiple files.
1985 * check destination buffer size
1987 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1989 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1990 UINT nCount
, nSizePath
;
1991 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1995 if(fodInfos
->unicode
)
1997 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1998 ofn
->lpstrFile
[0] = '\0';
2002 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2003 ofn
->lpstrFile
[0] = '\0';
2006 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2008 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2009 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2010 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2012 LPWSTR lpstrTemp
= lpstrFileList
;
2014 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2018 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2021 WCHAR lpstrNotFound
[100];
2022 WCHAR lpstrMsg
[100];
2024 static const WCHAR nl
[] = {'\n',0};
2026 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2027 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2029 lstrcpyW(tmp
, lpstrTemp
);
2031 lstrcatW(tmp
, lpstrNotFound
);
2033 lstrcatW(tmp
, lpstrMsg
);
2035 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2039 /* move to the next file in the list of files */
2040 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2041 COMDLG32_SHFree(pidl
);
2045 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2046 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2048 /* For "oldstyle" dialog the components have to
2049 be separated by blanks (not '\0'!) and short
2050 filenames have to be used! */
2051 FIXME("Components have to be separated by blanks\n");
2053 if(fodInfos
->unicode
)
2055 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2056 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2057 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2061 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2063 if (ofn
->lpstrFile
!= NULL
)
2065 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2066 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2067 if (ofn
->nMaxFile
> nSizePath
)
2069 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2070 ofn
->lpstrFile
+ nSizePath
,
2071 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2076 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2077 fodInfos
->ofnInfos
->nFileExtension
= 0;
2079 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2082 /* clean and exit */
2083 FILEDLG95_Clean(hwnd
);
2084 return EndDialog(hwnd
,TRUE
);
2087 /* Returns the 'slot name' of the given module_name in the registry's
2088 * most-recently-used list. This will be an ASCII value in the
2089 * range ['a','z'). Returns zero on error.
2091 * The slot's value in the registry has the form:
2092 * module_name\0mru_path\0
2094 * If stored_path is given, then stored_path will contain the path name
2095 * stored in the registry's MRU list for the given module_name.
2097 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2098 * MRU list key for the given module_name.
2100 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2102 WCHAR mru_list
[32], *cur_mru_slot
;
2103 BOOL taken
[25] = {0};
2104 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2105 HKEY hkey_tmp
, *hkey
;
2114 *stored_path
= '\0';
2116 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2118 WARN("Unable to create MRU key: %d\n", ret
);
2122 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2123 (LPBYTE
)mru_list
, &mru_list_size
);
2124 if(ret
|| key_type
!= REG_SZ
){
2125 if(ret
== ERROR_FILE_NOT_FOUND
)
2128 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2133 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2134 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2135 DWORD value_data_size
= sizeof(value_data
);
2137 *value_name
= *cur_mru_slot
;
2139 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2140 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2141 if(ret
|| key_type
!= REG_BINARY
){
2142 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2146 if(!strcmpiW(module_name
, value_data
)){
2150 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2158 /* the module name isn't in the registry, so find the next open slot */
2159 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2160 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2161 for(i
= 0; i
< 25; ++i
){
2166 /* all slots are taken, so return the last one in MRUList */
2168 return *cur_mru_slot
;
2171 /* save the given filename as most-recently-used path for this module */
2172 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2174 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2178 /* get the current executable's name */
2179 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2180 WARN("GotModuleFileName failed: %d\n", GetLastError());
2183 module_name
= strrchrW(module_path
, '\\');
2185 module_name
= module_path
;
2189 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2194 { /* update the slot's info */
2195 WCHAR
*path_ends
, *final
;
2196 DWORD path_len
, final_len
;
2198 /* use only the path segment of `filename' */
2199 path_ends
= strrchrW(filename
, '\\');
2200 path_len
= path_ends
- filename
;
2202 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2204 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2207 lstrcpyW(final
, module_name
);
2208 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2209 final
[final_len
-1] = '\0';
2211 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2212 final_len
* sizeof(WCHAR
));
2214 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2223 { /* update MRUList value */
2224 WCHAR old_mru_list
[32], new_mru_list
[32];
2225 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2226 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2228 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2229 (LPBYTE
)old_mru_list
, &mru_list_size
);
2230 if(ret
|| key_type
!= REG_SZ
){
2231 if(ret
== ERROR_FILE_NOT_FOUND
){
2232 new_mru_list
[0] = slot
;
2233 new_mru_list
[1] = '\0';
2235 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2240 /* copy old list data over so that the new slot is at the start
2242 *new_mru_slot
++ = slot
;
2243 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2244 if(*old_mru_slot
!= slot
)
2245 *new_mru_slot
++ = *old_mru_slot
;
2247 *new_mru_slot
= '\0';
2250 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2251 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2253 WARN("Error saving MRUList data: %d\n", ret
);
2260 /* load the most-recently-used path for this module */
2261 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2263 WCHAR module_path
[MAX_PATH
], *module_name
;
2265 /* get the current executable's name */
2266 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2267 WARN("GotModuleFileName failed: %d\n", GetLastError());
2270 module_name
= strrchrW(module_path
, '\\');
2272 module_name
= module_path
;
2276 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2277 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2280 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2282 WCHAR strMsgTitle
[MAX_PATH
];
2283 WCHAR strMsgText
[MAX_PATH
];
2285 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2287 strMsgTitle
[0] = '\0';
2288 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2289 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2292 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2293 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2295 int nOpenAction
= defAction
;
2296 LPWSTR lpszTemp
, lpszTemp1
;
2297 LPITEMIDLIST pidl
= NULL
;
2298 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2300 /* check for invalid chars */
2301 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2303 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2307 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2309 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2312 LPSHELLFOLDER lpsfChild
;
2313 WCHAR lpwstrTemp
[MAX_PATH
];
2314 DWORD dwEaten
, dwAttributes
;
2317 lstrcpyW(lpwstrTemp
, lpszTemp
);
2318 p
= PathFindNextComponentW(lpwstrTemp
);
2320 if (!p
) break; /* end of path */
2323 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2325 /* There are no wildcards when OFN_NOVALIDATE is set */
2326 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2328 static const WCHAR wszWild
[] = { '*', '?', 0 };
2329 /* if the last element is a wildcard do a search */
2330 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2332 nOpenAction
= ONOPEN_SEARCH
;
2336 lpszTemp1
= lpszTemp
;
2338 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2340 /* append a backslash to drive letters */
2341 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2342 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2343 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2345 PathAddBackslashW(lpwstrTemp
);
2348 dwAttributes
= SFGAO_FOLDER
;
2349 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2351 /* the path component is valid, we have a pidl of the next path component */
2352 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2353 if(dwAttributes
& SFGAO_FOLDER
)
2355 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2357 ERR("bind to failed\n"); /* should not fail */
2360 IShellFolder_Release(*ppsf
);
2368 /* end dialog, return value */
2369 nOpenAction
= ONOPEN_OPEN
;
2372 COMDLG32_SHFree(pidl
);
2375 else if (!(flags
& OFN_NOVALIDATE
))
2377 if(*lpszTemp
|| /* points to trailing null for last path element */
2378 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2380 if(flags
& OFN_PATHMUSTEXIST
)
2382 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2388 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2390 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2394 /* change to the current folder */
2395 nOpenAction
= ONOPEN_OPEN
;
2400 nOpenAction
= ONOPEN_OPEN
;
2404 if(pidl
) COMDLG32_SHFree(pidl
);
2409 /***********************************************************************
2412 * Ok button WM_COMMAND message handler
2414 * If the function succeeds, the return value is nonzero.
2416 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2418 LPWSTR lpstrFileList
;
2419 UINT nFileCount
= 0;
2422 WCHAR lpstrPathAndFile
[MAX_PATH
];
2423 LPSHELLFOLDER lpsf
= NULL
;
2425 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2427 TRACE("hwnd=%p\n", hwnd
);
2429 /* try to browse the selected item */
2430 if(BrowseSelectedFolder(hwnd
))
2433 /* get the files from the edit control */
2434 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2441 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2445 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2448 Step 1: Build a complete path name from the current folder and
2449 the filename or path in the edit box.
2451 - the path in the edit box is a root path
2452 (with or without drive letter)
2453 - the edit box contains ".." (or a path with ".." in it)
2456 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2457 MemFree(lpstrFileList
);
2460 Step 2: here we have a cleaned up path
2462 We have to parse the path step by step to see if we have to browse
2463 to a folder if the path points to a directory or the last
2464 valid element is a directory.
2467 lpstrPathAndFile: cleaned up path
2471 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2472 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2473 nOpenAction
= ONOPEN_OPEN
;
2475 nOpenAction
= ONOPEN_BROWSE
;
2477 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2478 fodInfos
->ofnInfos
->Flags
,
2479 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2485 Step 3: here we have a cleaned up and validated path
2488 lpsf: ShellFolder bound to the rightmost valid path component
2489 lpstrPathAndFile: cleaned up path
2490 nOpenAction: action to do
2492 TRACE("end validate sf=%p\n", lpsf
);
2496 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2497 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2500 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2503 /* replace the current filter */
2504 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2505 len
= lstrlenW(lpszTemp
)+1;
2506 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2507 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2509 /* set the filter cb to the extension when possible */
2510 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2511 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2514 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2515 TRACE("ONOPEN_BROWSE\n");
2517 IPersistFolder2
* ppf2
;
2518 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2520 LPITEMIDLIST pidlCurrent
;
2521 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2522 IPersistFolder2_Release(ppf2
);
2523 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2525 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2526 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2528 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2531 else if( nOpenAction
== ONOPEN_SEARCH
)
2533 if (fodInfos
->Shell
.FOIShellView
)
2534 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2536 COMDLG32_SHFree(pidlCurrent
);
2537 if (filename_is_edit( fodInfos
))
2538 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2543 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2544 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2548 /* update READONLY check box flag */
2549 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2550 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2552 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2554 /* Attach the file extension with file name*/
2555 ext
= PathFindExtensionW(lpstrPathAndFile
);
2556 if (! *ext
&& fodInfos
->defext
)
2558 /* if no extension is specified with file name, then */
2559 /* attach the extension from file filter or default one */
2561 WCHAR
*filterExt
= NULL
;
2562 LPWSTR lpstrFilter
= NULL
;
2563 static const WCHAR szwDot
[] = {'.',0};
2564 int PathLength
= lstrlenW(lpstrPathAndFile
);
2566 /*Get the file extension from file type filter*/
2567 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2568 fodInfos
->ofnInfos
->nFilterIndex
-1);
2570 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2572 WCHAR
* filterSearchIndex
;
2573 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2574 strcpyW(filterExt
, lpstrFilter
);
2576 /* if a semicolon-separated list of file extensions was given, do not include the
2577 semicolon or anything after it in the extension.
2578 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2579 filterSearchIndex
= strchrW(filterExt
, ';');
2580 if (filterSearchIndex
)
2582 filterSearchIndex
[0] = '\0';
2585 /* find the file extension by searching for the first dot in filterExt */
2586 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2587 /* if the extension is invalid or contains a glob, ignore it */
2588 filterSearchIndex
= strchrW(filterExt
, '.');
2589 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2591 strcpyW(filterExt
, filterSearchIndex
);
2595 HeapFree(GetProcessHeap(), 0, filterExt
);
2602 /* use the default file extension */
2603 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2604 strcpyW(filterExt
, fodInfos
->defext
);
2607 if (*filterExt
) /* ignore filterExt="" */
2610 lstrcatW(lpstrPathAndFile
, szwDot
);
2611 /* Attach the extension */
2612 lstrcatW(lpstrPathAndFile
, filterExt
);
2615 HeapFree(GetProcessHeap(), 0, filterExt
);
2617 /* In Open dialog: if file does not exist try without extension */
2618 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2619 lpstrPathAndFile
[PathLength
] = '\0';
2621 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2624 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2625 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2627 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2630 /* In Save dialog: check if the file already exists */
2631 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2632 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2633 && PathFileExistsW(lpstrPathAndFile
))
2635 WCHAR lpstrOverwrite
[100];
2638 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2639 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2640 MB_YESNO
| MB_ICONEXCLAMATION
);
2641 if (answer
== IDNO
|| answer
== IDCANCEL
)
2648 /* In Open dialog: check if it should be created if it doesn't exist */
2649 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2650 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2651 && !PathFileExistsW(lpstrPathAndFile
))
2653 WCHAR lpstrCreate
[100];
2656 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2657 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2658 MB_YESNO
| MB_ICONEXCLAMATION
);
2659 if (answer
== IDNO
|| answer
== IDCANCEL
)
2666 /* Check that the size of the file does not exceed buffer size.
2667 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2668 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2669 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2672 /* fill destination buffer */
2673 if (fodInfos
->ofnInfos
->lpstrFile
)
2675 if(fodInfos
->unicode
)
2677 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2679 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2680 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2681 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2685 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2687 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2688 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2689 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2690 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2694 if(fodInfos
->unicode
)
2698 /* set filename offset */
2699 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2700 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2702 /* set extension offset */
2703 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2704 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2709 CHAR tempFileA
[MAX_PATH
];
2711 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2712 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2713 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2715 /* set filename offset */
2716 lpszTemp
= PathFindFileNameA(tempFileA
);
2717 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2719 /* set extension offset */
2720 lpszTemp
= PathFindExtensionA(tempFileA
);
2721 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2724 /* copy currently selected filter to lpstrCustomFilter */
2725 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2727 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2728 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2729 NULL
, 0, NULL
, NULL
);
2730 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2732 LPSTR s
= ofn
->lpstrCustomFilter
;
2733 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2734 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2735 s
, len
, NULL
, NULL
);
2740 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2743 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2746 FILEDLG95_Clean(hwnd
);
2747 ret
= EndDialog(hwnd
, TRUE
);
2753 size
= lstrlenW(lpstrPathAndFile
) + 1;
2754 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2756 /* return needed size in first two bytes of lpstrFile */
2757 if(fodInfos
->ofnInfos
->lpstrFile
)
2758 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2759 FILEDLG95_Clean(hwnd
);
2760 ret
= EndDialog(hwnd
, FALSE
);
2761 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2768 if(lpsf
) IShellFolder_Release(lpsf
);
2772 /***********************************************************************
2773 * FILEDLG95_SHELL_Init
2775 * Initialisation of the shell objects
2777 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2779 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2784 * Initialisation of the FileOpenDialogInfos structure
2790 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2792 /* Disable multi-select if flag not set */
2793 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2795 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2797 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2798 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2800 /* Construct the IShellBrowser interface */
2801 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2806 /***********************************************************************
2807 * FILEDLG95_SHELL_ExecuteCommand
2809 * Change the folder option and refresh the view
2810 * If the function succeeds, the return value is nonzero.
2812 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2814 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2817 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2819 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2824 CMINVOKECOMMANDINFO ci
;
2825 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2826 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2830 IContextMenu_InvokeCommand(pcm
, &ci
);
2831 IContextMenu_Release(pcm
);
2837 /***********************************************************************
2838 * FILEDLG95_SHELL_UpFolder
2840 * Browse to the specified object
2841 * If the function succeeds, the return value is nonzero.
2843 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2845 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2849 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2853 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2854 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2860 /***********************************************************************
2861 * FILEDLG95_SHELL_BrowseToDesktop
2863 * Browse to the Desktop
2864 * If the function succeeds, the return value is nonzero.
2866 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2868 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2874 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2875 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2876 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2877 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2878 COMDLG32_SHFree(pidl
);
2879 return SUCCEEDED(hres
);
2881 /***********************************************************************
2882 * FILEDLG95_SHELL_Clean
2884 * Cleans the memory used by shell objects
2886 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2888 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2892 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2894 /* clean Shell interfaces */
2895 if (fodInfos
->Shell
.FOIShellView
)
2897 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2898 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2900 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2901 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2902 if (fodInfos
->Shell
.FOIDataObject
)
2903 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2906 /***********************************************************************
2907 * FILEDLG95_FILETYPE_Init
2909 * Initialisation of the file type combo box
2911 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2913 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2914 int nFilters
= 0; /* number of filters */
2919 if(fodInfos
->customfilter
)
2921 /* customfilter has one entry... title\0ext\0
2922 * Set first entry of combo box item with customfilter
2925 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2928 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2930 /* Copy the extensions */
2931 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2932 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2933 lstrcpyW(lpstrExt
,lpstrPos
);
2935 /* Add the item at the end of the combo */
2936 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2937 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2940 if(fodInfos
->filter
)
2942 LPCWSTR lpstrPos
= fodInfos
->filter
;
2946 /* filter is a list... title\0ext\0......\0\0
2947 * Set the combo item text to the title and the item data
2950 LPCWSTR lpstrDisplay
;
2954 if(! *lpstrPos
) break; /* end */
2955 lpstrDisplay
= lpstrPos
;
2956 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2958 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2962 /* Copy the extensions */
2963 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2964 lstrcpyW(lpstrExt
,lpstrPos
);
2965 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2967 /* Add the item at the end of the combo */
2968 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2970 /* malformed filters are added anyway... */
2971 if (!*lpstrExt
) break;
2976 * Set the current filter to the one specified
2977 * in the initialisation structure
2979 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2983 /* Check to make sure our index isn't out of bounds. */
2984 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2985 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2986 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2988 /* set default filter index */
2989 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2990 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2992 /* calculate index of Combo Box item */
2993 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2994 if (fodInfos
->customfilter
== NULL
)
2997 /* Set the current index selection. */
2998 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3000 /* Get the corresponding text string from the combo box. */
3001 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3004 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3010 CharLowerW(lpstrFilter
); /* lowercase */
3011 len
= lstrlenW(lpstrFilter
)+1;
3012 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3013 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3016 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3020 /***********************************************************************
3021 * FILEDLG95_FILETYPE_OnCommand
3023 * WM_COMMAND of the file type combo box
3024 * If the function succeeds, the return value is nonzero.
3026 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3028 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3036 /* Get the current item of the filetype combo box */
3037 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3039 /* set the current filter index */
3040 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3041 (fodInfos
->customfilter
== NULL
? 1 : 0);
3043 /* Set the current filter with the current selection */
3044 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3046 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3048 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3051 CharLowerW(lpstrFilter
); /* lowercase */
3052 len
= lstrlenW(lpstrFilter
)+1;
3053 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3054 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3055 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3056 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3059 /* Refresh the actual view to display the included items*/
3060 if (fodInfos
->Shell
.FOIShellView
)
3061 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3066 /***********************************************************************
3067 * FILEDLG95_FILETYPE_SearchExt
3069 * searches for an extension in the filetype box
3071 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3073 int i
, iCount
= CBGetCount(hwnd
);
3075 TRACE("%s\n", debugstr_w(lpstrExt
));
3077 if(iCount
!= CB_ERR
)
3079 for(i
=0;i
<iCount
;i
++)
3081 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3088 /***********************************************************************
3089 * FILEDLG95_FILETYPE_Clean
3091 * Clean the memory used by the filetype combo box
3093 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3095 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3097 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3101 /* Delete each string of the combo and their associated data */
3102 if(iCount
!= CB_ERR
)
3104 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3106 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3107 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3110 /* Current filter */
3111 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3115 /***********************************************************************
3116 * FILEDLG95_LOOKIN_Init
3118 * Initialisation of the look in combo box
3121 /* Small helper function, to determine if the unixfs shell extension is rooted
3122 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3124 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3126 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3127 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3128 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3129 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3130 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3131 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3132 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3134 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3141 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3143 IShellFolder
*psfRoot
, *psfDrives
;
3144 IEnumIDList
*lpeRoot
, *lpeDrives
;
3145 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3148 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3152 liInfos
->iMaxIndentation
= 0;
3154 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3156 hdc
= GetDC( hwndCombo
);
3157 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3158 GetTextMetricsW( hdc
, &tm
);
3159 ReleaseDC( hwndCombo
, hdc
);
3161 /* set item height for both text field and listbox */
3162 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3163 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3165 /* Turn on the extended UI for the combo box like Windows does */
3166 CBSetExtendedUI(hwndCombo
, TRUE
);
3168 /* Initialise data of Desktop folder */
3169 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3170 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3171 COMDLG32_SHFree(pidlTmp
);
3173 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3175 SHGetDesktopFolder(&psfRoot
);
3179 /* enumerate the contents of the desktop */
3180 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3182 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3184 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3186 /* If the unixfs extension is rooted, we don't expand the drives by default */
3187 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3189 /* special handling for CSIDL_DRIVES */
3190 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3192 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3194 /* enumerate the drives */
3195 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3197 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3199 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3200 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3201 COMDLG32_SHFree(pidlAbsTmp
);
3202 COMDLG32_SHFree(pidlTmp1
);
3204 IEnumIDList_Release(lpeDrives
);
3206 IShellFolder_Release(psfDrives
);
3211 COMDLG32_SHFree(pidlTmp
);
3213 IEnumIDList_Release(lpeRoot
);
3215 IShellFolder_Release(psfRoot
);
3218 COMDLG32_SHFree(pidlDrives
);
3221 /***********************************************************************
3222 * FILEDLG95_LOOKIN_DrawItem
3224 * WM_DRAWITEM message handler
3226 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3228 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3229 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3230 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3234 HIMAGELIST ilItemImage
;
3237 LPSFOLDER tmpFolder
;
3238 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3239 UINT icon_width
, icon_height
;
3243 if(pDIStruct
->itemID
== -1)
3246 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3247 pDIStruct
->itemID
)))
3251 icon_width
= GetSystemMetrics(SM_CXICON
);
3252 icon_height
= GetSystemMetrics(SM_CYICON
);
3253 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3255 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3256 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3257 shgfi_flags
|= SHGFI_SMALLICON
;
3260 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3261 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3263 /* Is this item selected ? */
3264 if(pDIStruct
->itemState
& ODS_SELECTED
)
3266 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3267 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3268 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3272 SetTextColor(pDIStruct
->hDC
,crText
);
3273 SetBkColor(pDIStruct
->hDC
,crWin
);
3274 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3277 /* Do not indent item if drawing in the edit of the combo */
3278 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3281 iIndentation
= tmpFolder
->m_iIndent
;
3283 /* Draw text and icon */
3285 /* Initialise the icon display area */
3286 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3287 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3288 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3289 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3291 /* Initialise the text display area */
3292 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3293 rectText
.left
= rectIcon
.right
;
3295 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3296 rectText
.right
= pDIStruct
->rcItem
.right
;
3298 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3300 /* Draw the icon from the image list */
3301 ImageList_Draw(ilItemImage
,
3308 /* Draw the associated text */
3309 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3313 /***********************************************************************
3314 * FILEDLG95_LOOKIN_OnCommand
3316 * LookIn combo box WM_COMMAND message handler
3317 * If the function succeeds, the return value is nonzero.
3319 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3321 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3323 TRACE("%p\n", fodInfos
);
3329 LPSFOLDER tmpFolder
;
3332 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3334 if( iItem
== CB_ERR
) return FALSE
;
3336 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3341 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3342 tmpFolder
->pidlItem
,
3345 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3346 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3356 /***********************************************************************
3357 * FILEDLG95_LOOKIN_AddItem
3359 * Adds an absolute pidl item to the lookin combo box
3360 * returns the index of the inserted item
3362 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3364 LPITEMIDLIST pidlNext
;
3367 LookInInfos
*liInfos
;
3369 TRACE("%08x\n", iInsertId
);
3374 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3377 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3378 tmpFolder
->m_iIndent
= 0;
3380 /* Calculate the indentation of the item in the lookin*/
3382 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3384 tmpFolder
->m_iIndent
++;
3387 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3389 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3390 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3392 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3393 SHGetFileInfoW((LPCWSTR
)pidl
,
3397 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3398 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3400 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3402 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3406 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3408 /* Add the item at the end of the list */
3411 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3413 /* Insert the item at the iInsertId position*/
3416 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3419 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3423 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3424 MemFree( tmpFolder
);
3429 /***********************************************************************
3430 * FILEDLG95_LOOKIN_InsertItemAfterParent
3432 * Insert an item below its parent
3434 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3437 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3442 if (pidl
== pidlParent
)
3445 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3449 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3452 /* Free pidlParent memory */
3453 COMDLG32_SHFree(pidlParent
);
3455 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3458 /***********************************************************************
3459 * FILEDLG95_LOOKIN_SelectItem
3461 * Adds an absolute pidl item to the lookin combo box
3462 * returns the index of the inserted item
3464 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3467 LookInInfos
*liInfos
;
3471 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3473 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3477 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3478 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3483 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3484 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3488 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3490 if(iRemovedItem
< iItemPos
)
3495 CBSetCurSel(hwnd
,iItemPos
);
3496 liInfos
->uSelectedItem
= iItemPos
;
3502 /***********************************************************************
3503 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3505 * Remove the item with an expansion level over iExpansionLevel
3507 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3510 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3514 if(liInfos
->iMaxIndentation
<= 2)
3517 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3519 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3520 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3522 CBDeleteString(hwnd
,iItemPos
);
3523 liInfos
->iMaxIndentation
--;
3531 /***********************************************************************
3532 * FILEDLG95_LOOKIN_SearchItem
3534 * Search for pidl in the lookin combo box
3535 * returns the index of the found item
3537 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3540 int iCount
= CBGetCount(hwnd
);
3542 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3544 if (iCount
!= CB_ERR
)
3548 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3550 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3552 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3560 /***********************************************************************
3561 * FILEDLG95_LOOKIN_Clean
3563 * Clean the memory used by the lookin combo box
3565 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3567 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3568 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3570 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3574 /* Delete each string of the combo and their associated data */
3575 if (iCount
!= CB_ERR
)
3577 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3579 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3580 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3582 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3586 /* LookInInfos structure */
3588 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3591 /***********************************************************************
3594 * Fill the FORMATETC used in the shell id list
3596 static FORMATETC
get_def_format(void)
3598 static CLIPFORMAT cfFormat
;
3599 FORMATETC formatetc
;
3601 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3602 formatetc
.cfFormat
= cfFormat
;
3604 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3605 formatetc
.lindex
= -1;
3606 formatetc
.tymed
= TYMED_HGLOBAL
;
3610 /***********************************************************************
3611 * FILEDLG95_FILENAME_FillFromSelection
3613 * fills the edit box from the cached DataObject
3615 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3617 FileOpenDlgInfos
*fodInfos
;
3619 LPWSTR lpstrAllFiles
, lpstrTmp
;
3620 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3623 FORMATETC formatetc
= get_def_format();
3626 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3628 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3631 cida
= GlobalLock(medium
.u
.hGlobal
);
3632 nFileSelected
= cida
->cidl
;
3634 /* Allocate a buffer */
3635 nAllFilesMaxLength
= MAX_PATH
+ 3;
3636 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3640 /* Loop through the selection, handle only files (not folders) */
3641 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3643 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3646 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3648 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3650 nAllFilesMaxLength
*= 2;
3651 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3654 lpstrAllFiles
= lpstrTmp
;
3657 lpstrAllFiles
[nAllFilesLength
++] = '"';
3658 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3659 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3660 nAllFilesLength
+= nThisFileLength
;
3661 lpstrAllFiles
[nAllFilesLength
++] = '"';
3662 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3669 /* If there's only one file, use the name as-is without quotes */
3670 lpstrTmp
= lpstrAllFiles
;
3674 lpstrTmp
[nThisFileLength
] = 0;
3676 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3677 /* Select the file name like Windows does */
3678 if (filename_is_edit(fodInfos
))
3679 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3683 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3684 COMCTL32_ReleaseStgMedium(medium
);
3688 /* copied from shell32 to avoid linking to it
3689 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3690 * is dependent on whether emulated OS is unicode or not.
3692 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3697 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3698 COMDLG32_SHFree(src
->u
.pOleStr
);
3702 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3707 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3712 FIXME("unknown type %x!\n", src
->uType
);
3713 if (len
) *dest
= '\0';
3719 /***********************************************************************
3720 * FILEDLG95_FILENAME_GetFileNames
3722 * Copies the filenames to a delimited string list.
3724 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3726 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3727 UINT nFileCount
= 0; /* number of files */
3728 UINT nStrLen
= 0; /* length of string in edit control */
3729 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3733 /* get the filenames from the filename control */
3734 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3735 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3736 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3738 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3740 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3746 * DATAOBJECT Helper functions
3749 /***********************************************************************
3750 * COMCTL32_ReleaseStgMedium
3752 * like ReleaseStgMedium from ole32
3754 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3756 if(medium
.pUnkForRelease
)
3758 IUnknown_Release(medium
.pUnkForRelease
);
3762 GlobalUnlock(medium
.u
.hGlobal
);
3763 GlobalFree(medium
.u
.hGlobal
);
3767 /***********************************************************************
3768 * GetPidlFromDataObject
3770 * Return pidl(s) by number from the cached DataObject
3772 * nPidlIndex=0 gets the fully qualified root path
3774 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3778 FORMATETC formatetc
= get_def_format();
3779 LPITEMIDLIST pidl
= NULL
;
3781 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3786 /* Get the pidls from IDataObject */
3787 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3789 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3790 if(nPidlIndex
<= cida
->cidl
)
3792 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3794 COMCTL32_ReleaseStgMedium(medium
);
3799 /***********************************************************************
3802 * Return the number of selected items in the DataObject.
3805 static UINT
GetNumSelected( IDataObject
*doSelected
)
3809 FORMATETC formatetc
= get_def_format();
3811 TRACE("sv=%p\n", doSelected
);
3813 if (!doSelected
) return 0;
3815 /* Get the pidls from IDataObject */
3816 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3818 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3819 retVal
= cida
->cidl
;
3820 COMCTL32_ReleaseStgMedium(medium
);
3830 /***********************************************************************
3833 * Get the pidl's display name (relative to folder) and
3834 * put it in lpstrFileName.
3836 * Return NOERROR on success,
3840 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3845 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3849 SHGetDesktopFolder(&lpsf
);
3850 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3851 IShellFolder_Release(lpsf
);
3855 /* Get the display name of the pidl relative to the folder */
3856 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3858 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3863 /***********************************************************************
3864 * GetShellFolderFromPidl
3866 * pidlRel is the item pidl relative
3867 * Return the IShellFolder of the absolute pidl
3869 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3871 IShellFolder
*psf
= NULL
,*psfParent
;
3873 TRACE("%p\n", pidlAbs
);
3875 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3878 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3880 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3882 IShellFolder_Release(psfParent
);
3886 /* return the desktop */
3892 /***********************************************************************
3895 * Return the LPITEMIDLIST to the parent of the pidl in the list
3897 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3899 LPITEMIDLIST pidlParent
;
3901 TRACE("%p\n", pidl
);
3903 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3904 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3909 /***********************************************************************
3912 * returns the pidl of the file name relative to folder
3913 * NULL if an error occurred
3915 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3917 LPITEMIDLIST pidl
= NULL
;
3920 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3922 if(!lpcstrFileName
) return NULL
;
3923 if(!*lpcstrFileName
) return NULL
;
3927 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3928 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3929 IShellFolder_Release(lpsf
);
3934 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3941 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3943 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3946 TRACE("%p, %p\n", psf
, pidl
);
3948 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3950 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3951 /* see documentation shell 4.1*/
3952 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3955 /***********************************************************************
3956 * BrowseSelectedFolder
3958 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3960 BOOL bBrowseSelFolder
= FALSE
;
3961 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3965 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3967 LPITEMIDLIST pidlSelection
;
3969 /* get the file selected */
3970 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3971 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3973 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3974 pidlSelection
, SBSP_RELATIVE
) ) )
3976 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3977 ' ','n','o','t',' ','e','x','i','s','t',0};
3978 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3980 bBrowseSelFolder
= TRUE
;
3981 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3982 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3984 COMDLG32_SHFree( pidlSelection
);
3987 return bBrowseSelFolder
;
3991 * Memory allocation methods */
3992 static void *MemAlloc(UINT size
)
3994 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3997 static void MemFree(void *mem
)
3999 HeapFree(GetProcessHeap(),0,mem
);
4002 static inline BOOL
valid_struct_size( DWORD size
)
4004 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4005 (size
== sizeof( OPENFILENAMEW
));
4008 static inline BOOL
is_win16_looks(DWORD flags
)
4010 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4011 !(flags
& OFN_EXPLORER
));
4014 /* ------------------ APIs ---------------------- */
4016 /***********************************************************************
4017 * GetOpenFileNameA (COMDLG32.@)
4019 * Creates a dialog box for the user to select a file to open.
4022 * TRUE on success: user enters a valid file
4023 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4026 BOOL WINAPI
GetOpenFileNameA(
4027 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4029 TRACE("flags %08x\n", ofn
->Flags
);
4031 if (!valid_struct_size( ofn
->lStructSize
))
4033 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4037 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4038 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4039 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4041 if (is_win16_looks(ofn
->Flags
))
4042 return GetFileName31A(ofn
, OPEN_DIALOG
);
4044 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4047 /***********************************************************************
4048 * GetOpenFileNameW (COMDLG32.@)
4050 * Creates a dialog box for the user to select a file to open.
4053 * TRUE on success: user enters a valid file
4054 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4057 BOOL WINAPI
GetOpenFileNameW(
4058 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4060 TRACE("flags %08x\n", ofn
->Flags
);
4062 if (!valid_struct_size( ofn
->lStructSize
))
4064 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4068 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4069 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4070 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4072 if (is_win16_looks(ofn
->Flags
))
4073 return GetFileName31W(ofn
, OPEN_DIALOG
);
4075 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4079 /***********************************************************************
4080 * GetSaveFileNameA (COMDLG32.@)
4082 * Creates a dialog box for the user to select a file to save.
4085 * TRUE on success: user enters a valid file
4086 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4089 BOOL WINAPI
GetSaveFileNameA(
4090 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4092 if (!valid_struct_size( ofn
->lStructSize
))
4094 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4098 if (is_win16_looks(ofn
->Flags
))
4099 return GetFileName31A(ofn
, SAVE_DIALOG
);
4101 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4104 /***********************************************************************
4105 * GetSaveFileNameW (COMDLG32.@)
4107 * Creates a dialog box for the user to select a file to save.
4110 * TRUE on success: user enters a valid file
4111 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4114 BOOL WINAPI
GetSaveFileNameW(
4115 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4117 if (!valid_struct_size( ofn
->lStructSize
))
4119 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4123 if (is_win16_looks(ofn
->Flags
))
4124 return GetFileName31W(ofn
, SAVE_DIALOG
);
4126 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4129 /***********************************************************************
4130 * GetFileTitleA (COMDLG32.@)
4132 * See GetFileTitleW.
4134 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4137 UNICODE_STRING strWFile
;
4140 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4141 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4142 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4143 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4144 RtlFreeUnicodeString( &strWFile
);
4145 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4150 /***********************************************************************
4151 * GetFileTitleW (COMDLG32.@)
4153 * Get the name of a file.
4156 * lpFile [I] name and location of file
4157 * lpTitle [O] returned file name
4158 * cbBuf [I] buffer size of lpTitle
4162 * Failure: negative number.
4164 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4167 static const WCHAR brkpoint
[] = {'*','[',']',0};
4168 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4170 if(lpFile
== NULL
|| lpTitle
== NULL
)
4173 len
= lstrlenW(lpFile
);
4178 if(strpbrkW(lpFile
, brkpoint
))
4183 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4186 for(i
= len
; i
>= 0; i
--)
4188 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4198 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4200 len
= lstrlenW(lpFile
+i
)+1;
4204 lstrcpyW(lpTitle
, &lpFile
[i
]);