2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
73 #include "filedlgbrowser.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex
; /* Index of picture in image list */
95 int m_iIndent
; /* Indentation index */
96 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
100 typedef struct tagLookInInfo
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
166 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
167 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
169 static const WCHAR LastVisitedMRUW
[] =
170 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
173 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
174 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
176 /***********************************************************************
180 /* Internal functions used by the dialog */
181 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
182 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
183 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
184 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
185 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
186 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
187 static void FILEDLG95_Clean(HWND hwnd
);
189 /* Functions used by the shell navigation */
190 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
191 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
192 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
199 /* Functions used by the filetype combo box */
200 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
201 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
207 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
208 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
216 /* Functions for dealing with the most-recently-used registry keys */
217 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
218 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
219 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
221 /* Miscellaneous tool functions */
222 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
223 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
224 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
225 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
226 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
227 static UINT
GetNumSelected( IDataObject
*doSelected
);
229 /* Shell memory allocation */
230 static void *MemAlloc(UINT size
);
231 static void MemFree(void *mem
);
233 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
234 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
235 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
236 static BOOL
BrowseSelectedFolder(HWND hwnd
);
238 /***********************************************************************
241 * Creates an Open common dialog box that lets the user select
242 * the drive, directory, and the name of a file or set of files to open.
244 * IN : The FileOpenDlgInfos structure associated with the dialog
245 * OUT : TRUE on success
246 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
248 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
252 LPCVOID origTemplate
;
254 LPDLGTEMPLATEW
template;
259 /* test for missing functionality */
260 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
262 FIXME("Flags 0x%08x not yet implemented\n",
263 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
266 /* Create the dialog from a template */
268 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
270 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
273 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
274 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
275 !(origTemplate
= LockResource(hDlgTmpl
)))
277 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
280 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
282 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
285 memcpy(template, origTemplate
, dwSize
);
287 /* msdn: explorer style dialogs permit sizing by default.
288 * The OFN_ENABLESIZING flag is only needed when a hook or
289 * custom tmeplate is provided */
290 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
291 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
292 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
294 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
296 template->style
|= WS_SIZEBOX
;
297 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
298 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
301 template->style
&= ~WS_SIZEBOX
;
304 /* old style hook messages */
305 if (IsHooked(fodInfos
))
307 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
308 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
309 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
310 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
313 /* Some shell namespace extensions depend on COM being initialized. */
314 hr
= OleInitialize(NULL
);
316 if (fodInfos
->unicode
)
317 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
319 fodInfos
->ofnInfos
->hwndOwner
,
323 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
325 fodInfos
->ofnInfos
->hwndOwner
,
331 HeapFree(GetProcessHeap(), 0, template);
333 /* Unable to create the dialog */
340 /***********************************************************************
343 * Call GetFileName95 with this structure and clean the memory.
345 * IN : The OPENFILENAMEA initialisation structure passed to
346 * GetOpenFileNameA win api function (see filedlg.c)
348 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
351 FileOpenDlgInfos fodInfos
;
352 LPSTR lpstrSavDir
= NULL
;
354 LPWSTR defext
= NULL
;
355 LPWSTR filter
= NULL
;
356 LPWSTR customfilter
= NULL
;
357 INITCOMMONCONTROLSEX icc
;
359 /* Initialize ComboBoxEx32 */
360 icc
.dwSize
= sizeof(icc
);
361 icc
.dwICC
= ICC_USEREX_CLASSES
;
362 InitCommonControlsEx(&icc
);
364 /* Initialize CommDlgExtendedError() */
365 COMDLG32_SetCommDlgExtendedError(0);
367 /* Initialize FileOpenDlgInfos structure */
368 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
370 /* Pass in the original ofn */
371 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
373 /* save current directory */
374 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
376 lpstrSavDir
= MemAlloc(MAX_PATH
);
377 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
380 fodInfos
.unicode
= FALSE
;
382 /* convert all the input strings to unicode */
383 if(ofn
->lpstrInitialDir
)
385 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
386 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
387 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
390 fodInfos
.initdir
= NULL
;
394 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
395 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
398 fodInfos
.filename
= NULL
;
402 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
403 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
404 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
406 fodInfos
.defext
= defext
;
410 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
411 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
412 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
414 fodInfos
.title
= title
;
416 if (ofn
->lpstrFilter
)
421 /* filter is a list... title\0ext\0......\0\0 */
422 s
= ofn
->lpstrFilter
;
423 while (*s
) s
= s
+strlen(s
)+1;
425 n
= s
- ofn
->lpstrFilter
;
426 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
427 filter
= MemAlloc(len
*sizeof(WCHAR
));
428 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
430 fodInfos
.filter
= filter
;
432 /* convert lpstrCustomFilter */
433 if (ofn
->lpstrCustomFilter
)
438 /* customfilter contains a pair of strings... title\0ext\0 */
439 s
= ofn
->lpstrCustomFilter
;
440 if (*s
) s
= s
+strlen(s
)+1;
441 if (*s
) s
= s
+strlen(s
)+1;
442 n
= s
- ofn
->lpstrCustomFilter
;
443 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
444 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
445 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
447 fodInfos
.customfilter
= customfilter
;
449 /* Initialize the dialog property */
450 fodInfos
.DlgInfos
.dwDlgProp
= 0;
451 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
456 ret
= GetFileName95(&fodInfos
);
459 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
460 ret
= GetFileName95(&fodInfos
);
468 SetCurrentDirectoryA(lpstrSavDir
);
469 MemFree(lpstrSavDir
);
475 MemFree(customfilter
);
476 MemFree(fodInfos
.initdir
);
477 MemFree(fodInfos
.filename
);
479 TRACE("selected file: %s\n",ofn
->lpstrFile
);
484 /***********************************************************************
487 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
488 * Call GetFileName95 with this structure and clean the memory.
491 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
494 FileOpenDlgInfos fodInfos
;
495 LPWSTR lpstrSavDir
= NULL
;
496 INITCOMMONCONTROLSEX icc
;
498 /* Initialize ComboBoxEx32 */
499 icc
.dwSize
= sizeof(icc
);
500 icc
.dwICC
= ICC_USEREX_CLASSES
;
501 InitCommonControlsEx(&icc
);
503 /* Initialize CommDlgExtendedError() */
504 COMDLG32_SetCommDlgExtendedError(0);
506 /* Initialize FileOpenDlgInfos structure */
507 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
509 /* Pass in the original ofn */
510 fodInfos
.ofnInfos
= ofn
;
512 fodInfos
.title
= ofn
->lpstrTitle
;
513 fodInfos
.defext
= ofn
->lpstrDefExt
;
514 fodInfos
.filter
= ofn
->lpstrFilter
;
515 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
517 /* convert string arguments, save others */
520 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
521 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
524 fodInfos
.filename
= NULL
;
526 if(ofn
->lpstrInitialDir
)
528 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
529 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
530 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
531 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
534 fodInfos
.initdir
= NULL
;
536 /* save current directory */
537 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
539 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
540 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
543 fodInfos
.unicode
= TRUE
;
548 ret
= GetFileName95(&fodInfos
);
551 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
552 ret
= GetFileName95(&fodInfos
);
560 SetCurrentDirectoryW(lpstrSavDir
);
561 MemFree(lpstrSavDir
);
564 /* restore saved IN arguments and convert OUT arguments back */
565 MemFree(fodInfos
.filename
);
566 MemFree(fodInfos
.initdir
);
570 /******************************************************************************
571 * COMDLG32_GetDisplayNameOf [internal]
573 * Helper function to get the display name for a pidl.
575 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
576 LPSHELLFOLDER psfDesktop
;
579 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
582 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
583 IShellFolder_Release(psfDesktop
);
587 IShellFolder_Release(psfDesktop
);
588 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
591 /******************************************************************************
592 * COMDLG32_GetCanonicalPath [internal]
594 * Helper function to get the canonical path.
596 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
597 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
599 WCHAR lpstrTemp
[MAX_PATH
];
601 /* Get the current directory name */
602 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
605 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
607 PathAddBackslashW(lpstrPathAndFile
);
609 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
611 /* if the user specified a fully qualified path use it */
612 if(PathIsRelativeW(lpstrFile
))
614 lstrcatW(lpstrPathAndFile
, lpstrFile
);
618 /* does the path have a drive letter? */
619 if (PathGetDriveNumberW(lpstrFile
) == -1)
620 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
622 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
625 /* resolve "." and ".." */
626 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
627 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
628 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
631 /***********************************************************************
632 * COMDLG32_SplitFileNames [internal]
634 * Creates a delimited list of filenames.
636 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
638 UINT nStrCharCount
= 0; /* index in src buffer */
639 UINT nFileIndex
= 0; /* index in dest buffer */
640 UINT nFileCount
= 0; /* number of files */
642 /* we might get single filename without any '"',
643 * so we need nStrLen + terminating \0 + end-of-list \0 */
644 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
647 /* build delimited file list from filenames */
648 while ( nStrCharCount
<= nStrLen
)
650 if ( lpstrEdit
[nStrCharCount
]=='"' )
653 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
655 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
658 (*lpstrFileList
)[nFileIndex
++] = 0;
664 /* single, unquoted string */
665 if ((nStrLen
> 0) && (nFileIndex
== 0) )
667 lstrcpyW(*lpstrFileList
, lpstrEdit
);
668 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
673 (*lpstrFileList
)[nFileIndex
++] = '\0';
675 *sizeUsed
= nFileIndex
;
679 /***********************************************************************
680 * ArrangeCtrlPositions [internal]
682 * NOTE: Make sure to add testcases for any changes made here.
684 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
686 HWND hwndChild
, hwndStc32
;
687 RECT rectParent
, rectChild
, rectStc32
;
691 /* Take into account if open as read only checkbox and help button
696 RECT rectHelp
, rectCancel
;
697 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
698 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
699 /* subtract the height of the help button plus the space between
700 * the help button and the cancel button to the height of the dialog
702 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
706 There are two possibilities to add components to the default file dialog box.
708 By default, all the new components are added below the standard dialog box (the else case).
710 However, if there is a static text component with the stc32 id, a special case happens.
711 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
712 in the window and the cx and cy indicate how to size the window.
713 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
714 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
718 GetClientRect(hwndParentDlg
, &rectParent
);
720 /* when arranging controls we have to use fixed parent size */
721 rectParent
.bottom
-= help_fixup
;
723 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
726 GetWindowRect(hwndStc32
, &rectStc32
);
727 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
729 /* set the size of the stc32 control according to the size of
730 * client area of the parent dialog
732 SetWindowPos(hwndStc32
, 0,
734 rectParent
.right
, rectParent
.bottom
,
735 SWP_NOMOVE
| SWP_NOZORDER
);
738 SetRectEmpty(&rectStc32
);
740 /* this part moves controls of the child dialog */
741 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
744 if (hwndChild
!= hwndStc32
)
746 GetWindowRect(hwndChild
, &rectChild
);
747 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
749 /* move only if stc32 exist */
750 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
752 /* move to the right of visible controls of the parent dialog */
753 rectChild
.left
+= rectParent
.right
;
754 rectChild
.left
-= rectStc32
.right
;
756 /* move even if stc32 doesn't exist */
757 if (rectChild
.top
>= rectStc32
.bottom
)
759 /* move below visible controls of the parent dialog */
760 rectChild
.top
+= rectParent
.bottom
;
761 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
764 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
765 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
767 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
770 /* this part moves controls of the parent dialog */
771 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
774 if (hwndChild
!= hwndChildDlg
)
776 GetWindowRect(hwndChild
, &rectChild
);
777 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
779 /* left,top of stc32 marks the position of controls
780 * from the parent dialog
782 rectChild
.left
+= rectStc32
.left
;
783 rectChild
.top
+= rectStc32
.top
;
785 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
786 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
788 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
791 /* calculate the size of the resulting dialog */
793 /* here we have to use original parent size */
794 GetClientRect(hwndParentDlg
, &rectParent
);
795 GetClientRect(hwndChildDlg
, &rectChild
);
796 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
797 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
802 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
803 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
805 chgx
= rectChild
.right
- rectParent
.right
;
807 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
808 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
810 /* Unconditionally set new dialog
811 * height to that of the child
813 chgy
= rectChild
.bottom
- rectParent
.bottom
;
818 chgy
= rectChild
.bottom
- help_fixup
;
820 /* set the size of the parent dialog */
821 GetWindowRect(hwndParentDlg
, &rectParent
);
822 SetWindowPos(hwndParentDlg
, 0,
824 rectParent
.right
- rectParent
.left
+ chgx
,
825 rectParent
.bottom
- rectParent
.top
+ chgy
,
826 SWP_NOMOVE
| SWP_NOZORDER
);
829 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
838 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
848 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
849 * structure's hInstance parameter is not a HINSTANCE, but
850 * instead a pointer to a template resource to use.
852 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
855 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
857 hinst
= COMDLG32_hInstance
;
858 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
860 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
866 hinst
= fodInfos
->ofnInfos
->hInstance
;
867 if(fodInfos
->unicode
)
869 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
870 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
874 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
875 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
879 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
882 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
883 !(template = LockResource( hDlgTmpl
)))
885 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
889 if (fodInfos
->unicode
)
890 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
891 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
892 (LPARAM
)fodInfos
->ofnInfos
);
894 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
895 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
896 (LPARAM
)fodInfos
->ofnInfos
);
899 else if( IsHooked(fodInfos
))
904 WORD menu
,class,title
;
906 GetClientRect(hwnd
,&rectHwnd
);
907 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
908 temp
.tmplate
.dwExtendedStyle
= 0;
909 temp
.tmplate
.cdit
= 0;
914 temp
.menu
= temp
.class = temp
.title
= 0;
916 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
917 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
924 /***********************************************************************
925 * SendCustomDlgNotificationMessage
927 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
930 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
932 LRESULT hook_result
= 0;
933 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
935 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
937 if(!fodInfos
) return 0;
939 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
941 TRACE("CALL NOTIFY for %x\n", uCode
);
942 if(fodInfos
->unicode
)
945 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
946 ofnNotify
.hdr
.idFrom
=0;
947 ofnNotify
.hdr
.code
= uCode
;
948 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
949 ofnNotify
.pszFile
= NULL
;
950 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
955 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
956 ofnNotify
.hdr
.idFrom
=0;
957 ofnNotify
.hdr
.code
= uCode
;
958 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
959 ofnNotify
.pszFile
= NULL
;
960 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
962 TRACE("RET NOTIFY\n");
964 TRACE("Retval: 0x%08lx\n", hook_result
);
968 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
972 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
974 TRACE("CDM_GETFILEPATH:\n");
976 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
979 /* get path and filenames */
980 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
981 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
982 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
985 p
= buffer
+ strlenW(buffer
);
987 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
989 if (fodInfos
->unicode
)
991 total
= strlenW( buffer
) + 1;
992 if (result
) lstrcpynW( result
, buffer
, size
);
993 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
997 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
998 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
999 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1001 HeapFree( GetProcessHeap(), 0, buffer
);
1005 /***********************************************************************
1006 * FILEDLG95_HandleCustomDialogMessages
1008 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1010 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1012 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1013 WCHAR lpstrPath
[MAX_PATH
];
1016 if(!fodInfos
) return FALSE
;
1020 case CDM_GETFILEPATH
:
1021 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1024 case CDM_GETFOLDERPATH
:
1025 TRACE("CDM_GETFOLDERPATH:\n");
1026 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1029 if (fodInfos
->unicode
)
1030 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1032 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1033 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1035 retval
= lstrlenW(lpstrPath
) + 1;
1038 case CDM_GETFOLDERIDLIST
:
1039 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1040 if (retval
<= wParam
)
1041 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1045 TRACE("CDM_GETSPEC:\n");
1046 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1049 if (fodInfos
->unicode
)
1050 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1052 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1056 case CDM_SETCONTROLTEXT
:
1057 TRACE("CDM_SETCONTROLTEXT:\n");
1060 if( fodInfos
->unicode
)
1061 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1063 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1068 case CDM_HIDECONTROL
:
1069 /* MSDN states that it should fail for not OFN_EXPLORER case */
1070 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1072 HWND control
= GetDlgItem( hwnd
, wParam
);
1073 if (control
) ShowWindow( control
, SW_HIDE
);
1076 else retval
= FALSE
;
1080 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1081 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1084 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1088 /***********************************************************************
1089 * FILEDLG95_OnWMGetMMI
1091 * WM_GETMINMAXINFO message handler for resizable dialogs
1093 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1095 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1096 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1097 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1099 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1104 /***********************************************************************
1105 * FILEDLG95_OnWMSize
1107 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1109 * FIXME: this could be made more elaborate. Now use a simple scheme
1110 * where the file view is enlarged and the controls are either moved
1111 * vertically or horizontally to get out of the way. Only the "grip"
1112 * is moved in both directions to stay in the corner.
1114 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1120 FileOpenDlgInfos
*fodInfos
;
1122 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1123 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1124 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1125 /* get the new dialog rectangle */
1126 GetWindowRect( hwnd
, &rc
);
1127 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1128 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1129 /* not initialized yet */
1130 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1131 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1132 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1134 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1135 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1136 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1137 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1138 /* change the size of the view window */
1139 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1140 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1141 hdwp
= BeginDeferWindowPos( 10);
1142 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1143 rcview
.right
- rcview
.left
+ chgx
,
1144 rcview
.bottom
- rcview
.top
+ chgy
,
1145 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1146 /* change position and sizes of the controls */
1147 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1149 int ctrlid
= GetDlgCtrlID( ctrl
);
1150 GetWindowRect( ctrl
, &rc
);
1151 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1152 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1154 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1156 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1158 else if( rc
.top
> rcview
.bottom
)
1160 /* if it was below the shell view
1164 /* file name (edit or comboboxex) and file types combo change also width */
1168 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1169 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1170 SWP_NOACTIVATE
| SWP_NOZORDER
);
1172 /* then these buttons must move out of the way */
1176 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1178 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1181 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1183 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1186 else if( rc
.left
> rcview
.right
)
1188 /* if it was to the right of the shell view
1190 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1192 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1199 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1201 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1202 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1203 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1205 case IDC_TOOLBARSTATIC
:
1207 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1209 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1212 /* not resized in windows. Since wine uses this invisible control
1213 * to size the browser view it needs to be resized */
1214 case IDC_SHELLSTATIC
:
1215 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1216 rc
.right
- rc
.left
+ chgx
,
1217 rc
.bottom
- rc
.top
+ chgy
,
1218 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1223 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1224 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1226 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1227 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1229 GetWindowRect( ctrl
, &rc
);
1230 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1231 if( rc
.top
> rcview
.bottom
)
1233 /* if it was below the shell view
1235 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1236 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1237 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1239 else if( rc
.left
> rcview
.right
)
1241 /* if it was to the right of the shell view
1243 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1244 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1245 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1248 /* size the custom dialog at the end: some applications do some
1249 * control re-arranging at this point */
1250 GetClientRect(hwnd
, &rc
);
1251 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1252 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1254 EndDeferWindowPos( hdwp
);
1255 /* should not be needed */
1256 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1260 /***********************************************************************
1263 * File open dialog procedure
1265 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1268 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1275 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1277 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1278 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1280 /* Adds the FileOpenDlgInfos in the property list of the dialog
1281 so it will be easily accessible through a GetPropA(...) */
1282 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1284 FILEDLG95_InitControls(hwnd
);
1286 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1288 GetWindowRect( hwnd
, &rc
);
1289 fodInfos
->DlgInfos
.hwndGrip
=
1290 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1291 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1292 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1293 rc
.right
- gripx
, rc
.bottom
- gripy
,
1294 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1297 fodInfos
->DlgInfos
.hwndCustomDlg
=
1298 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1300 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1301 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1303 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1304 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1306 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1307 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1308 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1311 /* if the app has changed the position of the invisible listbox,
1312 * change that of the listview (browser) as well */
1313 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1314 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1315 if( !EqualRect( &rc
, &rcstc
))
1317 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1318 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1319 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1320 SWP_NOACTIVATE
| SWP_NOZORDER
);
1323 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1325 GetWindowRect( hwnd
, &rc
);
1326 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1327 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1328 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1329 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1330 GetClientRect( hwnd
, &rc
);
1331 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1332 rc
.right
- gripx
, rc
.bottom
- gripy
,
1333 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1334 /* resize the dialog to the previous invocation */
1335 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1336 SetWindowPos( hwnd
, NULL
,
1337 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1338 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1341 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1342 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1347 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1348 case WM_GETMINMAXINFO
:
1349 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1351 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1354 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1357 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1363 case WM_GETISHELLBROWSER
:
1364 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1368 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1369 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1370 MemDialogSize
= fodInfos
->sizedlg
;
1371 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1376 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1379 /* set up the button tooltips strings */
1380 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1382 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1383 switch(lpnmh
->idFrom
)
1385 /* Up folder button */
1386 case FCIDM_TB_UPFOLDER
:
1387 stringId
= IDS_UPFOLDER
;
1389 /* New folder button */
1390 case FCIDM_TB_NEWFOLDER
:
1391 stringId
= IDS_NEWFOLDER
;
1393 /* List option button */
1394 case FCIDM_TB_SMALLICON
:
1395 stringId
= IDS_LISTVIEW
;
1397 /* Details option button */
1398 case FCIDM_TB_REPORTVIEW
:
1399 stringId
= IDS_REPORTVIEW
;
1401 /* Desktop button */
1402 case FCIDM_TB_DESKTOP
:
1403 stringId
= IDS_TODESKTOP
;
1408 lpdi
->hinst
= COMDLG32_hInstance
;
1409 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1414 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1415 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1420 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1422 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1423 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1426 /***********************************************************************
1427 * FILEDLG95_InitControls
1429 * WM_INITDIALOG message handler (before hook notification)
1431 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1433 BOOL win2000plus
= FALSE
;
1434 BOOL win98plus
= FALSE
;
1435 BOOL handledPath
= FALSE
;
1436 OSVERSIONINFOW osVi
;
1437 static const WCHAR szwSlash
[] = { '\\', 0 };
1438 static const WCHAR szwStar
[] = { '*',0 };
1440 static const TBBUTTON tbb
[] =
1442 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1443 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1444 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1445 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1446 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1447 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1448 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1449 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1450 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1452 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1457 HIMAGELIST toolbarImageList
;
1458 SHFILEINFOA shFileInfo
;
1459 ITEMIDLIST
*desktopPidl
;
1461 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1463 TRACE("%p\n", fodInfos
);
1465 /* Get windows version emulating */
1466 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1467 GetVersionExW(&osVi
);
1468 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1469 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1470 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1471 win2000plus
= (osVi
.dwMajorVersion
> 4);
1472 if (win2000plus
) win98plus
= TRUE
;
1474 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1477 /* Use either the edit or the comboboxex for the filename control */
1478 if (filename_is_edit( fodInfos
))
1480 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1481 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1485 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1486 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1489 /* Get the hwnd of the controls */
1490 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1491 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1493 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1494 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1496 /* construct the toolbar */
1497 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1498 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1500 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1501 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1502 rectTB
.left
= rectlook
.right
;
1503 rectTB
.top
= rectlook
.top
-1;
1505 if (fodInfos
->unicode
)
1506 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1507 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1508 rectTB
.left
, rectTB
.top
,
1509 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1510 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1512 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1513 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1514 rectTB
.left
, rectTB
.top
,
1515 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1516 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1518 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1520 /* FIXME: use TB_LOADIMAGES when implemented */
1521 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1522 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1523 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1525 /* Retrieve and add desktop icon to the toolbar */
1526 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1527 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1528 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1529 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1530 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1532 DestroyIcon(shFileInfo
.hIcon
);
1533 CoTaskMemFree(desktopPidl
);
1535 /* Finish Toolbar Construction */
1536 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1537 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1539 /* Set the window text with the text specified in the OPENFILENAME structure */
1542 SetWindowTextW(hwnd
,fodInfos
->title
);
1544 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1547 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1548 SetWindowTextW(hwnd
, buf
);
1551 /* Initialise the file name edit control */
1552 handledPath
= FALSE
;
1553 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1555 if(fodInfos
->filename
)
1557 /* 1. If win2000 or higher and filename contains a path, use it
1558 in preference over the lpstrInitialDir */
1559 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1560 WCHAR tmpBuf
[MAX_PATH
];
1564 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1567 /* nameBit is always shorter than the original filename */
1568 lstrcpyW(fodInfos
->filename
,nameBit
);
1571 MemFree(fodInfos
->initdir
);
1572 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1573 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1575 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1576 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1578 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1581 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1585 /* 2. (All platforms) If initdir is not null, then use it */
1586 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1588 /* Work out the proper path as supplied one might be relative */
1589 /* (Here because supplying '.' as dir browses to My Computer) */
1590 WCHAR tmpBuf
[MAX_PATH
];
1591 WCHAR tmpBuf2
[MAX_PATH
];
1595 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1596 if (PathFileExistsW(tmpBuf
)) {
1597 /* initdir does not have to be a directory. If a file is
1598 * specified, the dir part is taken */
1599 if (PathIsDirectoryW(tmpBuf
)) {
1600 PathAddBackslashW(tmpBuf
);
1601 lstrcatW(tmpBuf
, szwStar
);
1603 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1606 MemFree(fodInfos
->initdir
);
1607 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1608 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1610 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1613 else if (fodInfos
->initdir
)
1615 MemFree(fodInfos
->initdir
);
1616 fodInfos
->initdir
= NULL
;
1617 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1621 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1623 /* 3. All except w2k+: if filename contains a path use it */
1624 if (!win2000plus
&& fodInfos
->filename
&&
1625 *fodInfos
->filename
&&
1626 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1627 WCHAR tmpBuf
[MAX_PATH
];
1631 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1636 /* nameBit is always shorter than the original filename */
1637 lstrcpyW(fodInfos
->filename
, nameBit
);
1640 len
= lstrlenW(tmpBuf
);
1641 MemFree(fodInfos
->initdir
);
1642 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1643 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1646 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1647 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1649 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1652 /* 4. Win2000+: Recently used */
1653 if (!handledPath
&& win2000plus
) {
1654 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1655 fodInfos
->initdir
[0] = '\0';
1657 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1659 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1662 MemFree(fodInfos
->initdir
);
1663 fodInfos
->initdir
= NULL
;
1667 /* 5. win98+ and win2000+ if any files of specified filter types in
1668 current directory, use it */
1669 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1671 LPCWSTR lpstrPos
= fodInfos
->filter
;
1672 WIN32_FIND_DATAW FindFileData
;
1677 /* filter is a list... title\0ext\0......\0\0 */
1679 /* Skip the title */
1680 if(! *lpstrPos
) break; /* end */
1681 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1683 /* See if any files exist in the current dir with this extension */
1684 if(! *lpstrPos
) break; /* end */
1686 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1688 if (hFind
== INVALID_HANDLE_VALUE
) {
1689 /* None found - continue search */
1690 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1694 MemFree(fodInfos
->initdir
);
1695 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1696 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1699 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1700 debugstr_w(lpstrPos
));
1707 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1708 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1709 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1711 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1713 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1716 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1717 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1719 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1722 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1725 } else if (!handledPath
) {
1726 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1727 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1729 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1732 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1733 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1735 /* Must the open as read only check box be checked ?*/
1736 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1738 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1741 /* Must the open as read only check box be hidden? */
1742 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1744 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1745 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1748 /* Must the help button be hidden? */
1749 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1751 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1752 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1755 /* change Open to Save */
1756 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1759 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1760 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1761 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1762 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1765 /* Initialize the filter combo box */
1766 FILEDLG95_FILETYPE_Init(hwnd
);
1771 /***********************************************************************
1772 * FILEDLG95_ResizeControls
1774 * WM_INITDIALOG message handler (after hook notification)
1776 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1778 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1780 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1783 UINT flags
= SWP_NOACTIVATE
;
1785 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1786 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1788 /* resize the custom dialog to the parent size */
1789 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1790 GetClientRect(hwnd
, &rc
);
1793 /* our own fake template is zero sized and doesn't have children, so
1794 * there is no need to resize it. Picasa depends on it.
1796 flags
|= SWP_NOSIZE
;
1799 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1800 0, 0, rc
.right
, rc
.bottom
, flags
);
1804 /* Resize the height; if opened as read-only, checkbox and help button are
1805 * hidden and we are not using a custom template nor a customDialog
1807 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1808 (!(fodInfos
->ofnInfos
->Flags
&
1809 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1811 RECT rectDlg
, rectHelp
, rectCancel
;
1812 GetWindowRect(hwnd
, &rectDlg
);
1813 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1814 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1815 /* subtract the height of the help button plus the space between the help
1816 * button and the cancel button to the height of the dialog
1818 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1819 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1820 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1826 /***********************************************************************
1827 * FILEDLG95_FillControls
1829 * WM_INITDIALOG message handler (after hook notification)
1831 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1833 LPITEMIDLIST pidlItemId
= NULL
;
1835 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1837 TRACE("dir=%s file=%s\n",
1838 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1840 /* Get the initial directory pidl */
1842 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1844 WCHAR path
[MAX_PATH
];
1846 GetCurrentDirectoryW(MAX_PATH
,path
);
1847 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1850 /* Initialise shell objects */
1851 FILEDLG95_SHELL_Init(hwnd
);
1853 /* Initialize the Look In combo box */
1854 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1856 /* Browse to the initial directory */
1857 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1859 /* Free pidlItem memory */
1860 COMDLG32_SHFree(pidlItemId
);
1864 /***********************************************************************
1867 * Regroups all the cleaning functions of the filedlg
1869 void FILEDLG95_Clean(HWND hwnd
)
1871 FILEDLG95_FILETYPE_Clean(hwnd
);
1872 FILEDLG95_LOOKIN_Clean(hwnd
);
1873 FILEDLG95_SHELL_Clean(hwnd
);
1875 /***********************************************************************
1876 * FILEDLG95_OnWMCommand
1878 * WM_COMMAND message handler
1880 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1882 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1883 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1884 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1890 FILEDLG95_OnOpen(hwnd
);
1894 FILEDLG95_Clean(hwnd
);
1895 EndDialog(hwnd
, FALSE
);
1897 /* Filetype combo box */
1899 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1901 /* LookIn combo box */
1903 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1906 /* --- toolbar --- */
1907 /* Up folder button */
1908 case FCIDM_TB_UPFOLDER
:
1909 FILEDLG95_SHELL_UpFolder(hwnd
);
1911 /* New folder button */
1912 case FCIDM_TB_NEWFOLDER
:
1913 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1915 /* List option button */
1916 case FCIDM_TB_SMALLICON
:
1917 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1919 /* Details option button */
1920 case FCIDM_TB_REPORTVIEW
:
1921 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1923 /* Details option button */
1924 case FCIDM_TB_DESKTOP
:
1925 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1933 /* Do not use the listview selection anymore */
1934 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1938 /***********************************************************************
1939 * FILEDLG95_OnWMGetIShellBrowser
1941 * WM_GETISHELLBROWSER message handler
1943 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1945 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1949 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1955 /***********************************************************************
1956 * FILEDLG95_SendFileOK
1958 * Sends the CDN_FILEOK notification if required
1961 * TRUE if the dialog should close
1962 * FALSE if the dialog should not be closed
1964 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1966 /* ask the hook if we can close */
1967 if(IsHooked(fodInfos
))
1972 /* First send CDN_FILEOK as MSDN doc says */
1973 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1974 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1977 TRACE("canceled\n");
1981 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1982 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1983 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1986 TRACE("canceled\n");
1993 /***********************************************************************
1994 * FILEDLG95_OnOpenMultipleFiles
1996 * Handles the opening of multiple files.
1999 * check destination buffer size
2001 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2003 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2004 UINT nCount
, nSizePath
;
2005 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2009 if(fodInfos
->unicode
)
2011 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2012 ofn
->lpstrFile
[0] = '\0';
2016 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2017 ofn
->lpstrFile
[0] = '\0';
2020 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2022 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2023 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2024 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2026 LPWSTR lpstrTemp
= lpstrFileList
;
2028 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2032 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2035 WCHAR lpstrNotFound
[100];
2036 WCHAR lpstrMsg
[100];
2038 static const WCHAR nl
[] = {'\n',0};
2040 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2041 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2043 lstrcpyW(tmp
, lpstrTemp
);
2045 lstrcatW(tmp
, lpstrNotFound
);
2047 lstrcatW(tmp
, lpstrMsg
);
2049 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2053 /* move to the next file in the list of files */
2054 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2055 COMDLG32_SHFree(pidl
);
2059 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2060 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2062 /* For "oldstyle" dialog the components have to
2063 be separated by blanks (not '\0'!) and short
2064 filenames have to be used! */
2065 FIXME("Components have to be separated by blanks\n");
2067 if(fodInfos
->unicode
)
2069 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2070 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2071 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2075 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2077 if (ofn
->lpstrFile
!= NULL
)
2079 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2080 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2081 if (ofn
->nMaxFile
> nSizePath
)
2083 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2084 ofn
->lpstrFile
+ nSizePath
,
2085 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2090 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2091 fodInfos
->ofnInfos
->nFileExtension
= 0;
2093 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2096 /* clean and exit */
2097 FILEDLG95_Clean(hwnd
);
2098 return EndDialog(hwnd
,TRUE
);
2101 /* Returns the 'slot name' of the given module_name in the registry's
2102 * most-recently-used list. This will be an ASCII value in the
2103 * range ['a','z'). Returns zero on error.
2105 * The slot's value in the registry has the form:
2106 * module_name\0mru_path\0
2108 * If stored_path is given, then stored_path will contain the path name
2109 * stored in the registry's MRU list for the given module_name.
2111 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2112 * MRU list key for the given module_name.
2114 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2116 WCHAR mru_list
[32], *cur_mru_slot
;
2117 BOOL taken
[25] = {0};
2118 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2119 HKEY hkey_tmp
, *hkey
;
2128 *stored_path
= '\0';
2130 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2132 WARN("Unable to create MRU key: %d\n", ret
);
2136 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2137 (LPBYTE
)mru_list
, &mru_list_size
);
2138 if(ret
|| key_type
!= REG_SZ
){
2139 if(ret
== ERROR_FILE_NOT_FOUND
)
2142 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2147 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2148 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2149 DWORD value_data_size
= sizeof(value_data
);
2151 *value_name
= *cur_mru_slot
;
2153 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2154 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2155 if(ret
|| key_type
!= REG_BINARY
){
2156 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2160 if(!strcmpiW(module_name
, value_data
)){
2164 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2172 /* the module name isn't in the registry, so find the next open slot */
2173 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2174 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2175 for(i
= 0; i
< 25; ++i
){
2180 /* all slots are taken, so return the last one in MRUList */
2182 return *cur_mru_slot
;
2185 /* save the given filename as most-recently-used path for this module */
2186 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2188 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2192 /* get the current executable's name */
2193 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2194 WARN("GotModuleFileName failed: %d\n", GetLastError());
2197 module_name
= strrchrW(module_path
, '\\');
2199 module_name
= module_path
;
2203 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2208 { /* update the slot's info */
2209 WCHAR
*path_ends
, *final
;
2210 DWORD path_len
, final_len
;
2212 /* use only the path segment of `filename' */
2213 path_ends
= strrchrW(filename
, '\\');
2214 path_len
= path_ends
- filename
;
2216 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2218 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2221 lstrcpyW(final
, module_name
);
2222 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2223 final
[final_len
-1] = '\0';
2225 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2226 final_len
* sizeof(WCHAR
));
2228 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2237 { /* update MRUList value */
2238 WCHAR old_mru_list
[32], new_mru_list
[32];
2239 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2240 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2242 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2243 (LPBYTE
)old_mru_list
, &mru_list_size
);
2244 if(ret
|| key_type
!= REG_SZ
){
2245 if(ret
== ERROR_FILE_NOT_FOUND
){
2246 new_mru_list
[0] = slot
;
2247 new_mru_list
[1] = '\0';
2249 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2254 /* copy old list data over so that the new slot is at the start
2256 *new_mru_slot
++ = slot
;
2257 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2258 if(*old_mru_slot
!= slot
)
2259 *new_mru_slot
++ = *old_mru_slot
;
2261 *new_mru_slot
= '\0';
2264 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2265 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2267 WARN("Error saving MRUList data: %d\n", ret
);
2274 /* load the most-recently-used path for this module */
2275 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2277 WCHAR module_path
[MAX_PATH
], *module_name
;
2279 /* get the current executable's name */
2280 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2281 WARN("GotModuleFileName failed: %d\n", GetLastError());
2284 module_name
= strrchrW(module_path
, '\\');
2286 module_name
= module_path
;
2290 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2291 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2294 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2296 WCHAR strMsgTitle
[MAX_PATH
];
2297 WCHAR strMsgText
[MAX_PATH
];
2299 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2301 strMsgTitle
[0] = '\0';
2302 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2303 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2306 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2307 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2309 int nOpenAction
= defAction
;
2310 LPWSTR lpszTemp
, lpszTemp1
;
2311 LPITEMIDLIST pidl
= NULL
;
2312 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2314 /* check for invalid chars */
2315 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2317 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2321 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2323 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2326 LPSHELLFOLDER lpsfChild
;
2327 WCHAR lpwstrTemp
[MAX_PATH
];
2328 DWORD dwEaten
, dwAttributes
;
2331 lstrcpyW(lpwstrTemp
, lpszTemp
);
2332 p
= PathFindNextComponentW(lpwstrTemp
);
2334 if (!p
) break; /* end of path */
2337 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2339 /* There are no wildcards when OFN_NOVALIDATE is set */
2340 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2342 static const WCHAR wszWild
[] = { '*', '?', 0 };
2343 /* if the last element is a wildcard do a search */
2344 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2346 nOpenAction
= ONOPEN_SEARCH
;
2350 lpszTemp1
= lpszTemp
;
2352 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2354 /* append a backslash to drive letters */
2355 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2356 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2357 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2359 PathAddBackslashW(lpwstrTemp
);
2362 dwAttributes
= SFGAO_FOLDER
;
2363 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2365 /* the path component is valid, we have a pidl of the next path component */
2366 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2367 if(dwAttributes
& SFGAO_FOLDER
)
2369 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2371 ERR("bind to failed\n"); /* should not fail */
2374 IShellFolder_Release(*ppsf
);
2382 /* end dialog, return value */
2383 nOpenAction
= ONOPEN_OPEN
;
2386 COMDLG32_SHFree(pidl
);
2389 else if (!(flags
& OFN_NOVALIDATE
))
2391 if(*lpszTemp
|| /* points to trailing null for last path element */
2392 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2394 if(flags
& OFN_PATHMUSTEXIST
)
2396 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2402 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2404 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2408 /* change to the current folder */
2409 nOpenAction
= ONOPEN_OPEN
;
2414 nOpenAction
= ONOPEN_OPEN
;
2418 if(pidl
) COMDLG32_SHFree(pidl
);
2423 /***********************************************************************
2426 * Ok button WM_COMMAND message handler
2428 * If the function succeeds, the return value is nonzero.
2430 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2432 LPWSTR lpstrFileList
;
2433 UINT nFileCount
= 0;
2436 WCHAR lpstrPathAndFile
[MAX_PATH
];
2437 LPSHELLFOLDER lpsf
= NULL
;
2439 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2441 TRACE("hwnd=%p\n", hwnd
);
2443 /* try to browse the selected item */
2444 if(BrowseSelectedFolder(hwnd
))
2447 /* get the files from the edit control */
2448 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2455 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2459 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2462 Step 1: Build a complete path name from the current folder and
2463 the filename or path in the edit box.
2465 - the path in the edit box is a root path
2466 (with or without drive letter)
2467 - the edit box contains ".." (or a path with ".." in it)
2470 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2471 MemFree(lpstrFileList
);
2474 Step 2: here we have a cleaned up path
2476 We have to parse the path step by step to see if we have to browse
2477 to a folder if the path points to a directory or the last
2478 valid element is a directory.
2481 lpstrPathAndFile: cleaned up path
2485 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2486 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2487 nOpenAction
= ONOPEN_OPEN
;
2489 nOpenAction
= ONOPEN_BROWSE
;
2491 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2492 fodInfos
->ofnInfos
->Flags
,
2493 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2499 Step 3: here we have a cleaned up and validated path
2502 lpsf: ShellFolder bound to the rightmost valid path component
2503 lpstrPathAndFile: cleaned up path
2504 nOpenAction: action to do
2506 TRACE("end validate sf=%p\n", lpsf
);
2510 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2511 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2514 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2517 /* replace the current filter */
2518 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2519 len
= lstrlenW(lpszTemp
)+1;
2520 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2521 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2523 /* set the filter cb to the extension when possible */
2524 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2525 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2528 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2529 TRACE("ONOPEN_BROWSE\n");
2531 IPersistFolder2
* ppf2
;
2532 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2534 LPITEMIDLIST pidlCurrent
;
2535 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2536 IPersistFolder2_Release(ppf2
);
2537 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2539 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2540 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2542 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2545 else if( nOpenAction
== ONOPEN_SEARCH
)
2547 if (fodInfos
->Shell
.FOIShellView
)
2548 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2550 COMDLG32_SHFree(pidlCurrent
);
2551 if (filename_is_edit( fodInfos
))
2552 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2557 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2558 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2562 /* update READONLY check box flag */
2563 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2564 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2566 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2568 /* Attach the file extension with file name*/
2569 ext
= PathFindExtensionW(lpstrPathAndFile
);
2570 if (! *ext
&& fodInfos
->defext
)
2572 /* if no extension is specified with file name, then */
2573 /* attach the extension from file filter or default one */
2575 WCHAR
*filterExt
= NULL
;
2576 LPWSTR lpstrFilter
= NULL
;
2577 static const WCHAR szwDot
[] = {'.',0};
2578 int PathLength
= lstrlenW(lpstrPathAndFile
);
2580 /*Get the file extension from file type filter*/
2581 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2582 fodInfos
->ofnInfos
->nFilterIndex
-1);
2584 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2586 WCHAR
* filterSearchIndex
;
2587 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2588 strcpyW(filterExt
, lpstrFilter
);
2590 /* if a semicolon-separated list of file extensions was given, do not include the
2591 semicolon or anything after it in the extension.
2592 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2593 filterSearchIndex
= strchrW(filterExt
, ';');
2594 if (filterSearchIndex
)
2596 filterSearchIndex
[0] = '\0';
2599 /* find the file extension by searching for the first dot in filterExt */
2600 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2601 /* if the extension is invalid or contains a glob, ignore it */
2602 filterSearchIndex
= strchrW(filterExt
, '.');
2603 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2605 strcpyW(filterExt
, filterSearchIndex
);
2609 HeapFree(GetProcessHeap(), 0, filterExt
);
2616 /* use the default file extension */
2617 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2618 strcpyW(filterExt
, fodInfos
->defext
);
2621 if (*filterExt
) /* ignore filterExt="" */
2624 lstrcatW(lpstrPathAndFile
, szwDot
);
2625 /* Attach the extension */
2626 lstrcatW(lpstrPathAndFile
, filterExt
);
2629 HeapFree(GetProcessHeap(), 0, filterExt
);
2631 /* In Open dialog: if file does not exist try without extension */
2632 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2633 lpstrPathAndFile
[PathLength
] = '\0';
2635 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2638 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2639 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2641 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2644 /* In Save dialog: check if the file already exists */
2645 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2646 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2647 && PathFileExistsW(lpstrPathAndFile
))
2649 WCHAR lpstrOverwrite
[100];
2652 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2653 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2654 MB_YESNO
| MB_ICONEXCLAMATION
);
2655 if (answer
== IDNO
|| answer
== IDCANCEL
)
2662 /* In Open dialog: check if it should be created if it doesn't exist */
2663 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2664 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2665 && !PathFileExistsW(lpstrPathAndFile
))
2667 WCHAR lpstrCreate
[100];
2670 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2671 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2672 MB_YESNO
| MB_ICONEXCLAMATION
);
2673 if (answer
== IDNO
|| answer
== IDCANCEL
)
2680 /* Check that the size of the file does not exceed buffer size.
2681 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2682 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2683 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2686 /* fill destination buffer */
2687 if (fodInfos
->ofnInfos
->lpstrFile
)
2689 if(fodInfos
->unicode
)
2691 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2693 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2694 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2695 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2699 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2701 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2702 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2703 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2704 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2708 if(fodInfos
->unicode
)
2712 /* set filename offset */
2713 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2714 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2716 /* set extension offset */
2717 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2718 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2723 CHAR tempFileA
[MAX_PATH
];
2725 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2726 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2727 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2729 /* set filename offset */
2730 lpszTemp
= PathFindFileNameA(tempFileA
);
2731 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2733 /* set extension offset */
2734 lpszTemp
= PathFindExtensionA(tempFileA
);
2735 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2738 /* set the lpstrFileTitle */
2739 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2741 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2742 if(fodInfos
->unicode
)
2744 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2745 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2749 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2750 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2751 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2755 /* copy currently selected filter to lpstrCustomFilter */
2756 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2758 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2759 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2760 NULL
, 0, NULL
, NULL
);
2761 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2763 LPSTR s
= ofn
->lpstrCustomFilter
;
2764 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2765 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2766 s
, len
, NULL
, NULL
);
2771 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2774 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2777 FILEDLG95_Clean(hwnd
);
2778 ret
= EndDialog(hwnd
, TRUE
);
2784 size
= lstrlenW(lpstrPathAndFile
) + 1;
2785 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2787 /* return needed size in first two bytes of lpstrFile */
2788 if(fodInfos
->ofnInfos
->lpstrFile
)
2789 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2790 FILEDLG95_Clean(hwnd
);
2791 ret
= EndDialog(hwnd
, FALSE
);
2792 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2799 if(lpsf
) IShellFolder_Release(lpsf
);
2803 /***********************************************************************
2804 * FILEDLG95_SHELL_Init
2806 * Initialisation of the shell objects
2808 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2810 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2815 * Initialisation of the FileOpenDialogInfos structure
2821 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2823 /* Disable multi-select if flag not set */
2824 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2826 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2828 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2829 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2831 /* Construct the IShellBrowser interface */
2832 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2837 /***********************************************************************
2838 * FILEDLG95_SHELL_ExecuteCommand
2840 * Change the folder option and refresh the view
2841 * If the function succeeds, the return value is nonzero.
2843 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2845 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2848 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2850 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2855 CMINVOKECOMMANDINFO ci
;
2856 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2857 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2861 IContextMenu_InvokeCommand(pcm
, &ci
);
2862 IContextMenu_Release(pcm
);
2868 /***********************************************************************
2869 * FILEDLG95_SHELL_UpFolder
2871 * Browse to the specified object
2872 * If the function succeeds, the return value is nonzero.
2874 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2876 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2880 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2884 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2885 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2891 /***********************************************************************
2892 * FILEDLG95_SHELL_BrowseToDesktop
2894 * Browse to the Desktop
2895 * If the function succeeds, the return value is nonzero.
2897 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2899 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2905 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2906 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2907 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2908 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2909 COMDLG32_SHFree(pidl
);
2910 return SUCCEEDED(hres
);
2912 /***********************************************************************
2913 * FILEDLG95_SHELL_Clean
2915 * Cleans the memory used by shell objects
2917 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2919 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2923 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2925 /* clean Shell interfaces */
2926 if (fodInfos
->Shell
.FOIShellView
)
2928 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2929 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2931 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2932 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2933 if (fodInfos
->Shell
.FOIDataObject
)
2934 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2937 /***********************************************************************
2938 * FILEDLG95_FILETYPE_Init
2940 * Initialisation of the file type combo box
2942 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2944 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2945 int nFilters
= 0; /* number of filters */
2950 if(fodInfos
->customfilter
)
2952 /* customfilter has one entry... title\0ext\0
2953 * Set first entry of combo box item with customfilter
2956 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2959 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2961 /* Copy the extensions */
2962 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2963 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2964 lstrcpyW(lpstrExt
,lpstrPos
);
2966 /* Add the item at the end of the combo */
2967 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2968 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2971 if(fodInfos
->filter
)
2973 LPCWSTR lpstrPos
= fodInfos
->filter
;
2977 /* filter is a list... title\0ext\0......\0\0
2978 * Set the combo item text to the title and the item data
2981 LPCWSTR lpstrDisplay
;
2985 if(! *lpstrPos
) break; /* end */
2986 lpstrDisplay
= lpstrPos
;
2987 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2989 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2993 /* Copy the extensions */
2994 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2995 lstrcpyW(lpstrExt
,lpstrPos
);
2996 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2998 /* Add the item at the end of the combo */
2999 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
3001 /* malformed filters are added anyway... */
3002 if (!*lpstrExt
) break;
3007 * Set the current filter to the one specified
3008 * in the initialisation structure
3010 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3014 /* Check to make sure our index isn't out of bounds. */
3015 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3016 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3017 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3019 /* set default filter index */
3020 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3021 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3023 /* calculate index of Combo Box item */
3024 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3025 if (fodInfos
->customfilter
== NULL
)
3028 /* Set the current index selection. */
3029 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3031 /* Get the corresponding text string from the combo box. */
3032 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3035 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3041 CharLowerW(lpstrFilter
); /* lowercase */
3042 len
= lstrlenW(lpstrFilter
)+1;
3043 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3044 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3047 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3051 /***********************************************************************
3052 * FILEDLG95_FILETYPE_OnCommand
3054 * WM_COMMAND of the file type combo box
3055 * If the function succeeds, the return value is nonzero.
3057 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3059 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3067 /* Get the current item of the filetype combo box */
3068 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3070 /* set the current filter index */
3071 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3072 (fodInfos
->customfilter
== NULL
? 1 : 0);
3074 /* Set the current filter with the current selection */
3075 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3077 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3079 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3082 CharLowerW(lpstrFilter
); /* lowercase */
3083 len
= lstrlenW(lpstrFilter
)+1;
3084 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3085 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3086 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3087 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3090 /* Refresh the actual view to display the included items*/
3091 if (fodInfos
->Shell
.FOIShellView
)
3092 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3097 /***********************************************************************
3098 * FILEDLG95_FILETYPE_SearchExt
3100 * searches for an extension in the filetype box
3102 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3104 int i
, iCount
= CBGetCount(hwnd
);
3106 TRACE("%s\n", debugstr_w(lpstrExt
));
3108 if(iCount
!= CB_ERR
)
3110 for(i
=0;i
<iCount
;i
++)
3112 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3119 /***********************************************************************
3120 * FILEDLG95_FILETYPE_Clean
3122 * Clean the memory used by the filetype combo box
3124 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3126 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3128 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3132 /* Delete each string of the combo and their associated data */
3133 if(iCount
!= CB_ERR
)
3135 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3137 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3138 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3141 /* Current filter */
3142 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3146 /***********************************************************************
3147 * FILEDLG95_LOOKIN_Init
3149 * Initialisation of the look in combo box
3152 /* Small helper function, to determine if the unixfs shell extension is rooted
3153 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3155 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3157 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3158 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3160 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3161 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3162 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3163 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3165 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3172 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3174 IShellFolder
*psfRoot
, *psfDrives
;
3175 IEnumIDList
*lpeRoot
, *lpeDrives
;
3176 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3179 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3183 liInfos
->iMaxIndentation
= 0;
3185 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3187 hdc
= GetDC( hwndCombo
);
3188 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3189 GetTextMetricsW( hdc
, &tm
);
3190 ReleaseDC( hwndCombo
, hdc
);
3192 /* set item height for both text field and listbox */
3193 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3194 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3196 /* Turn on the extended UI for the combo box like Windows does */
3197 CBSetExtendedUI(hwndCombo
, TRUE
);
3199 /* Initialise data of Desktop folder */
3200 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3201 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3202 COMDLG32_SHFree(pidlTmp
);
3204 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3206 SHGetDesktopFolder(&psfRoot
);
3210 /* enumerate the contents of the desktop */
3211 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3213 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3215 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3217 /* If the unixfs extension is rooted, we don't expand the drives by default */
3218 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3220 /* special handling for CSIDL_DRIVES */
3221 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3223 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3225 /* enumerate the drives */
3226 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3228 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3230 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3231 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3232 COMDLG32_SHFree(pidlAbsTmp
);
3233 COMDLG32_SHFree(pidlTmp1
);
3235 IEnumIDList_Release(lpeDrives
);
3237 IShellFolder_Release(psfDrives
);
3242 COMDLG32_SHFree(pidlTmp
);
3244 IEnumIDList_Release(lpeRoot
);
3246 IShellFolder_Release(psfRoot
);
3249 COMDLG32_SHFree(pidlDrives
);
3252 /***********************************************************************
3253 * FILEDLG95_LOOKIN_DrawItem
3255 * WM_DRAWITEM message handler
3257 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3259 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3260 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3261 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3265 HIMAGELIST ilItemImage
;
3268 LPSFOLDER tmpFolder
;
3269 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3270 UINT icon_width
, icon_height
;
3274 if(pDIStruct
->itemID
== -1)
3277 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3278 pDIStruct
->itemID
)))
3282 icon_width
= GetSystemMetrics(SM_CXICON
);
3283 icon_height
= GetSystemMetrics(SM_CYICON
);
3284 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3286 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3287 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3288 shgfi_flags
|= SHGFI_SMALLICON
;
3291 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3292 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3294 /* Is this item selected ? */
3295 if(pDIStruct
->itemState
& ODS_SELECTED
)
3297 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3298 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3299 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3303 SetTextColor(pDIStruct
->hDC
,crText
);
3304 SetBkColor(pDIStruct
->hDC
,crWin
);
3305 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3308 /* Do not indent item if drawing in the edit of the combo */
3309 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3312 iIndentation
= tmpFolder
->m_iIndent
;
3314 /* Draw text and icon */
3316 /* Initialise the icon display area */
3317 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3318 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3319 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3320 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3322 /* Initialise the text display area */
3323 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3324 rectText
.left
= rectIcon
.right
;
3326 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3327 rectText
.right
= pDIStruct
->rcItem
.right
;
3329 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3331 /* Draw the icon from the image list */
3332 ImageList_Draw(ilItemImage
,
3339 /* Draw the associated text */
3340 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3344 /***********************************************************************
3345 * FILEDLG95_LOOKIN_OnCommand
3347 * LookIn combo box WM_COMMAND message handler
3348 * If the function succeeds, the return value is nonzero.
3350 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3352 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3354 TRACE("%p\n", fodInfos
);
3360 LPSFOLDER tmpFolder
;
3363 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3365 if( iItem
== CB_ERR
) return FALSE
;
3367 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3372 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3373 tmpFolder
->pidlItem
,
3376 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3377 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3387 /***********************************************************************
3388 * FILEDLG95_LOOKIN_AddItem
3390 * Adds an absolute pidl item to the lookin combo box
3391 * returns the index of the inserted item
3393 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3395 LPITEMIDLIST pidlNext
;
3398 LookInInfos
*liInfos
;
3400 TRACE("%08x\n", iInsertId
);
3405 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3408 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3409 tmpFolder
->m_iIndent
= 0;
3411 /* Calculate the indentation of the item in the lookin*/
3413 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3415 tmpFolder
->m_iIndent
++;
3418 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3420 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3421 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3423 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3424 SHGetFileInfoW((LPCWSTR
)pidl
,
3428 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3429 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3431 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3433 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3437 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3439 /* Add the item at the end of the list */
3442 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3444 /* Insert the item at the iInsertId position*/
3447 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3450 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3454 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3455 MemFree( tmpFolder
);
3460 /***********************************************************************
3461 * FILEDLG95_LOOKIN_InsertItemAfterParent
3463 * Insert an item below its parent
3465 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3468 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3473 if (pidl
== pidlParent
)
3476 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3480 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3483 /* Free pidlParent memory */
3484 COMDLG32_SHFree(pidlParent
);
3486 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3489 /***********************************************************************
3490 * FILEDLG95_LOOKIN_SelectItem
3492 * Adds an absolute pidl item to the lookin combo box
3493 * returns the index of the inserted item
3495 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3498 LookInInfos
*liInfos
;
3502 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3504 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3508 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3509 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3514 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3515 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3519 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3521 if(iRemovedItem
< iItemPos
)
3526 CBSetCurSel(hwnd
,iItemPos
);
3527 liInfos
->uSelectedItem
= iItemPos
;
3533 /***********************************************************************
3534 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3536 * Remove the item with an expansion level over iExpansionLevel
3538 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3541 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3545 if(liInfos
->iMaxIndentation
<= 2)
3548 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3550 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3551 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3553 CBDeleteString(hwnd
,iItemPos
);
3554 liInfos
->iMaxIndentation
--;
3562 /***********************************************************************
3563 * FILEDLG95_LOOKIN_SearchItem
3565 * Search for pidl in the lookin combo box
3566 * returns the index of the found item
3568 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3571 int iCount
= CBGetCount(hwnd
);
3573 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3575 if (iCount
!= CB_ERR
)
3579 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3581 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3583 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3591 /***********************************************************************
3592 * FILEDLG95_LOOKIN_Clean
3594 * Clean the memory used by the lookin combo box
3596 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3598 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3599 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3601 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3605 /* Delete each string of the combo and their associated data */
3606 if (iCount
!= CB_ERR
)
3608 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3610 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3611 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3613 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3617 /* LookInInfos structure */
3619 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3622 /***********************************************************************
3623 * FILEDLG95_FILENAME_FillFromSelection
3625 * fills the edit box from the cached DataObject
3627 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3629 FileOpenDlgInfos
*fodInfos
;
3631 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3632 WCHAR lpstrTemp
[MAX_PATH
];
3633 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3636 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3638 /* Count how many files we have */
3639 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3641 /* calculate the string length, count files */
3642 if (nFileSelected
>= 1)
3644 nLength
+= 3; /* first and last quotes, trailing \0 */
3645 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3647 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3651 /* get the total length of the selected file names */
3652 lpstrTemp
[0] = '\0';
3653 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3655 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3657 nLength
+= lstrlenW( lpstrTemp
) + 3;
3660 COMDLG32_SHFree( pidl
);
3665 /* allocate the buffer */
3666 if (nFiles
<= 1) nLength
= MAX_PATH
;
3667 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3669 /* Generate the string for the edit control */
3672 lpstrCurrFile
= lpstrAllFile
;
3673 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3675 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3679 /* get the file name */
3680 lpstrTemp
[0] = '\0';
3681 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3683 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3687 *lpstrCurrFile
++ = '\"';
3688 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3689 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3690 *lpstrCurrFile
++ = '\"';
3691 *lpstrCurrFile
++ = ' ';
3696 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3699 COMDLG32_SHFree( pidl
);
3702 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3704 /* Select the file name like Windows does */
3705 if (filename_is_edit( fodInfos
))
3706 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3708 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3712 /* copied from shell32 to avoid linking to it
3713 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3714 * is dependent on whether emulated OS is unicode or not.
3716 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3721 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3722 COMDLG32_SHFree(src
->u
.pOleStr
);
3726 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3731 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3736 FIXME("unknown type %x!\n", src
->uType
);
3737 if (len
) *dest
= '\0';
3743 /***********************************************************************
3744 * FILEDLG95_FILENAME_GetFileNames
3746 * Copies the filenames to a delimited string list.
3748 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3750 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3751 UINT nFileCount
= 0; /* number of files */
3752 UINT nStrLen
= 0; /* length of string in edit control */
3753 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3757 /* get the filenames from the filename control */
3758 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3759 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3760 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3762 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3764 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3769 #define SETDefFormatEtc(fe,cf,med) \
3771 (fe).cfFormat = cf;\
3772 (fe).dwAspect = DVASPECT_CONTENT; \
3779 * DATAOBJECT Helper functions
3782 /***********************************************************************
3783 * COMCTL32_ReleaseStgMedium
3785 * like ReleaseStgMedium from ole32
3787 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3789 if(medium
.pUnkForRelease
)
3791 IUnknown_Release(medium
.pUnkForRelease
);
3795 GlobalUnlock(medium
.u
.hGlobal
);
3796 GlobalFree(medium
.u
.hGlobal
);
3800 /***********************************************************************
3801 * GetPidlFromDataObject
3803 * Return pidl(s) by number from the cached DataObject
3805 * nPidlIndex=0 gets the fully qualified root path
3807 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3811 FORMATETC formatetc
;
3812 LPITEMIDLIST pidl
= NULL
;
3814 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3819 /* Set the FORMATETC structure*/
3820 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3822 /* Get the pidls from IDataObject */
3823 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3825 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3826 if(nPidlIndex
<= cida
->cidl
)
3828 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3830 COMCTL32_ReleaseStgMedium(medium
);
3835 /***********************************************************************
3838 * Return the number of selected items in the DataObject.
3841 static UINT
GetNumSelected( IDataObject
*doSelected
)
3845 FORMATETC formatetc
;
3847 TRACE("sv=%p\n", doSelected
);
3849 if (!doSelected
) return 0;
3851 /* Set the FORMATETC structure*/
3852 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3854 /* Get the pidls from IDataObject */
3855 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3857 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3858 retVal
= cida
->cidl
;
3859 COMCTL32_ReleaseStgMedium(medium
);
3869 /***********************************************************************
3872 * Get the pidl's display name (relative to folder) and
3873 * put it in lpstrFileName.
3875 * Return NOERROR on success,
3879 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3884 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3888 SHGetDesktopFolder(&lpsf
);
3889 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3890 IShellFolder_Release(lpsf
);
3894 /* Get the display name of the pidl relative to the folder */
3895 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3897 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3902 /***********************************************************************
3903 * GetShellFolderFromPidl
3905 * pidlRel is the item pidl relative
3906 * Return the IShellFolder of the absolute pidl
3908 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3910 IShellFolder
*psf
= NULL
,*psfParent
;
3912 TRACE("%p\n", pidlAbs
);
3914 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3917 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3919 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3921 IShellFolder_Release(psfParent
);
3925 /* return the desktop */
3931 /***********************************************************************
3934 * Return the LPITEMIDLIST to the parent of the pidl in the list
3936 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3938 LPITEMIDLIST pidlParent
;
3940 TRACE("%p\n", pidl
);
3942 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3943 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3948 /***********************************************************************
3951 * returns the pidl of the file name relative to folder
3952 * NULL if an error occurred
3954 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3956 LPITEMIDLIST pidl
= NULL
;
3959 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3961 if(!lpcstrFileName
) return NULL
;
3962 if(!*lpcstrFileName
) return NULL
;
3966 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3967 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3968 IShellFolder_Release(lpsf
);
3973 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3980 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3982 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3985 TRACE("%p, %p\n", psf
, pidl
);
3987 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3989 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3990 /* see documentation shell 4.1*/
3991 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3994 /***********************************************************************
3995 * BrowseSelectedFolder
3997 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3999 BOOL bBrowseSelFolder
= FALSE
;
4000 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
4004 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4006 LPITEMIDLIST pidlSelection
;
4008 /* get the file selected */
4009 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4010 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4012 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4013 pidlSelection
, SBSP_RELATIVE
) ) )
4015 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
4016 ' ','n','o','t',' ','e','x','i','s','t',0};
4017 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4019 bBrowseSelFolder
= TRUE
;
4020 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4021 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4023 COMDLG32_SHFree( pidlSelection
);
4026 return bBrowseSelFolder
;
4030 * Memory allocation methods */
4031 static void *MemAlloc(UINT size
)
4033 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4036 static void MemFree(void *mem
)
4038 HeapFree(GetProcessHeap(),0,mem
);
4041 static inline BOOL
valid_struct_size( DWORD size
)
4043 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4044 (size
== sizeof( OPENFILENAMEW
));
4047 static inline BOOL
is_win16_looks(DWORD flags
)
4049 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4050 !(flags
& OFN_EXPLORER
));
4053 /* ------------------ APIs ---------------------- */
4055 /***********************************************************************
4056 * GetOpenFileNameA (COMDLG32.@)
4058 * Creates a dialog box for the user to select a file to open.
4061 * TRUE on success: user enters a valid file
4062 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4065 BOOL WINAPI
GetOpenFileNameA(
4066 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4068 TRACE("flags %08x\n", ofn
->Flags
);
4070 if (!valid_struct_size( ofn
->lStructSize
))
4072 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4076 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4077 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4078 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4080 if (is_win16_looks(ofn
->Flags
))
4081 return GetFileName31A(ofn
, OPEN_DIALOG
);
4083 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4086 /***********************************************************************
4087 * GetOpenFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to open.
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI
GetOpenFileNameW(
4097 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4099 TRACE("flags %08x\n", ofn
->Flags
);
4101 if (!valid_struct_size( ofn
->lStructSize
))
4103 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4107 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4108 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4109 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4111 if (is_win16_looks(ofn
->Flags
))
4112 return GetFileName31W(ofn
, OPEN_DIALOG
);
4114 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4118 /***********************************************************************
4119 * GetSaveFileNameA (COMDLG32.@)
4121 * Creates a dialog box for the user to select a file to save.
4124 * TRUE on success: user enters a valid file
4125 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4128 BOOL WINAPI
GetSaveFileNameA(
4129 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4131 if (!valid_struct_size( ofn
->lStructSize
))
4133 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4137 if (is_win16_looks(ofn
->Flags
))
4138 return GetFileName31A(ofn
, SAVE_DIALOG
);
4140 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4143 /***********************************************************************
4144 * GetSaveFileNameW (COMDLG32.@)
4146 * Creates a dialog box for the user to select a file to save.
4149 * TRUE on success: user enters a valid file
4150 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4153 BOOL WINAPI
GetSaveFileNameW(
4154 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4156 if (!valid_struct_size( ofn
->lStructSize
))
4158 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4162 if (is_win16_looks(ofn
->Flags
))
4163 return GetFileName31W(ofn
, SAVE_DIALOG
);
4165 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4168 /***********************************************************************
4169 * GetFileTitleA (COMDLG32.@)
4171 * See GetFileTitleW.
4173 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4176 UNICODE_STRING strWFile
;
4179 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4180 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4181 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4182 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4183 RtlFreeUnicodeString( &strWFile
);
4184 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4189 /***********************************************************************
4190 * GetFileTitleW (COMDLG32.@)
4192 * Get the name of a file.
4195 * lpFile [I] name and location of file
4196 * lpTitle [O] returned file name
4197 * cbBuf [I] buffer size of lpTitle
4201 * Failure: negative number.
4203 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4206 static const WCHAR brkpoint
[] = {'*','[',']',0};
4207 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4209 if(lpFile
== NULL
|| lpTitle
== NULL
)
4212 len
= lstrlenW(lpFile
);
4217 if(strpbrkW(lpFile
, brkpoint
))
4222 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4225 for(i
= len
; i
>= 0; i
--)
4227 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4237 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4239 len
= lstrlenW(lpFile
+i
)+1;
4243 lstrcpyW(lpTitle
, &lpFile
[i
]);