2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
140 static const WCHAR LastVisitedMRUW
[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
147 /***********************************************************************
151 /* Internal functions used by the dialog */
152 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
153 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
154 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
155 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
156 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
157 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
158 static void FILEDLG95_Clean(HWND hwnd
);
160 /* Functions used by the shell navigation */
161 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
162 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
163 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
165 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
170 /* Functions used by the filetype combo box */
171 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
172 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
178 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
179 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
189 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
192 /* Miscellaneous tool functions */
193 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
194 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
195 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
196 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
197 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
198 static UINT
GetNumSelected( IDataObject
*doSelected
);
200 /* Shell memory allocation */
201 static void *MemAlloc(UINT size
);
202 static void MemFree(void *mem
);
204 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
205 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
207 static BOOL
BrowseSelectedFolder(HWND hwnd
);
209 /***********************************************************************
212 * Creates an Open common dialog box that lets the user select
213 * the drive, directory, and the name of a file or set of files to open.
215 * IN : The FileOpenDlgInfos structure associated with the dialog
216 * OUT : TRUE on success
217 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
219 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
223 LPCVOID origTemplate
;
225 LPDLGTEMPLATEW
template;
230 /* test for missing functionality */
231 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
233 FIXME("Flags 0x%08x not yet implemented\n",
234 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
237 /* Create the dialog from a template */
239 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
241 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
244 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
245 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
246 !(origTemplate
= LockResource(hDlgTmpl
)))
248 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
251 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
253 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
256 memcpy(template, origTemplate
, dwSize
);
258 /* msdn: explorer style dialogs permit sizing by default.
259 * The OFN_ENABLESIZING flag is only needed when a hook or
260 * custom tmeplate is provided */
261 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
262 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
263 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
265 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
267 template->style
|= WS_SIZEBOX
;
268 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
269 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
272 template->style
&= ~WS_SIZEBOX
;
275 /* old style hook messages */
276 if (IsHooked(fodInfos
))
278 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
279 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
280 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
281 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
284 /* Some shell namespace extensions depend on COM being initialized. */
285 hr
= OleInitialize(NULL
);
287 if (fodInfos
->unicode
)
288 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
290 fodInfos
->ofnInfos
->hwndOwner
,
294 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
296 fodInfos
->ofnInfos
->hwndOwner
,
302 HeapFree(GetProcessHeap(), 0, template);
304 /* Unable to create the dialog */
311 /***********************************************************************
314 * Call GetFileName95 with this structure and clean the memory.
316 * IN : The OPENFILENAMEA initialisation structure passed to
317 * GetOpenFileNameA win api function (see filedlg.c)
319 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
322 FileOpenDlgInfos fodInfos
;
323 LPSTR lpstrSavDir
= NULL
;
325 LPWSTR defext
= NULL
;
326 LPWSTR filter
= NULL
;
327 LPWSTR customfilter
= NULL
;
328 INITCOMMONCONTROLSEX icc
;
330 /* Initialize ComboBoxEx32 */
331 icc
.dwSize
= sizeof(icc
);
332 icc
.dwICC
= ICC_USEREX_CLASSES
;
333 InitCommonControlsEx(&icc
);
335 /* Initialize CommDlgExtendedError() */
336 COMDLG32_SetCommDlgExtendedError(0);
338 /* Initialize FileOpenDlgInfos structure */
339 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
341 /* Pass in the original ofn */
342 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
344 /* save current directory */
345 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
347 lpstrSavDir
= MemAlloc(MAX_PATH
);
348 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
351 fodInfos
.unicode
= FALSE
;
353 /* convert all the input strings to unicode */
354 if(ofn
->lpstrInitialDir
)
356 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
357 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
358 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
361 fodInfos
.initdir
= NULL
;
365 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
366 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
369 fodInfos
.filename
= NULL
;
373 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
374 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
375 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
377 fodInfos
.defext
= defext
;
381 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
382 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
383 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
385 fodInfos
.title
= title
;
387 if (ofn
->lpstrFilter
)
392 /* filter is a list... title\0ext\0......\0\0 */
393 s
= ofn
->lpstrFilter
;
394 while (*s
) s
= s
+strlen(s
)+1;
396 n
= s
- ofn
->lpstrFilter
;
397 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
398 filter
= MemAlloc(len
*sizeof(WCHAR
));
399 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
401 fodInfos
.filter
= filter
;
403 /* convert lpstrCustomFilter */
404 if (ofn
->lpstrCustomFilter
)
409 /* customfilter contains a pair of strings... title\0ext\0 */
410 s
= ofn
->lpstrCustomFilter
;
411 if (*s
) s
= s
+strlen(s
)+1;
412 if (*s
) s
= s
+strlen(s
)+1;
413 n
= s
- ofn
->lpstrCustomFilter
;
414 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
415 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
416 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
418 fodInfos
.customfilter
= customfilter
;
420 /* Initialize the dialog property */
421 fodInfos
.DlgInfos
.dwDlgProp
= 0;
422 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
427 ret
= GetFileName95(&fodInfos
);
430 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
431 ret
= GetFileName95(&fodInfos
);
439 SetCurrentDirectoryA(lpstrSavDir
);
440 MemFree(lpstrSavDir
);
446 MemFree(customfilter
);
447 MemFree(fodInfos
.initdir
);
448 MemFree(fodInfos
.filename
);
450 TRACE("selected file: %s\n",ofn
->lpstrFile
);
455 /***********************************************************************
458 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
459 * Call GetFileName95 with this structure and clean the memory.
462 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
465 FileOpenDlgInfos fodInfos
;
466 LPWSTR lpstrSavDir
= NULL
;
467 INITCOMMONCONTROLSEX icc
;
469 /* Initialize ComboBoxEx32 */
470 icc
.dwSize
= sizeof(icc
);
471 icc
.dwICC
= ICC_USEREX_CLASSES
;
472 InitCommonControlsEx(&icc
);
474 /* Initialize CommDlgExtendedError() */
475 COMDLG32_SetCommDlgExtendedError(0);
477 /* Initialize FileOpenDlgInfos structure */
478 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
480 /* Pass in the original ofn */
481 fodInfos
.ofnInfos
= ofn
;
483 fodInfos
.title
= ofn
->lpstrTitle
;
484 fodInfos
.defext
= ofn
->lpstrDefExt
;
485 fodInfos
.filter
= ofn
->lpstrFilter
;
486 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
488 /* convert string arguments, save others */
491 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
492 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
495 fodInfos
.filename
= NULL
;
497 if(ofn
->lpstrInitialDir
)
499 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
500 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
501 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
502 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
505 fodInfos
.initdir
= NULL
;
507 /* save current directory */
508 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
510 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
511 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
514 fodInfos
.unicode
= TRUE
;
519 ret
= GetFileName95(&fodInfos
);
522 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
523 ret
= GetFileName95(&fodInfos
);
531 SetCurrentDirectoryW(lpstrSavDir
);
532 MemFree(lpstrSavDir
);
535 /* restore saved IN arguments and convert OUT arguments back */
536 MemFree(fodInfos
.filename
);
537 MemFree(fodInfos
.initdir
);
541 /******************************************************************************
542 * COMDLG32_GetDisplayNameOf [internal]
544 * Helper function to get the display name for a pidl.
546 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
547 LPSHELLFOLDER psfDesktop
;
550 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
553 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
554 IShellFolder_Release(psfDesktop
);
558 IShellFolder_Release(psfDesktop
);
559 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
562 /******************************************************************************
563 * COMDLG32_GetCanonicalPath [internal]
565 * Helper function to get the canonical path.
567 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
568 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
570 WCHAR lpstrTemp
[MAX_PATH
];
572 /* Get the current directory name */
573 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
576 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
578 PathAddBackslashW(lpstrPathAndFile
);
580 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
582 /* if the user specified a fully qualified path use it */
583 if(PathIsRelativeW(lpstrFile
))
585 lstrcatW(lpstrPathAndFile
, lpstrFile
);
589 /* does the path have a drive letter? */
590 if (PathGetDriveNumberW(lpstrFile
) == -1)
591 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
593 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
596 /* resolve "." and ".." */
597 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
598 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
599 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
602 /***********************************************************************
603 * COMDLG32_SplitFileNames [internal]
605 * Creates a delimited list of filenames.
607 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
609 UINT nStrCharCount
= 0; /* index in src buffer */
610 UINT nFileIndex
= 0; /* index in dest buffer */
611 UINT nFileCount
= 0; /* number of files */
613 /* we might get single filename without any '"',
614 * so we need nStrLen + terminating \0 + end-of-list \0 */
615 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
618 /* build delimited file list from filenames */
619 while ( nStrCharCount
<= nStrLen
)
621 if ( lpstrEdit
[nStrCharCount
]=='"' )
624 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
626 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
629 (*lpstrFileList
)[nFileIndex
++] = 0;
635 /* single, unquoted string */
636 if ((nStrLen
> 0) && (nFileIndex
== 0) )
638 lstrcpyW(*lpstrFileList
, lpstrEdit
);
639 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
644 (*lpstrFileList
)[nFileIndex
++] = '\0';
646 *sizeUsed
= nFileIndex
;
650 /***********************************************************************
651 * ArrangeCtrlPositions [internal]
653 * NOTE: Make sure to add testcases for any changes made here.
655 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
657 HWND hwndChild
, hwndStc32
;
658 RECT rectParent
, rectChild
, rectStc32
;
662 /* Take into account if open as read only checkbox and help button
667 RECT rectHelp
, rectCancel
;
668 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
669 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
670 /* subtract the height of the help button plus the space between
671 * the help button and the cancel button to the height of the dialog
673 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
677 There are two possibilities to add components to the default file dialog box.
679 By default, all the new components are added below the standard dialog box (the else case).
681 However, if there is a static text component with the stc32 id, a special case happens.
682 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
683 in the window and the cx and cy indicate how to size the window.
684 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
685 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
689 GetClientRect(hwndParentDlg
, &rectParent
);
691 /* when arranging controls we have to use fixed parent size */
692 rectParent
.bottom
-= help_fixup
;
694 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
697 GetWindowRect(hwndStc32
, &rectStc32
);
698 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
700 /* set the size of the stc32 control according to the size of
701 * client area of the parent dialog
703 SetWindowPos(hwndStc32
, 0,
705 rectParent
.right
, rectParent
.bottom
,
706 SWP_NOMOVE
| SWP_NOZORDER
);
709 SetRectEmpty(&rectStc32
);
711 /* this part moves controls of the child dialog */
712 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
715 if (hwndChild
!= hwndStc32
)
717 GetWindowRect(hwndChild
, &rectChild
);
718 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
720 /* move only if stc32 exist */
721 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
723 /* move to the right of visible controls of the parent dialog */
724 rectChild
.left
+= rectParent
.right
;
725 rectChild
.left
-= rectStc32
.right
;
727 /* move even if stc32 doesn't exist */
728 if (rectChild
.top
>= rectStc32
.bottom
)
730 /* move below visible controls of the parent dialog */
731 rectChild
.top
+= rectParent
.bottom
;
732 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
735 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
736 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
738 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
741 /* this part moves controls of the parent dialog */
742 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
745 if (hwndChild
!= hwndChildDlg
)
747 GetWindowRect(hwndChild
, &rectChild
);
748 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
750 /* left,top of stc32 marks the position of controls
751 * from the parent dialog
753 rectChild
.left
+= rectStc32
.left
;
754 rectChild
.top
+= rectStc32
.top
;
756 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
757 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
759 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
762 /* calculate the size of the resulting dialog */
764 /* here we have to use original parent size */
765 GetClientRect(hwndParentDlg
, &rectParent
);
766 GetClientRect(hwndChildDlg
, &rectChild
);
767 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
768 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
773 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
774 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
776 chgx
= rectChild
.right
- rectParent
.right
;
778 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
779 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
781 /* Unconditionally set new dialog
782 * height to that of the child
784 chgy
= rectChild
.bottom
- rectParent
.bottom
;
789 chgy
= rectChild
.bottom
- help_fixup
;
791 /* set the size of the parent dialog */
792 GetWindowRect(hwndParentDlg
, &rectParent
);
793 SetWindowPos(hwndParentDlg
, 0,
795 rectParent
.right
- rectParent
.left
+ chgx
,
796 rectParent
.bottom
- rectParent
.top
+ chgy
,
797 SWP_NOMOVE
| SWP_NOZORDER
);
800 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
809 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
819 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
820 * structure's hInstance parameter is not a HINSTANCE, but
821 * instead a pointer to a template resource to use.
823 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
826 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
828 hinst
= COMDLG32_hInstance
;
829 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
831 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
837 hinst
= fodInfos
->ofnInfos
->hInstance
;
838 if(fodInfos
->unicode
)
840 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
841 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
845 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
846 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
850 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
853 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
854 !(template = LockResource( hDlgTmpl
)))
856 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
860 if (fodInfos
->unicode
)
861 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
862 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
863 (LPARAM
)fodInfos
->ofnInfos
);
865 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
866 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
867 (LPARAM
)fodInfos
->ofnInfos
);
870 else if( IsHooked(fodInfos
))
875 WORD menu
,class,title
;
877 GetClientRect(hwnd
,&rectHwnd
);
878 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
879 temp
.tmplate
.dwExtendedStyle
= 0;
880 temp
.tmplate
.cdit
= 0;
885 temp
.menu
= temp
.class = temp
.title
= 0;
887 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
888 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
895 /***********************************************************************
896 * SendCustomDlgNotificationMessage
898 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
901 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
903 LRESULT hook_result
= 0;
904 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
906 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
908 if(!fodInfos
) return 0;
910 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
912 TRACE("CALL NOTIFY for %x\n", uCode
);
913 if(fodInfos
->unicode
)
916 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
917 ofnNotify
.hdr
.idFrom
=0;
918 ofnNotify
.hdr
.code
= uCode
;
919 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
920 ofnNotify
.pszFile
= NULL
;
921 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
926 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
927 ofnNotify
.hdr
.idFrom
=0;
928 ofnNotify
.hdr
.code
= uCode
;
929 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
930 ofnNotify
.pszFile
= NULL
;
931 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
933 TRACE("RET NOTIFY\n");
935 TRACE("Retval: 0x%08lx\n", hook_result
);
939 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
943 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
945 TRACE("CDM_GETFILEPATH:\n");
947 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
950 /* get path and filenames */
951 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
952 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
953 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
956 p
= buffer
+ strlenW(buffer
);
958 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
960 if (fodInfos
->unicode
)
962 total
= strlenW( buffer
) + 1;
963 if (result
) lstrcpynW( result
, buffer
, size
);
964 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
968 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
969 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
970 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
972 HeapFree( GetProcessHeap(), 0, buffer
);
976 /***********************************************************************
977 * FILEDLG95_HandleCustomDialogMessages
979 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
981 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
983 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
984 WCHAR lpstrPath
[MAX_PATH
];
987 if(!fodInfos
) return FALSE
;
991 case CDM_GETFILEPATH
:
992 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
995 case CDM_GETFOLDERPATH
:
996 TRACE("CDM_GETFOLDERPATH:\n");
997 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1000 if (fodInfos
->unicode
)
1001 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1003 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1004 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1006 retval
= lstrlenW(lpstrPath
) + 1;
1009 case CDM_GETFOLDERIDLIST
:
1010 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1011 if (retval
<= wParam
)
1012 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1016 TRACE("CDM_GETSPEC:\n");
1017 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1020 if (fodInfos
->unicode
)
1021 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1023 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1027 case CDM_SETCONTROLTEXT
:
1028 TRACE("CDM_SETCONTROLTEXT:\n");
1031 if( fodInfos
->unicode
)
1032 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1034 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1039 case CDM_HIDECONTROL
:
1040 /* MSDN states that it should fail for not OFN_EXPLORER case */
1041 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1043 HWND control
= GetDlgItem( hwnd
, wParam
);
1044 if (control
) ShowWindow( control
, SW_HIDE
);
1047 else retval
= FALSE
;
1051 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1052 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1055 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1059 /***********************************************************************
1060 * FILEDLG95_OnWMGetMMI
1062 * WM_GETMINMAXINFO message handler for resizable dialogs
1064 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1066 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1067 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1068 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1070 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1075 /***********************************************************************
1076 * FILEDLG95_OnWMSize
1078 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1080 * FIXME: this could be made more elaborate. Now use a simple scheme
1081 * where the file view is enlarged and the controls are either moved
1082 * vertically or horizontally to get out of the way. Only the "grip"
1083 * is moved in both directions to stay in the corner.
1085 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1091 FileOpenDlgInfos
*fodInfos
;
1093 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1094 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1095 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1096 /* get the new dialog rectangle */
1097 GetWindowRect( hwnd
, &rc
);
1098 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1099 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1100 /* not initialized yet */
1101 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1102 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1103 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1105 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1106 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1107 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1108 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1109 /* change the size of the view window */
1110 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1111 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1112 hdwp
= BeginDeferWindowPos( 10);
1113 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1114 rcview
.right
- rcview
.left
+ chgx
,
1115 rcview
.bottom
- rcview
.top
+ chgy
,
1116 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1117 /* change position and sizes of the controls */
1118 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1120 int ctrlid
= GetDlgCtrlID( ctrl
);
1121 GetWindowRect( ctrl
, &rc
);
1122 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1123 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1125 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1127 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1129 else if( rc
.top
> rcview
.bottom
)
1131 /* if it was below the shell view
1135 /* file name (edit or comboboxex) and file types combo change also width */
1139 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1140 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1141 SWP_NOACTIVATE
| SWP_NOZORDER
);
1143 /* then these buttons must move out of the way */
1147 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1149 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1152 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1154 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1157 else if( rc
.left
> rcview
.right
)
1159 /* if it was to the right of the shell view
1161 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1163 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1170 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1172 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1173 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1174 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1176 case IDC_TOOLBARSTATIC
:
1178 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1180 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1183 /* not resized in windows. Since wine uses this invisible control
1184 * to size the browser view it needs to be resized */
1185 case IDC_SHELLSTATIC
:
1186 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1187 rc
.right
- rc
.left
+ chgx
,
1188 rc
.bottom
- rc
.top
+ chgy
,
1189 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1194 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1195 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1197 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1198 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1200 GetWindowRect( ctrl
, &rc
);
1201 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1202 if( rc
.top
> rcview
.bottom
)
1204 /* if it was below the shell view
1206 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1207 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1208 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1210 else if( rc
.left
> rcview
.right
)
1212 /* if it was to the right of the shell view
1214 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1215 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1216 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1219 /* size the custom dialog at the end: some applications do some
1220 * control re-arranging at this point */
1221 GetClientRect(hwnd
, &rc
);
1222 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1223 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1225 EndDeferWindowPos( hdwp
);
1226 /* should not be needed */
1227 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1231 /***********************************************************************
1234 * File open dialog procedure
1236 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1239 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1246 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1248 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1249 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1251 /* Adds the FileOpenDlgInfos in the property list of the dialog
1252 so it will be easily accessible through a GetPropA(...) */
1253 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1255 FILEDLG95_InitControls(hwnd
);
1257 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1259 GetWindowRect( hwnd
, &rc
);
1260 fodInfos
->DlgInfos
.hwndGrip
=
1261 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1262 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1263 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1264 rc
.right
- gripx
, rc
.bottom
- gripy
,
1265 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1268 fodInfos
->DlgInfos
.hwndCustomDlg
=
1269 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1271 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1272 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1274 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1275 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1277 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1278 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1279 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1282 /* if the app has changed the position of the invisible listbox,
1283 * change that of the listview (browser) as well */
1284 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1285 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1286 if( !EqualRect( &rc
, &rcstc
))
1288 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1289 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1290 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1291 SWP_NOACTIVATE
| SWP_NOZORDER
);
1294 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1296 GetWindowRect( hwnd
, &rc
);
1297 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1298 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1299 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1300 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1301 GetClientRect( hwnd
, &rc
);
1302 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1303 rc
.right
- gripx
, rc
.bottom
- gripy
,
1304 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1305 /* resize the dialog to the previous invocation */
1306 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1307 SetWindowPos( hwnd
, NULL
,
1308 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1309 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1312 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1313 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1318 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1319 case WM_GETMINMAXINFO
:
1320 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1322 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1325 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1328 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1334 case WM_GETISHELLBROWSER
:
1335 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1339 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1340 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1341 MemDialogSize
= fodInfos
->sizedlg
;
1342 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1347 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1350 /* set up the button tooltips strings */
1351 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1353 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1354 switch(lpnmh
->idFrom
)
1356 /* Up folder button */
1357 case FCIDM_TB_UPFOLDER
:
1358 stringId
= IDS_UPFOLDER
;
1360 /* New folder button */
1361 case FCIDM_TB_NEWFOLDER
:
1362 stringId
= IDS_NEWFOLDER
;
1364 /* List option button */
1365 case FCIDM_TB_SMALLICON
:
1366 stringId
= IDS_LISTVIEW
;
1368 /* Details option button */
1369 case FCIDM_TB_REPORTVIEW
:
1370 stringId
= IDS_REPORTVIEW
;
1372 /* Desktop button */
1373 case FCIDM_TB_DESKTOP
:
1374 stringId
= IDS_TODESKTOP
;
1379 lpdi
->hinst
= COMDLG32_hInstance
;
1380 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1385 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1386 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1391 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1393 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1394 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1397 /***********************************************************************
1398 * FILEDLG95_InitControls
1400 * WM_INITDIALOG message handler (before hook notification)
1402 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1404 int win2000plus
= 0;
1406 int handledPath
= FALSE
;
1407 OSVERSIONINFOW osVi
;
1408 static const WCHAR szwSlash
[] = { '\\', 0 };
1409 static const WCHAR szwStar
[] = { '*',0 };
1411 static const TBBUTTON tbb
[] =
1413 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1414 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1415 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1416 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1417 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1418 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1419 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1420 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1421 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1423 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1428 HIMAGELIST toolbarImageList
;
1429 SHFILEINFOA shFileInfo
;
1430 ITEMIDLIST
*desktopPidl
;
1432 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1434 TRACE("%p\n", fodInfos
);
1436 /* Get windows version emulating */
1437 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1438 GetVersionExW(&osVi
);
1439 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1440 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1441 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1442 win2000plus
= (osVi
.dwMajorVersion
> 4);
1443 if (win2000plus
) win98plus
= TRUE
;
1445 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1448 /* Use either the edit or the comboboxex for the filename control */
1449 if (filename_is_edit( fodInfos
))
1451 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1452 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1456 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1457 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1460 /* Get the hwnd of the controls */
1461 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1462 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1464 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1465 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1467 /* construct the toolbar */
1468 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1469 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1471 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1472 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1473 rectTB
.left
= rectlook
.right
;
1474 rectTB
.top
= rectlook
.top
-1;
1476 if (fodInfos
->unicode
)
1477 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1478 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1479 rectTB
.left
, rectTB
.top
,
1480 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1481 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1483 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1484 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1485 rectTB
.left
, rectTB
.top
,
1486 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1487 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1489 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1491 /* FIXME: use TB_LOADIMAGES when implemented */
1492 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1493 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1494 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1496 /* Retrieve and add desktop icon to the toolbar */
1497 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1498 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1499 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1500 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1501 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1503 DestroyIcon(shFileInfo
.hIcon
);
1504 CoTaskMemFree(desktopPidl
);
1506 /* Finish Toolbar Construction */
1507 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1508 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1510 /* Set the window text with the text specified in the OPENFILENAME structure */
1513 SetWindowTextW(hwnd
,fodInfos
->title
);
1515 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1518 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1519 SetWindowTextW(hwnd
, buf
);
1522 /* Initialise the file name edit control */
1523 handledPath
= FALSE
;
1524 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1526 if(fodInfos
->filename
)
1528 /* 1. If win2000 or higher and filename contains a path, use it
1529 in preference over the lpstrInitialDir */
1530 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1531 WCHAR tmpBuf
[MAX_PATH
];
1535 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1538 /* nameBit is always shorter than the original filename */
1539 lstrcpyW(fodInfos
->filename
,nameBit
);
1542 MemFree(fodInfos
->initdir
);
1543 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1544 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1546 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1547 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1549 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1552 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1556 /* 2. (All platforms) If initdir is not null, then use it */
1557 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1558 (*fodInfos
->initdir
!=0x00))
1560 /* Work out the proper path as supplied one might be relative */
1561 /* (Here because supplying '.' as dir browses to My Computer) */
1562 if (handledPath
==FALSE
) {
1563 WCHAR tmpBuf
[MAX_PATH
];
1564 WCHAR tmpBuf2
[MAX_PATH
];
1568 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1569 if( PathFileExistsW(tmpBuf
) ) {
1570 /* initdir does not have to be a directory. If a file is
1571 * specified, the dir part is taken */
1572 if( PathIsDirectoryW(tmpBuf
)) {
1573 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1574 lstrcatW(tmpBuf
, szwSlash
);
1576 lstrcatW(tmpBuf
, szwStar
);
1578 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1581 MemFree(fodInfos
->initdir
);
1582 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1583 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1585 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1588 else if (fodInfos
->initdir
)
1590 MemFree(fodInfos
->initdir
);
1591 fodInfos
->initdir
= NULL
;
1592 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1597 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1598 (*fodInfos
->initdir
==0x00)))
1600 /* 3. All except w2k+: if filename contains a path use it */
1601 if (!win2000plus
&& fodInfos
->filename
&&
1602 *fodInfos
->filename
&&
1603 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1604 WCHAR tmpBuf
[MAX_PATH
];
1608 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1613 /* nameBit is always shorter than the original filename */
1614 lstrcpyW(fodInfos
->filename
, nameBit
);
1617 len
= lstrlenW(tmpBuf
);
1618 MemFree(fodInfos
->initdir
);
1619 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1620 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1623 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1624 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1626 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1629 /* 4. Win2000+: Recently used */
1630 if (handledPath
== FALSE
&& win2000plus
) {
1631 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1632 fodInfos
->initdir
[0] = '\0';
1634 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1636 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1639 MemFree(fodInfos
->initdir
);
1640 fodInfos
->initdir
= NULL
;
1644 /* 5. win98+ and win2000+ if any files of specified filter types in
1645 current directory, use it */
1646 if ( win98plus
&& handledPath
== FALSE
&&
1647 fodInfos
->filter
&& *fodInfos
->filter
) {
1649 LPCWSTR lpstrPos
= fodInfos
->filter
;
1650 WIN32_FIND_DATAW FindFileData
;
1655 /* filter is a list... title\0ext\0......\0\0 */
1657 /* Skip the title */
1658 if(! *lpstrPos
) break; /* end */
1659 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1661 /* See if any files exist in the current dir with this extension */
1662 if(! *lpstrPos
) break; /* end */
1664 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1666 if (hFind
== INVALID_HANDLE_VALUE
) {
1667 /* None found - continue search */
1668 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1672 MemFree(fodInfos
->initdir
);
1673 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1674 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1677 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1678 debugstr_w(lpstrPos
));
1685 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1686 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1687 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1689 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1691 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1694 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1695 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1697 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1700 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1703 } else if (handledPath
==FALSE
) {
1704 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1705 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1707 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1710 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1711 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1713 /* Must the open as read only check box be checked ?*/
1714 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1716 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1719 /* Must the open as read only check box be hidden? */
1720 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1722 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1723 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1726 /* Must the help button be hidden? */
1727 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1729 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1730 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1733 /* change Open to Save */
1734 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1737 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1738 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1739 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1740 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1743 /* Initialize the filter combo box */
1744 FILEDLG95_FILETYPE_Init(hwnd
);
1749 /***********************************************************************
1750 * FILEDLG95_ResizeControls
1752 * WM_INITDIALOG message handler (after hook notification)
1754 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1756 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1758 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1761 UINT flags
= SWP_NOACTIVATE
;
1763 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1764 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1766 /* resize the custom dialog to the parent size */
1767 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1768 GetClientRect(hwnd
, &rc
);
1771 /* our own fake template is zero sized and doesn't have children, so
1772 * there is no need to resize it. Picasa depends on it.
1774 flags
|= SWP_NOSIZE
;
1777 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1778 0, 0, rc
.right
, rc
.bottom
, flags
);
1782 /* Resize the height, if open as read only checkbox ad help button are
1783 * hidden and we are not using a custom template nor a customDialog
1785 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1786 (!(fodInfos
->ofnInfos
->Flags
&
1787 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1789 RECT rectDlg
, rectHelp
, rectCancel
;
1790 GetWindowRect(hwnd
, &rectDlg
);
1791 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1792 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1793 /* subtract the height of the help button plus the space between the help
1794 * button and the cancel button to the height of the dialog
1796 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1797 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1798 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1804 /***********************************************************************
1805 * FILEDLG95_FillControls
1807 * WM_INITDIALOG message handler (after hook notification)
1809 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1811 LPITEMIDLIST pidlItemId
= NULL
;
1813 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1815 TRACE("dir=%s file=%s\n",
1816 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1818 /* Get the initial directory pidl */
1820 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1822 WCHAR path
[MAX_PATH
];
1824 GetCurrentDirectoryW(MAX_PATH
,path
);
1825 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1828 /* Initialise shell objects */
1829 FILEDLG95_SHELL_Init(hwnd
);
1831 /* Initialize the Look In combo box */
1832 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1834 /* Browse to the initial directory */
1835 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1837 /* Free pidlItem memory */
1838 COMDLG32_SHFree(pidlItemId
);
1842 /***********************************************************************
1845 * Regroups all the cleaning functions of the filedlg
1847 void FILEDLG95_Clean(HWND hwnd
)
1849 FILEDLG95_FILETYPE_Clean(hwnd
);
1850 FILEDLG95_LOOKIN_Clean(hwnd
);
1851 FILEDLG95_SHELL_Clean(hwnd
);
1853 /***********************************************************************
1854 * FILEDLG95_OnWMCommand
1856 * WM_COMMAND message handler
1858 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1860 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1861 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1862 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1868 FILEDLG95_OnOpen(hwnd
);
1872 FILEDLG95_Clean(hwnd
);
1873 EndDialog(hwnd
, FALSE
);
1875 /* Filetype combo box */
1877 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1879 /* LookIn combo box */
1881 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1884 /* --- toolbar --- */
1885 /* Up folder button */
1886 case FCIDM_TB_UPFOLDER
:
1887 FILEDLG95_SHELL_UpFolder(hwnd
);
1889 /* New folder button */
1890 case FCIDM_TB_NEWFOLDER
:
1891 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1893 /* List option button */
1894 case FCIDM_TB_SMALLICON
:
1895 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1897 /* Details option button */
1898 case FCIDM_TB_REPORTVIEW
:
1899 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1901 /* Details option button */
1902 case FCIDM_TB_DESKTOP
:
1903 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1911 /* Do not use the listview selection anymore */
1912 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1916 /***********************************************************************
1917 * FILEDLG95_OnWMGetIShellBrowser
1919 * WM_GETISHELLBROWSER message handler
1921 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1923 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1927 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1933 /***********************************************************************
1934 * FILEDLG95_SendFileOK
1936 * Sends the CDN_FILEOK notification if required
1939 * TRUE if the dialog should close
1940 * FALSE if the dialog should not be closed
1942 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1944 /* ask the hook if we can close */
1945 if(IsHooked(fodInfos
))
1950 /* First send CDN_FILEOK as MSDN doc says */
1951 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1952 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1955 TRACE("canceled\n");
1959 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1960 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1961 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1964 TRACE("canceled\n");
1971 /***********************************************************************
1972 * FILEDLG95_OnOpenMultipleFiles
1974 * Handles the opening of multiple files.
1977 * check destination buffer size
1979 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1981 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1982 UINT nCount
, nSizePath
;
1983 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1987 if(fodInfos
->unicode
)
1989 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1990 ofn
->lpstrFile
[0] = '\0';
1994 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1995 ofn
->lpstrFile
[0] = '\0';
1998 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2000 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2001 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2002 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2004 LPWSTR lpstrTemp
= lpstrFileList
;
2006 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2010 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2013 WCHAR lpstrNotFound
[100];
2014 WCHAR lpstrMsg
[100];
2016 static const WCHAR nl
[] = {'\n',0};
2018 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2019 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2021 lstrcpyW(tmp
, lpstrTemp
);
2023 lstrcatW(tmp
, lpstrNotFound
);
2025 lstrcatW(tmp
, lpstrMsg
);
2027 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2031 /* move to the next file in the list of files */
2032 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2033 COMDLG32_SHFree(pidl
);
2037 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2038 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2040 /* For "oldstyle" dialog the components have to
2041 be separated by blanks (not '\0'!) and short
2042 filenames have to be used! */
2043 FIXME("Components have to be separated by blanks\n");
2045 if(fodInfos
->unicode
)
2047 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2048 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2049 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2053 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2055 if (ofn
->lpstrFile
!= NULL
)
2057 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2058 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2059 if (ofn
->nMaxFile
> nSizePath
)
2061 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2062 ofn
->lpstrFile
+ nSizePath
,
2063 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2068 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2069 fodInfos
->ofnInfos
->nFileExtension
= 0;
2071 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2074 /* clean and exit */
2075 FILEDLG95_Clean(hwnd
);
2076 return EndDialog(hwnd
,TRUE
);
2079 /* Returns the 'slot name' of the given module_name in the registry's
2080 * most-recently-used list. This will be an ASCII value in the
2081 * range ['a','z'). Returns zero on error.
2083 * The slot's value in the registry has the form:
2084 * module_name\0mru_path\0
2086 * If stored_path is given, then stored_path will contain the path name
2087 * stored in the registry's MRU list for the given module_name.
2089 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2090 * MRU list key for the given module_name.
2092 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2094 WCHAR mru_list
[32], *cur_mru_slot
;
2095 BOOL taken
[25] = {0};
2096 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2097 HKEY hkey_tmp
, *hkey
;
2106 *stored_path
= '\0';
2108 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2110 WARN("Unable to create MRU key: %d\n", ret
);
2114 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2115 (LPBYTE
)mru_list
, &mru_list_size
);
2116 if(ret
|| key_type
!= REG_SZ
){
2117 if(ret
== ERROR_FILE_NOT_FOUND
)
2120 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2125 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2126 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2127 DWORD value_data_size
= sizeof(value_data
);
2129 *value_name
= *cur_mru_slot
;
2131 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2132 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2133 if(ret
|| key_type
!= REG_BINARY
){
2134 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2138 if(!strcmpiW(module_name
, value_data
)){
2142 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2150 /* the module name isn't in the registry, so find the next open slot */
2151 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2152 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2153 for(i
= 0; i
< 25; ++i
){
2158 /* all slots are taken, so return the last one in MRUList */
2160 return *cur_mru_slot
;
2163 /* save the given filename as most-recently-used path for this module */
2164 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2166 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2170 /* get the current executable's name */
2171 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2172 WARN("GotModuleFileName failed: %d\n", GetLastError());
2175 module_name
= strrchrW(module_path
, '\\');
2177 module_name
= module_path
;
2181 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2186 { /* update the slot's info */
2187 WCHAR
*path_ends
, *final
;
2188 DWORD path_len
, final_len
;
2190 /* use only the path segment of `filename' */
2191 path_ends
= strrchrW(filename
, '\\');
2192 path_len
= path_ends
- filename
;
2194 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2196 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2199 lstrcpyW(final
, module_name
);
2200 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2201 final
[final_len
-1] = '\0';
2203 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2204 final_len
* sizeof(WCHAR
));
2206 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2215 { /* update MRUList value */
2216 WCHAR old_mru_list
[32], new_mru_list
[32];
2217 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2218 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2220 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2221 (LPBYTE
)old_mru_list
, &mru_list_size
);
2222 if(ret
|| key_type
!= REG_SZ
){
2223 if(ret
== ERROR_FILE_NOT_FOUND
){
2224 new_mru_list
[0] = slot
;
2225 new_mru_list
[1] = '\0';
2227 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2232 /* copy old list data over so that the new slot is at the start
2234 *new_mru_slot
++ = slot
;
2235 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2236 if(*old_mru_slot
!= slot
)
2237 *new_mru_slot
++ = *old_mru_slot
;
2239 *new_mru_slot
= '\0';
2242 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2243 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2245 WARN("Error saving MRUList data: %d\n", ret
);
2252 /* load the most-recently-used path for this module */
2253 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2255 WCHAR module_path
[MAX_PATH
], *module_name
;
2257 /* get the current executable's name */
2258 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2259 WARN("GotModuleFileName failed: %d\n", GetLastError());
2262 module_name
= strrchrW(module_path
, '\\');
2264 module_name
= module_path
;
2268 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2269 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2272 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2274 WCHAR strMsgTitle
[MAX_PATH
];
2275 WCHAR strMsgText
[MAX_PATH
];
2277 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2279 strMsgTitle
[0] = '\0';
2280 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2281 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2284 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2285 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2287 int nOpenAction
= defAction
;
2288 LPWSTR lpszTemp
, lpszTemp1
;
2289 LPITEMIDLIST pidl
= NULL
;
2290 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2292 /* check for invalid chars */
2293 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2295 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2299 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2301 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2304 LPSHELLFOLDER lpsfChild
;
2305 WCHAR lpwstrTemp
[MAX_PATH
];
2306 DWORD dwEaten
, dwAttributes
;
2309 lstrcpyW(lpwstrTemp
, lpszTemp
);
2310 p
= PathFindNextComponentW(lpwstrTemp
);
2312 if (!p
) break; /* end of path */
2315 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2317 /* There are no wildcards when OFN_NOVALIDATE is set */
2318 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2320 static const WCHAR wszWild
[] = { '*', '?', 0 };
2321 /* if the last element is a wildcard do a search */
2322 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2324 nOpenAction
= ONOPEN_SEARCH
;
2328 lpszTemp1
= lpszTemp
;
2330 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2332 /* append a backslash to drive letters */
2333 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2334 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2335 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2337 PathAddBackslashW(lpwstrTemp
);
2340 dwAttributes
= SFGAO_FOLDER
;
2341 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2343 /* the path component is valid, we have a pidl of the next path component */
2344 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2345 if(dwAttributes
& SFGAO_FOLDER
)
2347 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2349 ERR("bind to failed\n"); /* should not fail */
2352 IShellFolder_Release(*ppsf
);
2360 /* end dialog, return value */
2361 nOpenAction
= ONOPEN_OPEN
;
2364 COMDLG32_SHFree(pidl
);
2367 else if (!(flags
& OFN_NOVALIDATE
))
2369 if(*lpszTemp
|| /* points to trailing null for last path element */
2370 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2372 if(flags
& OFN_PATHMUSTEXIST
)
2374 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2380 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2382 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2386 /* change to the current folder */
2387 nOpenAction
= ONOPEN_OPEN
;
2392 nOpenAction
= ONOPEN_OPEN
;
2396 if(pidl
) COMDLG32_SHFree(pidl
);
2401 /***********************************************************************
2404 * Ok button WM_COMMAND message handler
2406 * If the function succeeds, the return value is nonzero.
2408 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2410 LPWSTR lpstrFileList
;
2411 UINT nFileCount
= 0;
2414 WCHAR lpstrPathAndFile
[MAX_PATH
];
2415 LPSHELLFOLDER lpsf
= NULL
;
2417 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2419 TRACE("hwnd=%p\n", hwnd
);
2421 /* try to browse the selected item */
2422 if(BrowseSelectedFolder(hwnd
))
2425 /* get the files from the edit control */
2426 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2433 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2437 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2440 Step 1: Build a complete path name from the current folder and
2441 the filename or path in the edit box.
2443 - the path in the edit box is a root path
2444 (with or without drive letter)
2445 - the edit box contains ".." (or a path with ".." in it)
2448 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2449 MemFree(lpstrFileList
);
2452 Step 2: here we have a cleaned up path
2454 We have to parse the path step by step to see if we have to browse
2455 to a folder if the path points to a directory or the last
2456 valid element is a directory.
2459 lpstrPathAndFile: cleaned up path
2463 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2464 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2465 nOpenAction
= ONOPEN_OPEN
;
2467 nOpenAction
= ONOPEN_BROWSE
;
2469 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2470 fodInfos
->ofnInfos
->Flags
,
2471 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2477 Step 3: here we have a cleaned up and validated path
2480 lpsf: ShellFolder bound to the rightmost valid path component
2481 lpstrPathAndFile: cleaned up path
2482 nOpenAction: action to do
2484 TRACE("end validate sf=%p\n", lpsf
);
2488 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2489 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2492 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2495 /* replace the current filter */
2496 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2497 len
= lstrlenW(lpszTemp
)+1;
2498 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2499 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2501 /* set the filter cb to the extension when possible */
2502 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2503 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2506 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2507 TRACE("ONOPEN_BROWSE\n");
2509 IPersistFolder2
* ppf2
;
2510 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2512 LPITEMIDLIST pidlCurrent
;
2513 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2514 IPersistFolder2_Release(ppf2
);
2515 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2517 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2518 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2520 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2523 else if( nOpenAction
== ONOPEN_SEARCH
)
2525 if (fodInfos
->Shell
.FOIShellView
)
2526 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2528 COMDLG32_SHFree(pidlCurrent
);
2529 if (filename_is_edit( fodInfos
))
2530 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2535 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2536 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2540 /* update READONLY check box flag */
2541 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2542 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2544 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2546 /* Attach the file extension with file name*/
2547 ext
= PathFindExtensionW(lpstrPathAndFile
);
2548 if (! *ext
&& fodInfos
->defext
)
2550 /* if no extension is specified with file name, then */
2551 /* attach the extension from file filter or default one */
2553 WCHAR
*filterExt
= NULL
;
2554 LPWSTR lpstrFilter
= NULL
;
2555 static const WCHAR szwDot
[] = {'.',0};
2556 int PathLength
= lstrlenW(lpstrPathAndFile
);
2558 /*Get the file extension from file type filter*/
2559 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2560 fodInfos
->ofnInfos
->nFilterIndex
-1);
2562 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2564 WCHAR
* filterSearchIndex
;
2565 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2566 strcpyW(filterExt
, lpstrFilter
);
2568 /* if a semicolon-separated list of file extensions was given, do not include the
2569 semicolon or anything after it in the extension.
2570 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2571 filterSearchIndex
= strchrW(filterExt
, ';');
2572 if (filterSearchIndex
)
2574 filterSearchIndex
[0] = '\0';
2577 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2578 /* if the extension is invalid or contains a glob, ignore it */
2579 filterSearchIndex
= PathFindExtensionW(filterExt
);
2580 if (*filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2582 strcpyW(filterExt
, filterSearchIndex
);
2586 HeapFree(GetProcessHeap(), 0, filterExt
);
2593 /* use the default file extension */
2594 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2595 strcpyW(filterExt
, fodInfos
->defext
);
2598 if (*filterExt
) /* ignore filterExt="" */
2601 lstrcatW(lpstrPathAndFile
, szwDot
);
2602 /* Attach the extension */
2603 lstrcatW(lpstrPathAndFile
, filterExt
);
2606 HeapFree(GetProcessHeap(), 0, filterExt
);
2608 /* In Open dialog: if file does not exist try without extension */
2609 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2610 lpstrPathAndFile
[PathLength
] = '\0';
2612 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2615 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2616 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2618 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2621 /* In Save dialog: check if the file already exists */
2622 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2623 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2624 && PathFileExistsW(lpstrPathAndFile
))
2626 WCHAR lpstrOverwrite
[100];
2629 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2630 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2631 MB_YESNO
| MB_ICONEXCLAMATION
);
2632 if (answer
== IDNO
|| answer
== IDCANCEL
)
2639 /* In Open dialog: check if it should be created if it doesn't exist */
2640 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2641 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2642 && !PathFileExistsW(lpstrPathAndFile
))
2644 WCHAR lpstrCreate
[100];
2647 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2648 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2649 MB_YESNO
| MB_ICONEXCLAMATION
);
2650 if (answer
== IDNO
|| answer
== IDCANCEL
)
2657 /* Check that the size of the file does not exceed buffer size.
2658 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2659 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2660 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2663 /* fill destination buffer */
2664 if (fodInfos
->ofnInfos
->lpstrFile
)
2666 if(fodInfos
->unicode
)
2668 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2670 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2671 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2672 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2676 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2678 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2679 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2680 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2681 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2685 if(fodInfos
->unicode
)
2689 /* set filename offset */
2690 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2691 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2693 /* set extension offset */
2694 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2695 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2700 CHAR tempFileA
[MAX_PATH
];
2702 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2703 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2704 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2706 /* set filename offset */
2707 lpszTemp
= PathFindFileNameA(tempFileA
);
2708 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2710 /* set extension offset */
2711 lpszTemp
= PathFindExtensionA(tempFileA
);
2712 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2715 /* set the lpstrFileTitle */
2716 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2718 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2719 if(fodInfos
->unicode
)
2721 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2722 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2726 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2727 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2728 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2732 /* copy currently selected filter to lpstrCustomFilter */
2733 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2735 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2736 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2737 NULL
, 0, NULL
, NULL
);
2738 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2740 LPSTR s
= ofn
->lpstrCustomFilter
;
2741 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2742 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2743 s
, len
, NULL
, NULL
);
2748 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2751 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2754 FILEDLG95_Clean(hwnd
);
2755 ret
= EndDialog(hwnd
, TRUE
);
2761 size
= lstrlenW(lpstrPathAndFile
) + 1;
2762 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2764 /* return needed size in first two bytes of lpstrFile */
2765 if(fodInfos
->ofnInfos
->lpstrFile
)
2766 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2767 FILEDLG95_Clean(hwnd
);
2768 ret
= EndDialog(hwnd
, FALSE
);
2769 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2776 if(lpsf
) IShellFolder_Release(lpsf
);
2780 /***********************************************************************
2781 * FILEDLG95_SHELL_Init
2783 * Initialisation of the shell objects
2785 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2787 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2792 * Initialisation of the FileOpenDialogInfos structure
2798 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2800 /* Disable multi-select if flag not set */
2801 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2803 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2805 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2806 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2808 /* Construct the IShellBrowser interface */
2809 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2814 /***********************************************************************
2815 * FILEDLG95_SHELL_ExecuteCommand
2817 * Change the folder option and refresh the view
2818 * If the function succeeds, the return value is nonzero.
2820 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2822 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2825 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2827 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2832 CMINVOKECOMMANDINFO ci
;
2833 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2834 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2838 IContextMenu_InvokeCommand(pcm
, &ci
);
2839 IContextMenu_Release(pcm
);
2845 /***********************************************************************
2846 * FILEDLG95_SHELL_UpFolder
2848 * Browse to the specified object
2849 * If the function succeeds, the return value is nonzero.
2851 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2853 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2857 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2861 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2862 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2868 /***********************************************************************
2869 * FILEDLG95_SHELL_BrowseToDesktop
2871 * Browse to the Desktop
2872 * If the function succeeds, the return value is nonzero.
2874 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2876 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2882 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2883 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2884 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2885 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2886 COMDLG32_SHFree(pidl
);
2887 return SUCCEEDED(hres
);
2889 /***********************************************************************
2890 * FILEDLG95_SHELL_Clean
2892 * Cleans the memory used by shell objects
2894 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2896 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2900 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2902 /* clean Shell interfaces */
2903 if (fodInfos
->Shell
.FOIShellView
)
2905 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2906 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2908 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2909 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2910 if (fodInfos
->Shell
.FOIDataObject
)
2911 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2914 /***********************************************************************
2915 * FILEDLG95_FILETYPE_Init
2917 * Initialisation of the file type combo box
2919 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2921 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2922 int nFilters
= 0; /* number of filters */
2927 if(fodInfos
->customfilter
)
2929 /* customfilter has one entry... title\0ext\0
2930 * Set first entry of combo box item with customfilter
2933 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2936 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2938 /* Copy the extensions */
2939 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2940 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2941 lstrcpyW(lpstrExt
,lpstrPos
);
2943 /* Add the item at the end of the combo */
2944 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2945 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2948 if(fodInfos
->filter
)
2950 LPCWSTR lpstrPos
= fodInfos
->filter
;
2954 /* filter is a list... title\0ext\0......\0\0
2955 * Set the combo item text to the title and the item data
2958 LPCWSTR lpstrDisplay
;
2962 if(! *lpstrPos
) break; /* end */
2963 lpstrDisplay
= lpstrPos
;
2964 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2966 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2970 /* Copy the extensions */
2971 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2972 lstrcpyW(lpstrExt
,lpstrPos
);
2973 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2975 /* Add the item at the end of the combo */
2976 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2978 /* malformed filters are added anyway... */
2979 if (!*lpstrExt
) break;
2984 * Set the current filter to the one specified
2985 * in the initialisation structure
2987 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2991 /* Check to make sure our index isn't out of bounds. */
2992 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2993 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2994 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2996 /* set default filter index */
2997 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2998 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3000 /* calculate index of Combo Box item */
3001 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3002 if (fodInfos
->customfilter
== NULL
)
3005 /* Set the current index selection. */
3006 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3008 /* Get the corresponding text string from the combo box. */
3009 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3012 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3018 CharLowerW(lpstrFilter
); /* lowercase */
3019 len
= lstrlenW(lpstrFilter
)+1;
3020 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3021 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3024 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3028 /***********************************************************************
3029 * FILEDLG95_FILETYPE_OnCommand
3031 * WM_COMMAND of the file type combo box
3032 * If the function succeeds, the return value is nonzero.
3034 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3036 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3044 /* Get the current item of the filetype combo box */
3045 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3047 /* set the current filter index */
3048 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3049 (fodInfos
->customfilter
== NULL
? 1 : 0);
3051 /* Set the current filter with the current selection */
3052 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3054 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3056 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3059 CharLowerW(lpstrFilter
); /* lowercase */
3060 len
= lstrlenW(lpstrFilter
)+1;
3061 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3062 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3063 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3064 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3067 /* Refresh the actual view to display the included items*/
3068 if (fodInfos
->Shell
.FOIShellView
)
3069 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3074 /***********************************************************************
3075 * FILEDLG95_FILETYPE_SearchExt
3077 * searches for an extension in the filetype box
3079 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3081 int i
, iCount
= CBGetCount(hwnd
);
3083 TRACE("%s\n", debugstr_w(lpstrExt
));
3085 if(iCount
!= CB_ERR
)
3087 for(i
=0;i
<iCount
;i
++)
3089 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3096 /***********************************************************************
3097 * FILEDLG95_FILETYPE_Clean
3099 * Clean the memory used by the filetype combo box
3101 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3103 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3105 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3109 /* Delete each string of the combo and their associated data */
3110 if(iCount
!= CB_ERR
)
3112 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3114 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3115 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3118 /* Current filter */
3119 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3123 /***********************************************************************
3124 * FILEDLG95_LOOKIN_Init
3126 * Initialisation of the look in combo box
3129 /* Small helper function, to determine if the unixfs shell extension is rooted
3130 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3132 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3134 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3135 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3136 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3137 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3138 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3139 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3140 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3142 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3149 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3151 IShellFolder
*psfRoot
, *psfDrives
;
3152 IEnumIDList
*lpeRoot
, *lpeDrives
;
3153 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3156 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3160 liInfos
->iMaxIndentation
= 0;
3162 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3164 hdc
= GetDC( hwndCombo
);
3165 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3166 GetTextMetricsW( hdc
, &tm
);
3167 ReleaseDC( hwndCombo
, hdc
);
3169 /* set item height for both text field and listbox */
3170 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3171 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3173 /* Turn on the extended UI for the combo box like Windows does */
3174 CBSetExtendedUI(hwndCombo
, TRUE
);
3176 /* Initialise data of Desktop folder */
3177 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3178 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3179 COMDLG32_SHFree(pidlTmp
);
3181 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3183 SHGetDesktopFolder(&psfRoot
);
3187 /* enumerate the contents of the desktop */
3188 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3190 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3192 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3194 /* If the unixfs extension is rooted, we don't expand the drives by default */
3195 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3197 /* special handling for CSIDL_DRIVES */
3198 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3200 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3202 /* enumerate the drives */
3203 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3205 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3207 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3208 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3209 COMDLG32_SHFree(pidlAbsTmp
);
3210 COMDLG32_SHFree(pidlTmp1
);
3212 IEnumIDList_Release(lpeDrives
);
3214 IShellFolder_Release(psfDrives
);
3219 COMDLG32_SHFree(pidlTmp
);
3221 IEnumIDList_Release(lpeRoot
);
3223 IShellFolder_Release(psfRoot
);
3226 COMDLG32_SHFree(pidlDrives
);
3229 /***********************************************************************
3230 * FILEDLG95_LOOKIN_DrawItem
3232 * WM_DRAWITEM message handler
3234 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3236 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3237 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3238 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3242 HIMAGELIST ilItemImage
;
3245 LPSFOLDER tmpFolder
;
3246 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
3247 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3248 UINT icon_width
, icon_height
;
3252 if(pDIStruct
->itemID
== -1)
3255 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3256 pDIStruct
->itemID
)))
3260 icon_width
= GetSystemMetrics(SM_CXICON
);
3261 icon_height
= GetSystemMetrics(SM_CYICON
);
3262 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3264 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3265 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3266 shgfi_flags
|= SHGFI_SMALLICON
;
3269 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
3271 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3272 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3276 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3277 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3280 /* Is this item selected ? */
3281 if(pDIStruct
->itemState
& ODS_SELECTED
)
3283 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3284 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3285 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3289 SetTextColor(pDIStruct
->hDC
,crText
);
3290 SetBkColor(pDIStruct
->hDC
,crWin
);
3291 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3294 /* Do not indent item if drawing in the edit of the combo */
3295 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3298 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3299 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3304 iIndentation
= tmpFolder
->m_iIndent
;
3306 /* Draw text and icon */
3308 /* Initialise the icon display area */
3309 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3310 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3311 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3312 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3314 /* Initialise the text display area */
3315 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3316 rectText
.left
= rectIcon
.right
;
3318 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3319 rectText
.right
= pDIStruct
->rcItem
.right
;
3321 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3323 /* Draw the icon from the image list */
3324 ImageList_Draw(ilItemImage
,
3331 /* Draw the associated text */
3332 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3336 /***********************************************************************
3337 * FILEDLG95_LOOKIN_OnCommand
3339 * LookIn combo box WM_COMMAND message handler
3340 * If the function succeeds, the return value is nonzero.
3342 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3344 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3346 TRACE("%p\n", fodInfos
);
3352 LPSFOLDER tmpFolder
;
3355 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3357 if( iItem
== CB_ERR
) return FALSE
;
3359 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3364 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3365 tmpFolder
->pidlItem
,
3368 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3369 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3379 /***********************************************************************
3380 * FILEDLG95_LOOKIN_AddItem
3382 * Adds an absolute pidl item to the lookin combo box
3383 * returns the index of the inserted item
3385 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3387 LPITEMIDLIST pidlNext
;
3390 LookInInfos
*liInfos
;
3392 TRACE("%08x\n", iInsertId
);
3397 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3400 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3401 tmpFolder
->m_iIndent
= 0;
3403 /* Calculate the indentation of the item in the lookin*/
3405 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3407 tmpFolder
->m_iIndent
++;
3410 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3412 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3413 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3415 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3416 SHGetFileInfoW((LPCWSTR
)pidl
,
3420 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3421 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3423 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3425 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3429 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3431 /* Add the item at the end of the list */
3434 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3436 /* Insert the item at the iInsertId position*/
3439 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3442 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3446 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3447 MemFree( tmpFolder
);
3452 /***********************************************************************
3453 * FILEDLG95_LOOKIN_InsertItemAfterParent
3455 * Insert an item below its parent
3457 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3460 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3465 if (pidl
== pidlParent
)
3468 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3472 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3475 /* Free pidlParent memory */
3476 COMDLG32_SHFree(pidlParent
);
3478 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3481 /***********************************************************************
3482 * FILEDLG95_LOOKIN_SelectItem
3484 * Adds an absolute pidl item to the lookin combo box
3485 * returns the index of the inserted item
3487 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3490 LookInInfos
*liInfos
;
3494 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3496 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3500 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3501 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3506 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3507 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3511 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3513 if(iRemovedItem
< iItemPos
)
3518 CBSetCurSel(hwnd
,iItemPos
);
3519 liInfos
->uSelectedItem
= iItemPos
;
3525 /***********************************************************************
3526 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3528 * Remove the item with an expansion level over iExpansionLevel
3530 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3533 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3537 if(liInfos
->iMaxIndentation
<= 2)
3540 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3542 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3543 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3545 CBDeleteString(hwnd
,iItemPos
);
3546 liInfos
->iMaxIndentation
--;
3554 /***********************************************************************
3555 * FILEDLG95_LOOKIN_SearchItem
3557 * Search for pidl in the lookin combo box
3558 * returns the index of the found item
3560 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3563 int iCount
= CBGetCount(hwnd
);
3565 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3567 if (iCount
!= CB_ERR
)
3571 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3573 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3575 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3583 /***********************************************************************
3584 * FILEDLG95_LOOKIN_Clean
3586 * Clean the memory used by the lookin combo box
3588 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3590 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3591 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3593 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3597 /* Delete each string of the combo and their associated data */
3598 if (iCount
!= CB_ERR
)
3600 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3602 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3603 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3605 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3609 /* LookInInfos structure */
3611 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3614 /***********************************************************************
3615 * FILEDLG95_FILENAME_FillFromSelection
3617 * fills the edit box from the cached DataObject
3619 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3621 FileOpenDlgInfos
*fodInfos
;
3623 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3624 WCHAR lpstrTemp
[MAX_PATH
];
3625 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3628 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3630 /* Count how many files we have */
3631 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3633 /* calculate the string length, count files */
3634 if (nFileSelected
>= 1)
3636 nLength
+= 3; /* first and last quotes, trailing \0 */
3637 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3639 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3643 /* get the total length of the selected file names */
3644 lpstrTemp
[0] = '\0';
3645 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3647 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3649 nLength
+= lstrlenW( lpstrTemp
) + 3;
3652 COMDLG32_SHFree( pidl
);
3657 /* allocate the buffer */
3658 if (nFiles
<= 1) nLength
= MAX_PATH
;
3659 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3661 /* Generate the string for the edit control */
3664 lpstrCurrFile
= lpstrAllFile
;
3665 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3667 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3671 /* get the file name */
3672 lpstrTemp
[0] = '\0';
3673 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3675 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3679 *lpstrCurrFile
++ = '\"';
3680 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3681 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3682 *lpstrCurrFile
++ = '\"';
3683 *lpstrCurrFile
++ = ' ';
3688 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3691 COMDLG32_SHFree( pidl
);
3694 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3696 /* Select the file name like Windows does */
3697 if (filename_is_edit( fodInfos
))
3698 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3700 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3704 /* copied from shell32 to avoid linking to it
3705 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3706 * is dependent on whether emulated OS is unicode or not.
3708 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3713 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3714 COMDLG32_SHFree(src
->u
.pOleStr
);
3718 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3723 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3728 FIXME("unknown type %x!\n", src
->uType
);
3729 if (len
) *dest
= '\0';
3735 /***********************************************************************
3736 * FILEDLG95_FILENAME_GetFileNames
3738 * Copies the filenames to a delimited string list.
3740 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3742 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3743 UINT nFileCount
= 0; /* number of files */
3744 UINT nStrLen
= 0; /* length of string in edit control */
3745 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3749 /* get the filenames from the filename control */
3750 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3751 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3752 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3754 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3756 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3761 #define SETDefFormatEtc(fe,cf,med) \
3763 (fe).cfFormat = cf;\
3764 (fe).dwAspect = DVASPECT_CONTENT; \
3771 * DATAOBJECT Helper functions
3774 /***********************************************************************
3775 * COMCTL32_ReleaseStgMedium
3777 * like ReleaseStgMedium from ole32
3779 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3781 if(medium
.pUnkForRelease
)
3783 IUnknown_Release(medium
.pUnkForRelease
);
3787 GlobalUnlock(medium
.u
.hGlobal
);
3788 GlobalFree(medium
.u
.hGlobal
);
3792 /***********************************************************************
3793 * GetPidlFromDataObject
3795 * Return pidl(s) by number from the cached DataObject
3797 * nPidlIndex=0 gets the fully qualified root path
3799 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3803 FORMATETC formatetc
;
3804 LPITEMIDLIST pidl
= NULL
;
3806 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3811 /* Set the FORMATETC structure*/
3812 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3814 /* Get the pidls from IDataObject */
3815 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3817 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3818 if(nPidlIndex
<= cida
->cidl
)
3820 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3822 COMCTL32_ReleaseStgMedium(medium
);
3827 /***********************************************************************
3830 * Return the number of selected items in the DataObject.
3833 static UINT
GetNumSelected( IDataObject
*doSelected
)
3837 FORMATETC formatetc
;
3839 TRACE("sv=%p\n", doSelected
);
3841 if (!doSelected
) return 0;
3843 /* Set the FORMATETC structure*/
3844 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3846 /* Get the pidls from IDataObject */
3847 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3849 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3850 retVal
= cida
->cidl
;
3851 COMCTL32_ReleaseStgMedium(medium
);
3861 /***********************************************************************
3864 * Get the pidl's display name (relative to folder) and
3865 * put it in lpstrFileName.
3867 * Return NOERROR on success,
3871 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3876 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3880 SHGetDesktopFolder(&lpsf
);
3881 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3882 IShellFolder_Release(lpsf
);
3886 /* Get the display name of the pidl relative to the folder */
3887 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3889 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3894 /***********************************************************************
3895 * GetShellFolderFromPidl
3897 * pidlRel is the item pidl relative
3898 * Return the IShellFolder of the absolute pidl
3900 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3902 IShellFolder
*psf
= NULL
,*psfParent
;
3904 TRACE("%p\n", pidlAbs
);
3906 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3909 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3911 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3913 IShellFolder_Release(psfParent
);
3917 /* return the desktop */
3923 /***********************************************************************
3926 * Return the LPITEMIDLIST to the parent of the pidl in the list
3928 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3930 LPITEMIDLIST pidlParent
;
3932 TRACE("%p\n", pidl
);
3934 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3935 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3940 /***********************************************************************
3943 * returns the pidl of the file name relative to folder
3944 * NULL if an error occurred
3946 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3948 LPITEMIDLIST pidl
= NULL
;
3951 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3953 if(!lpcstrFileName
) return NULL
;
3954 if(!*lpcstrFileName
) return NULL
;
3958 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3959 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3960 IShellFolder_Release(lpsf
);
3965 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3972 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3974 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3977 TRACE("%p, %p\n", psf
, pidl
);
3979 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3981 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3982 /* see documentation shell 4.1*/
3983 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3986 /***********************************************************************
3987 * BrowseSelectedFolder
3989 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3991 BOOL bBrowseSelFolder
= FALSE
;
3992 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3996 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3998 LPITEMIDLIST pidlSelection
;
4000 /* get the file selected */
4001 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4002 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4004 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4005 pidlSelection
, SBSP_RELATIVE
) ) )
4007 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
4008 ' ','n','o','t',' ','e','x','i','s','t',0};
4009 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4011 bBrowseSelFolder
= TRUE
;
4012 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4013 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4015 COMDLG32_SHFree( pidlSelection
);
4018 return bBrowseSelFolder
;
4022 * Memory allocation methods */
4023 static void *MemAlloc(UINT size
)
4025 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4028 static void MemFree(void *mem
)
4030 HeapFree(GetProcessHeap(),0,mem
);
4033 static inline BOOL
valid_struct_size( DWORD size
)
4035 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4036 (size
== sizeof( OPENFILENAMEW
));
4039 static inline BOOL
is_win16_looks(DWORD flags
)
4041 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4042 !(flags
& OFN_EXPLORER
));
4045 /* ------------------ APIs ---------------------- */
4047 /***********************************************************************
4048 * GetOpenFileNameA (COMDLG32.@)
4050 * Creates a dialog box for the user to select a file to open.
4053 * TRUE on success: user enters a valid file
4054 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4057 BOOL WINAPI
GetOpenFileNameA(
4058 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4060 TRACE("flags %08x\n", ofn
->Flags
);
4062 if (!valid_struct_size( ofn
->lStructSize
))
4064 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4068 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4069 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4070 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4072 if (is_win16_looks(ofn
->Flags
))
4073 return GetFileName31A(ofn
, OPEN_DIALOG
);
4075 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4078 /***********************************************************************
4079 * GetOpenFileNameW (COMDLG32.@)
4081 * Creates a dialog box for the user to select a file to open.
4084 * TRUE on success: user enters a valid file
4085 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4088 BOOL WINAPI
GetOpenFileNameW(
4089 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4091 TRACE("flags %08x\n", ofn
->Flags
);
4093 if (!valid_struct_size( ofn
->lStructSize
))
4095 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4099 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4100 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4101 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4103 if (is_win16_looks(ofn
->Flags
))
4104 return GetFileName31W(ofn
, OPEN_DIALOG
);
4106 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4110 /***********************************************************************
4111 * GetSaveFileNameA (COMDLG32.@)
4113 * Creates a dialog box for the user to select a file to save.
4116 * TRUE on success: user enters a valid file
4117 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4120 BOOL WINAPI
GetSaveFileNameA(
4121 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4123 if (!valid_struct_size( ofn
->lStructSize
))
4125 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4129 if (is_win16_looks(ofn
->Flags
))
4130 return GetFileName31A(ofn
, SAVE_DIALOG
);
4132 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4135 /***********************************************************************
4136 * GetSaveFileNameW (COMDLG32.@)
4138 * Creates a dialog box for the user to select a file to save.
4141 * TRUE on success: user enters a valid file
4142 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4145 BOOL WINAPI
GetSaveFileNameW(
4146 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4148 if (!valid_struct_size( ofn
->lStructSize
))
4150 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4154 if (is_win16_looks(ofn
->Flags
))
4155 return GetFileName31W(ofn
, SAVE_DIALOG
);
4157 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4160 /***********************************************************************
4161 * GetFileTitleA (COMDLG32.@)
4163 * See GetFileTitleW.
4165 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4168 UNICODE_STRING strWFile
;
4171 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4172 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4173 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4174 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4175 RtlFreeUnicodeString( &strWFile
);
4176 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4181 /***********************************************************************
4182 * GetFileTitleW (COMDLG32.@)
4184 * Get the name of a file.
4187 * lpFile [I] name and location of file
4188 * lpTitle [O] returned file name
4189 * cbBuf [I] buffer size of lpTitle
4193 * Failure: negative number.
4195 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4198 static const WCHAR brkpoint
[] = {'*','[',']',0};
4199 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4201 if(lpFile
== NULL
|| lpTitle
== NULL
)
4204 len
= lstrlenW(lpFile
);
4209 if(strpbrkW(lpFile
, brkpoint
))
4214 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4217 for(i
= len
; i
>= 0; i
--)
4219 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4229 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4231 len
= lstrlenW(lpFile
+i
)+1;
4235 lstrcpyW(lpTitle
, &lpFile
[i
]);