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 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2955 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2956 if (fodInfos
->Shell
.FOIDataObject
)
2957 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2960 /***********************************************************************
2961 * FILEDLG95_FILETYPE_Init
2963 * Initialisation of the file type combo box
2965 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2967 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2968 int nFilters
= 0; /* number of filters */
2973 if(fodInfos
->customfilter
)
2975 /* customfilter has one entry... title\0ext\0
2976 * Set first entry of combo box item with customfilter
2979 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2982 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2984 /* Copy the extensions */
2985 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2986 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2987 lstrcpyW(lpstrExt
,lpstrPos
);
2989 /* Add the item at the end of the combo */
2990 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2991 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2994 if(fodInfos
->filter
)
2996 LPCWSTR lpstrPos
= fodInfos
->filter
;
3000 /* filter is a list... title\0ext\0......\0\0
3001 * Set the combo item text to the title and the item data
3004 LPCWSTR lpstrDisplay
;
3008 if(! *lpstrPos
) break; /* end */
3009 lpstrDisplay
= lpstrPos
;
3010 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3012 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
3016 /* Copy the extensions */
3017 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3018 lstrcpyW(lpstrExt
,lpstrPos
);
3019 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3021 /* Add the item at the end of the combo */
3022 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
3024 /* malformed filters are added anyway... */
3025 if (!*lpstrExt
) break;
3030 * Set the current filter to the one specified
3031 * in the initialisation structure
3033 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3037 /* Check to make sure our index isn't out of bounds. */
3038 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3039 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3040 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3042 /* set default filter index */
3043 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3044 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3046 /* calculate index of Combo Box item */
3047 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3048 if (fodInfos
->customfilter
== NULL
)
3051 /* Set the current index selection. */
3052 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3054 /* Get the corresponding text string from the combo box. */
3055 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3058 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3064 CharLowerW(lpstrFilter
); /* lowercase */
3065 len
= lstrlenW(lpstrFilter
)+1;
3066 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3067 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3070 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3074 /***********************************************************************
3075 * FILEDLG95_FILETYPE_OnCommand
3077 * WM_COMMAND of the file type combo box
3078 * If the function succeeds, the return value is nonzero.
3080 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3082 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3090 /* Get the current item of the filetype combo box */
3091 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3093 /* set the current filter index */
3094 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3095 (fodInfos
->customfilter
== NULL
? 1 : 0);
3097 /* Set the current filter with the current selection */
3098 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3100 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3102 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3105 CharLowerW(lpstrFilter
); /* lowercase */
3106 len
= lstrlenW(lpstrFilter
)+1;
3107 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3108 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3109 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3110 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3113 /* Refresh the actual view to display the included items*/
3114 if (fodInfos
->Shell
.FOIShellView
)
3115 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3120 /***********************************************************************
3121 * FILEDLG95_FILETYPE_SearchExt
3123 * searches for an extension in the filetype box
3125 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3127 int i
, iCount
= CBGetCount(hwnd
);
3129 TRACE("%s\n", debugstr_w(lpstrExt
));
3131 if(iCount
!= CB_ERR
)
3133 for(i
=0;i
<iCount
;i
++)
3135 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3142 /***********************************************************************
3143 * FILEDLG95_FILETYPE_Clean
3145 * Clean the memory used by the filetype combo box
3147 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3149 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3151 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3155 /* Delete each string of the combo and their associated data */
3156 if(iCount
!= CB_ERR
)
3158 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3160 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3161 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3164 /* Current filter */
3165 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3169 /***********************************************************************
3170 * FILEDLG95_LOOKIN_Init
3172 * Initialisation of the look in combo box
3175 /* Small helper function, to determine if the unixfs shell extension is rooted
3176 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3178 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3180 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3181 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3183 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3184 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3185 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3186 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3188 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3195 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3197 IShellFolder
*psfRoot
, *psfDrives
;
3198 IEnumIDList
*lpeRoot
, *lpeDrives
;
3199 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3202 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3206 liInfos
->iMaxIndentation
= 0;
3208 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3210 hdc
= GetDC( hwndCombo
);
3211 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3212 GetTextMetricsW( hdc
, &tm
);
3213 ReleaseDC( hwndCombo
, hdc
);
3215 /* set item height for both text field and listbox */
3216 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3217 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3219 /* Turn on the extended UI for the combo box like Windows does */
3220 CBSetExtendedUI(hwndCombo
, TRUE
);
3222 /* Initialise data of Desktop folder */
3223 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3224 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3225 COMDLG32_SHFree(pidlTmp
);
3227 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3229 SHGetDesktopFolder(&psfRoot
);
3233 /* enumerate the contents of the desktop */
3234 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3236 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3238 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3240 /* If the unixfs extension is rooted, we don't expand the drives by default */
3241 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3243 /* special handling for CSIDL_DRIVES */
3244 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3246 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3248 /* enumerate the drives */
3249 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3251 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3253 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3254 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3255 COMDLG32_SHFree(pidlAbsTmp
);
3256 COMDLG32_SHFree(pidlTmp1
);
3258 IEnumIDList_Release(lpeDrives
);
3260 IShellFolder_Release(psfDrives
);
3265 COMDLG32_SHFree(pidlTmp
);
3267 IEnumIDList_Release(lpeRoot
);
3269 IShellFolder_Release(psfRoot
);
3272 COMDLG32_SHFree(pidlDrives
);
3275 /***********************************************************************
3276 * FILEDLG95_LOOKIN_DrawItem
3278 * WM_DRAWITEM message handler
3280 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3282 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3283 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3284 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3288 HIMAGELIST ilItemImage
;
3291 LPSFOLDER tmpFolder
;
3292 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3293 UINT icon_width
, icon_height
;
3297 if(pDIStruct
->itemID
== -1)
3300 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3301 pDIStruct
->itemID
)))
3305 icon_width
= GetSystemMetrics(SM_CXICON
);
3306 icon_height
= GetSystemMetrics(SM_CYICON
);
3307 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3309 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3310 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3311 shgfi_flags
|= SHGFI_SMALLICON
;
3314 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3315 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3317 /* Is this item selected ? */
3318 if(pDIStruct
->itemState
& ODS_SELECTED
)
3320 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3321 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3322 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3326 SetTextColor(pDIStruct
->hDC
,crText
);
3327 SetBkColor(pDIStruct
->hDC
,crWin
);
3328 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3331 /* Do not indent item if drawing in the edit of the combo */
3332 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3335 iIndentation
= tmpFolder
->m_iIndent
;
3337 /* Draw text and icon */
3339 /* Initialise the icon display area */
3340 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3341 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3342 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3343 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3345 /* Initialise the text display area */
3346 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3347 rectText
.left
= rectIcon
.right
;
3349 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3350 rectText
.right
= pDIStruct
->rcItem
.right
;
3352 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3354 /* Draw the icon from the image list */
3355 ImageList_Draw(ilItemImage
,
3362 /* Draw the associated text */
3363 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3367 /***********************************************************************
3368 * FILEDLG95_LOOKIN_OnCommand
3370 * LookIn combo box WM_COMMAND message handler
3371 * If the function succeeds, the return value is nonzero.
3373 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3375 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3377 TRACE("%p\n", fodInfos
);
3383 LPSFOLDER tmpFolder
;
3386 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3388 if( iItem
== CB_ERR
) return FALSE
;
3390 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3395 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3396 tmpFolder
->pidlItem
,
3399 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3400 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3410 /***********************************************************************
3411 * FILEDLG95_LOOKIN_AddItem
3413 * Adds an absolute pidl item to the lookin combo box
3414 * returns the index of the inserted item
3416 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3418 LPITEMIDLIST pidlNext
;
3421 LookInInfos
*liInfos
;
3423 TRACE("%08x\n", iInsertId
);
3428 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3431 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3432 tmpFolder
->m_iIndent
= 0;
3434 /* Calculate the indentation of the item in the lookin*/
3436 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3438 tmpFolder
->m_iIndent
++;
3441 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3443 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3444 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3446 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3447 SHGetFileInfoW((LPCWSTR
)pidl
,
3451 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3452 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3454 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3456 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3460 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3462 /* Add the item at the end of the list */
3465 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3467 /* Insert the item at the iInsertId position*/
3470 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3473 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3477 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3478 MemFree( tmpFolder
);
3483 /***********************************************************************
3484 * FILEDLG95_LOOKIN_InsertItemAfterParent
3486 * Insert an item below its parent
3488 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3491 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3496 if (pidl
== pidlParent
)
3499 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3503 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3506 /* Free pidlParent memory */
3507 COMDLG32_SHFree(pidlParent
);
3509 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3512 /***********************************************************************
3513 * FILEDLG95_LOOKIN_SelectItem
3515 * Adds an absolute pidl item to the lookin combo box
3516 * returns the index of the inserted item
3518 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3521 LookInInfos
*liInfos
;
3525 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3527 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3531 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3532 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3537 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3538 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3542 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3544 if(iRemovedItem
< iItemPos
)
3549 CBSetCurSel(hwnd
,iItemPos
);
3550 liInfos
->uSelectedItem
= iItemPos
;
3556 /***********************************************************************
3557 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3559 * Remove the item with an expansion level over iExpansionLevel
3561 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3564 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3568 if(liInfos
->iMaxIndentation
<= 2)
3571 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3573 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3574 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3576 CBDeleteString(hwnd
,iItemPos
);
3577 liInfos
->iMaxIndentation
--;
3585 /***********************************************************************
3586 * FILEDLG95_LOOKIN_SearchItem
3588 * Search for pidl in the lookin combo box
3589 * returns the index of the found item
3591 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3594 int iCount
= CBGetCount(hwnd
);
3596 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3598 if (iCount
!= CB_ERR
)
3602 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3604 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3606 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3614 /***********************************************************************
3615 * FILEDLG95_LOOKIN_Clean
3617 * Clean the memory used by the lookin combo box
3619 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3621 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3622 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3624 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3628 /* Delete each string of the combo and their associated data */
3629 if (iCount
!= CB_ERR
)
3631 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3633 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3634 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3636 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3640 /* LookInInfos structure */
3642 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3645 /***********************************************************************
3648 * Fill the FORMATETC used in the shell id list
3650 static FORMATETC
get_def_format(void)
3652 static CLIPFORMAT cfFormat
;
3653 FORMATETC formatetc
;
3655 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3656 formatetc
.cfFormat
= cfFormat
;
3658 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3659 formatetc
.lindex
= -1;
3660 formatetc
.tymed
= TYMED_HGLOBAL
;
3664 /***********************************************************************
3665 * FILEDLG95_FILENAME_FillFromSelection
3667 * fills the edit box from the cached DataObject
3669 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3671 FileOpenDlgInfos
*fodInfos
;
3673 LPWSTR lpstrAllFiles
, lpstrTmp
;
3674 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3677 FORMATETC formatetc
= get_def_format();
3680 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3682 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3685 cida
= GlobalLock(medium
.u
.hGlobal
);
3686 nFileSelected
= cida
->cidl
;
3688 /* Allocate a buffer */
3689 nAllFilesMaxLength
= MAX_PATH
+ 3;
3690 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3694 /* Loop through the selection, handle only files (not folders) */
3695 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3697 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3700 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3702 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3704 nAllFilesMaxLength
*= 2;
3705 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3708 lpstrAllFiles
= lpstrTmp
;
3711 lpstrAllFiles
[nAllFilesLength
++] = '"';
3712 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3713 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3714 nAllFilesLength
+= nThisFileLength
;
3715 lpstrAllFiles
[nAllFilesLength
++] = '"';
3716 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3723 /* If there's only one file, use the name as-is without quotes */
3724 lpstrTmp
= lpstrAllFiles
;
3728 lpstrTmp
[nThisFileLength
] = 0;
3730 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3731 /* Select the file name like Windows does */
3732 if (filename_is_edit(fodInfos
))
3733 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3737 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3738 COMCTL32_ReleaseStgMedium(medium
);
3742 /* copied from shell32 to avoid linking to it
3743 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3744 * is dependent on whether emulated OS is unicode or not.
3746 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3751 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3752 COMDLG32_SHFree(src
->u
.pOleStr
);
3756 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3761 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3766 FIXME("unknown type %x!\n", src
->uType
);
3767 if (len
) *dest
= '\0';
3773 /***********************************************************************
3774 * FILEDLG95_FILENAME_GetFileNames
3776 * Copies the filenames to a delimited string list.
3778 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3780 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3781 UINT nFileCount
= 0; /* number of files */
3782 UINT nStrLen
= 0; /* length of string in edit control */
3783 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3787 /* get the filenames from the filename control */
3788 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3789 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3790 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3792 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3794 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3800 * DATAOBJECT Helper functions
3803 /***********************************************************************
3804 * COMCTL32_ReleaseStgMedium
3806 * like ReleaseStgMedium from ole32
3808 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3810 if(medium
.pUnkForRelease
)
3812 IUnknown_Release(medium
.pUnkForRelease
);
3816 GlobalUnlock(medium
.u
.hGlobal
);
3817 GlobalFree(medium
.u
.hGlobal
);
3821 /***********************************************************************
3822 * GetPidlFromDataObject
3824 * Return pidl(s) by number from the cached DataObject
3826 * nPidlIndex=0 gets the fully qualified root path
3828 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3832 FORMATETC formatetc
= get_def_format();
3833 LPITEMIDLIST pidl
= NULL
;
3835 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3840 /* Get the pidls from IDataObject */
3841 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3843 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3844 if(nPidlIndex
<= cida
->cidl
)
3846 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3848 COMCTL32_ReleaseStgMedium(medium
);
3853 /***********************************************************************
3856 * Return the number of selected items in the DataObject.
3859 static UINT
GetNumSelected( IDataObject
*doSelected
)
3863 FORMATETC formatetc
= get_def_format();
3865 TRACE("sv=%p\n", doSelected
);
3867 if (!doSelected
) return 0;
3869 /* Get the pidls from IDataObject */
3870 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3872 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3873 retVal
= cida
->cidl
;
3874 COMCTL32_ReleaseStgMedium(medium
);
3884 /***********************************************************************
3887 * Get the pidl's display name (relative to folder) and
3888 * put it in lpstrFileName.
3890 * Return NOERROR on success,
3894 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3899 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3903 SHGetDesktopFolder(&lpsf
);
3904 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3905 IShellFolder_Release(lpsf
);
3909 /* Get the display name of the pidl relative to the folder */
3910 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3912 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3917 /***********************************************************************
3918 * GetShellFolderFromPidl
3920 * pidlRel is the item pidl relative
3921 * Return the IShellFolder of the absolute pidl
3923 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3925 IShellFolder
*psf
= NULL
,*psfParent
;
3927 TRACE("%p\n", pidlAbs
);
3929 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3932 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3934 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3936 IShellFolder_Release(psfParent
);
3940 /* return the desktop */
3946 /***********************************************************************
3949 * Return the LPITEMIDLIST to the parent of the pidl in the list
3951 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3953 LPITEMIDLIST pidlParent
;
3955 TRACE("%p\n", pidl
);
3957 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3958 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3963 /***********************************************************************
3966 * returns the pidl of the file name relative to folder
3967 * NULL if an error occurred
3969 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3971 LPITEMIDLIST pidl
= NULL
;
3974 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3976 if(!lpcstrFileName
) return NULL
;
3977 if(!*lpcstrFileName
) return NULL
;
3981 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3982 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3983 IShellFolder_Release(lpsf
);
3988 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3995 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3997 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4000 TRACE("%p, %p\n", psf
, pidl
);
4002 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4004 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
4005 /* see documentation shell 4.1*/
4006 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4009 /***********************************************************************
4010 * BrowseSelectedFolder
4012 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4014 BOOL bBrowseSelFolder
= FALSE
;
4015 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
4019 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4021 LPITEMIDLIST pidlSelection
;
4023 /* get the file selected */
4024 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4025 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4027 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4028 pidlSelection
, SBSP_RELATIVE
) ) )
4031 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
4032 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4034 bBrowseSelFolder
= TRUE
;
4035 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4036 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4038 COMDLG32_SHFree( pidlSelection
);
4041 return bBrowseSelFolder
;
4045 * Memory allocation methods */
4046 static void *MemAlloc(UINT size
)
4048 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4051 static void MemFree(void *mem
)
4053 HeapFree(GetProcessHeap(),0,mem
);
4056 static inline BOOL
valid_struct_size( DWORD size
)
4058 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4059 (size
== sizeof( OPENFILENAMEW
));
4062 static inline BOOL
is_win16_looks(DWORD flags
)
4064 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4065 !(flags
& OFN_EXPLORER
));
4068 /* ------------------ APIs ---------------------- */
4070 /***********************************************************************
4071 * GetOpenFileNameA (COMDLG32.@)
4073 * Creates a dialog box for the user to select a file to open.
4076 * TRUE on success: user enters a valid file
4077 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4080 BOOL WINAPI
GetOpenFileNameA(
4081 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4083 TRACE("flags %08x\n", ofn
->Flags
);
4085 if (!valid_struct_size( ofn
->lStructSize
))
4087 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4091 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4092 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4093 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4095 if (is_win16_looks(ofn
->Flags
))
4096 return GetFileName31A(ofn
, OPEN_DIALOG
);
4098 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4101 /***********************************************************************
4102 * GetOpenFileNameW (COMDLG32.@)
4104 * Creates a dialog box for the user to select a file to open.
4107 * TRUE on success: user enters a valid file
4108 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4111 BOOL WINAPI
GetOpenFileNameW(
4112 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4114 TRACE("flags %08x\n", ofn
->Flags
);
4116 if (!valid_struct_size( ofn
->lStructSize
))
4118 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4122 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4123 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4124 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4126 if (is_win16_looks(ofn
->Flags
))
4127 return GetFileName31W(ofn
, OPEN_DIALOG
);
4129 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4133 /***********************************************************************
4134 * GetSaveFileNameA (COMDLG32.@)
4136 * Creates a dialog box for the user to select a file to save.
4139 * TRUE on success: user enters a valid file
4140 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4143 BOOL WINAPI
GetSaveFileNameA(
4144 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4146 if (!valid_struct_size( ofn
->lStructSize
))
4148 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4152 if (is_win16_looks(ofn
->Flags
))
4153 return GetFileName31A(ofn
, SAVE_DIALOG
);
4155 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4158 /***********************************************************************
4159 * GetSaveFileNameW (COMDLG32.@)
4161 * Creates a dialog box for the user to select a file to save.
4164 * TRUE on success: user enters a valid file
4165 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4168 BOOL WINAPI
GetSaveFileNameW(
4169 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4171 if (!valid_struct_size( ofn
->lStructSize
))
4173 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4177 if (is_win16_looks(ofn
->Flags
))
4178 return GetFileName31W(ofn
, SAVE_DIALOG
);
4180 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4183 /***********************************************************************
4184 * GetFileTitleA (COMDLG32.@)
4186 * See GetFileTitleW.
4188 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4191 UNICODE_STRING strWFile
;
4194 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4195 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4196 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4197 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4198 RtlFreeUnicodeString( &strWFile
);
4199 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4204 /***********************************************************************
4205 * GetFileTitleW (COMDLG32.@)
4207 * Get the name of a file.
4210 * lpFile [I] name and location of file
4211 * lpTitle [O] returned file name
4212 * cbBuf [I] buffer size of lpTitle
4216 * Failure: negative number.
4218 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4221 static const WCHAR brkpoint
[] = {'*','[',']',0};
4222 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4224 if(lpFile
== NULL
|| lpTitle
== NULL
)
4227 len
= lstrlenW(lpFile
);
4232 if(strpbrkW(lpFile
, brkpoint
))
4237 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4240 for(i
= len
; i
>= 0; i
--)
4242 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4252 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4254 len
= lstrlenW(lpFile
+i
)+1;
4258 lstrcpyW(lpTitle
, &lpFile
[i
]);