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 ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
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 BOOL win2000plus
= FALSE
;
1405 BOOL win98plus
= FALSE
;
1406 BOOL 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
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1559 /* Work out the proper path as supplied one might be relative */
1560 /* (Here because supplying '.' as dir browses to My Computer) */
1561 WCHAR tmpBuf
[MAX_PATH
];
1562 WCHAR tmpBuf2
[MAX_PATH
];
1566 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1567 if (PathFileExistsW(tmpBuf
)) {
1568 /* initdir does not have to be a directory. If a file is
1569 * specified, the dir part is taken */
1570 if (PathIsDirectoryW(tmpBuf
)) {
1571 PathAddBackslashW(tmpBuf
);
1572 lstrcatW(tmpBuf
, szwStar
);
1574 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1577 MemFree(fodInfos
->initdir
);
1578 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1579 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1581 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1584 else if (fodInfos
->initdir
)
1586 MemFree(fodInfos
->initdir
);
1587 fodInfos
->initdir
= NULL
;
1588 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1592 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1594 /* 3. All except w2k+: if filename contains a path use it */
1595 if (!win2000plus
&& fodInfos
->filename
&&
1596 *fodInfos
->filename
&&
1597 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1598 WCHAR tmpBuf
[MAX_PATH
];
1602 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1607 /* nameBit is always shorter than the original filename */
1608 lstrcpyW(fodInfos
->filename
, nameBit
);
1611 len
= lstrlenW(tmpBuf
);
1612 MemFree(fodInfos
->initdir
);
1613 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1614 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1617 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1618 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1620 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1623 /* 4. Win2000+: Recently used */
1624 if (!handledPath
&& win2000plus
) {
1625 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1626 fodInfos
->initdir
[0] = '\0';
1628 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1630 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1633 MemFree(fodInfos
->initdir
);
1634 fodInfos
->initdir
= NULL
;
1638 /* 5. win98+ and win2000+ if any files of specified filter types in
1639 current directory, use it */
1640 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1642 LPCWSTR lpstrPos
= fodInfos
->filter
;
1643 WIN32_FIND_DATAW FindFileData
;
1648 /* filter is a list... title\0ext\0......\0\0 */
1650 /* Skip the title */
1651 if(! *lpstrPos
) break; /* end */
1652 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1654 /* See if any files exist in the current dir with this extension */
1655 if(! *lpstrPos
) break; /* end */
1657 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1659 if (hFind
== INVALID_HANDLE_VALUE
) {
1660 /* None found - continue search */
1661 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1665 MemFree(fodInfos
->initdir
);
1666 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1667 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1670 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1671 debugstr_w(lpstrPos
));
1678 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1679 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1680 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1682 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1684 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1687 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1688 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1690 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1693 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1696 } else if (!handledPath
) {
1697 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1698 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1700 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1703 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1704 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1706 /* Must the open as read only check box be checked ?*/
1707 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1709 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1712 /* Must the open as read only check box be hidden? */
1713 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1715 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1716 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1719 /* Must the help button be hidden? */
1720 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1722 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1723 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1726 /* change Open to Save */
1727 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1730 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1731 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1732 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1733 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1736 /* Initialize the filter combo box */
1737 FILEDLG95_FILETYPE_Init(hwnd
);
1742 /***********************************************************************
1743 * FILEDLG95_ResizeControls
1745 * WM_INITDIALOG message handler (after hook notification)
1747 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1749 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1751 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1754 UINT flags
= SWP_NOACTIVATE
;
1756 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1757 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1759 /* resize the custom dialog to the parent size */
1760 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1761 GetClientRect(hwnd
, &rc
);
1764 /* our own fake template is zero sized and doesn't have children, so
1765 * there is no need to resize it. Picasa depends on it.
1767 flags
|= SWP_NOSIZE
;
1770 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1771 0, 0, rc
.right
, rc
.bottom
, flags
);
1775 /* Resize the height; if opened as read-only, checkbox and help button are
1776 * hidden and we are not using a custom template nor a customDialog
1778 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1779 (!(fodInfos
->ofnInfos
->Flags
&
1780 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1782 RECT rectDlg
, rectHelp
, rectCancel
;
1783 GetWindowRect(hwnd
, &rectDlg
);
1784 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1785 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1786 /* subtract the height of the help button plus the space between the help
1787 * button and the cancel button to the height of the dialog
1789 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1790 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1791 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1797 /***********************************************************************
1798 * FILEDLG95_FillControls
1800 * WM_INITDIALOG message handler (after hook notification)
1802 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1804 LPITEMIDLIST pidlItemId
= NULL
;
1806 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1808 TRACE("dir=%s file=%s\n",
1809 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1811 /* Get the initial directory pidl */
1813 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1815 WCHAR path
[MAX_PATH
];
1817 GetCurrentDirectoryW(MAX_PATH
,path
);
1818 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1821 /* Initialise shell objects */
1822 FILEDLG95_SHELL_Init(hwnd
);
1824 /* Initialize the Look In combo box */
1825 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1827 /* Browse to the initial directory */
1828 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1830 /* Free pidlItem memory */
1831 COMDLG32_SHFree(pidlItemId
);
1835 /***********************************************************************
1838 * Regroups all the cleaning functions of the filedlg
1840 void FILEDLG95_Clean(HWND hwnd
)
1842 FILEDLG95_FILETYPE_Clean(hwnd
);
1843 FILEDLG95_LOOKIN_Clean(hwnd
);
1844 FILEDLG95_SHELL_Clean(hwnd
);
1846 /***********************************************************************
1847 * FILEDLG95_OnWMCommand
1849 * WM_COMMAND message handler
1851 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1853 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1854 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1855 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1861 FILEDLG95_OnOpen(hwnd
);
1865 FILEDLG95_Clean(hwnd
);
1866 EndDialog(hwnd
, FALSE
);
1868 /* Filetype combo box */
1870 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1872 /* LookIn combo box */
1874 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1877 /* --- toolbar --- */
1878 /* Up folder button */
1879 case FCIDM_TB_UPFOLDER
:
1880 FILEDLG95_SHELL_UpFolder(hwnd
);
1882 /* New folder button */
1883 case FCIDM_TB_NEWFOLDER
:
1884 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1886 /* List option button */
1887 case FCIDM_TB_SMALLICON
:
1888 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1890 /* Details option button */
1891 case FCIDM_TB_REPORTVIEW
:
1892 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1894 /* Details option button */
1895 case FCIDM_TB_DESKTOP
:
1896 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1904 /* Do not use the listview selection anymore */
1905 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1909 /***********************************************************************
1910 * FILEDLG95_OnWMGetIShellBrowser
1912 * WM_GETISHELLBROWSER message handler
1914 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1916 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1920 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1926 /***********************************************************************
1927 * FILEDLG95_SendFileOK
1929 * Sends the CDN_FILEOK notification if required
1932 * TRUE if the dialog should close
1933 * FALSE if the dialog should not be closed
1935 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1937 /* ask the hook if we can close */
1938 if(IsHooked(fodInfos
))
1943 /* First send CDN_FILEOK as MSDN doc says */
1944 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1945 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1948 TRACE("canceled\n");
1952 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1953 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1954 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1957 TRACE("canceled\n");
1964 /***********************************************************************
1965 * FILEDLG95_OnOpenMultipleFiles
1967 * Handles the opening of multiple files.
1970 * check destination buffer size
1972 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1974 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1975 UINT nCount
, nSizePath
;
1976 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1980 if(fodInfos
->unicode
)
1982 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1983 ofn
->lpstrFile
[0] = '\0';
1987 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1988 ofn
->lpstrFile
[0] = '\0';
1991 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1993 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1994 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1995 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1997 LPWSTR lpstrTemp
= lpstrFileList
;
1999 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2003 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2006 WCHAR lpstrNotFound
[100];
2007 WCHAR lpstrMsg
[100];
2009 static const WCHAR nl
[] = {'\n',0};
2011 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2012 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2014 lstrcpyW(tmp
, lpstrTemp
);
2016 lstrcatW(tmp
, lpstrNotFound
);
2018 lstrcatW(tmp
, lpstrMsg
);
2020 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2024 /* move to the next file in the list of files */
2025 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2026 COMDLG32_SHFree(pidl
);
2030 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2031 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2033 /* For "oldstyle" dialog the components have to
2034 be separated by blanks (not '\0'!) and short
2035 filenames have to be used! */
2036 FIXME("Components have to be separated by blanks\n");
2038 if(fodInfos
->unicode
)
2040 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2041 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2042 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2046 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2048 if (ofn
->lpstrFile
!= NULL
)
2050 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2051 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2052 if (ofn
->nMaxFile
> nSizePath
)
2054 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2055 ofn
->lpstrFile
+ nSizePath
,
2056 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2061 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2062 fodInfos
->ofnInfos
->nFileExtension
= 0;
2064 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2067 /* clean and exit */
2068 FILEDLG95_Clean(hwnd
);
2069 return EndDialog(hwnd
,TRUE
);
2072 /* Returns the 'slot name' of the given module_name in the registry's
2073 * most-recently-used list. This will be an ASCII value in the
2074 * range ['a','z'). Returns zero on error.
2076 * The slot's value in the registry has the form:
2077 * module_name\0mru_path\0
2079 * If stored_path is given, then stored_path will contain the path name
2080 * stored in the registry's MRU list for the given module_name.
2082 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2083 * MRU list key for the given module_name.
2085 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2087 WCHAR mru_list
[32], *cur_mru_slot
;
2088 BOOL taken
[25] = {0};
2089 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2090 HKEY hkey_tmp
, *hkey
;
2099 *stored_path
= '\0';
2101 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2103 WARN("Unable to create MRU key: %d\n", ret
);
2107 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2108 (LPBYTE
)mru_list
, &mru_list_size
);
2109 if(ret
|| key_type
!= REG_SZ
){
2110 if(ret
== ERROR_FILE_NOT_FOUND
)
2113 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2118 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2119 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2120 DWORD value_data_size
= sizeof(value_data
);
2122 *value_name
= *cur_mru_slot
;
2124 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2125 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2126 if(ret
|| key_type
!= REG_BINARY
){
2127 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2131 if(!strcmpiW(module_name
, value_data
)){
2135 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2143 /* the module name isn't in the registry, so find the next open slot */
2144 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2145 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2146 for(i
= 0; i
< 25; ++i
){
2151 /* all slots are taken, so return the last one in MRUList */
2153 return *cur_mru_slot
;
2156 /* save the given filename as most-recently-used path for this module */
2157 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2159 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2163 /* get the current executable's name */
2164 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2165 WARN("GotModuleFileName failed: %d\n", GetLastError());
2168 module_name
= strrchrW(module_path
, '\\');
2170 module_name
= module_path
;
2174 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2179 { /* update the slot's info */
2180 WCHAR
*path_ends
, *final
;
2181 DWORD path_len
, final_len
;
2183 /* use only the path segment of `filename' */
2184 path_ends
= strrchrW(filename
, '\\');
2185 path_len
= path_ends
- filename
;
2187 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2189 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2192 lstrcpyW(final
, module_name
);
2193 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2194 final
[final_len
-1] = '\0';
2196 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2197 final_len
* sizeof(WCHAR
));
2199 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2208 { /* update MRUList value */
2209 WCHAR old_mru_list
[32], new_mru_list
[32];
2210 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2211 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2213 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2214 (LPBYTE
)old_mru_list
, &mru_list_size
);
2215 if(ret
|| key_type
!= REG_SZ
){
2216 if(ret
== ERROR_FILE_NOT_FOUND
){
2217 new_mru_list
[0] = slot
;
2218 new_mru_list
[1] = '\0';
2220 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2225 /* copy old list data over so that the new slot is at the start
2227 *new_mru_slot
++ = slot
;
2228 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2229 if(*old_mru_slot
!= slot
)
2230 *new_mru_slot
++ = *old_mru_slot
;
2232 *new_mru_slot
= '\0';
2235 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2236 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2238 WARN("Error saving MRUList data: %d\n", ret
);
2245 /* load the most-recently-used path for this module */
2246 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2248 WCHAR module_path
[MAX_PATH
], *module_name
;
2250 /* get the current executable's name */
2251 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2252 WARN("GotModuleFileName failed: %d\n", GetLastError());
2255 module_name
= strrchrW(module_path
, '\\');
2257 module_name
= module_path
;
2261 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2262 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2265 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2267 WCHAR strMsgTitle
[MAX_PATH
];
2268 WCHAR strMsgText
[MAX_PATH
];
2270 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2272 strMsgTitle
[0] = '\0';
2273 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2274 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2277 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2278 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2280 int nOpenAction
= defAction
;
2281 LPWSTR lpszTemp
, lpszTemp1
;
2282 LPITEMIDLIST pidl
= NULL
;
2283 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2285 /* check for invalid chars */
2286 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2288 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2292 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2294 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2297 LPSHELLFOLDER lpsfChild
;
2298 WCHAR lpwstrTemp
[MAX_PATH
];
2299 DWORD dwEaten
, dwAttributes
;
2302 lstrcpyW(lpwstrTemp
, lpszTemp
);
2303 p
= PathFindNextComponentW(lpwstrTemp
);
2305 if (!p
) break; /* end of path */
2308 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2310 /* There are no wildcards when OFN_NOVALIDATE is set */
2311 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2313 static const WCHAR wszWild
[] = { '*', '?', 0 };
2314 /* if the last element is a wildcard do a search */
2315 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2317 nOpenAction
= ONOPEN_SEARCH
;
2321 lpszTemp1
= lpszTemp
;
2323 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2325 /* append a backslash to drive letters */
2326 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2327 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2328 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2330 PathAddBackslashW(lpwstrTemp
);
2333 dwAttributes
= SFGAO_FOLDER
;
2334 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2336 /* the path component is valid, we have a pidl of the next path component */
2337 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2338 if(dwAttributes
& SFGAO_FOLDER
)
2340 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2342 ERR("bind to failed\n"); /* should not fail */
2345 IShellFolder_Release(*ppsf
);
2353 /* end dialog, return value */
2354 nOpenAction
= ONOPEN_OPEN
;
2357 COMDLG32_SHFree(pidl
);
2360 else if (!(flags
& OFN_NOVALIDATE
))
2362 if(*lpszTemp
|| /* points to trailing null for last path element */
2363 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2365 if(flags
& OFN_PATHMUSTEXIST
)
2367 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2373 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2375 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2379 /* change to the current folder */
2380 nOpenAction
= ONOPEN_OPEN
;
2385 nOpenAction
= ONOPEN_OPEN
;
2389 if(pidl
) COMDLG32_SHFree(pidl
);
2394 /***********************************************************************
2397 * Ok button WM_COMMAND message handler
2399 * If the function succeeds, the return value is nonzero.
2401 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2403 LPWSTR lpstrFileList
;
2404 UINT nFileCount
= 0;
2407 WCHAR lpstrPathAndFile
[MAX_PATH
];
2408 LPSHELLFOLDER lpsf
= NULL
;
2410 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2412 TRACE("hwnd=%p\n", hwnd
);
2414 /* try to browse the selected item */
2415 if(BrowseSelectedFolder(hwnd
))
2418 /* get the files from the edit control */
2419 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2426 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2430 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2433 Step 1: Build a complete path name from the current folder and
2434 the filename or path in the edit box.
2436 - the path in the edit box is a root path
2437 (with or without drive letter)
2438 - the edit box contains ".." (or a path with ".." in it)
2441 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2442 MemFree(lpstrFileList
);
2445 Step 2: here we have a cleaned up path
2447 We have to parse the path step by step to see if we have to browse
2448 to a folder if the path points to a directory or the last
2449 valid element is a directory.
2452 lpstrPathAndFile: cleaned up path
2456 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2457 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2458 nOpenAction
= ONOPEN_OPEN
;
2460 nOpenAction
= ONOPEN_BROWSE
;
2462 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2463 fodInfos
->ofnInfos
->Flags
,
2464 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2470 Step 3: here we have a cleaned up and validated path
2473 lpsf: ShellFolder bound to the rightmost valid path component
2474 lpstrPathAndFile: cleaned up path
2475 nOpenAction: action to do
2477 TRACE("end validate sf=%p\n", lpsf
);
2481 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2482 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2485 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2488 /* replace the current filter */
2489 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2490 len
= lstrlenW(lpszTemp
)+1;
2491 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2492 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2494 /* set the filter cb to the extension when possible */
2495 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2496 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2499 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2500 TRACE("ONOPEN_BROWSE\n");
2502 IPersistFolder2
* ppf2
;
2503 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2505 LPITEMIDLIST pidlCurrent
;
2506 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2507 IPersistFolder2_Release(ppf2
);
2508 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2510 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2511 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2513 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2516 else if( nOpenAction
== ONOPEN_SEARCH
)
2518 if (fodInfos
->Shell
.FOIShellView
)
2519 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2521 COMDLG32_SHFree(pidlCurrent
);
2522 if (filename_is_edit( fodInfos
))
2523 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2528 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2529 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2533 /* update READONLY check box flag */
2534 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2535 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2537 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2539 /* Attach the file extension with file name*/
2540 ext
= PathFindExtensionW(lpstrPathAndFile
);
2541 if (! *ext
&& fodInfos
->defext
)
2543 /* if no extension is specified with file name, then */
2544 /* attach the extension from file filter or default one */
2546 WCHAR
*filterExt
= NULL
;
2547 LPWSTR lpstrFilter
= NULL
;
2548 static const WCHAR szwDot
[] = {'.',0};
2549 int PathLength
= lstrlenW(lpstrPathAndFile
);
2551 /*Get the file extension from file type filter*/
2552 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2553 fodInfos
->ofnInfos
->nFilterIndex
-1);
2555 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2557 WCHAR
* filterSearchIndex
;
2558 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2559 strcpyW(filterExt
, lpstrFilter
);
2561 /* if a semicolon-separated list of file extensions was given, do not include the
2562 semicolon or anything after it in the extension.
2563 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2564 filterSearchIndex
= strchrW(filterExt
, ';');
2565 if (filterSearchIndex
)
2567 filterSearchIndex
[0] = '\0';
2570 /* find the file extension by searching for the first dot in filterExt */
2571 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2572 /* if the extension is invalid or contains a glob, ignore it */
2573 filterSearchIndex
= strchrW(filterExt
, '.');
2574 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2576 strcpyW(filterExt
, filterSearchIndex
);
2580 HeapFree(GetProcessHeap(), 0, filterExt
);
2587 /* use the default file extension */
2588 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2589 strcpyW(filterExt
, fodInfos
->defext
);
2592 if (*filterExt
) /* ignore filterExt="" */
2595 lstrcatW(lpstrPathAndFile
, szwDot
);
2596 /* Attach the extension */
2597 lstrcatW(lpstrPathAndFile
, filterExt
);
2600 HeapFree(GetProcessHeap(), 0, filterExt
);
2602 /* In Open dialog: if file does not exist try without extension */
2603 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2604 lpstrPathAndFile
[PathLength
] = '\0';
2606 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2609 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2610 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2612 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2615 /* In Save dialog: check if the file already exists */
2616 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2617 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2618 && PathFileExistsW(lpstrPathAndFile
))
2620 WCHAR lpstrOverwrite
[100];
2623 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2624 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2625 MB_YESNO
| MB_ICONEXCLAMATION
);
2626 if (answer
== IDNO
|| answer
== IDCANCEL
)
2633 /* In Open dialog: check if it should be created if it doesn't exist */
2634 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2635 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2636 && !PathFileExistsW(lpstrPathAndFile
))
2638 WCHAR lpstrCreate
[100];
2641 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2642 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2643 MB_YESNO
| MB_ICONEXCLAMATION
);
2644 if (answer
== IDNO
|| answer
== IDCANCEL
)
2651 /* Check that the size of the file does not exceed buffer size.
2652 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2653 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2654 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2657 /* fill destination buffer */
2658 if (fodInfos
->ofnInfos
->lpstrFile
)
2660 if(fodInfos
->unicode
)
2662 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2664 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2665 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2666 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2670 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2672 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2673 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2674 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2675 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2679 if(fodInfos
->unicode
)
2683 /* set filename offset */
2684 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2685 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2687 /* set extension offset */
2688 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2689 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2694 CHAR tempFileA
[MAX_PATH
];
2696 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2697 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2698 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2700 /* set filename offset */
2701 lpszTemp
= PathFindFileNameA(tempFileA
);
2702 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2704 /* set extension offset */
2705 lpszTemp
= PathFindExtensionA(tempFileA
);
2706 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2709 /* set the lpstrFileTitle */
2710 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2712 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2713 if(fodInfos
->unicode
)
2715 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2716 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2720 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2721 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2722 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2726 /* copy currently selected filter to lpstrCustomFilter */
2727 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2729 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2730 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2731 NULL
, 0, NULL
, NULL
);
2732 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2734 LPSTR s
= ofn
->lpstrCustomFilter
;
2735 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2736 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2737 s
, len
, NULL
, NULL
);
2742 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2745 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2748 FILEDLG95_Clean(hwnd
);
2749 ret
= EndDialog(hwnd
, TRUE
);
2755 size
= lstrlenW(lpstrPathAndFile
) + 1;
2756 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2758 /* return needed size in first two bytes of lpstrFile */
2759 if(fodInfos
->ofnInfos
->lpstrFile
)
2760 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2761 FILEDLG95_Clean(hwnd
);
2762 ret
= EndDialog(hwnd
, FALSE
);
2763 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2770 if(lpsf
) IShellFolder_Release(lpsf
);
2774 /***********************************************************************
2775 * FILEDLG95_SHELL_Init
2777 * Initialisation of the shell objects
2779 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2781 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2786 * Initialisation of the FileOpenDialogInfos structure
2792 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2794 /* Disable multi-select if flag not set */
2795 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2797 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2799 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2800 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2802 /* Construct the IShellBrowser interface */
2803 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2808 /***********************************************************************
2809 * FILEDLG95_SHELL_ExecuteCommand
2811 * Change the folder option and refresh the view
2812 * If the function succeeds, the return value is nonzero.
2814 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2816 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2819 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2821 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2826 CMINVOKECOMMANDINFO ci
;
2827 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2828 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2832 IContextMenu_InvokeCommand(pcm
, &ci
);
2833 IContextMenu_Release(pcm
);
2839 /***********************************************************************
2840 * FILEDLG95_SHELL_UpFolder
2842 * Browse to the specified object
2843 * If the function succeeds, the return value is nonzero.
2845 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2847 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2851 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2855 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2856 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2862 /***********************************************************************
2863 * FILEDLG95_SHELL_BrowseToDesktop
2865 * Browse to the Desktop
2866 * If the function succeeds, the return value is nonzero.
2868 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2870 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2876 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2877 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2878 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2879 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2880 COMDLG32_SHFree(pidl
);
2881 return SUCCEEDED(hres
);
2883 /***********************************************************************
2884 * FILEDLG95_SHELL_Clean
2886 * Cleans the memory used by shell objects
2888 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2890 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2894 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2896 /* clean Shell interfaces */
2897 if (fodInfos
->Shell
.FOIShellView
)
2899 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2900 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2902 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2903 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2904 if (fodInfos
->Shell
.FOIDataObject
)
2905 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2908 /***********************************************************************
2909 * FILEDLG95_FILETYPE_Init
2911 * Initialisation of the file type combo box
2913 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2915 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2916 int nFilters
= 0; /* number of filters */
2921 if(fodInfos
->customfilter
)
2923 /* customfilter has one entry... title\0ext\0
2924 * Set first entry of combo box item with customfilter
2927 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2930 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2932 /* Copy the extensions */
2933 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2934 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2935 lstrcpyW(lpstrExt
,lpstrPos
);
2937 /* Add the item at the end of the combo */
2938 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2939 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2942 if(fodInfos
->filter
)
2944 LPCWSTR lpstrPos
= fodInfos
->filter
;
2948 /* filter is a list... title\0ext\0......\0\0
2949 * Set the combo item text to the title and the item data
2952 LPCWSTR lpstrDisplay
;
2956 if(! *lpstrPos
) break; /* end */
2957 lpstrDisplay
= lpstrPos
;
2958 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2960 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2964 /* Copy the extensions */
2965 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2966 lstrcpyW(lpstrExt
,lpstrPos
);
2967 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2969 /* Add the item at the end of the combo */
2970 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2972 /* malformed filters are added anyway... */
2973 if (!*lpstrExt
) break;
2978 * Set the current filter to the one specified
2979 * in the initialisation structure
2981 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2985 /* Check to make sure our index isn't out of bounds. */
2986 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2987 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2988 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2990 /* set default filter index */
2991 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2992 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2994 /* calculate index of Combo Box item */
2995 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2996 if (fodInfos
->customfilter
== NULL
)
2999 /* Set the current index selection. */
3000 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3002 /* Get the corresponding text string from the combo box. */
3003 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3006 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3012 CharLowerW(lpstrFilter
); /* lowercase */
3013 len
= lstrlenW(lpstrFilter
)+1;
3014 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3015 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3018 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3022 /***********************************************************************
3023 * FILEDLG95_FILETYPE_OnCommand
3025 * WM_COMMAND of the file type combo box
3026 * If the function succeeds, the return value is nonzero.
3028 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3030 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3038 /* Get the current item of the filetype combo box */
3039 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3041 /* set the current filter index */
3042 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3043 (fodInfos
->customfilter
== NULL
? 1 : 0);
3045 /* Set the current filter with the current selection */
3046 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3048 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3050 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3053 CharLowerW(lpstrFilter
); /* lowercase */
3054 len
= lstrlenW(lpstrFilter
)+1;
3055 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3056 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3057 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3058 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3061 /* Refresh the actual view to display the included items*/
3062 if (fodInfos
->Shell
.FOIShellView
)
3063 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3068 /***********************************************************************
3069 * FILEDLG95_FILETYPE_SearchExt
3071 * searches for an extension in the filetype box
3073 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3075 int i
, iCount
= CBGetCount(hwnd
);
3077 TRACE("%s\n", debugstr_w(lpstrExt
));
3079 if(iCount
!= CB_ERR
)
3081 for(i
=0;i
<iCount
;i
++)
3083 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3090 /***********************************************************************
3091 * FILEDLG95_FILETYPE_Clean
3093 * Clean the memory used by the filetype combo box
3095 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3097 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3099 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3103 /* Delete each string of the combo and their associated data */
3104 if(iCount
!= CB_ERR
)
3106 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3108 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3109 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3112 /* Current filter */
3113 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3117 /***********************************************************************
3118 * FILEDLG95_LOOKIN_Init
3120 * Initialisation of the look in combo box
3123 /* Small helper function, to determine if the unixfs shell extension is rooted
3124 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3126 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3128 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3129 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3130 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3131 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3132 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3133 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3134 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3136 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3143 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3145 IShellFolder
*psfRoot
, *psfDrives
;
3146 IEnumIDList
*lpeRoot
, *lpeDrives
;
3147 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3150 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3154 liInfos
->iMaxIndentation
= 0;
3156 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3158 hdc
= GetDC( hwndCombo
);
3159 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3160 GetTextMetricsW( hdc
, &tm
);
3161 ReleaseDC( hwndCombo
, hdc
);
3163 /* set item height for both text field and listbox */
3164 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3165 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3167 /* Turn on the extended UI for the combo box like Windows does */
3168 CBSetExtendedUI(hwndCombo
, TRUE
);
3170 /* Initialise data of Desktop folder */
3171 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3172 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3173 COMDLG32_SHFree(pidlTmp
);
3175 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3177 SHGetDesktopFolder(&psfRoot
);
3181 /* enumerate the contents of the desktop */
3182 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3184 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3186 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3188 /* If the unixfs extension is rooted, we don't expand the drives by default */
3189 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3191 /* special handling for CSIDL_DRIVES */
3192 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3194 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3196 /* enumerate the drives */
3197 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3199 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3201 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3202 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3203 COMDLG32_SHFree(pidlAbsTmp
);
3204 COMDLG32_SHFree(pidlTmp1
);
3206 IEnumIDList_Release(lpeDrives
);
3208 IShellFolder_Release(psfDrives
);
3213 COMDLG32_SHFree(pidlTmp
);
3215 IEnumIDList_Release(lpeRoot
);
3217 IShellFolder_Release(psfRoot
);
3220 COMDLG32_SHFree(pidlDrives
);
3223 /***********************************************************************
3224 * FILEDLG95_LOOKIN_DrawItem
3226 * WM_DRAWITEM message handler
3228 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3230 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3231 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3232 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3236 HIMAGELIST ilItemImage
;
3239 LPSFOLDER tmpFolder
;
3240 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3241 UINT icon_width
, icon_height
;
3245 if(pDIStruct
->itemID
== -1)
3248 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3249 pDIStruct
->itemID
)))
3253 icon_width
= GetSystemMetrics(SM_CXICON
);
3254 icon_height
= GetSystemMetrics(SM_CYICON
);
3255 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3257 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3258 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3259 shgfi_flags
|= SHGFI_SMALLICON
;
3262 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3263 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3265 /* Is this item selected ? */
3266 if(pDIStruct
->itemState
& ODS_SELECTED
)
3268 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3269 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3270 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3274 SetTextColor(pDIStruct
->hDC
,crText
);
3275 SetBkColor(pDIStruct
->hDC
,crWin
);
3276 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3279 /* Do not indent item if drawing in the edit of the combo */
3280 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3283 iIndentation
= tmpFolder
->m_iIndent
;
3285 /* Draw text and icon */
3287 /* Initialise the icon display area */
3288 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3289 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3290 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3291 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3293 /* Initialise the text display area */
3294 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3295 rectText
.left
= rectIcon
.right
;
3297 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3298 rectText
.right
= pDIStruct
->rcItem
.right
;
3300 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3302 /* Draw the icon from the image list */
3303 ImageList_Draw(ilItemImage
,
3310 /* Draw the associated text */
3311 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3315 /***********************************************************************
3316 * FILEDLG95_LOOKIN_OnCommand
3318 * LookIn combo box WM_COMMAND message handler
3319 * If the function succeeds, the return value is nonzero.
3321 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3323 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3325 TRACE("%p\n", fodInfos
);
3331 LPSFOLDER tmpFolder
;
3334 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3336 if( iItem
== CB_ERR
) return FALSE
;
3338 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3343 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3344 tmpFolder
->pidlItem
,
3347 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3348 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3358 /***********************************************************************
3359 * FILEDLG95_LOOKIN_AddItem
3361 * Adds an absolute pidl item to the lookin combo box
3362 * returns the index of the inserted item
3364 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3366 LPITEMIDLIST pidlNext
;
3369 LookInInfos
*liInfos
;
3371 TRACE("%08x\n", iInsertId
);
3376 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3379 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3380 tmpFolder
->m_iIndent
= 0;
3382 /* Calculate the indentation of the item in the lookin*/
3384 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3386 tmpFolder
->m_iIndent
++;
3389 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3391 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3392 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3394 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3395 SHGetFileInfoW((LPCWSTR
)pidl
,
3399 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3400 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3402 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3404 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3408 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3410 /* Add the item at the end of the list */
3413 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3415 /* Insert the item at the iInsertId position*/
3418 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3421 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3425 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3426 MemFree( tmpFolder
);
3431 /***********************************************************************
3432 * FILEDLG95_LOOKIN_InsertItemAfterParent
3434 * Insert an item below its parent
3436 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3439 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3444 if (pidl
== pidlParent
)
3447 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3451 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3454 /* Free pidlParent memory */
3455 COMDLG32_SHFree(pidlParent
);
3457 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3460 /***********************************************************************
3461 * FILEDLG95_LOOKIN_SelectItem
3463 * Adds an absolute pidl item to the lookin combo box
3464 * returns the index of the inserted item
3466 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3469 LookInInfos
*liInfos
;
3473 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3475 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3479 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3480 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3485 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3486 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3490 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3492 if(iRemovedItem
< iItemPos
)
3497 CBSetCurSel(hwnd
,iItemPos
);
3498 liInfos
->uSelectedItem
= iItemPos
;
3504 /***********************************************************************
3505 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3507 * Remove the item with an expansion level over iExpansionLevel
3509 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3512 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3516 if(liInfos
->iMaxIndentation
<= 2)
3519 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3521 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3522 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3524 CBDeleteString(hwnd
,iItemPos
);
3525 liInfos
->iMaxIndentation
--;
3533 /***********************************************************************
3534 * FILEDLG95_LOOKIN_SearchItem
3536 * Search for pidl in the lookin combo box
3537 * returns the index of the found item
3539 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3542 int iCount
= CBGetCount(hwnd
);
3544 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3546 if (iCount
!= CB_ERR
)
3550 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3552 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3554 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3562 /***********************************************************************
3563 * FILEDLG95_LOOKIN_Clean
3565 * Clean the memory used by the lookin combo box
3567 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3569 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3570 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3572 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3576 /* Delete each string of the combo and their associated data */
3577 if (iCount
!= CB_ERR
)
3579 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3581 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3582 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3584 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3588 /* LookInInfos structure */
3590 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3593 /***********************************************************************
3594 * FILEDLG95_FILENAME_FillFromSelection
3596 * fills the edit box from the cached DataObject
3598 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3600 FileOpenDlgInfos
*fodInfos
;
3602 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3603 WCHAR lpstrTemp
[MAX_PATH
];
3604 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3607 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3609 /* Count how many files we have */
3610 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3612 /* calculate the string length, count files */
3613 if (nFileSelected
>= 1)
3615 nLength
+= 3; /* first and last quotes, trailing \0 */
3616 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3618 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3622 /* get the total length of the selected file names */
3623 lpstrTemp
[0] = '\0';
3624 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3626 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3628 nLength
+= lstrlenW( lpstrTemp
) + 3;
3631 COMDLG32_SHFree( pidl
);
3636 /* allocate the buffer */
3637 if (nFiles
<= 1) nLength
= MAX_PATH
;
3638 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3640 /* Generate the string for the edit control */
3643 lpstrCurrFile
= lpstrAllFile
;
3644 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3646 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3650 /* get the file name */
3651 lpstrTemp
[0] = '\0';
3652 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3654 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3658 *lpstrCurrFile
++ = '\"';
3659 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3660 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3661 *lpstrCurrFile
++ = '\"';
3662 *lpstrCurrFile
++ = ' ';
3667 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3670 COMDLG32_SHFree( pidl
);
3673 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3675 /* Select the file name like Windows does */
3676 if (filename_is_edit( fodInfos
))
3677 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3679 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3683 /* copied from shell32 to avoid linking to it
3684 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3685 * is dependent on whether emulated OS is unicode or not.
3687 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3692 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3693 COMDLG32_SHFree(src
->u
.pOleStr
);
3697 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3702 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3707 FIXME("unknown type %x!\n", src
->uType
);
3708 if (len
) *dest
= '\0';
3714 /***********************************************************************
3715 * FILEDLG95_FILENAME_GetFileNames
3717 * Copies the filenames to a delimited string list.
3719 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3721 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3722 UINT nFileCount
= 0; /* number of files */
3723 UINT nStrLen
= 0; /* length of string in edit control */
3724 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3728 /* get the filenames from the filename control */
3729 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3730 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3731 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3733 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3735 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3740 #define SETDefFormatEtc(fe,cf,med) \
3742 (fe).cfFormat = cf;\
3743 (fe).dwAspect = DVASPECT_CONTENT; \
3750 * DATAOBJECT Helper functions
3753 /***********************************************************************
3754 * COMCTL32_ReleaseStgMedium
3756 * like ReleaseStgMedium from ole32
3758 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3760 if(medium
.pUnkForRelease
)
3762 IUnknown_Release(medium
.pUnkForRelease
);
3766 GlobalUnlock(medium
.u
.hGlobal
);
3767 GlobalFree(medium
.u
.hGlobal
);
3771 /***********************************************************************
3772 * GetPidlFromDataObject
3774 * Return pidl(s) by number from the cached DataObject
3776 * nPidlIndex=0 gets the fully qualified root path
3778 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3782 FORMATETC formatetc
;
3783 LPITEMIDLIST pidl
= NULL
;
3785 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3790 /* Set the FORMATETC structure*/
3791 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3793 /* Get the pidls from IDataObject */
3794 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3796 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3797 if(nPidlIndex
<= cida
->cidl
)
3799 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3801 COMCTL32_ReleaseStgMedium(medium
);
3806 /***********************************************************************
3809 * Return the number of selected items in the DataObject.
3812 static UINT
GetNumSelected( IDataObject
*doSelected
)
3816 FORMATETC formatetc
;
3818 TRACE("sv=%p\n", doSelected
);
3820 if (!doSelected
) return 0;
3822 /* Set the FORMATETC structure*/
3823 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3825 /* Get the pidls from IDataObject */
3826 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3828 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3829 retVal
= cida
->cidl
;
3830 COMCTL32_ReleaseStgMedium(medium
);
3840 /***********************************************************************
3843 * Get the pidl's display name (relative to folder) and
3844 * put it in lpstrFileName.
3846 * Return NOERROR on success,
3850 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3855 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3859 SHGetDesktopFolder(&lpsf
);
3860 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3861 IShellFolder_Release(lpsf
);
3865 /* Get the display name of the pidl relative to the folder */
3866 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3868 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3873 /***********************************************************************
3874 * GetShellFolderFromPidl
3876 * pidlRel is the item pidl relative
3877 * Return the IShellFolder of the absolute pidl
3879 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3881 IShellFolder
*psf
= NULL
,*psfParent
;
3883 TRACE("%p\n", pidlAbs
);
3885 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3888 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3890 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3892 IShellFolder_Release(psfParent
);
3896 /* return the desktop */
3902 /***********************************************************************
3905 * Return the LPITEMIDLIST to the parent of the pidl in the list
3907 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3909 LPITEMIDLIST pidlParent
;
3911 TRACE("%p\n", pidl
);
3913 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3914 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3919 /***********************************************************************
3922 * returns the pidl of the file name relative to folder
3923 * NULL if an error occurred
3925 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3927 LPITEMIDLIST pidl
= NULL
;
3930 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3932 if(!lpcstrFileName
) return NULL
;
3933 if(!*lpcstrFileName
) return NULL
;
3937 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3938 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3939 IShellFolder_Release(lpsf
);
3944 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3951 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3953 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3956 TRACE("%p, %p\n", psf
, pidl
);
3958 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3960 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3961 /* see documentation shell 4.1*/
3962 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3965 /***********************************************************************
3966 * BrowseSelectedFolder
3968 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3970 BOOL bBrowseSelFolder
= FALSE
;
3971 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3975 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3977 LPITEMIDLIST pidlSelection
;
3979 /* get the file selected */
3980 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3981 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3983 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3984 pidlSelection
, SBSP_RELATIVE
) ) )
3986 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3987 ' ','n','o','t',' ','e','x','i','s','t',0};
3988 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3990 bBrowseSelFolder
= TRUE
;
3991 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3992 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3994 COMDLG32_SHFree( pidlSelection
);
3997 return bBrowseSelFolder
;
4001 * Memory allocation methods */
4002 static void *MemAlloc(UINT size
)
4004 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4007 static void MemFree(void *mem
)
4009 HeapFree(GetProcessHeap(),0,mem
);
4012 static inline BOOL
valid_struct_size( DWORD size
)
4014 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4015 (size
== sizeof( OPENFILENAMEW
));
4018 static inline BOOL
is_win16_looks(DWORD flags
)
4020 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4021 !(flags
& OFN_EXPLORER
));
4024 /* ------------------ APIs ---------------------- */
4026 /***********************************************************************
4027 * GetOpenFileNameA (COMDLG32.@)
4029 * Creates a dialog box for the user to select a file to open.
4032 * TRUE on success: user enters a valid file
4033 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4036 BOOL WINAPI
GetOpenFileNameA(
4037 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4039 TRACE("flags %08x\n", ofn
->Flags
);
4041 if (!valid_struct_size( ofn
->lStructSize
))
4043 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4047 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4048 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4049 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4051 if (is_win16_looks(ofn
->Flags
))
4052 return GetFileName31A(ofn
, OPEN_DIALOG
);
4054 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4057 /***********************************************************************
4058 * GetOpenFileNameW (COMDLG32.@)
4060 * Creates a dialog box for the user to select a file to open.
4063 * TRUE on success: user enters a valid file
4064 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4067 BOOL WINAPI
GetOpenFileNameW(
4068 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4070 TRACE("flags %08x\n", ofn
->Flags
);
4072 if (!valid_struct_size( ofn
->lStructSize
))
4074 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4078 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4079 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4080 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4082 if (is_win16_looks(ofn
->Flags
))
4083 return GetFileName31W(ofn
, OPEN_DIALOG
);
4085 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4089 /***********************************************************************
4090 * GetSaveFileNameA (COMDLG32.@)
4092 * Creates a dialog box for the user to select a file to save.
4095 * TRUE on success: user enters a valid file
4096 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4099 BOOL WINAPI
GetSaveFileNameA(
4100 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4102 if (!valid_struct_size( ofn
->lStructSize
))
4104 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4108 if (is_win16_looks(ofn
->Flags
))
4109 return GetFileName31A(ofn
, SAVE_DIALOG
);
4111 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4114 /***********************************************************************
4115 * GetSaveFileNameW (COMDLG32.@)
4117 * Creates a dialog box for the user to select a file to save.
4120 * TRUE on success: user enters a valid file
4121 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4124 BOOL WINAPI
GetSaveFileNameW(
4125 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4127 if (!valid_struct_size( ofn
->lStructSize
))
4129 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4133 if (is_win16_looks(ofn
->Flags
))
4134 return GetFileName31W(ofn
, SAVE_DIALOG
);
4136 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4139 /***********************************************************************
4140 * GetFileTitleA (COMDLG32.@)
4142 * See GetFileTitleW.
4144 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4147 UNICODE_STRING strWFile
;
4150 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4151 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4152 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4153 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4154 RtlFreeUnicodeString( &strWFile
);
4155 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4160 /***********************************************************************
4161 * GetFileTitleW (COMDLG32.@)
4163 * Get the name of a file.
4166 * lpFile [I] name and location of file
4167 * lpTitle [O] returned file name
4168 * cbBuf [I] buffer size of lpTitle
4172 * Failure: negative number.
4174 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4177 static const WCHAR brkpoint
[] = {'*','[',']',0};
4178 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4180 if(lpFile
== NULL
|| lpTitle
== NULL
)
4183 len
= lstrlenW(lpFile
);
4188 if(strpbrkW(lpFile
, brkpoint
))
4193 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4196 for(i
= len
; i
>= 0; i
--)
4198 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4208 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4210 len
= lstrlenW(lpFile
+i
)+1;
4214 lstrcpyW(lpTitle
, &lpFile
[i
]);