2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
140 static const WCHAR LastVisitedMRUW
[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
147 /***********************************************************************
151 /* Internal functions used by the dialog */
152 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
153 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
154 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
155 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
156 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
157 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
158 static void FILEDLG95_Clean(HWND hwnd
);
160 /* Functions used by the shell navigation */
161 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
162 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
163 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
165 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
170 /* Functions used by the filetype combo box */
171 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
172 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
178 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
179 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
189 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
192 /* Miscellaneous tool functions */
193 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
194 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
195 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
196 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
197 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
198 static UINT
GetNumSelected( IDataObject
*doSelected
);
199 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
201 /* Shell memory allocation */
202 static void *MemAlloc(UINT size
);
203 static void MemFree(void *mem
);
205 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
207 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
208 static BOOL
BrowseSelectedFolder(HWND hwnd
);
210 /***********************************************************************
213 * Creates an Open common dialog box that lets the user select
214 * the drive, directory, and the name of a file or set of files to open.
216 * IN : The FileOpenDlgInfos structure associated with the dialog
217 * OUT : TRUE on success
218 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
220 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
227 /* test for missing functionality */
228 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
230 FIXME("Flags 0x%08x not yet implemented\n",
231 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
234 /* Create the dialog from a template */
236 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
238 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
241 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
242 !(template = LockResource( hDlgTmpl
)))
244 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
248 /* msdn: explorer style dialogs permit sizing by default.
249 * The OFN_ENABLESIZING flag is only needed when a hook or
250 * custom template is provided */
251 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
252 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
253 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
255 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
257 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
258 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
261 /* old style hook messages */
262 if (IsHooked(fodInfos
))
264 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
265 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
266 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
267 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
270 if (fodInfos
->unicode
)
271 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
273 fodInfos
->ofnInfos
->hwndOwner
,
277 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
279 fodInfos
->ofnInfos
->hwndOwner
,
282 if (fodInfos
->ole_initialized
)
285 /* Unable to create the dialog */
292 /***********************************************************************
295 * Call GetFileName95 with this structure and clean the memory.
297 * IN : The OPENFILENAMEA initialisation structure passed to
298 * GetOpenFileNameA win api function (see filedlg.c)
300 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
303 FileOpenDlgInfos fodInfos
;
304 LPSTR lpstrSavDir
= NULL
;
306 LPWSTR defext
= NULL
;
307 LPWSTR filter
= NULL
;
308 LPWSTR customfilter
= NULL
;
309 INITCOMMONCONTROLSEX icc
;
311 /* Initialize ComboBoxEx32 */
312 icc
.dwSize
= sizeof(icc
);
313 icc
.dwICC
= ICC_USEREX_CLASSES
;
314 InitCommonControlsEx(&icc
);
316 /* Initialize CommDlgExtendedError() */
317 COMDLG32_SetCommDlgExtendedError(0);
319 /* Initialize FileOpenDlgInfos structure */
320 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
322 /* Pass in the original ofn */
323 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
325 /* save current directory */
326 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
328 lpstrSavDir
= MemAlloc(MAX_PATH
);
329 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
332 fodInfos
.unicode
= FALSE
;
334 /* convert all the input strings to unicode */
335 if(ofn
->lpstrInitialDir
)
337 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
338 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
339 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
342 fodInfos
.initdir
= NULL
;
346 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
347 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
350 fodInfos
.filename
= NULL
;
354 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
355 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
356 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
358 fodInfos
.defext
= defext
;
362 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
363 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
364 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
366 fodInfos
.title
= title
;
368 if (ofn
->lpstrFilter
)
373 /* filter is a list... title\0ext\0......\0\0 */
374 s
= ofn
->lpstrFilter
;
375 while (*s
) s
= s
+strlen(s
)+1;
377 n
= s
- ofn
->lpstrFilter
;
378 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
379 filter
= MemAlloc(len
*sizeof(WCHAR
));
380 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
382 fodInfos
.filter
= filter
;
384 /* convert lpstrCustomFilter */
385 if (ofn
->lpstrCustomFilter
)
390 /* customfilter contains a pair of strings... title\0ext\0 */
391 s
= ofn
->lpstrCustomFilter
;
392 if (*s
) s
= s
+strlen(s
)+1;
393 if (*s
) s
= s
+strlen(s
)+1;
394 n
= s
- ofn
->lpstrCustomFilter
;
395 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
396 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
397 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
399 fodInfos
.customfilter
= customfilter
;
401 /* Initialize the dialog property */
402 fodInfos
.DlgInfos
.dwDlgProp
= 0;
403 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
408 ret
= GetFileName95(&fodInfos
);
411 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
412 ret
= GetFileName95(&fodInfos
);
418 /* set the lpstrFileTitle */
419 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
421 LPSTR lpstrFileTitle
= PathFindFileNameA(ofn
->lpstrFile
);
422 lstrcpynA(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
427 SetCurrentDirectoryA(lpstrSavDir
);
428 MemFree(lpstrSavDir
);
434 MemFree(customfilter
);
435 MemFree(fodInfos
.initdir
);
436 MemFree(fodInfos
.filename
);
438 TRACE("selected file: %s\n",ofn
->lpstrFile
);
443 /***********************************************************************
446 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
447 * Call GetFileName95 with this structure and clean the memory.
450 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
453 FileOpenDlgInfos fodInfos
;
454 LPWSTR lpstrSavDir
= NULL
;
455 INITCOMMONCONTROLSEX icc
;
457 /* Initialize ComboBoxEx32 */
458 icc
.dwSize
= sizeof(icc
);
459 icc
.dwICC
= ICC_USEREX_CLASSES
;
460 InitCommonControlsEx(&icc
);
462 /* Initialize CommDlgExtendedError() */
463 COMDLG32_SetCommDlgExtendedError(0);
465 /* Initialize FileOpenDlgInfos structure */
466 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
468 /* Pass in the original ofn */
469 fodInfos
.ofnInfos
= ofn
;
471 fodInfos
.title
= ofn
->lpstrTitle
;
472 fodInfos
.defext
= ofn
->lpstrDefExt
;
473 fodInfos
.filter
= ofn
->lpstrFilter
;
474 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
476 /* convert string arguments, save others */
479 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
480 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
483 fodInfos
.filename
= NULL
;
485 if(ofn
->lpstrInitialDir
)
487 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
488 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
489 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
490 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
493 fodInfos
.initdir
= NULL
;
495 /* save current directory */
496 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
498 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
499 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
502 fodInfos
.unicode
= TRUE
;
507 ret
= GetFileName95(&fodInfos
);
510 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
511 ret
= GetFileName95(&fodInfos
);
517 /* set the lpstrFileTitle */
518 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
520 LPWSTR lpstrFileTitle
= PathFindFileNameW(ofn
->lpstrFile
);
521 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
526 SetCurrentDirectoryW(lpstrSavDir
);
527 MemFree(lpstrSavDir
);
530 /* restore saved IN arguments and convert OUT arguments back */
531 MemFree(fodInfos
.filename
);
532 MemFree(fodInfos
.initdir
);
536 /******************************************************************************
537 * COMDLG32_GetDisplayNameOf [internal]
539 * Helper function to get the display name for a pidl.
541 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
542 LPSHELLFOLDER psfDesktop
;
545 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
548 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
549 IShellFolder_Release(psfDesktop
);
553 IShellFolder_Release(psfDesktop
);
554 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
557 /******************************************************************************
558 * COMDLG32_GetCanonicalPath [internal]
560 * Helper function to get the canonical path.
562 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
563 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
565 WCHAR lpstrTemp
[MAX_PATH
];
567 /* Get the current directory name */
568 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
571 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
573 PathAddBackslashW(lpstrPathAndFile
);
575 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
577 /* if the user specified a fully qualified path use it */
578 if(PathIsRelativeW(lpstrFile
))
580 lstrcatW(lpstrPathAndFile
, lpstrFile
);
584 /* does the path have a drive letter? */
585 if (PathGetDriveNumberW(lpstrFile
) == -1)
586 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
588 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
591 /* resolve "." and ".." */
592 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
593 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
594 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
597 /***********************************************************************
598 * COMDLG32_SplitFileNames [internal]
600 * Creates a delimited list of filenames.
602 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
604 UINT nStrCharCount
= 0; /* index in src buffer */
605 UINT nFileIndex
= 0; /* index in dest buffer */
606 UINT nFileCount
= 0; /* number of files */
608 /* we might get single filename without any '"',
609 * so we need nStrLen + terminating \0 + end-of-list \0 */
610 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
613 /* build delimited file list from filenames */
614 while ( nStrCharCount
<= nStrLen
)
616 if ( lpstrEdit
[nStrCharCount
]=='"' )
619 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
621 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
624 (*lpstrFileList
)[nFileIndex
++] = 0;
630 /* single, unquoted string */
631 if ((nStrLen
> 0) && (nFileIndex
== 0) )
633 lstrcpyW(*lpstrFileList
, lpstrEdit
);
634 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
639 (*lpstrFileList
)[nFileIndex
++] = '\0';
641 *sizeUsed
= nFileIndex
;
645 /***********************************************************************
646 * ArrangeCtrlPositions [internal]
648 * NOTE: Make sure to add testcases for any changes made here.
650 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
652 HWND hwndChild
, hwndStc32
;
653 RECT rectParent
, rectChild
, rectStc32
;
657 /* Take into account if open as read only checkbox and help button
662 RECT rectHelp
, rectCancel
;
663 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
664 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
665 /* subtract the height of the help button plus the space between
666 * the help button and the cancel button to the height of the dialog
668 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
672 There are two possibilities to add components to the default file dialog box.
674 By default, all the new components are added below the standard dialog box (the else case).
676 However, if there is a static text component with the stc32 id, a special case happens.
677 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
678 in the window and the cx and cy indicate how to size the window.
679 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
680 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
684 GetClientRect(hwndParentDlg
, &rectParent
);
686 /* when arranging controls we have to use fixed parent size */
687 rectParent
.bottom
-= help_fixup
;
689 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
692 GetWindowRect(hwndStc32
, &rectStc32
);
693 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
695 /* set the size of the stc32 control according to the size of
696 * client area of the parent dialog
698 SetWindowPos(hwndStc32
, 0,
700 rectParent
.right
, rectParent
.bottom
,
701 SWP_NOMOVE
| SWP_NOZORDER
);
704 SetRectEmpty(&rectStc32
);
706 /* this part moves controls of the child dialog */
707 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
710 if (hwndChild
!= hwndStc32
)
712 GetWindowRect(hwndChild
, &rectChild
);
713 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
715 /* move only if stc32 exist */
716 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
718 /* move to the right of visible controls of the parent dialog */
719 rectChild
.left
+= rectParent
.right
;
720 rectChild
.left
-= rectStc32
.right
;
722 /* move even if stc32 doesn't exist */
723 if (rectChild
.top
>= rectStc32
.bottom
)
725 /* move below visible controls of the parent dialog */
726 rectChild
.top
+= rectParent
.bottom
;
727 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
730 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
731 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
733 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
736 /* this part moves controls of the parent dialog */
737 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
740 if (hwndChild
!= hwndChildDlg
)
742 GetWindowRect(hwndChild
, &rectChild
);
743 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
745 /* left,top of stc32 marks the position of controls
746 * from the parent dialog
748 rectChild
.left
+= rectStc32
.left
;
749 rectChild
.top
+= rectStc32
.top
;
751 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
752 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
754 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
757 /* calculate the size of the resulting dialog */
759 /* here we have to use original parent size */
760 GetClientRect(hwndParentDlg
, &rectParent
);
761 GetClientRect(hwndChildDlg
, &rectChild
);
762 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
763 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
768 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
769 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
771 chgx
= rectChild
.right
- rectParent
.right
;
773 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
774 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
776 /* Unconditionally set new dialog
777 * height to that of the child
779 chgy
= rectChild
.bottom
- rectParent
.bottom
;
784 chgy
= rectChild
.bottom
- help_fixup
;
786 /* set the size of the parent dialog */
787 GetWindowRect(hwndParentDlg
, &rectParent
);
788 SetWindowPos(hwndParentDlg
, 0,
790 rectParent
.right
- rectParent
.left
+ chgx
,
791 rectParent
.bottom
- rectParent
.top
+ chgy
,
792 SWP_NOMOVE
| SWP_NOZORDER
);
795 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
804 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
814 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
815 * structure's hInstance parameter is not a HINSTANCE, but
816 * instead a pointer to a template resource to use.
818 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
821 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
823 hinst
= COMDLG32_hInstance
;
824 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
826 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
832 hinst
= fodInfos
->ofnInfos
->hInstance
;
833 if(fodInfos
->unicode
)
835 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
836 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
840 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
841 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
845 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
848 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
849 !(template = LockResource( hDlgTmpl
)))
851 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
855 if (fodInfos
->unicode
)
856 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
857 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
858 (LPARAM
)fodInfos
->ofnInfos
);
860 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
861 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
862 (LPARAM
)fodInfos
->ofnInfos
);
865 else if( IsHooked(fodInfos
))
870 WORD menu
,class,title
;
872 GetClientRect(hwnd
,&rectHwnd
);
873 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
874 temp
.tmplate
.dwExtendedStyle
= 0;
875 temp
.tmplate
.cdit
= 0;
880 temp
.menu
= temp
.class = temp
.title
= 0;
882 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
883 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
890 /***********************************************************************
891 * SendCustomDlgNotificationMessage
893 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
896 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
898 LRESULT hook_result
= 0;
899 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
901 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
903 if(!fodInfos
) return 0;
905 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
907 TRACE("CALL NOTIFY for %x\n", uCode
);
908 if(fodInfos
->unicode
)
911 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
912 ofnNotify
.hdr
.idFrom
=0;
913 ofnNotify
.hdr
.code
= uCode
;
914 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
915 ofnNotify
.pszFile
= NULL
;
916 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
921 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
922 ofnNotify
.hdr
.idFrom
=0;
923 ofnNotify
.hdr
.code
= uCode
;
924 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
925 ofnNotify
.pszFile
= NULL
;
926 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
928 TRACE("RET NOTIFY\n");
930 TRACE("Retval: 0x%08lx\n", hook_result
);
934 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
938 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
940 TRACE("CDM_GETFILEPATH:\n");
942 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
945 /* get path and filenames */
946 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
947 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
948 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
951 p
= buffer
+ strlenW(buffer
);
953 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
955 if (fodInfos
->unicode
)
957 total
= strlenW( buffer
) + 1;
958 if (result
) lstrcpynW( result
, buffer
, size
);
959 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
963 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
964 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
965 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
967 HeapFree( GetProcessHeap(), 0, buffer
);
971 /***********************************************************************
972 * FILEDLG95_HandleCustomDialogMessages
974 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
976 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
978 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
979 WCHAR lpstrPath
[MAX_PATH
];
982 if(!fodInfos
) return FALSE
;
986 case CDM_GETFILEPATH
:
987 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
990 case CDM_GETFOLDERPATH
:
991 TRACE("CDM_GETFOLDERPATH:\n");
992 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
995 if (fodInfos
->unicode
)
996 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
998 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
999 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1001 retval
= lstrlenW(lpstrPath
) + 1;
1004 case CDM_GETFOLDERIDLIST
:
1005 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1006 if (retval
<= wParam
)
1007 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1011 TRACE("CDM_GETSPEC:\n");
1012 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1015 if (fodInfos
->unicode
)
1016 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1018 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1022 case CDM_SETCONTROLTEXT
:
1023 TRACE("CDM_SETCONTROLTEXT:\n");
1026 if( fodInfos
->unicode
)
1027 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1029 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1034 case CDM_HIDECONTROL
:
1035 /* MSDN states that it should fail for not OFN_EXPLORER case */
1036 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1038 HWND control
= GetDlgItem( hwnd
, wParam
);
1039 if (control
) ShowWindow( control
, SW_HIDE
);
1042 else retval
= FALSE
;
1046 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1047 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1050 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1054 /***********************************************************************
1055 * FILEDLG95_OnWMGetMMI
1057 * WM_GETMINMAXINFO message handler for resizable dialogs
1059 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1061 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1062 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1063 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1065 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1070 /***********************************************************************
1071 * FILEDLG95_OnWMSize
1073 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1075 * FIXME: this could be made more elaborate. Now use a simple scheme
1076 * where the file view is enlarged and the controls are either moved
1077 * vertically or horizontally to get out of the way. Only the "grip"
1078 * is moved in both directions to stay in the corner.
1080 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1086 FileOpenDlgInfos
*fodInfos
;
1088 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1089 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1090 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1091 /* get the new dialog rectangle */
1092 GetWindowRect( hwnd
, &rc
);
1093 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1094 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1095 /* not initialized yet */
1096 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1097 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1098 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1100 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1101 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1102 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1103 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1104 /* change the size of the view window */
1105 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1106 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1107 hdwp
= BeginDeferWindowPos( 10);
1108 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1109 rcview
.right
- rcview
.left
+ chgx
,
1110 rcview
.bottom
- rcview
.top
+ chgy
,
1111 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1112 /* change position and sizes of the controls */
1113 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1115 int ctrlid
= GetDlgCtrlID( ctrl
);
1116 GetWindowRect( ctrl
, &rc
);
1117 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1118 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1120 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1122 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1124 else if( rc
.top
> rcview
.bottom
)
1126 /* if it was below the shell view
1130 /* file name (edit or comboboxex) and file types combo change also width */
1134 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1135 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1136 SWP_NOACTIVATE
| SWP_NOZORDER
);
1138 /* then these buttons must move out of the way */
1142 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1144 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1147 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1149 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1152 else if( rc
.left
> rcview
.right
)
1154 /* if it was to the right of the shell view
1156 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1158 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1165 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1167 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1168 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1169 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1171 case IDC_TOOLBARSTATIC
:
1173 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1175 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1178 /* not resized in windows. Since wine uses this invisible control
1179 * to size the browser view it needs to be resized */
1180 case IDC_SHELLSTATIC
:
1181 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1182 rc
.right
- rc
.left
+ chgx
,
1183 rc
.bottom
- rc
.top
+ chgy
,
1184 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1189 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1190 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1192 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1193 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1195 GetWindowRect( ctrl
, &rc
);
1196 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1197 if( rc
.top
> rcview
.bottom
)
1199 /* if it was below the shell view
1201 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1202 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1203 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1205 else if( rc
.left
> rcview
.right
)
1207 /* if it was to the right of the shell view
1209 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1210 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1211 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1214 /* size the custom dialog at the end: some applications do some
1215 * control re-arranging at this point */
1216 GetClientRect(hwnd
, &rc
);
1217 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1218 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1220 EndDeferWindowPos( hdwp
);
1221 /* should not be needed */
1222 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1226 /***********************************************************************
1229 * File open dialog procedure
1231 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1234 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1241 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1243 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1244 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1246 /* Some shell namespace extensions depend on COM being initialized. */
1247 if (SUCCEEDED(OleInitialize(NULL
)))
1248 fodInfos
->ole_initialized
= TRUE
;
1250 /* Adds the FileOpenDlgInfos in the property list of the dialog
1251 so it will be easily accessible through a GetPropA(...) */
1252 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1254 FILEDLG95_InitControls(hwnd
);
1256 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1258 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1259 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1260 RECT client
, client_adjusted
;
1262 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1264 style
|= WS_SIZEBOX
;
1265 ex_style
|= WS_EX_WINDOWEDGE
;
1268 style
&= ~WS_SIZEBOX
;
1269 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1270 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1272 GetClientRect( hwnd
, &client
);
1273 GetClientRect( hwnd
, &client_adjusted
);
1274 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1276 GetWindowRect( hwnd
, &rc
);
1277 rc
.right
+= client_adjusted
.right
- client
.right
;
1278 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1279 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1280 SWP_NOZORDER
| SWP_NOMOVE
);
1282 GetWindowRect( hwnd
, &rc
);
1283 fodInfos
->DlgInfos
.hwndGrip
=
1284 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1285 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1286 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1287 rc
.right
- gripx
, rc
.bottom
- gripy
,
1288 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1291 fodInfos
->DlgInfos
.hwndCustomDlg
=
1292 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1294 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1295 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1297 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1298 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1300 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1301 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1302 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1305 /* if the app has changed the position of the invisible listbox,
1306 * change that of the listview (browser) as well */
1307 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1308 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1309 if( !EqualRect( &rc
, &rcstc
))
1311 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1312 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1313 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1314 SWP_NOACTIVATE
| SWP_NOZORDER
);
1317 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1319 GetWindowRect( hwnd
, &rc
);
1320 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1321 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1322 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1323 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1324 GetClientRect( hwnd
, &rc
);
1325 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1326 rc
.right
- gripx
, rc
.bottom
- gripy
,
1327 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1328 /* resize the dialog to the previous invocation */
1329 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1330 SetWindowPos( hwnd
, NULL
,
1331 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1332 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1335 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1336 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1341 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1342 case WM_GETMINMAXINFO
:
1343 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1345 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1348 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1351 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1357 case WM_GETISHELLBROWSER
:
1358 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1362 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1363 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1364 MemDialogSize
= fodInfos
->sizedlg
;
1365 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1370 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1373 /* set up the button tooltips strings */
1374 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1376 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1377 switch(lpnmh
->idFrom
)
1379 /* Up folder button */
1380 case FCIDM_TB_UPFOLDER
:
1381 stringId
= IDS_UPFOLDER
;
1383 /* New folder button */
1384 case FCIDM_TB_NEWFOLDER
:
1385 stringId
= IDS_NEWFOLDER
;
1387 /* List option button */
1388 case FCIDM_TB_SMALLICON
:
1389 stringId
= IDS_LISTVIEW
;
1391 /* Details option button */
1392 case FCIDM_TB_REPORTVIEW
:
1393 stringId
= IDS_REPORTVIEW
;
1395 /* Desktop button */
1396 case FCIDM_TB_DESKTOP
:
1397 stringId
= IDS_TODESKTOP
;
1402 lpdi
->hinst
= COMDLG32_hInstance
;
1403 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1408 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1409 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1414 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1416 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1417 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1420 /***********************************************************************
1421 * FILEDLG95_InitControls
1423 * WM_INITDIALOG message handler (before hook notification)
1425 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1427 BOOL win2000plus
= FALSE
;
1428 BOOL win98plus
= FALSE
;
1429 BOOL handledPath
= FALSE
;
1430 OSVERSIONINFOW osVi
;
1431 static const WCHAR szwSlash
[] = { '\\', 0 };
1432 static const WCHAR szwStar
[] = { '*',0 };
1434 static const TBBUTTON tbb
[] =
1436 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1437 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1438 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1439 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1440 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1441 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1442 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1443 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1444 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1446 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1451 HIMAGELIST toolbarImageList
;
1452 SHFILEINFOA shFileInfo
;
1453 ITEMIDLIST
*desktopPidl
;
1455 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1457 TRACE("%p\n", fodInfos
);
1459 /* Get windows version emulating */
1460 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1461 GetVersionExW(&osVi
);
1462 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1463 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1464 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1465 win2000plus
= (osVi
.dwMajorVersion
> 4);
1466 if (win2000plus
) win98plus
= TRUE
;
1468 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1471 /* Use either the edit or the comboboxex for the filename control */
1472 if (filename_is_edit( fodInfos
))
1474 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1475 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1479 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1480 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1483 /* Get the hwnd of the controls */
1484 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1485 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1487 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1488 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1490 /* construct the toolbar */
1491 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1492 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1494 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1495 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1496 rectTB
.left
= rectlook
.right
;
1497 rectTB
.top
= rectlook
.top
-1;
1499 if (fodInfos
->unicode
)
1500 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1501 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1502 rectTB
.left
, rectTB
.top
,
1503 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1504 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1506 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, 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 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1514 /* FIXME: use TB_LOADIMAGES when implemented */
1515 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1516 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1517 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1519 /* Retrieve and add desktop icon to the toolbar */
1520 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1521 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1522 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1523 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1524 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1526 DestroyIcon(shFileInfo
.hIcon
);
1527 CoTaskMemFree(desktopPidl
);
1529 /* Finish Toolbar Construction */
1530 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1531 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1533 /* Set the window text with the text specified in the OPENFILENAME structure */
1536 SetWindowTextW(hwnd
,fodInfos
->title
);
1538 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1541 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1542 SetWindowTextW(hwnd
, buf
);
1545 /* Initialise the file name edit control */
1546 handledPath
= FALSE
;
1547 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1549 if(fodInfos
->filename
)
1551 /* 1. If win2000 or higher and filename contains a path, use it
1552 in preference over the lpstrInitialDir */
1553 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1554 WCHAR tmpBuf
[MAX_PATH
];
1558 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1561 /* nameBit is always shorter than the original filename. It may be NULL
1562 * when the filename contains only a drive name instead of file name */
1565 lstrcpyW(fodInfos
->filename
,nameBit
);
1569 *fodInfos
->filename
= '\0';
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
);
2543 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2546 else if( nOpenAction
== ONOPEN_SEARCH
)
2548 if (fodInfos
->Shell
.FOIShellView
)
2549 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2551 COMDLG32_SHFree(pidlCurrent
);
2552 if (filename_is_edit( fodInfos
))
2553 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2558 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2559 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2565 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2566 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2570 /* update READONLY check box flag */
2571 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2572 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2574 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2576 /* Attach the file extension with file name*/
2577 ext
= PathFindExtensionW(lpstrPathAndFile
);
2578 if (! *ext
&& fodInfos
->defext
)
2580 /* if no extension is specified with file name, then */
2581 /* attach the extension from file filter or default one */
2583 WCHAR
*filterExt
= NULL
;
2584 LPWSTR lpstrFilter
= NULL
;
2585 static const WCHAR szwDot
[] = {'.',0};
2586 int PathLength
= lstrlenW(lpstrPathAndFile
);
2588 /*Get the file extension from file type filter*/
2589 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2590 fodInfos
->ofnInfos
->nFilterIndex
-1);
2592 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2594 WCHAR
* filterSearchIndex
;
2595 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2596 strcpyW(filterExt
, lpstrFilter
);
2598 /* if a semicolon-separated list of file extensions was given, do not include the
2599 semicolon or anything after it in the extension.
2600 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2601 filterSearchIndex
= strchrW(filterExt
, ';');
2602 if (filterSearchIndex
)
2604 filterSearchIndex
[0] = '\0';
2607 /* find the file extension by searching for the first dot in filterExt */
2608 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2609 /* if the extension is invalid or contains a glob, ignore it */
2610 filterSearchIndex
= strchrW(filterExt
, '.');
2611 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2613 strcpyW(filterExt
, filterSearchIndex
);
2617 HeapFree(GetProcessHeap(), 0, filterExt
);
2624 /* use the default file extension */
2625 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2626 strcpyW(filterExt
, fodInfos
->defext
);
2629 if (*filterExt
) /* ignore filterExt="" */
2632 lstrcatW(lpstrPathAndFile
, szwDot
);
2633 /* Attach the extension */
2634 lstrcatW(lpstrPathAndFile
, filterExt
);
2637 HeapFree(GetProcessHeap(), 0, filterExt
);
2639 /* In Open dialog: if file does not exist try without extension */
2640 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2641 lpstrPathAndFile
[PathLength
] = '\0';
2643 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2646 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2647 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2649 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2652 /* In Save dialog: check if the file already exists */
2653 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2654 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2655 && PathFileExistsW(lpstrPathAndFile
))
2657 WCHAR lpstrOverwrite
[100];
2660 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2661 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2662 MB_YESNO
| MB_ICONEXCLAMATION
);
2663 if (answer
== IDNO
|| answer
== IDCANCEL
)
2670 /* In Open dialog: check if it should be created if it doesn't exist */
2671 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2672 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2673 && !PathFileExistsW(lpstrPathAndFile
))
2675 WCHAR lpstrCreate
[100];
2678 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2679 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2680 MB_YESNO
| MB_ICONEXCLAMATION
);
2681 if (answer
== IDNO
|| answer
== IDCANCEL
)
2688 /* Check that the size of the file does not exceed buffer size.
2689 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2690 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2691 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2694 /* fill destination buffer */
2695 if (fodInfos
->ofnInfos
->lpstrFile
)
2697 if(fodInfos
->unicode
)
2699 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2701 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2702 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2703 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2707 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2709 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2710 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2711 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2712 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2716 if(fodInfos
->unicode
)
2720 /* set filename offset */
2721 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2722 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2724 /* set extension offset */
2725 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2726 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2731 CHAR tempFileA
[MAX_PATH
];
2733 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2734 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2735 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2737 /* set filename offset */
2738 lpszTemp
= PathFindFileNameA(tempFileA
);
2739 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2741 /* set extension offset */
2742 lpszTemp
= PathFindExtensionA(tempFileA
);
2743 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2746 /* copy currently selected filter to lpstrCustomFilter */
2747 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2749 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2750 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2751 NULL
, 0, NULL
, NULL
);
2752 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2754 LPSTR s
= ofn
->lpstrCustomFilter
;
2755 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2756 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2757 s
, len
, NULL
, NULL
);
2762 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2765 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2768 FILEDLG95_Clean(hwnd
);
2769 ret
= EndDialog(hwnd
, TRUE
);
2775 size
= lstrlenW(lpstrPathAndFile
) + 1;
2776 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2778 /* return needed size in first two bytes of lpstrFile */
2779 if(fodInfos
->ofnInfos
->lpstrFile
)
2780 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2781 FILEDLG95_Clean(hwnd
);
2782 ret
= EndDialog(hwnd
, FALSE
);
2783 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2790 if(lpsf
) IShellFolder_Release(lpsf
);
2794 /***********************************************************************
2795 * FILEDLG95_SHELL_Init
2797 * Initialisation of the shell objects
2799 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2801 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2806 * Initialisation of the FileOpenDialogInfos structure
2812 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2814 /* Disable multi-select if flag not set */
2815 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2817 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2819 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2820 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2822 /* Construct the IShellBrowser interface */
2823 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2828 /***********************************************************************
2829 * FILEDLG95_SHELL_ExecuteCommand
2831 * Change the folder option and refresh the view
2832 * If the function succeeds, the return value is nonzero.
2834 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2836 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2839 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2841 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2846 CMINVOKECOMMANDINFO ci
;
2847 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2848 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2852 IContextMenu_InvokeCommand(pcm
, &ci
);
2853 IContextMenu_Release(pcm
);
2859 /***********************************************************************
2860 * FILEDLG95_SHELL_UpFolder
2862 * Browse to the specified object
2863 * If the function succeeds, the return value is nonzero.
2865 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2867 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2871 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2875 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2876 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2882 /***********************************************************************
2883 * FILEDLG95_SHELL_BrowseToDesktop
2885 * Browse to the Desktop
2886 * If the function succeeds, the return value is nonzero.
2888 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2890 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2896 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2897 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2898 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2899 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2900 COMDLG32_SHFree(pidl
);
2901 return SUCCEEDED(hres
);
2903 /***********************************************************************
2904 * FILEDLG95_SHELL_Clean
2906 * Cleans the memory used by shell objects
2908 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2910 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2914 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2916 /* clean Shell interfaces */
2917 if (fodInfos
->Shell
.FOIShellView
)
2919 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2920 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2922 if (fodInfos
->Shell
.FOIShellFolder
)
2923 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2924 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2925 if (fodInfos
->Shell
.FOIDataObject
)
2926 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2929 /***********************************************************************
2930 * FILEDLG95_FILETYPE_Init
2932 * Initialisation of the file type combo box
2934 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2936 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2937 int nFilters
= 0; /* number of filters */
2942 if(fodInfos
->customfilter
)
2944 /* customfilter has one entry... title\0ext\0
2945 * Set first entry of combo box item with customfilter
2948 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2951 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2953 /* Copy the extensions */
2954 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2955 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2956 lstrcpyW(lpstrExt
,lpstrPos
);
2958 /* Add the item at the end of the combo */
2959 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2960 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2963 if(fodInfos
->filter
)
2965 LPCWSTR lpstrPos
= fodInfos
->filter
;
2969 /* filter is a list... title\0ext\0......\0\0
2970 * Set the combo item text to the title and the item data
2973 LPCWSTR lpstrDisplay
;
2977 if(! *lpstrPos
) break; /* end */
2978 lpstrDisplay
= lpstrPos
;
2979 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2981 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2985 /* Copy the extensions */
2986 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2987 lstrcpyW(lpstrExt
,lpstrPos
);
2988 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2990 /* Add the item at the end of the combo */
2991 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2993 /* malformed filters are added anyway... */
2994 if (!*lpstrExt
) break;
2999 * Set the current filter to the one specified
3000 * in the initialisation structure
3002 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3006 /* Check to make sure our index isn't out of bounds. */
3007 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3008 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3009 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3011 /* set default filter index */
3012 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3013 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3015 /* calculate index of Combo Box item */
3016 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3017 if (fodInfos
->customfilter
== NULL
)
3020 /* Set the current index selection. */
3021 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3023 /* Get the corresponding text string from the combo box. */
3024 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3027 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3033 CharLowerW(lpstrFilter
); /* lowercase */
3034 len
= lstrlenW(lpstrFilter
)+1;
3035 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3036 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3039 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3043 /***********************************************************************
3044 * FILEDLG95_FILETYPE_OnCommand
3046 * WM_COMMAND of the file type combo box
3047 * If the function succeeds, the return value is nonzero.
3049 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3051 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3059 /* Get the current item of the filetype combo box */
3060 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3062 /* set the current filter index */
3063 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3064 (fodInfos
->customfilter
== NULL
? 1 : 0);
3066 /* Set the current filter with the current selection */
3067 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3069 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3071 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3074 CharLowerW(lpstrFilter
); /* lowercase */
3075 len
= lstrlenW(lpstrFilter
)+1;
3076 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3077 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3078 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3079 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3082 /* Refresh the actual view to display the included items*/
3083 if (fodInfos
->Shell
.FOIShellView
)
3084 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3089 /***********************************************************************
3090 * FILEDLG95_FILETYPE_SearchExt
3092 * searches for an extension in the filetype box
3094 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3096 int i
, iCount
= CBGetCount(hwnd
);
3098 TRACE("%s\n", debugstr_w(lpstrExt
));
3100 if(iCount
!= CB_ERR
)
3102 for(i
=0;i
<iCount
;i
++)
3104 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3111 /***********************************************************************
3112 * FILEDLG95_FILETYPE_Clean
3114 * Clean the memory used by the filetype combo box
3116 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3118 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3120 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3124 /* Delete each string of the combo and their associated data */
3125 if(iCount
!= CB_ERR
)
3127 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3129 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3130 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3133 /* Current filter */
3134 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3138 /***********************************************************************
3139 * FILEDLG95_LOOKIN_Init
3141 * Initialisation of the look in combo box
3144 /* Small helper function, to determine if the unixfs shell extension is rooted
3145 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3147 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3149 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3150 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3151 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3152 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3153 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3154 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3155 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3157 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3164 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3166 IShellFolder
*psfRoot
, *psfDrives
;
3167 IEnumIDList
*lpeRoot
, *lpeDrives
;
3168 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3171 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3175 liInfos
->iMaxIndentation
= 0;
3177 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3179 hdc
= GetDC( hwndCombo
);
3180 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3181 GetTextMetricsW( hdc
, &tm
);
3182 ReleaseDC( hwndCombo
, hdc
);
3184 /* set item height for both text field and listbox */
3185 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3186 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3188 /* Turn on the extended UI for the combo box like Windows does */
3189 CBSetExtendedUI(hwndCombo
, TRUE
);
3191 /* Initialise data of Desktop folder */
3192 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3193 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3194 COMDLG32_SHFree(pidlTmp
);
3196 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3198 SHGetDesktopFolder(&psfRoot
);
3202 /* enumerate the contents of the desktop */
3203 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3205 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3207 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3209 /* If the unixfs extension is rooted, we don't expand the drives by default */
3210 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3212 /* special handling for CSIDL_DRIVES */
3213 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3215 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3217 /* enumerate the drives */
3218 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3220 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3222 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3223 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3224 COMDLG32_SHFree(pidlAbsTmp
);
3225 COMDLG32_SHFree(pidlTmp1
);
3227 IEnumIDList_Release(lpeDrives
);
3229 IShellFolder_Release(psfDrives
);
3234 COMDLG32_SHFree(pidlTmp
);
3236 IEnumIDList_Release(lpeRoot
);
3238 IShellFolder_Release(psfRoot
);
3241 COMDLG32_SHFree(pidlDrives
);
3244 /***********************************************************************
3245 * FILEDLG95_LOOKIN_DrawItem
3247 * WM_DRAWITEM message handler
3249 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3251 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3252 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3253 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3257 HIMAGELIST ilItemImage
;
3260 LPSFOLDER tmpFolder
;
3261 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3262 UINT icon_width
, icon_height
;
3266 if(pDIStruct
->itemID
== -1)
3269 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3270 pDIStruct
->itemID
)))
3274 icon_width
= GetSystemMetrics(SM_CXICON
);
3275 icon_height
= GetSystemMetrics(SM_CYICON
);
3276 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3278 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3279 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3280 shgfi_flags
|= SHGFI_SMALLICON
;
3283 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3284 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3286 /* Is this item selected ? */
3287 if(pDIStruct
->itemState
& ODS_SELECTED
)
3289 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3290 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3291 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3295 SetTextColor(pDIStruct
->hDC
,crText
);
3296 SetBkColor(pDIStruct
->hDC
,crWin
);
3297 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3300 /* Do not indent item if drawing in the edit of the combo */
3301 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3304 iIndentation
= tmpFolder
->m_iIndent
;
3306 /* Draw text and icon */
3308 /* Initialise the icon display area */
3309 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3310 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3311 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3312 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3314 /* Initialise the text display area */
3315 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3316 rectText
.left
= rectIcon
.right
;
3318 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3319 rectText
.right
= pDIStruct
->rcItem
.right
;
3321 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3323 /* Draw the icon from the image list */
3324 ImageList_Draw(ilItemImage
,
3331 /* Draw the associated text */
3332 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3336 /***********************************************************************
3337 * FILEDLG95_LOOKIN_OnCommand
3339 * LookIn combo box WM_COMMAND message handler
3340 * If the function succeeds, the return value is nonzero.
3342 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3344 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3346 TRACE("%p\n", fodInfos
);
3352 LPSFOLDER tmpFolder
;
3355 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3357 if( iItem
== CB_ERR
) return FALSE
;
3359 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3364 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3365 tmpFolder
->pidlItem
,
3368 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3369 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3379 /***********************************************************************
3380 * FILEDLG95_LOOKIN_AddItem
3382 * Adds an absolute pidl item to the lookin combo box
3383 * returns the index of the inserted item
3385 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3387 LPITEMIDLIST pidlNext
;
3390 LookInInfos
*liInfos
;
3392 TRACE("%08x\n", iInsertId
);
3397 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3400 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3401 tmpFolder
->m_iIndent
= 0;
3403 /* Calculate the indentation of the item in the lookin*/
3405 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3407 tmpFolder
->m_iIndent
++;
3410 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3412 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3413 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3415 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3416 SHGetFileInfoW((LPCWSTR
)pidl
,
3420 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3421 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3423 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3425 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3429 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3431 /* Add the item at the end of the list */
3434 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3436 /* Insert the item at the iInsertId position*/
3439 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3442 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3446 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3447 MemFree( tmpFolder
);
3452 /***********************************************************************
3453 * FILEDLG95_LOOKIN_InsertItemAfterParent
3455 * Insert an item below its parent
3457 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3460 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3465 if (pidl
== pidlParent
)
3468 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3472 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3475 /* Free pidlParent memory */
3476 COMDLG32_SHFree(pidlParent
);
3478 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3481 /***********************************************************************
3482 * FILEDLG95_LOOKIN_SelectItem
3484 * Adds an absolute pidl item to the lookin combo box
3485 * returns the index of the inserted item
3487 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3490 LookInInfos
*liInfos
;
3494 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3496 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3500 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3501 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3506 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3507 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3511 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3513 if(iRemovedItem
< iItemPos
)
3518 CBSetCurSel(hwnd
,iItemPos
);
3519 liInfos
->uSelectedItem
= iItemPos
;
3525 /***********************************************************************
3526 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3528 * Remove the item with an expansion level over iExpansionLevel
3530 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3533 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3537 if(liInfos
->iMaxIndentation
<= 2)
3540 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3542 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3543 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3545 CBDeleteString(hwnd
,iItemPos
);
3546 liInfos
->iMaxIndentation
--;
3554 /***********************************************************************
3555 * FILEDLG95_LOOKIN_SearchItem
3557 * Search for pidl in the lookin combo box
3558 * returns the index of the found item
3560 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3563 int iCount
= CBGetCount(hwnd
);
3565 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3567 if (iCount
!= CB_ERR
)
3571 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3573 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3575 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3583 /***********************************************************************
3584 * FILEDLG95_LOOKIN_Clean
3586 * Clean the memory used by the lookin combo box
3588 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3590 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3591 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3593 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3597 /* Delete each string of the combo and their associated data */
3598 if (iCount
!= CB_ERR
)
3600 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3602 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3603 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3605 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3609 /* LookInInfos structure */
3611 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3614 /***********************************************************************
3617 * Fill the FORMATETC used in the shell id list
3619 static FORMATETC
get_def_format(void)
3621 static CLIPFORMAT cfFormat
;
3622 FORMATETC formatetc
;
3624 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3625 formatetc
.cfFormat
= cfFormat
;
3627 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3628 formatetc
.lindex
= -1;
3629 formatetc
.tymed
= TYMED_HGLOBAL
;
3633 /***********************************************************************
3634 * FILEDLG95_FILENAME_FillFromSelection
3636 * fills the edit box from the cached DataObject
3638 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3640 FileOpenDlgInfos
*fodInfos
;
3642 LPWSTR lpstrAllFiles
, lpstrTmp
;
3643 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3646 FORMATETC formatetc
= get_def_format();
3649 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3651 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3654 cida
= GlobalLock(medium
.u
.hGlobal
);
3655 nFileSelected
= cida
->cidl
;
3657 /* Allocate a buffer */
3658 nAllFilesMaxLength
= MAX_PATH
+ 3;
3659 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3663 /* Loop through the selection, handle only files (not folders) */
3664 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3666 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3669 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3671 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3673 nAllFilesMaxLength
*= 2;
3674 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3677 lpstrAllFiles
= lpstrTmp
;
3680 lpstrAllFiles
[nAllFilesLength
++] = '"';
3681 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3682 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3683 nAllFilesLength
+= nThisFileLength
;
3684 lpstrAllFiles
[nAllFilesLength
++] = '"';
3685 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3692 /* If there's only one file, use the name as-is without quotes */
3693 lpstrTmp
= lpstrAllFiles
;
3697 lpstrTmp
[nThisFileLength
] = 0;
3699 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3700 /* Select the file name like Windows does */
3701 if (filename_is_edit(fodInfos
))
3702 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3706 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3707 COMCTL32_ReleaseStgMedium(medium
);
3711 /* copied from shell32 to avoid linking to it
3712 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3713 * is dependent on whether emulated OS is unicode or not.
3715 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3720 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3721 COMDLG32_SHFree(src
->u
.pOleStr
);
3725 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3730 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3735 FIXME("unknown type %x!\n", src
->uType
);
3736 if (len
) *dest
= '\0';
3742 /***********************************************************************
3743 * FILEDLG95_FILENAME_GetFileNames
3745 * Copies the filenames to a delimited string list.
3747 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3749 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3750 UINT nFileCount
= 0; /* number of files */
3751 UINT nStrLen
= 0; /* length of string in edit control */
3752 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3756 /* get the filenames from the filename control */
3757 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3758 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3759 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3761 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3763 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3769 * DATAOBJECT Helper functions
3772 /***********************************************************************
3773 * COMCTL32_ReleaseStgMedium
3775 * like ReleaseStgMedium from ole32
3777 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3779 if(medium
.pUnkForRelease
)
3781 IUnknown_Release(medium
.pUnkForRelease
);
3785 GlobalUnlock(medium
.u
.hGlobal
);
3786 GlobalFree(medium
.u
.hGlobal
);
3790 /***********************************************************************
3791 * GetPidlFromDataObject
3793 * Return pidl(s) by number from the cached DataObject
3795 * nPidlIndex=0 gets the fully qualified root path
3797 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3801 FORMATETC formatetc
= get_def_format();
3802 LPITEMIDLIST pidl
= NULL
;
3804 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3809 /* Get the pidls from IDataObject */
3810 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3812 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3813 if(nPidlIndex
<= cida
->cidl
)
3815 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3817 COMCTL32_ReleaseStgMedium(medium
);
3822 /***********************************************************************
3825 * Return the number of selected items in the DataObject.
3828 static UINT
GetNumSelected( IDataObject
*doSelected
)
3832 FORMATETC formatetc
= get_def_format();
3834 TRACE("sv=%p\n", doSelected
);
3836 if (!doSelected
) return 0;
3838 /* Get the pidls from IDataObject */
3839 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3841 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3842 retVal
= cida
->cidl
;
3843 COMCTL32_ReleaseStgMedium(medium
);
3853 /***********************************************************************
3856 * Get the pidl's display name (relative to folder) and
3857 * put it in lpstrFileName.
3859 * Return NOERROR on success,
3863 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3868 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3872 SHGetDesktopFolder(&lpsf
);
3873 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3874 IShellFolder_Release(lpsf
);
3878 /* Get the display name of the pidl relative to the folder */
3879 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3881 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3886 /***********************************************************************
3887 * GetShellFolderFromPidl
3889 * pidlRel is the item pidl relative
3890 * Return the IShellFolder of the absolute pidl
3892 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3894 IShellFolder
*psf
= NULL
,*psfParent
;
3896 TRACE("%p\n", pidlAbs
);
3898 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3901 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3903 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3905 IShellFolder_Release(psfParent
);
3909 /* return the desktop */
3915 /***********************************************************************
3918 * Return the LPITEMIDLIST to the parent of the pidl in the list
3920 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3922 LPITEMIDLIST pidlParent
;
3924 TRACE("%p\n", pidl
);
3926 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3927 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3932 /***********************************************************************
3935 * returns the pidl of the file name relative to folder
3936 * NULL if an error occurred
3938 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3940 LPITEMIDLIST pidl
= NULL
;
3943 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3945 if(!lpcstrFileName
) return NULL
;
3946 if(!*lpcstrFileName
) return NULL
;
3950 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3951 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3952 IShellFolder_Release(lpsf
);
3957 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3964 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3966 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3969 TRACE("%p, %p\n", psf
, pidl
);
3971 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3973 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3974 /* see documentation shell 4.1*/
3975 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3978 /***********************************************************************
3979 * BrowseSelectedFolder
3981 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3983 BOOL bBrowseSelFolder
= FALSE
;
3984 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3988 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3990 LPITEMIDLIST pidlSelection
;
3992 /* get the file selected */
3993 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3994 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3996 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3997 pidlSelection
, SBSP_RELATIVE
) ) )
4000 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
4001 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4003 bBrowseSelFolder
= TRUE
;
4004 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4005 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4007 COMDLG32_SHFree( pidlSelection
);
4010 return bBrowseSelFolder
;
4014 * Memory allocation methods */
4015 static void *MemAlloc(UINT size
)
4017 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4020 static void MemFree(void *mem
)
4022 HeapFree(GetProcessHeap(),0,mem
);
4025 static inline BOOL
valid_struct_size( DWORD size
)
4027 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4028 (size
== sizeof( OPENFILENAMEW
));
4031 static inline BOOL
is_win16_looks(DWORD flags
)
4033 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4034 !(flags
& OFN_EXPLORER
));
4037 /* ------------------ APIs ---------------------- */
4039 /***********************************************************************
4040 * GetOpenFileNameA (COMDLG32.@)
4042 * Creates a dialog box for the user to select a file to open.
4045 * TRUE on success: user enters a valid file
4046 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4049 BOOL WINAPI
GetOpenFileNameA(
4050 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4052 TRACE("flags %08x\n", ofn
->Flags
);
4054 if (!valid_struct_size( ofn
->lStructSize
))
4056 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4060 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4061 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4062 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4064 if (is_win16_looks(ofn
->Flags
))
4065 return GetFileName31A(ofn
, OPEN_DIALOG
);
4067 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4070 /***********************************************************************
4071 * GetOpenFileNameW (COMDLG32.@)
4073 * Creates a dialog box for the user to select a file to open.
4076 * TRUE on success: user enters a valid file
4077 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4080 BOOL WINAPI
GetOpenFileNameW(
4081 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4083 TRACE("flags %08x\n", ofn
->Flags
);
4085 if (!valid_struct_size( ofn
->lStructSize
))
4087 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4091 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4092 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4093 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4095 if (is_win16_looks(ofn
->Flags
))
4096 return GetFileName31W(ofn
, OPEN_DIALOG
);
4098 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4102 /***********************************************************************
4103 * GetSaveFileNameA (COMDLG32.@)
4105 * Creates a dialog box for the user to select a file to save.
4108 * TRUE on success: user enters a valid file
4109 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4112 BOOL WINAPI
GetSaveFileNameA(
4113 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4115 if (!valid_struct_size( ofn
->lStructSize
))
4117 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4121 if (is_win16_looks(ofn
->Flags
))
4122 return GetFileName31A(ofn
, SAVE_DIALOG
);
4124 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4127 /***********************************************************************
4128 * GetSaveFileNameW (COMDLG32.@)
4130 * Creates a dialog box for the user to select a file to save.
4133 * TRUE on success: user enters a valid file
4134 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4137 BOOL WINAPI
GetSaveFileNameW(
4138 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4140 if (!valid_struct_size( ofn
->lStructSize
))
4142 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4146 if (is_win16_looks(ofn
->Flags
))
4147 return GetFileName31W(ofn
, SAVE_DIALOG
);
4149 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4152 /***********************************************************************
4153 * GetFileTitleA (COMDLG32.@)
4155 * See GetFileTitleW.
4157 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4160 UNICODE_STRING strWFile
;
4163 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4164 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4165 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4166 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4167 RtlFreeUnicodeString( &strWFile
);
4168 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4173 /***********************************************************************
4174 * GetFileTitleW (COMDLG32.@)
4176 * Get the name of a file.
4179 * lpFile [I] name and location of file
4180 * lpTitle [O] returned file name
4181 * cbBuf [I] buffer size of lpTitle
4185 * Failure: negative number.
4187 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4190 static const WCHAR brkpoint
[] = {'*','[',']',0};
4191 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4193 if(lpFile
== NULL
|| lpTitle
== NULL
)
4196 len
= lstrlenW(lpFile
);
4201 if(strpbrkW(lpFile
, brkpoint
))
4206 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4209 for(i
= len
; i
>= 0; i
--)
4211 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4221 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4223 len
= lstrlenW(lpFile
+i
)+1;
4227 lstrcpyW(lpTitle
, &lpFile
[i
]);