2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
73 #include "filedlgbrowser.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex
; /* Index of picture in image list */
95 int m_iIndent
; /* Indentation index */
96 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
100 typedef struct tagLookInInfo
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
166 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
167 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
169 static const WCHAR LastVisitedMRUW
[] =
170 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
173 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
174 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
176 /***********************************************************************
180 /* Internal functions used by the dialog */
181 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
182 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
183 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
184 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
185 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
186 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
187 static void FILEDLG95_Clean(HWND hwnd
);
189 /* Functions used by the shell navigation */
190 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
191 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
192 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
199 /* Functions used by the filetype combo box */
200 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
201 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
207 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
208 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
216 /* Functions for dealing with the most-recently-used registry keys */
217 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
218 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
219 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
221 /* Miscellaneous tool functions */
222 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
223 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
224 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
225 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
226 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
227 static UINT
GetNumSelected( IDataObject
*doSelected
);
228 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
230 /* Shell memory allocation */
231 static void *MemAlloc(UINT size
);
232 static void MemFree(void *mem
);
234 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
235 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
236 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
237 static BOOL
BrowseSelectedFolder(HWND hwnd
);
239 /***********************************************************************
242 * Creates an Open common dialog box that lets the user select
243 * the drive, directory, and the name of a file or set of files to open.
245 * IN : The FileOpenDlgInfos structure associated with the dialog
246 * OUT : TRUE on success
247 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
249 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
256 /* test for missing functionality */
257 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
259 FIXME("Flags 0x%08x not yet implemented\n",
260 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
263 /* Create the dialog from a template */
265 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
267 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
270 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
271 !(template = LockResource( hDlgTmpl
)))
273 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
277 /* msdn: explorer style dialogs permit sizing by default.
278 * The OFN_ENABLESIZING flag is only needed when a hook or
279 * custom template is provided */
280 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
281 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
282 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
284 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
286 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
287 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
290 /* old style hook messages */
291 if (IsHooked(fodInfos
))
293 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
294 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
295 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
296 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
299 if (fodInfos
->unicode
)
300 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
302 fodInfos
->ofnInfos
->hwndOwner
,
306 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
308 fodInfos
->ofnInfos
->hwndOwner
,
311 if (fodInfos
->ole_initialized
)
314 /* Unable to create the dialog */
321 /***********************************************************************
324 * Call GetFileName95 with this structure and clean the memory.
326 * IN : The OPENFILENAMEA initialisation structure passed to
327 * GetOpenFileNameA win api function (see filedlg.c)
329 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
332 FileOpenDlgInfos fodInfos
;
333 LPSTR lpstrSavDir
= NULL
;
335 LPWSTR defext
= NULL
;
336 LPWSTR filter
= NULL
;
337 LPWSTR customfilter
= NULL
;
338 INITCOMMONCONTROLSEX icc
;
340 /* Initialize ComboBoxEx32 */
341 icc
.dwSize
= sizeof(icc
);
342 icc
.dwICC
= ICC_USEREX_CLASSES
;
343 InitCommonControlsEx(&icc
);
345 /* Initialize CommDlgExtendedError() */
346 COMDLG32_SetCommDlgExtendedError(0);
348 /* Initialize FileOpenDlgInfos structure */
349 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
351 /* Pass in the original ofn */
352 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
354 /* save current directory */
355 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
357 lpstrSavDir
= MemAlloc(MAX_PATH
);
358 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
361 fodInfos
.unicode
= FALSE
;
363 /* convert all the input strings to unicode */
364 if(ofn
->lpstrInitialDir
)
366 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
367 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
368 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
371 fodInfos
.initdir
= NULL
;
375 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
379 fodInfos
.filename
= NULL
;
383 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
384 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
385 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
387 fodInfos
.defext
= defext
;
391 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
392 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
393 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
395 fodInfos
.title
= title
;
397 if (ofn
->lpstrFilter
)
402 /* filter is a list... title\0ext\0......\0\0 */
403 s
= ofn
->lpstrFilter
;
404 while (*s
) s
= s
+strlen(s
)+1;
406 n
= s
- ofn
->lpstrFilter
;
407 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
408 filter
= MemAlloc(len
*sizeof(WCHAR
));
409 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
411 fodInfos
.filter
= filter
;
413 /* convert lpstrCustomFilter */
414 if (ofn
->lpstrCustomFilter
)
419 /* customfilter contains a pair of strings... title\0ext\0 */
420 s
= ofn
->lpstrCustomFilter
;
421 if (*s
) s
= s
+strlen(s
)+1;
422 if (*s
) s
= s
+strlen(s
)+1;
423 n
= s
- ofn
->lpstrCustomFilter
;
424 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
425 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
426 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
428 fodInfos
.customfilter
= customfilter
;
430 /* Initialize the dialog property */
431 fodInfos
.DlgInfos
.dwDlgProp
= 0;
432 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
437 ret
= GetFileName95(&fodInfos
);
440 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
441 ret
= GetFileName95(&fodInfos
);
449 SetCurrentDirectoryA(lpstrSavDir
);
450 MemFree(lpstrSavDir
);
456 MemFree(customfilter
);
457 MemFree(fodInfos
.initdir
);
458 MemFree(fodInfos
.filename
);
460 TRACE("selected file: %s\n",ofn
->lpstrFile
);
465 /***********************************************************************
468 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
469 * Call GetFileName95 with this structure and clean the memory.
472 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
475 FileOpenDlgInfos fodInfos
;
476 LPWSTR lpstrSavDir
= NULL
;
477 INITCOMMONCONTROLSEX icc
;
479 /* Initialize ComboBoxEx32 */
480 icc
.dwSize
= sizeof(icc
);
481 icc
.dwICC
= ICC_USEREX_CLASSES
;
482 InitCommonControlsEx(&icc
);
484 /* Initialize CommDlgExtendedError() */
485 COMDLG32_SetCommDlgExtendedError(0);
487 /* Initialize FileOpenDlgInfos structure */
488 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
490 /* Pass in the original ofn */
491 fodInfos
.ofnInfos
= ofn
;
493 fodInfos
.title
= ofn
->lpstrTitle
;
494 fodInfos
.defext
= ofn
->lpstrDefExt
;
495 fodInfos
.filter
= ofn
->lpstrFilter
;
496 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
498 /* convert string arguments, save others */
501 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
502 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
505 fodInfos
.filename
= NULL
;
507 if(ofn
->lpstrInitialDir
)
509 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
510 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
511 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
512 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
515 fodInfos
.initdir
= NULL
;
517 /* save current directory */
518 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
520 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
521 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
524 fodInfos
.unicode
= TRUE
;
529 ret
= GetFileName95(&fodInfos
);
532 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
533 ret
= GetFileName95(&fodInfos
);
541 SetCurrentDirectoryW(lpstrSavDir
);
542 MemFree(lpstrSavDir
);
545 /* restore saved IN arguments and convert OUT arguments back */
546 MemFree(fodInfos
.filename
);
547 MemFree(fodInfos
.initdir
);
551 /******************************************************************************
552 * COMDLG32_GetDisplayNameOf [internal]
554 * Helper function to get the display name for a pidl.
556 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
557 LPSHELLFOLDER psfDesktop
;
560 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
563 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
564 IShellFolder_Release(psfDesktop
);
568 IShellFolder_Release(psfDesktop
);
569 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
572 /******************************************************************************
573 * COMDLG32_GetCanonicalPath [internal]
575 * Helper function to get the canonical path.
577 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
578 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
580 WCHAR lpstrTemp
[MAX_PATH
];
582 /* Get the current directory name */
583 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
586 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
588 PathAddBackslashW(lpstrPathAndFile
);
590 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
592 /* if the user specified a fully qualified path use it */
593 if(PathIsRelativeW(lpstrFile
))
595 lstrcatW(lpstrPathAndFile
, lpstrFile
);
599 /* does the path have a drive letter? */
600 if (PathGetDriveNumberW(lpstrFile
) == -1)
601 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
603 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
606 /* resolve "." and ".." */
607 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
608 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
609 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
612 /***********************************************************************
613 * COMDLG32_SplitFileNames [internal]
615 * Creates a delimited list of filenames.
617 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
619 UINT nStrCharCount
= 0; /* index in src buffer */
620 UINT nFileIndex
= 0; /* index in dest buffer */
621 UINT nFileCount
= 0; /* number of files */
623 /* we might get single filename without any '"',
624 * so we need nStrLen + terminating \0 + end-of-list \0 */
625 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
628 /* build delimited file list from filenames */
629 while ( nStrCharCount
<= nStrLen
)
631 if ( lpstrEdit
[nStrCharCount
]=='"' )
634 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
636 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
639 (*lpstrFileList
)[nFileIndex
++] = 0;
645 /* single, unquoted string */
646 if ((nStrLen
> 0) && (nFileIndex
== 0) )
648 lstrcpyW(*lpstrFileList
, lpstrEdit
);
649 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
654 (*lpstrFileList
)[nFileIndex
++] = '\0';
656 *sizeUsed
= nFileIndex
;
660 /***********************************************************************
661 * ArrangeCtrlPositions [internal]
663 * NOTE: Make sure to add testcases for any changes made here.
665 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
667 HWND hwndChild
, hwndStc32
;
668 RECT rectParent
, rectChild
, rectStc32
;
672 /* Take into account if open as read only checkbox and help button
677 RECT rectHelp
, rectCancel
;
678 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
679 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
680 /* subtract the height of the help button plus the space between
681 * the help button and the cancel button to the height of the dialog
683 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
687 There are two possibilities to add components to the default file dialog box.
689 By default, all the new components are added below the standard dialog box (the else case).
691 However, if there is a static text component with the stc32 id, a special case happens.
692 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
693 in the window and the cx and cy indicate how to size the window.
694 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
695 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
699 GetClientRect(hwndParentDlg
, &rectParent
);
701 /* when arranging controls we have to use fixed parent size */
702 rectParent
.bottom
-= help_fixup
;
704 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
707 GetWindowRect(hwndStc32
, &rectStc32
);
708 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
710 /* set the size of the stc32 control according to the size of
711 * client area of the parent dialog
713 SetWindowPos(hwndStc32
, 0,
715 rectParent
.right
, rectParent
.bottom
,
716 SWP_NOMOVE
| SWP_NOZORDER
);
719 SetRectEmpty(&rectStc32
);
721 /* this part moves controls of the child dialog */
722 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
725 if (hwndChild
!= hwndStc32
)
727 GetWindowRect(hwndChild
, &rectChild
);
728 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
730 /* move only if stc32 exist */
731 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
733 /* move to the right of visible controls of the parent dialog */
734 rectChild
.left
+= rectParent
.right
;
735 rectChild
.left
-= rectStc32
.right
;
737 /* move even if stc32 doesn't exist */
738 if (rectChild
.top
>= rectStc32
.bottom
)
740 /* move below visible controls of the parent dialog */
741 rectChild
.top
+= rectParent
.bottom
;
742 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
745 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
746 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
748 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
751 /* this part moves controls of the parent dialog */
752 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
755 if (hwndChild
!= hwndChildDlg
)
757 GetWindowRect(hwndChild
, &rectChild
);
758 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
760 /* left,top of stc32 marks the position of controls
761 * from the parent dialog
763 rectChild
.left
+= rectStc32
.left
;
764 rectChild
.top
+= rectStc32
.top
;
766 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
767 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
769 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
772 /* calculate the size of the resulting dialog */
774 /* here we have to use original parent size */
775 GetClientRect(hwndParentDlg
, &rectParent
);
776 GetClientRect(hwndChildDlg
, &rectChild
);
777 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
778 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
783 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
784 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
786 chgx
= rectChild
.right
- rectParent
.right
;
788 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
789 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
791 /* Unconditionally set new dialog
792 * height to that of the child
794 chgy
= rectChild
.bottom
- rectParent
.bottom
;
799 chgy
= rectChild
.bottom
- help_fixup
;
801 /* set the size of the parent dialog */
802 GetWindowRect(hwndParentDlg
, &rectParent
);
803 SetWindowPos(hwndParentDlg
, 0,
805 rectParent
.right
- rectParent
.left
+ chgx
,
806 rectParent
.bottom
- rectParent
.top
+ chgy
,
807 SWP_NOMOVE
| SWP_NOZORDER
);
810 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
819 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
829 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
830 * structure's hInstance parameter is not a HINSTANCE, but
831 * instead a pointer to a template resource to use.
833 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
836 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
838 hinst
= COMDLG32_hInstance
;
839 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
841 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
847 hinst
= fodInfos
->ofnInfos
->hInstance
;
848 if(fodInfos
->unicode
)
850 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
851 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
855 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
856 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
860 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
863 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
864 !(template = LockResource( hDlgTmpl
)))
866 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
870 if (fodInfos
->unicode
)
871 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
872 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
873 (LPARAM
)fodInfos
->ofnInfos
);
875 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
876 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
877 (LPARAM
)fodInfos
->ofnInfos
);
880 else if( IsHooked(fodInfos
))
885 WORD menu
,class,title
;
887 GetClientRect(hwnd
,&rectHwnd
);
888 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
889 temp
.tmplate
.dwExtendedStyle
= 0;
890 temp
.tmplate
.cdit
= 0;
895 temp
.menu
= temp
.class = temp
.title
= 0;
897 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
898 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
905 /***********************************************************************
906 * SendCustomDlgNotificationMessage
908 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
911 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
913 LRESULT hook_result
= 0;
914 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
916 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
918 if(!fodInfos
) return 0;
920 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
922 TRACE("CALL NOTIFY for %x\n", uCode
);
923 if(fodInfos
->unicode
)
926 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
927 ofnNotify
.hdr
.idFrom
=0;
928 ofnNotify
.hdr
.code
= uCode
;
929 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
930 ofnNotify
.pszFile
= NULL
;
931 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
936 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
937 ofnNotify
.hdr
.idFrom
=0;
938 ofnNotify
.hdr
.code
= uCode
;
939 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
940 ofnNotify
.pszFile
= NULL
;
941 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
943 TRACE("RET NOTIFY\n");
945 TRACE("Retval: 0x%08lx\n", hook_result
);
949 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
953 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
955 TRACE("CDM_GETFILEPATH:\n");
957 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
960 /* get path and filenames */
961 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
962 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
963 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
966 p
= buffer
+ strlenW(buffer
);
968 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
970 if (fodInfos
->unicode
)
972 total
= strlenW( buffer
) + 1;
973 if (result
) lstrcpynW( result
, buffer
, size
);
974 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
978 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
979 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
980 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
982 HeapFree( GetProcessHeap(), 0, buffer
);
986 /***********************************************************************
987 * FILEDLG95_HandleCustomDialogMessages
989 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
991 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
993 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
994 WCHAR lpstrPath
[MAX_PATH
];
997 if(!fodInfos
) return FALSE
;
1001 case CDM_GETFILEPATH
:
1002 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1005 case CDM_GETFOLDERPATH
:
1006 TRACE("CDM_GETFOLDERPATH:\n");
1007 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1010 if (fodInfos
->unicode
)
1011 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1013 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1014 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1016 retval
= lstrlenW(lpstrPath
) + 1;
1019 case CDM_GETFOLDERIDLIST
:
1020 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1021 if (retval
<= wParam
)
1022 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1026 TRACE("CDM_GETSPEC:\n");
1027 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1030 if (fodInfos
->unicode
)
1031 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1033 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1037 case CDM_SETCONTROLTEXT
:
1038 TRACE("CDM_SETCONTROLTEXT:\n");
1041 if( fodInfos
->unicode
)
1042 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1044 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1049 case CDM_HIDECONTROL
:
1050 /* MSDN states that it should fail for not OFN_EXPLORER case */
1051 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1053 HWND control
= GetDlgItem( hwnd
, wParam
);
1054 if (control
) ShowWindow( control
, SW_HIDE
);
1057 else retval
= FALSE
;
1061 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1062 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1065 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1069 /***********************************************************************
1070 * FILEDLG95_OnWMGetMMI
1072 * WM_GETMINMAXINFO message handler for resizable dialogs
1074 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1076 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1077 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1078 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1080 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1085 /***********************************************************************
1086 * FILEDLG95_OnWMSize
1088 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1090 * FIXME: this could be made more elaborate. Now use a simple scheme
1091 * where the file view is enlarged and the controls are either moved
1092 * vertically or horizontally to get out of the way. Only the "grip"
1093 * is moved in both directions to stay in the corner.
1095 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1101 FileOpenDlgInfos
*fodInfos
;
1103 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1104 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1105 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1106 /* get the new dialog rectangle */
1107 GetWindowRect( hwnd
, &rc
);
1108 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1109 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1110 /* not initialized yet */
1111 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1112 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1113 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1115 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1116 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1117 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1118 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1119 /* change the size of the view window */
1120 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1121 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1122 hdwp
= BeginDeferWindowPos( 10);
1123 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1124 rcview
.right
- rcview
.left
+ chgx
,
1125 rcview
.bottom
- rcview
.top
+ chgy
,
1126 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1127 /* change position and sizes of the controls */
1128 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1130 int ctrlid
= GetDlgCtrlID( ctrl
);
1131 GetWindowRect( ctrl
, &rc
);
1132 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1133 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1135 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1137 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1139 else if( rc
.top
> rcview
.bottom
)
1141 /* if it was below the shell view
1145 /* file name (edit or comboboxex) and file types combo change also width */
1149 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1150 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1151 SWP_NOACTIVATE
| SWP_NOZORDER
);
1153 /* then these buttons must move out of the way */
1157 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1159 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1162 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1164 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1167 else if( rc
.left
> rcview
.right
)
1169 /* if it was to the right of the shell view
1171 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1173 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1180 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1182 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1183 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1184 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1186 case IDC_TOOLBARSTATIC
:
1188 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1190 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1193 /* not resized in windows. Since wine uses this invisible control
1194 * to size the browser view it needs to be resized */
1195 case IDC_SHELLSTATIC
:
1196 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1197 rc
.right
- rc
.left
+ chgx
,
1198 rc
.bottom
- rc
.top
+ chgy
,
1199 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1204 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1205 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1207 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1208 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1210 GetWindowRect( ctrl
, &rc
);
1211 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1212 if( rc
.top
> rcview
.bottom
)
1214 /* if it was below the shell view
1216 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1217 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1218 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1220 else if( rc
.left
> rcview
.right
)
1222 /* if it was to the right of the shell view
1224 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1225 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1226 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1229 /* size the custom dialog at the end: some applications do some
1230 * control re-arranging at this point */
1231 GetClientRect(hwnd
, &rc
);
1232 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1233 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1235 EndDeferWindowPos( hdwp
);
1236 /* should not be needed */
1237 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1241 /***********************************************************************
1244 * File open dialog procedure
1246 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1249 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1256 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1258 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1259 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1261 /* Some shell namespace extensions depend on COM being initialized. */
1262 if (SUCCEEDED(OleInitialize(NULL
)))
1263 fodInfos
->ole_initialized
= TRUE
;
1265 /* Adds the FileOpenDlgInfos in the property list of the dialog
1266 so it will be easily accessible through a GetPropA(...) */
1267 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1269 FILEDLG95_InitControls(hwnd
);
1271 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1273 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1274 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1275 RECT client
, client_adjusted
;
1277 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1279 style
|= WS_SIZEBOX
;
1280 ex_style
|= WS_EX_WINDOWEDGE
;
1283 style
&= ~WS_SIZEBOX
;
1284 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1285 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1287 GetClientRect( hwnd
, &client
);
1288 GetClientRect( hwnd
, &client_adjusted
);
1289 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1291 GetWindowRect( hwnd
, &rc
);
1292 rc
.right
+= client_adjusted
.right
- client
.right
;
1293 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1294 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1295 SWP_NOZORDER
| SWP_NOMOVE
);
1297 GetWindowRect( hwnd
, &rc
);
1298 fodInfos
->DlgInfos
.hwndGrip
=
1299 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1300 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1301 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1302 rc
.right
- gripx
, rc
.bottom
- gripy
,
1303 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1306 fodInfos
->DlgInfos
.hwndCustomDlg
=
1307 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1309 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1310 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1312 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1313 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1315 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1316 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1317 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1320 /* if the app has changed the position of the invisible listbox,
1321 * change that of the listview (browser) as well */
1322 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1323 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1324 if( !EqualRect( &rc
, &rcstc
))
1326 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1327 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1328 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1329 SWP_NOACTIVATE
| SWP_NOZORDER
);
1332 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1334 GetWindowRect( hwnd
, &rc
);
1335 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1336 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1337 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1338 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1339 GetClientRect( hwnd
, &rc
);
1340 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1341 rc
.right
- gripx
, rc
.bottom
- gripy
,
1342 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1343 /* resize the dialog to the previous invocation */
1344 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1345 SetWindowPos( hwnd
, NULL
,
1346 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1347 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1350 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1351 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1356 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1357 case WM_GETMINMAXINFO
:
1358 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1360 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1363 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1366 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1372 case WM_GETISHELLBROWSER
:
1373 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1377 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1378 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1379 MemDialogSize
= fodInfos
->sizedlg
;
1380 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1385 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1388 /* set up the button tooltips strings */
1389 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1391 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1392 switch(lpnmh
->idFrom
)
1394 /* Up folder button */
1395 case FCIDM_TB_UPFOLDER
:
1396 stringId
= IDS_UPFOLDER
;
1398 /* New folder button */
1399 case FCIDM_TB_NEWFOLDER
:
1400 stringId
= IDS_NEWFOLDER
;
1402 /* List option button */
1403 case FCIDM_TB_SMALLICON
:
1404 stringId
= IDS_LISTVIEW
;
1406 /* Details option button */
1407 case FCIDM_TB_REPORTVIEW
:
1408 stringId
= IDS_REPORTVIEW
;
1410 /* Desktop button */
1411 case FCIDM_TB_DESKTOP
:
1412 stringId
= IDS_TODESKTOP
;
1417 lpdi
->hinst
= COMDLG32_hInstance
;
1418 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1423 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1424 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1429 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1431 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1432 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1435 /***********************************************************************
1436 * FILEDLG95_InitControls
1438 * WM_INITDIALOG message handler (before hook notification)
1440 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1442 BOOL win2000plus
= FALSE
;
1443 BOOL win98plus
= FALSE
;
1444 BOOL handledPath
= FALSE
;
1445 OSVERSIONINFOW osVi
;
1446 static const WCHAR szwSlash
[] = { '\\', 0 };
1447 static const WCHAR szwStar
[] = { '*',0 };
1449 static const TBBUTTON tbb
[] =
1451 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1452 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1453 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1454 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1455 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1456 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1457 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1458 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1459 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1461 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1466 HIMAGELIST toolbarImageList
;
1467 SHFILEINFOA shFileInfo
;
1468 ITEMIDLIST
*desktopPidl
;
1470 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1472 TRACE("%p\n", fodInfos
);
1474 /* Get windows version emulating */
1475 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1476 GetVersionExW(&osVi
);
1477 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1478 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1479 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1480 win2000plus
= (osVi
.dwMajorVersion
> 4);
1481 if (win2000plus
) win98plus
= TRUE
;
1483 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1486 /* Use either the edit or the comboboxex for the filename control */
1487 if (filename_is_edit( fodInfos
))
1489 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1490 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1494 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1495 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1498 /* Get the hwnd of the controls */
1499 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1500 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1502 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1503 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1505 /* construct the toolbar */
1506 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1507 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1509 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1510 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1511 rectTB
.left
= rectlook
.right
;
1512 rectTB
.top
= rectlook
.top
-1;
1514 if (fodInfos
->unicode
)
1515 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1516 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1517 rectTB
.left
, rectTB
.top
,
1518 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1519 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1521 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1522 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1523 rectTB
.left
, rectTB
.top
,
1524 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1525 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1527 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1529 /* FIXME: use TB_LOADIMAGES when implemented */
1530 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1531 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1532 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1534 /* Retrieve and add desktop icon to the toolbar */
1535 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1536 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1537 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1538 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1539 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1541 DestroyIcon(shFileInfo
.hIcon
);
1542 CoTaskMemFree(desktopPidl
);
1544 /* Finish Toolbar Construction */
1545 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1546 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1548 /* Set the window text with the text specified in the OPENFILENAME structure */
1551 SetWindowTextW(hwnd
,fodInfos
->title
);
1553 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1556 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1557 SetWindowTextW(hwnd
, buf
);
1560 /* Initialise the file name edit control */
1561 handledPath
= FALSE
;
1562 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1564 if(fodInfos
->filename
)
1566 /* 1. If win2000 or higher and filename contains a path, use it
1567 in preference over the lpstrInitialDir */
1568 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1569 WCHAR tmpBuf
[MAX_PATH
];
1573 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1576 /* nameBit is always shorter than the original filename. It may be NULL
1577 * when the filename contains only a drive name instead of file name */
1580 lstrcpyW(fodInfos
->filename
,nameBit
);
1584 *fodInfos
->filename
= '\0';
1586 MemFree(fodInfos
->initdir
);
1587 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1588 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1590 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1591 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1593 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1596 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1600 /* 2. (All platforms) If initdir is not null, then use it */
1601 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1603 /* Work out the proper path as supplied one might be relative */
1604 /* (Here because supplying '.' as dir browses to My Computer) */
1605 WCHAR tmpBuf
[MAX_PATH
];
1606 WCHAR tmpBuf2
[MAX_PATH
];
1610 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1611 if (PathFileExistsW(tmpBuf
)) {
1612 /* initdir does not have to be a directory. If a file is
1613 * specified, the dir part is taken */
1614 if (PathIsDirectoryW(tmpBuf
)) {
1615 PathAddBackslashW(tmpBuf
);
1616 lstrcatW(tmpBuf
, szwStar
);
1618 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1621 MemFree(fodInfos
->initdir
);
1622 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1623 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1625 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1628 else if (fodInfos
->initdir
)
1630 MemFree(fodInfos
->initdir
);
1631 fodInfos
->initdir
= NULL
;
1632 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1636 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1638 /* 3. All except w2k+: if filename contains a path use it */
1639 if (!win2000plus
&& fodInfos
->filename
&&
1640 *fodInfos
->filename
&&
1641 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1642 WCHAR tmpBuf
[MAX_PATH
];
1646 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1651 /* nameBit is always shorter than the original filename */
1652 lstrcpyW(fodInfos
->filename
, nameBit
);
1655 len
= lstrlenW(tmpBuf
);
1656 MemFree(fodInfos
->initdir
);
1657 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1658 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1661 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1662 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1664 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1667 /* 4. Win2000+: Recently used */
1668 if (!handledPath
&& win2000plus
) {
1669 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1670 fodInfos
->initdir
[0] = '\0';
1672 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1674 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1677 MemFree(fodInfos
->initdir
);
1678 fodInfos
->initdir
= NULL
;
1682 /* 5. win98+ and win2000+ if any files of specified filter types in
1683 current directory, use it */
1684 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1686 LPCWSTR lpstrPos
= fodInfos
->filter
;
1687 WIN32_FIND_DATAW FindFileData
;
1692 /* filter is a list... title\0ext\0......\0\0 */
1694 /* Skip the title */
1695 if(! *lpstrPos
) break; /* end */
1696 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1698 /* See if any files exist in the current dir with this extension */
1699 if(! *lpstrPos
) break; /* end */
1701 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1703 if (hFind
== INVALID_HANDLE_VALUE
) {
1704 /* None found - continue search */
1705 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1709 MemFree(fodInfos
->initdir
);
1710 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1711 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1714 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1715 debugstr_w(lpstrPos
));
1722 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1723 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1724 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1726 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1728 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1731 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1732 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1734 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1737 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1740 } else if (!handledPath
) {
1741 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1742 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1744 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1747 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1748 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1750 /* Must the open as read only check box be checked ?*/
1751 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1753 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1756 /* Must the open as read only check box be hidden? */
1757 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1759 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1760 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1763 /* Must the help button be hidden? */
1764 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1766 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1767 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1770 /* change Open to Save */
1771 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1774 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1775 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1776 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1777 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1780 /* Initialize the filter combo box */
1781 FILEDLG95_FILETYPE_Init(hwnd
);
1786 /***********************************************************************
1787 * FILEDLG95_ResizeControls
1789 * WM_INITDIALOG message handler (after hook notification)
1791 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1793 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1795 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1798 UINT flags
= SWP_NOACTIVATE
;
1800 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1801 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1803 /* resize the custom dialog to the parent size */
1804 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1805 GetClientRect(hwnd
, &rc
);
1808 /* our own fake template is zero sized and doesn't have children, so
1809 * there is no need to resize it. Picasa depends on it.
1811 flags
|= SWP_NOSIZE
;
1814 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1815 0, 0, rc
.right
, rc
.bottom
, flags
);
1819 /* Resize the height; if opened as read-only, checkbox and help button are
1820 * hidden and we are not using a custom template nor a customDialog
1822 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1823 (!(fodInfos
->ofnInfos
->Flags
&
1824 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1826 RECT rectDlg
, rectHelp
, rectCancel
;
1827 GetWindowRect(hwnd
, &rectDlg
);
1828 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1829 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1830 /* subtract the height of the help button plus the space between the help
1831 * button and the cancel button to the height of the dialog
1833 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1834 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1835 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1841 /***********************************************************************
1842 * FILEDLG95_FillControls
1844 * WM_INITDIALOG message handler (after hook notification)
1846 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1848 LPITEMIDLIST pidlItemId
= NULL
;
1850 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1852 TRACE("dir=%s file=%s\n",
1853 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1855 /* Get the initial directory pidl */
1857 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1859 WCHAR path
[MAX_PATH
];
1861 GetCurrentDirectoryW(MAX_PATH
,path
);
1862 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1865 /* Initialise shell objects */
1866 FILEDLG95_SHELL_Init(hwnd
);
1868 /* Initialize the Look In combo box */
1869 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1871 /* Browse to the initial directory */
1872 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1874 /* Free pidlItem memory */
1875 COMDLG32_SHFree(pidlItemId
);
1879 /***********************************************************************
1882 * Regroups all the cleaning functions of the filedlg
1884 void FILEDLG95_Clean(HWND hwnd
)
1886 FILEDLG95_FILETYPE_Clean(hwnd
);
1887 FILEDLG95_LOOKIN_Clean(hwnd
);
1888 FILEDLG95_SHELL_Clean(hwnd
);
1890 /***********************************************************************
1891 * FILEDLG95_OnWMCommand
1893 * WM_COMMAND message handler
1895 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1897 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1898 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1899 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1905 FILEDLG95_OnOpen(hwnd
);
1909 FILEDLG95_Clean(hwnd
);
1910 EndDialog(hwnd
, FALSE
);
1912 /* Filetype combo box */
1914 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1916 /* LookIn combo box */
1918 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1921 /* --- toolbar --- */
1922 /* Up folder button */
1923 case FCIDM_TB_UPFOLDER
:
1924 FILEDLG95_SHELL_UpFolder(hwnd
);
1926 /* New folder button */
1927 case FCIDM_TB_NEWFOLDER
:
1928 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1930 /* List option button */
1931 case FCIDM_TB_SMALLICON
:
1932 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1934 /* Details option button */
1935 case FCIDM_TB_REPORTVIEW
:
1936 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1938 /* Details option button */
1939 case FCIDM_TB_DESKTOP
:
1940 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1948 /* Do not use the listview selection anymore */
1949 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1953 /***********************************************************************
1954 * FILEDLG95_OnWMGetIShellBrowser
1956 * WM_GETISHELLBROWSER message handler
1958 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1960 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1964 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1970 /***********************************************************************
1971 * FILEDLG95_SendFileOK
1973 * Sends the CDN_FILEOK notification if required
1976 * TRUE if the dialog should close
1977 * FALSE if the dialog should not be closed
1979 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1981 /* ask the hook if we can close */
1982 if(IsHooked(fodInfos
))
1987 /* First send CDN_FILEOK as MSDN doc says */
1988 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1989 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1992 TRACE("canceled\n");
1996 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1997 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1998 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
2001 TRACE("canceled\n");
2008 /***********************************************************************
2009 * FILEDLG95_OnOpenMultipleFiles
2011 * Handles the opening of multiple files.
2014 * check destination buffer size
2016 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2018 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2019 UINT nCount
, nSizePath
;
2020 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2024 if(fodInfos
->unicode
)
2026 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2027 ofn
->lpstrFile
[0] = '\0';
2031 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2032 ofn
->lpstrFile
[0] = '\0';
2035 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2037 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2038 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2039 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2041 LPWSTR lpstrTemp
= lpstrFileList
;
2043 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2047 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2050 WCHAR lpstrNotFound
[100];
2051 WCHAR lpstrMsg
[100];
2053 static const WCHAR nl
[] = {'\n',0};
2055 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2056 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2058 lstrcpyW(tmp
, lpstrTemp
);
2060 lstrcatW(tmp
, lpstrNotFound
);
2062 lstrcatW(tmp
, lpstrMsg
);
2064 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2068 /* move to the next file in the list of files */
2069 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2070 COMDLG32_SHFree(pidl
);
2074 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2075 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2077 /* For "oldstyle" dialog the components have to
2078 be separated by blanks (not '\0'!) and short
2079 filenames have to be used! */
2080 FIXME("Components have to be separated by blanks\n");
2082 if(fodInfos
->unicode
)
2084 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2085 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2086 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2090 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2092 if (ofn
->lpstrFile
!= NULL
)
2094 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2095 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2096 if (ofn
->nMaxFile
> nSizePath
)
2098 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2099 ofn
->lpstrFile
+ nSizePath
,
2100 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2105 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2106 fodInfos
->ofnInfos
->nFileExtension
= 0;
2108 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2111 /* clean and exit */
2112 FILEDLG95_Clean(hwnd
);
2113 return EndDialog(hwnd
,TRUE
);
2116 /* Returns the 'slot name' of the given module_name in the registry's
2117 * most-recently-used list. This will be an ASCII value in the
2118 * range ['a','z'). Returns zero on error.
2120 * The slot's value in the registry has the form:
2121 * module_name\0mru_path\0
2123 * If stored_path is given, then stored_path will contain the path name
2124 * stored in the registry's MRU list for the given module_name.
2126 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2127 * MRU list key for the given module_name.
2129 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2131 WCHAR mru_list
[32], *cur_mru_slot
;
2132 BOOL taken
[25] = {0};
2133 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2134 HKEY hkey_tmp
, *hkey
;
2143 *stored_path
= '\0';
2145 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2147 WARN("Unable to create MRU key: %d\n", ret
);
2151 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2152 (LPBYTE
)mru_list
, &mru_list_size
);
2153 if(ret
|| key_type
!= REG_SZ
){
2154 if(ret
== ERROR_FILE_NOT_FOUND
)
2157 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2162 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2163 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2164 DWORD value_data_size
= sizeof(value_data
);
2166 *value_name
= *cur_mru_slot
;
2168 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2169 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2170 if(ret
|| key_type
!= REG_BINARY
){
2171 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2175 if(!strcmpiW(module_name
, value_data
)){
2179 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2187 /* the module name isn't in the registry, so find the next open slot */
2188 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2189 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2190 for(i
= 0; i
< 25; ++i
){
2195 /* all slots are taken, so return the last one in MRUList */
2197 return *cur_mru_slot
;
2200 /* save the given filename as most-recently-used path for this module */
2201 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2203 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2207 /* get the current executable's name */
2208 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2209 WARN("GotModuleFileName failed: %d\n", GetLastError());
2212 module_name
= strrchrW(module_path
, '\\');
2214 module_name
= module_path
;
2218 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2223 { /* update the slot's info */
2224 WCHAR
*path_ends
, *final
;
2225 DWORD path_len
, final_len
;
2227 /* use only the path segment of `filename' */
2228 path_ends
= strrchrW(filename
, '\\');
2229 path_len
= path_ends
- filename
;
2231 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2233 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2236 lstrcpyW(final
, module_name
);
2237 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2238 final
[final_len
-1] = '\0';
2240 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2241 final_len
* sizeof(WCHAR
));
2243 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2252 { /* update MRUList value */
2253 WCHAR old_mru_list
[32], new_mru_list
[32];
2254 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2255 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2257 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2258 (LPBYTE
)old_mru_list
, &mru_list_size
);
2259 if(ret
|| key_type
!= REG_SZ
){
2260 if(ret
== ERROR_FILE_NOT_FOUND
){
2261 new_mru_list
[0] = slot
;
2262 new_mru_list
[1] = '\0';
2264 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2269 /* copy old list data over so that the new slot is at the start
2271 *new_mru_slot
++ = slot
;
2272 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2273 if(*old_mru_slot
!= slot
)
2274 *new_mru_slot
++ = *old_mru_slot
;
2276 *new_mru_slot
= '\0';
2279 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2280 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2282 WARN("Error saving MRUList data: %d\n", ret
);
2289 /* load the most-recently-used path for this module */
2290 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2292 WCHAR module_path
[MAX_PATH
], *module_name
;
2294 /* get the current executable's name */
2295 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2296 WARN("GotModuleFileName failed: %d\n", GetLastError());
2299 module_name
= strrchrW(module_path
, '\\');
2301 module_name
= module_path
;
2305 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2306 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2309 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2311 WCHAR strMsgTitle
[MAX_PATH
];
2312 WCHAR strMsgText
[MAX_PATH
];
2314 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2316 strMsgTitle
[0] = '\0';
2317 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2318 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2321 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2322 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2324 int nOpenAction
= defAction
;
2325 LPWSTR lpszTemp
, lpszTemp1
;
2326 LPITEMIDLIST pidl
= NULL
;
2327 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2329 /* check for invalid chars */
2330 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2332 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2336 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2338 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2341 LPSHELLFOLDER lpsfChild
;
2342 WCHAR lpwstrTemp
[MAX_PATH
];
2343 DWORD dwEaten
, dwAttributes
;
2346 lstrcpyW(lpwstrTemp
, lpszTemp
);
2347 p
= PathFindNextComponentW(lpwstrTemp
);
2349 if (!p
) break; /* end of path */
2352 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2354 /* There are no wildcards when OFN_NOVALIDATE is set */
2355 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2357 static const WCHAR wszWild
[] = { '*', '?', 0 };
2358 /* if the last element is a wildcard do a search */
2359 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2361 nOpenAction
= ONOPEN_SEARCH
;
2365 lpszTemp1
= lpszTemp
;
2367 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2369 /* append a backslash to drive letters */
2370 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2371 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2372 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2374 PathAddBackslashW(lpwstrTemp
);
2377 dwAttributes
= SFGAO_FOLDER
;
2378 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2380 /* the path component is valid, we have a pidl of the next path component */
2381 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2382 if(dwAttributes
& SFGAO_FOLDER
)
2384 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2386 ERR("bind to failed\n"); /* should not fail */
2389 IShellFolder_Release(*ppsf
);
2397 /* end dialog, return value */
2398 nOpenAction
= ONOPEN_OPEN
;
2401 COMDLG32_SHFree(pidl
);
2404 else if (!(flags
& OFN_NOVALIDATE
))
2406 if(*lpszTemp
|| /* points to trailing null for last path element */
2407 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2409 if(flags
& OFN_PATHMUSTEXIST
)
2411 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2417 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2419 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2423 /* change to the current folder */
2424 nOpenAction
= ONOPEN_OPEN
;
2429 nOpenAction
= ONOPEN_OPEN
;
2433 if(pidl
) COMDLG32_SHFree(pidl
);
2438 /***********************************************************************
2441 * Ok button WM_COMMAND message handler
2443 * If the function succeeds, the return value is nonzero.
2445 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2447 LPWSTR lpstrFileList
;
2448 UINT nFileCount
= 0;
2451 WCHAR lpstrPathAndFile
[MAX_PATH
];
2452 LPSHELLFOLDER lpsf
= NULL
;
2454 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2456 TRACE("hwnd=%p\n", hwnd
);
2458 /* try to browse the selected item */
2459 if(BrowseSelectedFolder(hwnd
))
2462 /* get the files from the edit control */
2463 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2470 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2474 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2477 Step 1: Build a complete path name from the current folder and
2478 the filename or path in the edit box.
2480 - the path in the edit box is a root path
2481 (with or without drive letter)
2482 - the edit box contains ".." (or a path with ".." in it)
2485 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2486 MemFree(lpstrFileList
);
2489 Step 2: here we have a cleaned up path
2491 We have to parse the path step by step to see if we have to browse
2492 to a folder if the path points to a directory or the last
2493 valid element is a directory.
2496 lpstrPathAndFile: cleaned up path
2500 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2501 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2502 nOpenAction
= ONOPEN_OPEN
;
2504 nOpenAction
= ONOPEN_BROWSE
;
2506 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2507 fodInfos
->ofnInfos
->Flags
,
2508 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2514 Step 3: here we have a cleaned up and validated path
2517 lpsf: ShellFolder bound to the rightmost valid path component
2518 lpstrPathAndFile: cleaned up path
2519 nOpenAction: action to do
2521 TRACE("end validate sf=%p\n", lpsf
);
2525 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2526 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2529 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2532 /* replace the current filter */
2533 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2534 len
= lstrlenW(lpszTemp
)+1;
2535 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2536 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2538 /* set the filter cb to the extension when possible */
2539 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2540 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2543 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2544 TRACE("ONOPEN_BROWSE\n");
2546 IPersistFolder2
* ppf2
;
2547 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2549 LPITEMIDLIST pidlCurrent
;
2550 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2551 IPersistFolder2_Release(ppf2
);
2552 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2554 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2555 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2557 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2558 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2561 else if( nOpenAction
== ONOPEN_SEARCH
)
2563 if (fodInfos
->Shell
.FOIShellView
)
2564 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2566 COMDLG32_SHFree(pidlCurrent
);
2567 if (filename_is_edit( fodInfos
))
2568 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2573 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2574 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2580 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2581 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2585 /* update READONLY check box flag */
2586 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2587 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2589 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2591 /* Attach the file extension with file name*/
2592 ext
= PathFindExtensionW(lpstrPathAndFile
);
2593 if (! *ext
&& fodInfos
->defext
)
2595 /* if no extension is specified with file name, then */
2596 /* attach the extension from file filter or default one */
2598 WCHAR
*filterExt
= NULL
;
2599 LPWSTR lpstrFilter
= NULL
;
2600 static const WCHAR szwDot
[] = {'.',0};
2601 int PathLength
= lstrlenW(lpstrPathAndFile
);
2603 /*Get the file extension from file type filter*/
2604 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2605 fodInfos
->ofnInfos
->nFilterIndex
-1);
2607 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2609 WCHAR
* filterSearchIndex
;
2610 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2611 strcpyW(filterExt
, lpstrFilter
);
2613 /* if a semicolon-separated list of file extensions was given, do not include the
2614 semicolon or anything after it in the extension.
2615 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2616 filterSearchIndex
= strchrW(filterExt
, ';');
2617 if (filterSearchIndex
)
2619 filterSearchIndex
[0] = '\0';
2622 /* find the file extension by searching for the first dot in filterExt */
2623 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2624 /* if the extension is invalid or contains a glob, ignore it */
2625 filterSearchIndex
= strchrW(filterExt
, '.');
2626 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2628 strcpyW(filterExt
, filterSearchIndex
);
2632 HeapFree(GetProcessHeap(), 0, filterExt
);
2639 /* use the default file extension */
2640 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2641 strcpyW(filterExt
, fodInfos
->defext
);
2644 if (*filterExt
) /* ignore filterExt="" */
2647 lstrcatW(lpstrPathAndFile
, szwDot
);
2648 /* Attach the extension */
2649 lstrcatW(lpstrPathAndFile
, filterExt
);
2652 HeapFree(GetProcessHeap(), 0, filterExt
);
2654 /* In Open dialog: if file does not exist try without extension */
2655 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2656 lpstrPathAndFile
[PathLength
] = '\0';
2658 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2661 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2662 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2664 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2667 /* In Save dialog: check if the file already exists */
2668 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2669 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2670 && PathFileExistsW(lpstrPathAndFile
))
2672 WCHAR lpstrOverwrite
[100];
2675 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2676 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2677 MB_YESNO
| MB_ICONEXCLAMATION
);
2678 if (answer
== IDNO
|| answer
== IDCANCEL
)
2685 /* In Open dialog: check if it should be created if it doesn't exist */
2686 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2687 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2688 && !PathFileExistsW(lpstrPathAndFile
))
2690 WCHAR lpstrCreate
[100];
2693 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2694 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2695 MB_YESNO
| MB_ICONEXCLAMATION
);
2696 if (answer
== IDNO
|| answer
== IDCANCEL
)
2703 /* Check that the size of the file does not exceed buffer size.
2704 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2705 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2706 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2709 /* fill destination buffer */
2710 if (fodInfos
->ofnInfos
->lpstrFile
)
2712 if(fodInfos
->unicode
)
2714 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2716 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2717 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2718 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2722 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2724 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2725 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2726 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2727 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2731 if(fodInfos
->unicode
)
2735 /* set filename offset */
2736 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2737 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2739 /* set extension offset */
2740 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2741 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2746 CHAR tempFileA
[MAX_PATH
];
2748 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2749 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2750 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2752 /* set filename offset */
2753 lpszTemp
= PathFindFileNameA(tempFileA
);
2754 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2756 /* set extension offset */
2757 lpszTemp
= PathFindExtensionA(tempFileA
);
2758 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2761 /* set the lpstrFileTitle */
2762 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2764 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2765 if(fodInfos
->unicode
)
2767 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2768 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2772 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2773 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2774 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2778 /* copy currently selected filter to lpstrCustomFilter */
2779 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2781 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2782 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2783 NULL
, 0, NULL
, NULL
);
2784 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2786 LPSTR s
= ofn
->lpstrCustomFilter
;
2787 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2788 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2789 s
, len
, NULL
, NULL
);
2794 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2797 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2800 FILEDLG95_Clean(hwnd
);
2801 ret
= EndDialog(hwnd
, TRUE
);
2807 size
= lstrlenW(lpstrPathAndFile
) + 1;
2808 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2810 /* return needed size in first two bytes of lpstrFile */
2811 if(fodInfos
->ofnInfos
->lpstrFile
)
2812 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2813 FILEDLG95_Clean(hwnd
);
2814 ret
= EndDialog(hwnd
, FALSE
);
2815 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2822 if(lpsf
) IShellFolder_Release(lpsf
);
2826 /***********************************************************************
2827 * FILEDLG95_SHELL_Init
2829 * Initialisation of the shell objects
2831 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2833 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2838 * Initialisation of the FileOpenDialogInfos structure
2844 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2846 /* Disable multi-select if flag not set */
2847 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2849 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2851 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2852 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2854 /* Construct the IShellBrowser interface */
2855 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2860 /***********************************************************************
2861 * FILEDLG95_SHELL_ExecuteCommand
2863 * Change the folder option and refresh the view
2864 * If the function succeeds, the return value is nonzero.
2866 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2868 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2871 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2873 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2878 CMINVOKECOMMANDINFO ci
;
2879 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2880 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2884 IContextMenu_InvokeCommand(pcm
, &ci
);
2885 IContextMenu_Release(pcm
);
2891 /***********************************************************************
2892 * FILEDLG95_SHELL_UpFolder
2894 * Browse to the specified object
2895 * If the function succeeds, the return value is nonzero.
2897 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2899 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2903 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2907 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2908 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2914 /***********************************************************************
2915 * FILEDLG95_SHELL_BrowseToDesktop
2917 * Browse to the Desktop
2918 * If the function succeeds, the return value is nonzero.
2920 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2922 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2928 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2929 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2930 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2931 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2932 COMDLG32_SHFree(pidl
);
2933 return SUCCEEDED(hres
);
2935 /***********************************************************************
2936 * FILEDLG95_SHELL_Clean
2938 * Cleans the memory used by shell objects
2940 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2942 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2946 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2948 /* clean Shell interfaces */
2949 if (fodInfos
->Shell
.FOIShellView
)
2951 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2952 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2954 if (fodInfos
->Shell
.FOIShellFolder
)
2955 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2956 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2957 if (fodInfos
->Shell
.FOIDataObject
)
2958 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2961 /***********************************************************************
2962 * FILEDLG95_FILETYPE_Init
2964 * Initialisation of the file type combo box
2966 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2968 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2969 int nFilters
= 0; /* number of filters */
2974 if(fodInfos
->customfilter
)
2976 /* customfilter has one entry... title\0ext\0
2977 * Set first entry of combo box item with customfilter
2980 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2983 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2985 /* Copy the extensions */
2986 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2987 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2988 lstrcpyW(lpstrExt
,lpstrPos
);
2990 /* Add the item at the end of the combo */
2991 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2992 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2995 if(fodInfos
->filter
)
2997 LPCWSTR lpstrPos
= fodInfos
->filter
;
3001 /* filter is a list... title\0ext\0......\0\0
3002 * Set the combo item text to the title and the item data
3005 LPCWSTR lpstrDisplay
;
3009 if(! *lpstrPos
) break; /* end */
3010 lpstrDisplay
= lpstrPos
;
3011 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3013 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
3017 /* Copy the extensions */
3018 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3019 lstrcpyW(lpstrExt
,lpstrPos
);
3020 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3022 /* Add the item at the end of the combo */
3023 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
3025 /* malformed filters are added anyway... */
3026 if (!*lpstrExt
) break;
3031 * Set the current filter to the one specified
3032 * in the initialisation structure
3034 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3038 /* Check to make sure our index isn't out of bounds. */
3039 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3040 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3041 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3043 /* set default filter index */
3044 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3045 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3047 /* calculate index of Combo Box item */
3048 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3049 if (fodInfos
->customfilter
== NULL
)
3052 /* Set the current index selection. */
3053 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3055 /* Get the corresponding text string from the combo box. */
3056 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3059 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3065 CharLowerW(lpstrFilter
); /* lowercase */
3066 len
= lstrlenW(lpstrFilter
)+1;
3067 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3068 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3071 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3075 /***********************************************************************
3076 * FILEDLG95_FILETYPE_OnCommand
3078 * WM_COMMAND of the file type combo box
3079 * If the function succeeds, the return value is nonzero.
3081 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3083 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3091 /* Get the current item of the filetype combo box */
3092 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3094 /* set the current filter index */
3095 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3096 (fodInfos
->customfilter
== NULL
? 1 : 0);
3098 /* Set the current filter with the current selection */
3099 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3101 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3103 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3106 CharLowerW(lpstrFilter
); /* lowercase */
3107 len
= lstrlenW(lpstrFilter
)+1;
3108 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3109 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3110 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3111 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3114 /* Refresh the actual view to display the included items*/
3115 if (fodInfos
->Shell
.FOIShellView
)
3116 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3121 /***********************************************************************
3122 * FILEDLG95_FILETYPE_SearchExt
3124 * searches for an extension in the filetype box
3126 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3128 int i
, iCount
= CBGetCount(hwnd
);
3130 TRACE("%s\n", debugstr_w(lpstrExt
));
3132 if(iCount
!= CB_ERR
)
3134 for(i
=0;i
<iCount
;i
++)
3136 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3143 /***********************************************************************
3144 * FILEDLG95_FILETYPE_Clean
3146 * Clean the memory used by the filetype combo box
3148 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3150 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3152 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3156 /* Delete each string of the combo and their associated data */
3157 if(iCount
!= CB_ERR
)
3159 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3161 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3162 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3165 /* Current filter */
3166 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3170 /***********************************************************************
3171 * FILEDLG95_LOOKIN_Init
3173 * Initialisation of the look in combo box
3176 /* Small helper function, to determine if the unixfs shell extension is rooted
3177 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3179 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3181 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3182 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3184 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3185 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3186 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3187 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3189 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3196 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3198 IShellFolder
*psfRoot
, *psfDrives
;
3199 IEnumIDList
*lpeRoot
, *lpeDrives
;
3200 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3203 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3207 liInfos
->iMaxIndentation
= 0;
3209 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3211 hdc
= GetDC( hwndCombo
);
3212 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3213 GetTextMetricsW( hdc
, &tm
);
3214 ReleaseDC( hwndCombo
, hdc
);
3216 /* set item height for both text field and listbox */
3217 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3218 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3220 /* Turn on the extended UI for the combo box like Windows does */
3221 CBSetExtendedUI(hwndCombo
, TRUE
);
3223 /* Initialise data of Desktop folder */
3224 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3225 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3226 COMDLG32_SHFree(pidlTmp
);
3228 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3230 SHGetDesktopFolder(&psfRoot
);
3234 /* enumerate the contents of the desktop */
3235 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3237 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3239 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3241 /* If the unixfs extension is rooted, we don't expand the drives by default */
3242 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3244 /* special handling for CSIDL_DRIVES */
3245 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3247 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3249 /* enumerate the drives */
3250 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3252 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3254 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3255 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3256 COMDLG32_SHFree(pidlAbsTmp
);
3257 COMDLG32_SHFree(pidlTmp1
);
3259 IEnumIDList_Release(lpeDrives
);
3261 IShellFolder_Release(psfDrives
);
3266 COMDLG32_SHFree(pidlTmp
);
3268 IEnumIDList_Release(lpeRoot
);
3270 IShellFolder_Release(psfRoot
);
3273 COMDLG32_SHFree(pidlDrives
);
3276 /***********************************************************************
3277 * FILEDLG95_LOOKIN_DrawItem
3279 * WM_DRAWITEM message handler
3281 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3283 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3284 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3285 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3289 HIMAGELIST ilItemImage
;
3292 LPSFOLDER tmpFolder
;
3293 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3294 UINT icon_width
, icon_height
;
3298 if(pDIStruct
->itemID
== -1)
3301 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3302 pDIStruct
->itemID
)))
3306 icon_width
= GetSystemMetrics(SM_CXICON
);
3307 icon_height
= GetSystemMetrics(SM_CYICON
);
3308 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3310 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3311 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3312 shgfi_flags
|= SHGFI_SMALLICON
;
3315 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3316 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3318 /* Is this item selected ? */
3319 if(pDIStruct
->itemState
& ODS_SELECTED
)
3321 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3322 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3323 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3327 SetTextColor(pDIStruct
->hDC
,crText
);
3328 SetBkColor(pDIStruct
->hDC
,crWin
);
3329 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3332 /* Do not indent item if drawing in the edit of the combo */
3333 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3336 iIndentation
= tmpFolder
->m_iIndent
;
3338 /* Draw text and icon */
3340 /* Initialise the icon display area */
3341 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3342 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3343 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3344 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3346 /* Initialise the text display area */
3347 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3348 rectText
.left
= rectIcon
.right
;
3350 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3351 rectText
.right
= pDIStruct
->rcItem
.right
;
3353 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3355 /* Draw the icon from the image list */
3356 ImageList_Draw(ilItemImage
,
3363 /* Draw the associated text */
3364 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3368 /***********************************************************************
3369 * FILEDLG95_LOOKIN_OnCommand
3371 * LookIn combo box WM_COMMAND message handler
3372 * If the function succeeds, the return value is nonzero.
3374 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3376 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3378 TRACE("%p\n", fodInfos
);
3384 LPSFOLDER tmpFolder
;
3387 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3389 if( iItem
== CB_ERR
) return FALSE
;
3391 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3396 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3397 tmpFolder
->pidlItem
,
3400 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3401 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3411 /***********************************************************************
3412 * FILEDLG95_LOOKIN_AddItem
3414 * Adds an absolute pidl item to the lookin combo box
3415 * returns the index of the inserted item
3417 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3419 LPITEMIDLIST pidlNext
;
3422 LookInInfos
*liInfos
;
3424 TRACE("%08x\n", iInsertId
);
3429 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3432 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3433 tmpFolder
->m_iIndent
= 0;
3435 /* Calculate the indentation of the item in the lookin*/
3437 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3439 tmpFolder
->m_iIndent
++;
3442 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3444 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3445 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3447 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3448 SHGetFileInfoW((LPCWSTR
)pidl
,
3452 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3453 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3455 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3457 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3461 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3463 /* Add the item at the end of the list */
3466 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3468 /* Insert the item at the iInsertId position*/
3471 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3474 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3478 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3479 MemFree( tmpFolder
);
3484 /***********************************************************************
3485 * FILEDLG95_LOOKIN_InsertItemAfterParent
3487 * Insert an item below its parent
3489 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3492 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3497 if (pidl
== pidlParent
)
3500 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3504 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3507 /* Free pidlParent memory */
3508 COMDLG32_SHFree(pidlParent
);
3510 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3513 /***********************************************************************
3514 * FILEDLG95_LOOKIN_SelectItem
3516 * Adds an absolute pidl item to the lookin combo box
3517 * returns the index of the inserted item
3519 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3522 LookInInfos
*liInfos
;
3526 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3528 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3532 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3533 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3538 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3539 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3543 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3545 if(iRemovedItem
< iItemPos
)
3550 CBSetCurSel(hwnd
,iItemPos
);
3551 liInfos
->uSelectedItem
= iItemPos
;
3557 /***********************************************************************
3558 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3560 * Remove the item with an expansion level over iExpansionLevel
3562 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3565 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3569 if(liInfos
->iMaxIndentation
<= 2)
3572 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3574 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3575 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3577 CBDeleteString(hwnd
,iItemPos
);
3578 liInfos
->iMaxIndentation
--;
3586 /***********************************************************************
3587 * FILEDLG95_LOOKIN_SearchItem
3589 * Search for pidl in the lookin combo box
3590 * returns the index of the found item
3592 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3595 int iCount
= CBGetCount(hwnd
);
3597 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3599 if (iCount
!= CB_ERR
)
3603 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3605 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3607 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3615 /***********************************************************************
3616 * FILEDLG95_LOOKIN_Clean
3618 * Clean the memory used by the lookin combo box
3620 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3622 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3623 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3625 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3629 /* Delete each string of the combo and their associated data */
3630 if (iCount
!= CB_ERR
)
3632 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3634 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3635 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3637 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3641 /* LookInInfos structure */
3643 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3646 /***********************************************************************
3649 * Fill the FORMATETC used in the shell id list
3651 static FORMATETC
get_def_format(void)
3653 static CLIPFORMAT cfFormat
;
3654 FORMATETC formatetc
;
3656 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3657 formatetc
.cfFormat
= cfFormat
;
3659 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3660 formatetc
.lindex
= -1;
3661 formatetc
.tymed
= TYMED_HGLOBAL
;
3665 /***********************************************************************
3666 * FILEDLG95_FILENAME_FillFromSelection
3668 * fills the edit box from the cached DataObject
3670 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3672 FileOpenDlgInfos
*fodInfos
;
3674 LPWSTR lpstrAllFiles
, lpstrTmp
;
3675 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3678 FORMATETC formatetc
= get_def_format();
3681 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3683 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3686 cida
= GlobalLock(medium
.u
.hGlobal
);
3687 nFileSelected
= cida
->cidl
;
3689 /* Allocate a buffer */
3690 nAllFilesMaxLength
= MAX_PATH
+ 3;
3691 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3695 /* Loop through the selection, handle only files (not folders) */
3696 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3698 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3701 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3703 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3705 nAllFilesMaxLength
*= 2;
3706 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3709 lpstrAllFiles
= lpstrTmp
;
3712 lpstrAllFiles
[nAllFilesLength
++] = '"';
3713 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3714 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3715 nAllFilesLength
+= nThisFileLength
;
3716 lpstrAllFiles
[nAllFilesLength
++] = '"';
3717 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3724 /* If there's only one file, use the name as-is without quotes */
3725 lpstrTmp
= lpstrAllFiles
;
3729 lpstrTmp
[nThisFileLength
] = 0;
3731 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3732 /* Select the file name like Windows does */
3733 if (filename_is_edit(fodInfos
))
3734 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3738 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3739 COMCTL32_ReleaseStgMedium(medium
);
3743 /* copied from shell32 to avoid linking to it
3744 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3745 * is dependent on whether emulated OS is unicode or not.
3747 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3752 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3753 COMDLG32_SHFree(src
->u
.pOleStr
);
3757 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3762 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3767 FIXME("unknown type %x!\n", src
->uType
);
3768 if (len
) *dest
= '\0';
3774 /***********************************************************************
3775 * FILEDLG95_FILENAME_GetFileNames
3777 * Copies the filenames to a delimited string list.
3779 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3781 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3782 UINT nFileCount
= 0; /* number of files */
3783 UINT nStrLen
= 0; /* length of string in edit control */
3784 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3788 /* get the filenames from the filename control */
3789 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3790 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3791 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3793 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3795 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3801 * DATAOBJECT Helper functions
3804 /***********************************************************************
3805 * COMCTL32_ReleaseStgMedium
3807 * like ReleaseStgMedium from ole32
3809 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3811 if(medium
.pUnkForRelease
)
3813 IUnknown_Release(medium
.pUnkForRelease
);
3817 GlobalUnlock(medium
.u
.hGlobal
);
3818 GlobalFree(medium
.u
.hGlobal
);
3822 /***********************************************************************
3823 * GetPidlFromDataObject
3825 * Return pidl(s) by number from the cached DataObject
3827 * nPidlIndex=0 gets the fully qualified root path
3829 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3833 FORMATETC formatetc
= get_def_format();
3834 LPITEMIDLIST pidl
= NULL
;
3836 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3841 /* Get the pidls from IDataObject */
3842 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3844 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3845 if(nPidlIndex
<= cida
->cidl
)
3847 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3849 COMCTL32_ReleaseStgMedium(medium
);
3854 /***********************************************************************
3857 * Return the number of selected items in the DataObject.
3860 static UINT
GetNumSelected( IDataObject
*doSelected
)
3864 FORMATETC formatetc
= get_def_format();
3866 TRACE("sv=%p\n", doSelected
);
3868 if (!doSelected
) return 0;
3870 /* Get the pidls from IDataObject */
3871 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3873 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3874 retVal
= cida
->cidl
;
3875 COMCTL32_ReleaseStgMedium(medium
);
3885 /***********************************************************************
3888 * Get the pidl's display name (relative to folder) and
3889 * put it in lpstrFileName.
3891 * Return NOERROR on success,
3895 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3900 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3904 SHGetDesktopFolder(&lpsf
);
3905 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3906 IShellFolder_Release(lpsf
);
3910 /* Get the display name of the pidl relative to the folder */
3911 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3913 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3918 /***********************************************************************
3919 * GetShellFolderFromPidl
3921 * pidlRel is the item pidl relative
3922 * Return the IShellFolder of the absolute pidl
3924 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3926 IShellFolder
*psf
= NULL
,*psfParent
;
3928 TRACE("%p\n", pidlAbs
);
3930 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3933 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3935 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3937 IShellFolder_Release(psfParent
);
3941 /* return the desktop */
3947 /***********************************************************************
3950 * Return the LPITEMIDLIST to the parent of the pidl in the list
3952 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3954 LPITEMIDLIST pidlParent
;
3956 TRACE("%p\n", pidl
);
3958 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3959 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3964 /***********************************************************************
3967 * returns the pidl of the file name relative to folder
3968 * NULL if an error occurred
3970 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3972 LPITEMIDLIST pidl
= NULL
;
3975 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3977 if(!lpcstrFileName
) return NULL
;
3978 if(!*lpcstrFileName
) return NULL
;
3982 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3983 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3984 IShellFolder_Release(lpsf
);
3989 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3996 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3998 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4001 TRACE("%p, %p\n", psf
, pidl
);
4003 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4005 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
4006 /* see documentation shell 4.1*/
4007 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4010 /***********************************************************************
4011 * BrowseSelectedFolder
4013 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4015 BOOL bBrowseSelFolder
= FALSE
;
4016 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
4020 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4022 LPITEMIDLIST pidlSelection
;
4024 /* get the file selected */
4025 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4026 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4028 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4029 pidlSelection
, SBSP_RELATIVE
) ) )
4032 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
4033 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4035 bBrowseSelFolder
= TRUE
;
4036 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4037 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4039 COMDLG32_SHFree( pidlSelection
);
4042 return bBrowseSelFolder
;
4046 * Memory allocation methods */
4047 static void *MemAlloc(UINT size
)
4049 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4052 static void MemFree(void *mem
)
4054 HeapFree(GetProcessHeap(),0,mem
);
4057 static inline BOOL
valid_struct_size( DWORD size
)
4059 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4060 (size
== sizeof( OPENFILENAMEW
));
4063 static inline BOOL
is_win16_looks(DWORD flags
)
4065 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4066 !(flags
& OFN_EXPLORER
));
4069 /* ------------------ APIs ---------------------- */
4071 /***********************************************************************
4072 * GetOpenFileNameA (COMDLG32.@)
4074 * Creates a dialog box for the user to select a file to open.
4077 * TRUE on success: user enters a valid file
4078 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4081 BOOL WINAPI
GetOpenFileNameA(
4082 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4084 TRACE("flags %08x\n", ofn
->Flags
);
4086 if (!valid_struct_size( ofn
->lStructSize
))
4088 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4092 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4093 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4094 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4096 if (is_win16_looks(ofn
->Flags
))
4097 return GetFileName31A(ofn
, OPEN_DIALOG
);
4099 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4102 /***********************************************************************
4103 * GetOpenFileNameW (COMDLG32.@)
4105 * Creates a dialog box for the user to select a file to open.
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
GetOpenFileNameW(
4113 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4115 TRACE("flags %08x\n", ofn
->Flags
);
4117 if (!valid_struct_size( ofn
->lStructSize
))
4119 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4123 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4124 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4125 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4127 if (is_win16_looks(ofn
->Flags
))
4128 return GetFileName31W(ofn
, OPEN_DIALOG
);
4130 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4134 /***********************************************************************
4135 * GetSaveFileNameA (COMDLG32.@)
4137 * Creates a dialog box for the user to select a file to save.
4140 * TRUE on success: user enters a valid file
4141 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4144 BOOL WINAPI
GetSaveFileNameA(
4145 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4147 if (!valid_struct_size( ofn
->lStructSize
))
4149 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4153 if (is_win16_looks(ofn
->Flags
))
4154 return GetFileName31A(ofn
, SAVE_DIALOG
);
4156 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4159 /***********************************************************************
4160 * GetSaveFileNameW (COMDLG32.@)
4162 * Creates a dialog box for the user to select a file to save.
4165 * TRUE on success: user enters a valid file
4166 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4169 BOOL WINAPI
GetSaveFileNameW(
4170 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4172 if (!valid_struct_size( ofn
->lStructSize
))
4174 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4178 if (is_win16_looks(ofn
->Flags
))
4179 return GetFileName31W(ofn
, SAVE_DIALOG
);
4181 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4184 /***********************************************************************
4185 * GetFileTitleA (COMDLG32.@)
4187 * See GetFileTitleW.
4189 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4192 UNICODE_STRING strWFile
;
4195 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4196 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4197 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4198 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4199 RtlFreeUnicodeString( &strWFile
);
4200 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4205 /***********************************************************************
4206 * GetFileTitleW (COMDLG32.@)
4208 * Get the name of a file.
4211 * lpFile [I] name and location of file
4212 * lpTitle [O] returned file name
4213 * cbBuf [I] buffer size of lpTitle
4217 * Failure: negative number.
4219 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4222 static const WCHAR brkpoint
[] = {'*','[',']',0};
4223 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4225 if(lpFile
== NULL
|| lpTitle
== NULL
)
4228 len
= lstrlenW(lpFile
);
4233 if(strpbrkW(lpFile
, brkpoint
))
4238 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4241 for(i
= len
; i
>= 0; i
--)
4243 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4253 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4255 len
= lstrlenW(lpFile
+i
)+1;
4259 lstrcpyW(lpTitle
, &lpFile
[i
]);