2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
140 static const WCHAR LastVisitedMRUW
[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
147 /***********************************************************************
151 /* Internal functions used by the dialog */
152 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
153 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
154 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
155 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
156 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
157 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
158 static void FILEDLG95_Clean(HWND hwnd
);
160 /* Functions used by the shell navigation */
161 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
162 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
163 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
165 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
170 /* Functions used by the filetype combo box */
171 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
172 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
178 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
179 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
189 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
192 /* Miscellaneous tool functions */
193 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
194 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
195 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
196 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
197 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
198 static UINT
GetNumSelected( IDataObject
*doSelected
);
200 /* Shell memory allocation */
201 static void *MemAlloc(UINT size
);
202 static void MemFree(void *mem
);
204 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
205 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
207 static BOOL
BrowseSelectedFolder(HWND hwnd
);
209 /***********************************************************************
212 * Creates an Open common dialog box that lets the user select
213 * the drive, directory, and the name of a file or set of files to open.
215 * IN : The FileOpenDlgInfos structure associated with the dialog
216 * OUT : TRUE on success
217 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
219 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
223 LPCVOID origTemplate
;
225 LPDLGTEMPLATEW
template;
230 /* test for missing functionality */
231 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
233 FIXME("Flags 0x%08x not yet implemented\n",
234 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
237 /* Create the dialog from a template */
239 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
241 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
244 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
245 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
246 !(origTemplate
= LockResource(hDlgTmpl
)))
248 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
251 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
253 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
256 memcpy(template, origTemplate
, dwSize
);
258 /* msdn: explorer style dialogs permit sizing by default.
259 * The OFN_ENABLESIZING flag is only needed when a hook or
260 * custom tmeplate is provided */
261 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
262 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
263 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
265 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
267 template->style
|= WS_SIZEBOX
;
268 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
269 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
272 template->style
&= ~WS_SIZEBOX
;
275 /* old style hook messages */
276 if (IsHooked(fodInfos
))
278 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
279 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
280 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
281 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
284 /* Some shell namespace extensions depend on COM being initialized. */
285 hr
= OleInitialize(NULL
);
287 if (fodInfos
->unicode
)
288 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
290 fodInfos
->ofnInfos
->hwndOwner
,
294 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
296 fodInfos
->ofnInfos
->hwndOwner
,
302 HeapFree(GetProcessHeap(), 0, template);
304 /* Unable to create the dialog */
311 /***********************************************************************
314 * Call GetFileName95 with this structure and clean the memory.
316 * IN : The OPENFILENAMEA initialisation structure passed to
317 * GetOpenFileNameA win api function (see filedlg.c)
319 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
322 FileOpenDlgInfos fodInfos
;
323 LPSTR lpstrSavDir
= NULL
;
325 LPWSTR defext
= NULL
;
326 LPWSTR filter
= NULL
;
327 LPWSTR customfilter
= NULL
;
328 INITCOMMONCONTROLSEX icc
;
330 /* Initialize ComboBoxEx32 */
331 icc
.dwSize
= sizeof(icc
);
332 icc
.dwICC
= ICC_USEREX_CLASSES
;
333 InitCommonControlsEx(&icc
);
335 /* Initialize CommDlgExtendedError() */
336 COMDLG32_SetCommDlgExtendedError(0);
338 /* Initialize FileOpenDlgInfos structure */
339 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
341 /* Pass in the original ofn */
342 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
344 /* save current directory */
345 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
347 lpstrSavDir
= MemAlloc(MAX_PATH
);
348 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
351 fodInfos
.unicode
= FALSE
;
353 /* convert all the input strings to unicode */
354 if(ofn
->lpstrInitialDir
)
356 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
357 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
358 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
361 fodInfos
.initdir
= NULL
;
365 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
366 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
369 fodInfos
.filename
= NULL
;
373 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
374 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
375 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
377 fodInfos
.defext
= defext
;
381 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
382 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
383 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
385 fodInfos
.title
= title
;
387 if (ofn
->lpstrFilter
)
392 /* filter is a list... title\0ext\0......\0\0 */
393 s
= ofn
->lpstrFilter
;
394 while (*s
) s
= s
+strlen(s
)+1;
396 n
= s
- ofn
->lpstrFilter
;
397 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
398 filter
= MemAlloc(len
*sizeof(WCHAR
));
399 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
401 fodInfos
.filter
= filter
;
403 /* convert lpstrCustomFilter */
404 if (ofn
->lpstrCustomFilter
)
409 /* customfilter contains a pair of strings... title\0ext\0 */
410 s
= ofn
->lpstrCustomFilter
;
411 if (*s
) s
= s
+strlen(s
)+1;
412 if (*s
) s
= s
+strlen(s
)+1;
413 n
= s
- ofn
->lpstrCustomFilter
;
414 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
415 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
416 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
418 fodInfos
.customfilter
= customfilter
;
420 /* Initialize the dialog property */
421 fodInfos
.DlgInfos
.dwDlgProp
= 0;
422 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
427 ret
= GetFileName95(&fodInfos
);
430 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
431 ret
= GetFileName95(&fodInfos
);
439 SetCurrentDirectoryA(lpstrSavDir
);
440 MemFree(lpstrSavDir
);
446 MemFree(customfilter
);
447 MemFree(fodInfos
.initdir
);
448 MemFree(fodInfos
.filename
);
450 TRACE("selected file: %s\n",ofn
->lpstrFile
);
455 /***********************************************************************
458 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
459 * Call GetFileName95 with this structure and clean the memory.
462 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
465 FileOpenDlgInfos fodInfos
;
466 LPWSTR lpstrSavDir
= NULL
;
467 INITCOMMONCONTROLSEX icc
;
469 /* Initialize ComboBoxEx32 */
470 icc
.dwSize
= sizeof(icc
);
471 icc
.dwICC
= ICC_USEREX_CLASSES
;
472 InitCommonControlsEx(&icc
);
474 /* Initialize CommDlgExtendedError() */
475 COMDLG32_SetCommDlgExtendedError(0);
477 /* Initialize FileOpenDlgInfos structure */
478 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
480 /* Pass in the original ofn */
481 fodInfos
.ofnInfos
= ofn
;
483 fodInfos
.title
= ofn
->lpstrTitle
;
484 fodInfos
.defext
= ofn
->lpstrDefExt
;
485 fodInfos
.filter
= ofn
->lpstrFilter
;
486 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
488 /* convert string arguments, save others */
491 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
492 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
495 fodInfos
.filename
= NULL
;
497 if(ofn
->lpstrInitialDir
)
499 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
500 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
501 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
502 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
505 fodInfos
.initdir
= NULL
;
507 /* save current directory */
508 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
510 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
511 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
514 fodInfos
.unicode
= TRUE
;
519 ret
= GetFileName95(&fodInfos
);
522 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
523 ret
= GetFileName95(&fodInfos
);
531 SetCurrentDirectoryW(lpstrSavDir
);
532 MemFree(lpstrSavDir
);
535 /* restore saved IN arguments and convert OUT arguments back */
536 MemFree(fodInfos
.filename
);
537 MemFree(fodInfos
.initdir
);
541 /******************************************************************************
542 * COMDLG32_GetDisplayNameOf [internal]
544 * Helper function to get the display name for a pidl.
546 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
547 LPSHELLFOLDER psfDesktop
;
550 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
553 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
554 IShellFolder_Release(psfDesktop
);
558 IShellFolder_Release(psfDesktop
);
559 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
562 /******************************************************************************
563 * COMDLG32_GetCanonicalPath [internal]
565 * Helper function to get the canonical path.
567 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
568 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
570 WCHAR lpstrTemp
[MAX_PATH
];
572 /* Get the current directory name */
573 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
576 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
578 PathAddBackslashW(lpstrPathAndFile
);
580 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
582 /* if the user specified a fully qualified path use it */
583 if(PathIsRelativeW(lpstrFile
))
585 lstrcatW(lpstrPathAndFile
, lpstrFile
);
589 /* does the path have a drive letter? */
590 if (PathGetDriveNumberW(lpstrFile
) == -1)
591 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
593 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
596 /* resolve "." and ".." */
597 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
598 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
599 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
602 /***********************************************************************
603 * COMDLG32_SplitFileNames [internal]
605 * Creates a delimited list of filenames.
607 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
609 UINT nStrCharCount
= 0; /* index in src buffer */
610 UINT nFileIndex
= 0; /* index in dest buffer */
611 UINT nFileCount
= 0; /* number of files */
613 /* we might get single filename without any '"',
614 * so we need nStrLen + terminating \0 + end-of-list \0 */
615 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
618 /* build delimited file list from filenames */
619 while ( nStrCharCount
<= nStrLen
)
621 if ( lpstrEdit
[nStrCharCount
]=='"' )
624 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
626 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
629 (*lpstrFileList
)[nFileIndex
++] = 0;
635 /* single, unquoted string */
636 if ((nStrLen
> 0) && (nFileIndex
== 0) )
638 lstrcpyW(*lpstrFileList
, lpstrEdit
);
639 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
644 (*lpstrFileList
)[nFileIndex
++] = '\0';
646 *sizeUsed
= nFileIndex
;
650 /***********************************************************************
651 * ArrangeCtrlPositions [internal]
653 * NOTE: Make sure to add testcases for any changes made here.
655 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
657 HWND hwndChild
, hwndStc32
;
658 RECT rectParent
, rectChild
, rectStc32
;
662 /* Take into account if open as read only checkbox and help button
667 RECT rectHelp
, rectCancel
;
668 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
669 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
670 /* subtract the height of the help button plus the space between
671 * the help button and the cancel button to the height of the dialog
673 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
677 There are two possibilities to add components to the default file dialog box.
679 By default, all the new components are added below the standard dialog box (the else case).
681 However, if there is a static text component with the stc32 id, a special case happens.
682 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
683 in the window and the cx and cy indicate how to size the window.
684 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
685 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
689 GetClientRect(hwndParentDlg
, &rectParent
);
691 /* when arranging controls we have to use fixed parent size */
692 rectParent
.bottom
-= help_fixup
;
694 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
697 GetWindowRect(hwndStc32
, &rectStc32
);
698 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
700 /* set the size of the stc32 control according to the size of
701 * client area of the parent dialog
703 SetWindowPos(hwndStc32
, 0,
705 rectParent
.right
, rectParent
.bottom
,
706 SWP_NOMOVE
| SWP_NOZORDER
);
709 SetRectEmpty(&rectStc32
);
711 /* this part moves controls of the child dialog */
712 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
715 if (hwndChild
!= hwndStc32
)
717 GetWindowRect(hwndChild
, &rectChild
);
718 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
720 /* move only if stc32 exist */
721 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
723 /* move to the right of visible controls of the parent dialog */
724 rectChild
.left
+= rectParent
.right
;
725 rectChild
.left
-= rectStc32
.right
;
727 /* move even if stc32 doesn't exist */
728 if (rectChild
.top
>= rectStc32
.bottom
)
730 /* move below visible controls of the parent dialog */
731 rectChild
.top
+= rectParent
.bottom
;
732 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
735 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
736 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
738 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
741 /* this part moves controls of the parent dialog */
742 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
745 if (hwndChild
!= hwndChildDlg
)
747 GetWindowRect(hwndChild
, &rectChild
);
748 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
750 /* left,top of stc32 marks the position of controls
751 * from the parent dialog
753 rectChild
.left
+= rectStc32
.left
;
754 rectChild
.top
+= rectStc32
.top
;
756 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
757 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
759 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
762 /* calculate the size of the resulting dialog */
764 /* here we have to use original parent size */
765 GetClientRect(hwndParentDlg
, &rectParent
);
766 GetClientRect(hwndChildDlg
, &rectChild
);
767 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
768 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
773 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
774 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
776 chgx
= rectChild
.right
- rectParent
.right
;
778 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
779 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
781 /* Unconditionally set new dialog
782 * height to that of the child
784 chgy
= rectChild
.bottom
- rectParent
.bottom
;
789 chgy
= rectChild
.bottom
- help_fixup
;
791 /* set the size of the parent dialog */
792 GetWindowRect(hwndParentDlg
, &rectParent
);
793 SetWindowPos(hwndParentDlg
, 0,
795 rectParent
.right
- rectParent
.left
+ chgx
,
796 rectParent
.bottom
- rectParent
.top
+ chgy
,
797 SWP_NOMOVE
| SWP_NOZORDER
);
800 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
809 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
819 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
820 * structure's hInstance parameter is not a HINSTANCE, but
821 * instead a pointer to a template resource to use.
823 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
826 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
828 hinst
= COMDLG32_hInstance
;
829 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
831 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
837 hinst
= fodInfos
->ofnInfos
->hInstance
;
838 if(fodInfos
->unicode
)
840 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
841 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
845 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
846 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
850 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
853 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
854 !(template = LockResource( hDlgTmpl
)))
856 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
860 if (fodInfos
->unicode
)
861 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
862 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
863 (LPARAM
)fodInfos
->ofnInfos
);
865 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
866 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
867 (LPARAM
)fodInfos
->ofnInfos
);
870 else if( IsHooked(fodInfos
))
875 WORD menu
,class,title
;
877 GetClientRect(hwnd
,&rectHwnd
);
878 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
879 temp
.tmplate
.dwExtendedStyle
= 0;
880 temp
.tmplate
.cdit
= 0;
885 temp
.menu
= temp
.class = temp
.title
= 0;
887 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
888 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
895 /***********************************************************************
896 * SendCustomDlgNotificationMessage
898 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
901 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
903 LRESULT hook_result
= 0;
904 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
906 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
908 if(!fodInfos
) return 0;
910 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
912 TRACE("CALL NOTIFY for %x\n", uCode
);
913 if(fodInfos
->unicode
)
916 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
917 ofnNotify
.hdr
.idFrom
=0;
918 ofnNotify
.hdr
.code
= uCode
;
919 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
920 ofnNotify
.pszFile
= NULL
;
921 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
926 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
927 ofnNotify
.hdr
.idFrom
=0;
928 ofnNotify
.hdr
.code
= uCode
;
929 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
930 ofnNotify
.pszFile
= NULL
;
931 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
933 TRACE("RET NOTIFY\n");
935 TRACE("Retval: 0x%08lx\n", hook_result
);
939 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
943 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
945 TRACE("CDM_GETFILEPATH:\n");
947 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
950 /* get path and filenames */
951 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
952 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
953 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
956 p
= buffer
+ strlenW(buffer
);
958 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
960 if (fodInfos
->unicode
)
962 total
= strlenW( buffer
) + 1;
963 if (result
) lstrcpynW( result
, buffer
, size
);
964 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
968 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
969 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
970 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
972 HeapFree( GetProcessHeap(), 0, buffer
);
976 /***********************************************************************
977 * FILEDLG95_HandleCustomDialogMessages
979 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
981 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
983 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
984 WCHAR lpstrPath
[MAX_PATH
];
987 if(!fodInfos
) return FALSE
;
991 case CDM_GETFILEPATH
:
992 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
995 case CDM_GETFOLDERPATH
:
996 TRACE("CDM_GETFOLDERPATH:\n");
997 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1000 if (fodInfos
->unicode
)
1001 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1003 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1004 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1006 retval
= lstrlenW(lpstrPath
) + 1;
1009 case CDM_GETFOLDERIDLIST
:
1010 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1011 if (retval
<= wParam
)
1012 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1016 TRACE("CDM_GETSPEC:\n");
1017 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1020 if (fodInfos
->unicode
)
1021 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1023 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1027 case CDM_SETCONTROLTEXT
:
1028 TRACE("CDM_SETCONTROLTEXT:\n");
1031 if( fodInfos
->unicode
)
1032 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1034 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1039 case CDM_HIDECONTROL
:
1040 /* MSDN states that it should fail for not OFN_EXPLORER case */
1041 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1043 HWND control
= GetDlgItem( hwnd
, wParam
);
1044 if (control
) ShowWindow( control
, SW_HIDE
);
1047 else retval
= FALSE
;
1051 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1052 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1055 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1059 /***********************************************************************
1060 * FILEDLG95_OnWMGetMMI
1062 * WM_GETMINMAXINFO message handler for resizable dialogs
1064 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1066 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1067 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1068 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1070 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1075 /***********************************************************************
1076 * FILEDLG95_OnWMSize
1078 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1080 * FIXME: this could be made more elaborate. Now use a simple scheme
1081 * where the file view is enlarged and the controls are either moved
1082 * vertically or horizontally to get out of the way. Only the "grip"
1083 * is moved in both directions to stay in the corner.
1085 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1091 FileOpenDlgInfos
*fodInfos
;
1093 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1094 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1095 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1096 /* get the new dialog rectangle */
1097 GetWindowRect( hwnd
, &rc
);
1098 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1099 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1100 /* not initialized yet */
1101 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1102 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1103 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1105 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1106 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1107 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1108 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1109 /* change the size of the view window */
1110 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1111 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1112 hdwp
= BeginDeferWindowPos( 10);
1113 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1114 rcview
.right
- rcview
.left
+ chgx
,
1115 rcview
.bottom
- rcview
.top
+ chgy
,
1116 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1117 /* change position and sizes of the controls */
1118 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1120 int ctrlid
= GetDlgCtrlID( ctrl
);
1121 GetWindowRect( ctrl
, &rc
);
1122 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1123 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1125 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1127 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1129 else if( rc
.top
> rcview
.bottom
)
1131 /* if it was below the shell view
1135 /* file name (edit or comboboxex) and file types combo change also width */
1139 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1140 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1141 SWP_NOACTIVATE
| SWP_NOZORDER
);
1143 /* then these buttons must move out of the way */
1147 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1149 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1152 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1154 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1157 else if( rc
.left
> rcview
.right
)
1159 /* if it was to the right of the shell view
1161 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1163 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1170 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1172 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1173 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1174 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1176 case IDC_TOOLBARSTATIC
:
1178 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1180 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1183 /* not resized in windows. Since wine uses this invisible control
1184 * to size the browser view it needs to be resized */
1185 case IDC_SHELLSTATIC
:
1186 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1187 rc
.right
- rc
.left
+ chgx
,
1188 rc
.bottom
- rc
.top
+ chgy
,
1189 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1194 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1195 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1197 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1198 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1200 GetWindowRect( ctrl
, &rc
);
1201 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1202 if( rc
.top
> rcview
.bottom
)
1204 /* if it was below the shell view
1206 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1207 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1208 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1210 else if( rc
.left
> rcview
.right
)
1212 /* if it was to the right of the shell view
1214 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1215 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1216 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1219 /* size the custom dialog at the end: some applications do some
1220 * control re-arranging at this point */
1221 GetClientRect(hwnd
, &rc
);
1222 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1223 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1225 EndDeferWindowPos( hdwp
);
1226 /* should not be needed */
1227 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1231 /***********************************************************************
1234 * File open dialog procedure
1236 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1239 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1246 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1248 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1249 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1251 /* Adds the FileOpenDlgInfos in the property list of the dialog
1252 so it will be easily accessible through a GetPropA(...) */
1253 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1255 FILEDLG95_InitControls(hwnd
);
1257 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1259 GetWindowRect( hwnd
, &rc
);
1260 fodInfos
->DlgInfos
.hwndGrip
=
1261 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1262 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1263 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1264 rc
.right
- gripx
, rc
.bottom
- gripy
,
1265 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1268 fodInfos
->DlgInfos
.hwndCustomDlg
=
1269 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1271 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1272 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1274 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1275 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1277 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1278 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1279 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1282 /* if the app has changed the position of the invisible listbox,
1283 * change that of the listview (browser) as well */
1284 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1285 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1286 if( !EqualRect( &rc
, &rcstc
))
1288 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1289 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1290 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1291 SWP_NOACTIVATE
| SWP_NOZORDER
);
1294 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1296 GetWindowRect( hwnd
, &rc
);
1297 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1298 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1299 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1300 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1301 GetClientRect( hwnd
, &rc
);
1302 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1303 rc
.right
- gripx
, rc
.bottom
- gripy
,
1304 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1305 /* resize the dialog to the previous invocation */
1306 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1307 SetWindowPos( hwnd
, NULL
,
1308 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1309 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1312 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1313 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1318 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1319 case WM_GETMINMAXINFO
:
1320 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1322 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1325 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1328 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1334 case WM_GETISHELLBROWSER
:
1335 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1339 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1340 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1341 MemDialogSize
= fodInfos
->sizedlg
;
1342 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1347 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1350 /* set up the button tooltips strings */
1351 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1353 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1354 switch(lpnmh
->idFrom
)
1356 /* Up folder button */
1357 case FCIDM_TB_UPFOLDER
:
1358 stringId
= IDS_UPFOLDER
;
1360 /* New folder button */
1361 case FCIDM_TB_NEWFOLDER
:
1362 stringId
= IDS_NEWFOLDER
;
1364 /* List option button */
1365 case FCIDM_TB_SMALLICON
:
1366 stringId
= IDS_LISTVIEW
;
1368 /* Details option button */
1369 case FCIDM_TB_REPORTVIEW
:
1370 stringId
= IDS_REPORTVIEW
;
1372 /* Desktop button */
1373 case FCIDM_TB_DESKTOP
:
1374 stringId
= IDS_TODESKTOP
;
1379 lpdi
->hinst
= COMDLG32_hInstance
;
1380 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1385 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1386 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1391 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1393 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1394 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1397 /***********************************************************************
1398 * FILEDLG95_InitControls
1400 * WM_INITDIALOG message handler (before hook notification)
1402 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1404 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) */
1562 WCHAR tmpBuf
[MAX_PATH
];
1563 WCHAR tmpBuf2
[MAX_PATH
];
1567 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1568 if( PathFileExistsW(tmpBuf
) ) {
1569 /* initdir does not have to be a directory. If a file is
1570 * specified, the dir part is taken */
1571 if( PathIsDirectoryW(tmpBuf
)) {
1572 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1573 lstrcatW(tmpBuf
, szwSlash
);
1575 lstrcatW(tmpBuf
, szwStar
);
1577 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1580 MemFree(fodInfos
->initdir
);
1581 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1582 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1584 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1587 else if (fodInfos
->initdir
)
1589 MemFree(fodInfos
->initdir
);
1590 fodInfos
->initdir
= NULL
;
1591 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1596 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1598 /* 3. All except w2k+: if filename contains a path use it */
1599 if (!win2000plus
&& fodInfos
->filename
&&
1600 *fodInfos
->filename
&&
1601 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1602 WCHAR tmpBuf
[MAX_PATH
];
1606 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1611 /* nameBit is always shorter than the original filename */
1612 lstrcpyW(fodInfos
->filename
, nameBit
);
1615 len
= lstrlenW(tmpBuf
);
1616 MemFree(fodInfos
->initdir
);
1617 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1618 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1621 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1622 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1624 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1627 /* 4. Win2000+: Recently used */
1628 if (!handledPath
&& win2000plus
) {
1629 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1630 fodInfos
->initdir
[0] = '\0';
1632 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1634 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1637 MemFree(fodInfos
->initdir
);
1638 fodInfos
->initdir
= NULL
;
1642 /* 5. win98+ and win2000+ if any files of specified filter types in
1643 current directory, use it */
1644 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1646 LPCWSTR lpstrPos
= fodInfos
->filter
;
1647 WIN32_FIND_DATAW FindFileData
;
1652 /* filter is a list... title\0ext\0......\0\0 */
1654 /* Skip the title */
1655 if(! *lpstrPos
) break; /* end */
1656 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1658 /* See if any files exist in the current dir with this extension */
1659 if(! *lpstrPos
) break; /* end */
1661 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1663 if (hFind
== INVALID_HANDLE_VALUE
) {
1664 /* None found - continue search */
1665 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1669 MemFree(fodInfos
->initdir
);
1670 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1671 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1674 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1675 debugstr_w(lpstrPos
));
1682 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1683 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1684 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1686 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1688 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1691 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1692 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1694 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1697 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1700 } else if (!handledPath
) {
1701 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1702 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1704 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1707 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1708 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1710 /* Must the open as read only check box be checked ?*/
1711 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1713 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1716 /* Must the open as read only check box be hidden? */
1717 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1719 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1720 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1723 /* Must the help button be hidden? */
1724 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1726 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1727 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1730 /* change Open to Save */
1731 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1734 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1735 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1736 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1737 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1740 /* Initialize the filter combo box */
1741 FILEDLG95_FILETYPE_Init(hwnd
);
1746 /***********************************************************************
1747 * FILEDLG95_ResizeControls
1749 * WM_INITDIALOG message handler (after hook notification)
1751 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1753 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1755 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1758 UINT flags
= SWP_NOACTIVATE
;
1760 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1761 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1763 /* resize the custom dialog to the parent size */
1764 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1765 GetClientRect(hwnd
, &rc
);
1768 /* our own fake template is zero sized and doesn't have children, so
1769 * there is no need to resize it. Picasa depends on it.
1771 flags
|= SWP_NOSIZE
;
1774 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1775 0, 0, rc
.right
, rc
.bottom
, flags
);
1779 /* Resize the height, if open as read only checkbox ad help button are
1780 * hidden and we are not using a custom template nor a customDialog
1782 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1783 (!(fodInfos
->ofnInfos
->Flags
&
1784 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1786 RECT rectDlg
, rectHelp
, rectCancel
;
1787 GetWindowRect(hwnd
, &rectDlg
);
1788 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1789 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1790 /* subtract the height of the help button plus the space between the help
1791 * button and the cancel button to the height of the dialog
1793 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1794 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1795 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1801 /***********************************************************************
1802 * FILEDLG95_FillControls
1804 * WM_INITDIALOG message handler (after hook notification)
1806 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1808 LPITEMIDLIST pidlItemId
= NULL
;
1810 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1812 TRACE("dir=%s file=%s\n",
1813 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1815 /* Get the initial directory pidl */
1817 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1819 WCHAR path
[MAX_PATH
];
1821 GetCurrentDirectoryW(MAX_PATH
,path
);
1822 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1825 /* Initialise shell objects */
1826 FILEDLG95_SHELL_Init(hwnd
);
1828 /* Initialize the Look In combo box */
1829 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1831 /* Browse to the initial directory */
1832 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1834 /* Free pidlItem memory */
1835 COMDLG32_SHFree(pidlItemId
);
1839 /***********************************************************************
1842 * Regroups all the cleaning functions of the filedlg
1844 void FILEDLG95_Clean(HWND hwnd
)
1846 FILEDLG95_FILETYPE_Clean(hwnd
);
1847 FILEDLG95_LOOKIN_Clean(hwnd
);
1848 FILEDLG95_SHELL_Clean(hwnd
);
1850 /***********************************************************************
1851 * FILEDLG95_OnWMCommand
1853 * WM_COMMAND message handler
1855 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1857 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1858 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1859 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1865 FILEDLG95_OnOpen(hwnd
);
1869 FILEDLG95_Clean(hwnd
);
1870 EndDialog(hwnd
, FALSE
);
1872 /* Filetype combo box */
1874 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1876 /* LookIn combo box */
1878 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1881 /* --- toolbar --- */
1882 /* Up folder button */
1883 case FCIDM_TB_UPFOLDER
:
1884 FILEDLG95_SHELL_UpFolder(hwnd
);
1886 /* New folder button */
1887 case FCIDM_TB_NEWFOLDER
:
1888 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1890 /* List option button */
1891 case FCIDM_TB_SMALLICON
:
1892 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1894 /* Details option button */
1895 case FCIDM_TB_REPORTVIEW
:
1896 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1898 /* Details option button */
1899 case FCIDM_TB_DESKTOP
:
1900 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1908 /* Do not use the listview selection anymore */
1909 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1913 /***********************************************************************
1914 * FILEDLG95_OnWMGetIShellBrowser
1916 * WM_GETISHELLBROWSER message handler
1918 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1920 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1924 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1930 /***********************************************************************
1931 * FILEDLG95_SendFileOK
1933 * Sends the CDN_FILEOK notification if required
1936 * TRUE if the dialog should close
1937 * FALSE if the dialog should not be closed
1939 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1941 /* ask the hook if we can close */
1942 if(IsHooked(fodInfos
))
1947 /* First send CDN_FILEOK as MSDN doc says */
1948 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1949 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1952 TRACE("canceled\n");
1956 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1957 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1958 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1961 TRACE("canceled\n");
1968 /***********************************************************************
1969 * FILEDLG95_OnOpenMultipleFiles
1971 * Handles the opening of multiple files.
1974 * check destination buffer size
1976 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1978 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1979 UINT nCount
, nSizePath
;
1980 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1984 if(fodInfos
->unicode
)
1986 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1987 ofn
->lpstrFile
[0] = '\0';
1991 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1992 ofn
->lpstrFile
[0] = '\0';
1995 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1997 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1998 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1999 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2001 LPWSTR lpstrTemp
= lpstrFileList
;
2003 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2007 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2010 WCHAR lpstrNotFound
[100];
2011 WCHAR lpstrMsg
[100];
2013 static const WCHAR nl
[] = {'\n',0};
2015 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2016 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2018 lstrcpyW(tmp
, lpstrTemp
);
2020 lstrcatW(tmp
, lpstrNotFound
);
2022 lstrcatW(tmp
, lpstrMsg
);
2024 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2028 /* move to the next file in the list of files */
2029 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2030 COMDLG32_SHFree(pidl
);
2034 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2035 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2037 /* For "oldstyle" dialog the components have to
2038 be separated by blanks (not '\0'!) and short
2039 filenames have to be used! */
2040 FIXME("Components have to be separated by blanks\n");
2042 if(fodInfos
->unicode
)
2044 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2045 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2046 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2050 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2052 if (ofn
->lpstrFile
!= NULL
)
2054 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2055 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2056 if (ofn
->nMaxFile
> nSizePath
)
2058 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2059 ofn
->lpstrFile
+ nSizePath
,
2060 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2065 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2066 fodInfos
->ofnInfos
->nFileExtension
= 0;
2068 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2071 /* clean and exit */
2072 FILEDLG95_Clean(hwnd
);
2073 return EndDialog(hwnd
,TRUE
);
2076 /* Returns the 'slot name' of the given module_name in the registry's
2077 * most-recently-used list. This will be an ASCII value in the
2078 * range ['a','z'). Returns zero on error.
2080 * The slot's value in the registry has the form:
2081 * module_name\0mru_path\0
2083 * If stored_path is given, then stored_path will contain the path name
2084 * stored in the registry's MRU list for the given module_name.
2086 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2087 * MRU list key for the given module_name.
2089 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2091 WCHAR mru_list
[32], *cur_mru_slot
;
2092 BOOL taken
[25] = {0};
2093 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2094 HKEY hkey_tmp
, *hkey
;
2103 *stored_path
= '\0';
2105 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2107 WARN("Unable to create MRU key: %d\n", ret
);
2111 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2112 (LPBYTE
)mru_list
, &mru_list_size
);
2113 if(ret
|| key_type
!= REG_SZ
){
2114 if(ret
== ERROR_FILE_NOT_FOUND
)
2117 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2122 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2123 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2124 DWORD value_data_size
= sizeof(value_data
);
2126 *value_name
= *cur_mru_slot
;
2128 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2129 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2130 if(ret
|| key_type
!= REG_BINARY
){
2131 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2135 if(!strcmpiW(module_name
, value_data
)){
2139 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2147 /* the module name isn't in the registry, so find the next open slot */
2148 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2149 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2150 for(i
= 0; i
< 25; ++i
){
2155 /* all slots are taken, so return the last one in MRUList */
2157 return *cur_mru_slot
;
2160 /* save the given filename as most-recently-used path for this module */
2161 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2163 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2167 /* get the current executable's name */
2168 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2169 WARN("GotModuleFileName failed: %d\n", GetLastError());
2172 module_name
= strrchrW(module_path
, '\\');
2174 module_name
= module_path
;
2178 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2183 { /* update the slot's info */
2184 WCHAR
*path_ends
, *final
;
2185 DWORD path_len
, final_len
;
2187 /* use only the path segment of `filename' */
2188 path_ends
= strrchrW(filename
, '\\');
2189 path_len
= path_ends
- filename
;
2191 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2193 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2196 lstrcpyW(final
, module_name
);
2197 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2198 final
[final_len
-1] = '\0';
2200 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2201 final_len
* sizeof(WCHAR
));
2203 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2212 { /* update MRUList value */
2213 WCHAR old_mru_list
[32], new_mru_list
[32];
2214 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2215 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2217 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2218 (LPBYTE
)old_mru_list
, &mru_list_size
);
2219 if(ret
|| key_type
!= REG_SZ
){
2220 if(ret
== ERROR_FILE_NOT_FOUND
){
2221 new_mru_list
[0] = slot
;
2222 new_mru_list
[1] = '\0';
2224 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2229 /* copy old list data over so that the new slot is at the start
2231 *new_mru_slot
++ = slot
;
2232 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2233 if(*old_mru_slot
!= slot
)
2234 *new_mru_slot
++ = *old_mru_slot
;
2236 *new_mru_slot
= '\0';
2239 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2240 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2242 WARN("Error saving MRUList data: %d\n", ret
);
2249 /* load the most-recently-used path for this module */
2250 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2252 WCHAR module_path
[MAX_PATH
], *module_name
;
2254 /* get the current executable's name */
2255 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2256 WARN("GotModuleFileName failed: %d\n", GetLastError());
2259 module_name
= strrchrW(module_path
, '\\');
2261 module_name
= module_path
;
2265 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2266 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2269 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2271 WCHAR strMsgTitle
[MAX_PATH
];
2272 WCHAR strMsgText
[MAX_PATH
];
2274 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2276 strMsgTitle
[0] = '\0';
2277 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2278 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2281 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2282 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2284 int nOpenAction
= defAction
;
2285 LPWSTR lpszTemp
, lpszTemp1
;
2286 LPITEMIDLIST pidl
= NULL
;
2287 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2289 /* check for invalid chars */
2290 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2292 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2296 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2298 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2301 LPSHELLFOLDER lpsfChild
;
2302 WCHAR lpwstrTemp
[MAX_PATH
];
2303 DWORD dwEaten
, dwAttributes
;
2306 lstrcpyW(lpwstrTemp
, lpszTemp
);
2307 p
= PathFindNextComponentW(lpwstrTemp
);
2309 if (!p
) break; /* end of path */
2312 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2314 /* There are no wildcards when OFN_NOVALIDATE is set */
2315 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2317 static const WCHAR wszWild
[] = { '*', '?', 0 };
2318 /* if the last element is a wildcard do a search */
2319 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2321 nOpenAction
= ONOPEN_SEARCH
;
2325 lpszTemp1
= lpszTemp
;
2327 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2329 /* append a backslash to drive letters */
2330 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2331 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2332 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2334 PathAddBackslashW(lpwstrTemp
);
2337 dwAttributes
= SFGAO_FOLDER
;
2338 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2340 /* the path component is valid, we have a pidl of the next path component */
2341 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2342 if(dwAttributes
& SFGAO_FOLDER
)
2344 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2346 ERR("bind to failed\n"); /* should not fail */
2349 IShellFolder_Release(*ppsf
);
2357 /* end dialog, return value */
2358 nOpenAction
= ONOPEN_OPEN
;
2361 COMDLG32_SHFree(pidl
);
2364 else if (!(flags
& OFN_NOVALIDATE
))
2366 if(*lpszTemp
|| /* points to trailing null for last path element */
2367 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2369 if(flags
& OFN_PATHMUSTEXIST
)
2371 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2377 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2379 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2383 /* change to the current folder */
2384 nOpenAction
= ONOPEN_OPEN
;
2389 nOpenAction
= ONOPEN_OPEN
;
2393 if(pidl
) COMDLG32_SHFree(pidl
);
2398 /***********************************************************************
2401 * Ok button WM_COMMAND message handler
2403 * If the function succeeds, the return value is nonzero.
2405 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2407 LPWSTR lpstrFileList
;
2408 UINT nFileCount
= 0;
2411 WCHAR lpstrPathAndFile
[MAX_PATH
];
2412 LPSHELLFOLDER lpsf
= NULL
;
2414 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2416 TRACE("hwnd=%p\n", hwnd
);
2418 /* try to browse the selected item */
2419 if(BrowseSelectedFolder(hwnd
))
2422 /* get the files from the edit control */
2423 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2430 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2434 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2437 Step 1: Build a complete path name from the current folder and
2438 the filename or path in the edit box.
2440 - the path in the edit box is a root path
2441 (with or without drive letter)
2442 - the edit box contains ".." (or a path with ".." in it)
2445 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2446 MemFree(lpstrFileList
);
2449 Step 2: here we have a cleaned up path
2451 We have to parse the path step by step to see if we have to browse
2452 to a folder if the path points to a directory or the last
2453 valid element is a directory.
2456 lpstrPathAndFile: cleaned up path
2460 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2461 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2462 nOpenAction
= ONOPEN_OPEN
;
2464 nOpenAction
= ONOPEN_BROWSE
;
2466 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2467 fodInfos
->ofnInfos
->Flags
,
2468 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2474 Step 3: here we have a cleaned up and validated path
2477 lpsf: ShellFolder bound to the rightmost valid path component
2478 lpstrPathAndFile: cleaned up path
2479 nOpenAction: action to do
2481 TRACE("end validate sf=%p\n", lpsf
);
2485 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2486 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2489 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2492 /* replace the current filter */
2493 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2494 len
= lstrlenW(lpszTemp
)+1;
2495 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2496 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2498 /* set the filter cb to the extension when possible */
2499 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2500 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2503 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2504 TRACE("ONOPEN_BROWSE\n");
2506 IPersistFolder2
* ppf2
;
2507 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2509 LPITEMIDLIST pidlCurrent
;
2510 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2511 IPersistFolder2_Release(ppf2
);
2512 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2514 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2515 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2517 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2520 else if( nOpenAction
== ONOPEN_SEARCH
)
2522 if (fodInfos
->Shell
.FOIShellView
)
2523 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2525 COMDLG32_SHFree(pidlCurrent
);
2526 if (filename_is_edit( fodInfos
))
2527 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2532 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2533 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2537 /* update READONLY check box flag */
2538 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2539 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2541 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2543 /* Attach the file extension with file name*/
2544 ext
= PathFindExtensionW(lpstrPathAndFile
);
2545 if (! *ext
&& fodInfos
->defext
)
2547 /* if no extension is specified with file name, then */
2548 /* attach the extension from file filter or default one */
2550 WCHAR
*filterExt
= NULL
;
2551 LPWSTR lpstrFilter
= NULL
;
2552 static const WCHAR szwDot
[] = {'.',0};
2553 int PathLength
= lstrlenW(lpstrPathAndFile
);
2555 /*Get the file extension from file type filter*/
2556 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2557 fodInfos
->ofnInfos
->nFilterIndex
-1);
2559 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2561 WCHAR
* filterSearchIndex
;
2562 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2563 strcpyW(filterExt
, lpstrFilter
);
2565 /* if a semicolon-separated list of file extensions was given, do not include the
2566 semicolon or anything after it in the extension.
2567 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2568 filterSearchIndex
= strchrW(filterExt
, ';');
2569 if (filterSearchIndex
)
2571 filterSearchIndex
[0] = '\0';
2574 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2575 /* if the extension is invalid or contains a glob, ignore it */
2576 filterSearchIndex
= PathFindExtensionW(filterExt
);
2577 if (*filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2579 strcpyW(filterExt
, filterSearchIndex
);
2583 HeapFree(GetProcessHeap(), 0, filterExt
);
2590 /* use the default file extension */
2591 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2592 strcpyW(filterExt
, fodInfos
->defext
);
2595 if (*filterExt
) /* ignore filterExt="" */
2598 lstrcatW(lpstrPathAndFile
, szwDot
);
2599 /* Attach the extension */
2600 lstrcatW(lpstrPathAndFile
, filterExt
);
2603 HeapFree(GetProcessHeap(), 0, filterExt
);
2605 /* In Open dialog: if file does not exist try without extension */
2606 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2607 lpstrPathAndFile
[PathLength
] = '\0';
2609 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2612 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2613 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2615 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2618 /* In Save dialog: check if the file already exists */
2619 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2620 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2621 && PathFileExistsW(lpstrPathAndFile
))
2623 WCHAR lpstrOverwrite
[100];
2626 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2627 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2628 MB_YESNO
| MB_ICONEXCLAMATION
);
2629 if (answer
== IDNO
|| answer
== IDCANCEL
)
2636 /* In Open dialog: check if it should be created if it doesn't exist */
2637 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2638 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2639 && !PathFileExistsW(lpstrPathAndFile
))
2641 WCHAR lpstrCreate
[100];
2644 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2645 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2646 MB_YESNO
| MB_ICONEXCLAMATION
);
2647 if (answer
== IDNO
|| answer
== IDCANCEL
)
2654 /* Check that the size of the file does not exceed buffer size.
2655 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2656 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2657 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2660 /* fill destination buffer */
2661 if (fodInfos
->ofnInfos
->lpstrFile
)
2663 if(fodInfos
->unicode
)
2665 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2667 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2668 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2669 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2673 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2675 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2676 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2677 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2678 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2682 if(fodInfos
->unicode
)
2686 /* set filename offset */
2687 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2688 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2690 /* set extension offset */
2691 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2692 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2697 CHAR tempFileA
[MAX_PATH
];
2699 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2700 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2701 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2703 /* set filename offset */
2704 lpszTemp
= PathFindFileNameA(tempFileA
);
2705 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2707 /* set extension offset */
2708 lpszTemp
= PathFindExtensionA(tempFileA
);
2709 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2712 /* set the lpstrFileTitle */
2713 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2715 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2716 if(fodInfos
->unicode
)
2718 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2719 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2723 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2724 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2725 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2729 /* copy currently selected filter to lpstrCustomFilter */
2730 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2732 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2733 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2734 NULL
, 0, NULL
, NULL
);
2735 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2737 LPSTR s
= ofn
->lpstrCustomFilter
;
2738 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2739 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2740 s
, len
, NULL
, NULL
);
2745 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2748 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2751 FILEDLG95_Clean(hwnd
);
2752 ret
= EndDialog(hwnd
, TRUE
);
2758 size
= lstrlenW(lpstrPathAndFile
) + 1;
2759 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2761 /* return needed size in first two bytes of lpstrFile */
2762 if(fodInfos
->ofnInfos
->lpstrFile
)
2763 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2764 FILEDLG95_Clean(hwnd
);
2765 ret
= EndDialog(hwnd
, FALSE
);
2766 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2773 if(lpsf
) IShellFolder_Release(lpsf
);
2777 /***********************************************************************
2778 * FILEDLG95_SHELL_Init
2780 * Initialisation of the shell objects
2782 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2784 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2789 * Initialisation of the FileOpenDialogInfos structure
2795 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2797 /* Disable multi-select if flag not set */
2798 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2800 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2802 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2803 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2805 /* Construct the IShellBrowser interface */
2806 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2811 /***********************************************************************
2812 * FILEDLG95_SHELL_ExecuteCommand
2814 * Change the folder option and refresh the view
2815 * If the function succeeds, the return value is nonzero.
2817 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2819 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2822 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2824 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2829 CMINVOKECOMMANDINFO ci
;
2830 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2831 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2835 IContextMenu_InvokeCommand(pcm
, &ci
);
2836 IContextMenu_Release(pcm
);
2842 /***********************************************************************
2843 * FILEDLG95_SHELL_UpFolder
2845 * Browse to the specified object
2846 * If the function succeeds, the return value is nonzero.
2848 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2850 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2854 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2858 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2859 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2865 /***********************************************************************
2866 * FILEDLG95_SHELL_BrowseToDesktop
2868 * Browse to the Desktop
2869 * If the function succeeds, the return value is nonzero.
2871 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2873 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2879 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2880 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2881 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2882 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2883 COMDLG32_SHFree(pidl
);
2884 return SUCCEEDED(hres
);
2886 /***********************************************************************
2887 * FILEDLG95_SHELL_Clean
2889 * Cleans the memory used by shell objects
2891 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2893 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2897 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2899 /* clean Shell interfaces */
2900 if (fodInfos
->Shell
.FOIShellView
)
2902 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2903 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2905 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2906 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2907 if (fodInfos
->Shell
.FOIDataObject
)
2908 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2911 /***********************************************************************
2912 * FILEDLG95_FILETYPE_Init
2914 * Initialisation of the file type combo box
2916 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2918 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2919 int nFilters
= 0; /* number of filters */
2924 if(fodInfos
->customfilter
)
2926 /* customfilter has one entry... title\0ext\0
2927 * Set first entry of combo box item with customfilter
2930 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2933 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2935 /* Copy the extensions */
2936 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2937 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2938 lstrcpyW(lpstrExt
,lpstrPos
);
2940 /* Add the item at the end of the combo */
2941 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2942 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2945 if(fodInfos
->filter
)
2947 LPCWSTR lpstrPos
= fodInfos
->filter
;
2951 /* filter is a list... title\0ext\0......\0\0
2952 * Set the combo item text to the title and the item data
2955 LPCWSTR lpstrDisplay
;
2959 if(! *lpstrPos
) break; /* end */
2960 lpstrDisplay
= lpstrPos
;
2961 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2963 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2967 /* Copy the extensions */
2968 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2969 lstrcpyW(lpstrExt
,lpstrPos
);
2970 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2972 /* Add the item at the end of the combo */
2973 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2975 /* malformed filters are added anyway... */
2976 if (!*lpstrExt
) break;
2981 * Set the current filter to the one specified
2982 * in the initialisation structure
2984 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2988 /* Check to make sure our index isn't out of bounds. */
2989 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2990 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2991 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2993 /* set default filter index */
2994 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2995 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2997 /* calculate index of Combo Box item */
2998 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2999 if (fodInfos
->customfilter
== NULL
)
3002 /* Set the current index selection. */
3003 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3005 /* Get the corresponding text string from the combo box. */
3006 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3009 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3015 CharLowerW(lpstrFilter
); /* lowercase */
3016 len
= lstrlenW(lpstrFilter
)+1;
3017 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3018 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3021 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3025 /***********************************************************************
3026 * FILEDLG95_FILETYPE_OnCommand
3028 * WM_COMMAND of the file type combo box
3029 * If the function succeeds, the return value is nonzero.
3031 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3033 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3041 /* Get the current item of the filetype combo box */
3042 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3044 /* set the current filter index */
3045 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3046 (fodInfos
->customfilter
== NULL
? 1 : 0);
3048 /* Set the current filter with the current selection */
3049 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3051 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3053 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3056 CharLowerW(lpstrFilter
); /* lowercase */
3057 len
= lstrlenW(lpstrFilter
)+1;
3058 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3059 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3060 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3061 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3064 /* Refresh the actual view to display the included items*/
3065 if (fodInfos
->Shell
.FOIShellView
)
3066 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3071 /***********************************************************************
3072 * FILEDLG95_FILETYPE_SearchExt
3074 * searches for an extension in the filetype box
3076 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3078 int i
, iCount
= CBGetCount(hwnd
);
3080 TRACE("%s\n", debugstr_w(lpstrExt
));
3082 if(iCount
!= CB_ERR
)
3084 for(i
=0;i
<iCount
;i
++)
3086 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3093 /***********************************************************************
3094 * FILEDLG95_FILETYPE_Clean
3096 * Clean the memory used by the filetype combo box
3098 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3100 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3102 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3106 /* Delete each string of the combo and their associated data */
3107 if(iCount
!= CB_ERR
)
3109 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3111 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3112 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3115 /* Current filter */
3116 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3120 /***********************************************************************
3121 * FILEDLG95_LOOKIN_Init
3123 * Initialisation of the look in combo box
3126 /* Small helper function, to determine if the unixfs shell extension is rooted
3127 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3129 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3131 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3132 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3133 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3134 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3135 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3136 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3137 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3139 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3146 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3148 IShellFolder
*psfRoot
, *psfDrives
;
3149 IEnumIDList
*lpeRoot
, *lpeDrives
;
3150 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3153 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3157 liInfos
->iMaxIndentation
= 0;
3159 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3161 hdc
= GetDC( hwndCombo
);
3162 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3163 GetTextMetricsW( hdc
, &tm
);
3164 ReleaseDC( hwndCombo
, hdc
);
3166 /* set item height for both text field and listbox */
3167 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3168 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3170 /* Turn on the extended UI for the combo box like Windows does */
3171 CBSetExtendedUI(hwndCombo
, TRUE
);
3173 /* Initialise data of Desktop folder */
3174 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3175 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3176 COMDLG32_SHFree(pidlTmp
);
3178 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3180 SHGetDesktopFolder(&psfRoot
);
3184 /* enumerate the contents of the desktop */
3185 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3187 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3189 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3191 /* If the unixfs extension is rooted, we don't expand the drives by default */
3192 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3194 /* special handling for CSIDL_DRIVES */
3195 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3197 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3199 /* enumerate the drives */
3200 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3202 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3204 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3205 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3206 COMDLG32_SHFree(pidlAbsTmp
);
3207 COMDLG32_SHFree(pidlTmp1
);
3209 IEnumIDList_Release(lpeDrives
);
3211 IShellFolder_Release(psfDrives
);
3216 COMDLG32_SHFree(pidlTmp
);
3218 IEnumIDList_Release(lpeRoot
);
3220 IShellFolder_Release(psfRoot
);
3223 COMDLG32_SHFree(pidlDrives
);
3226 /***********************************************************************
3227 * FILEDLG95_LOOKIN_DrawItem
3229 * WM_DRAWITEM message handler
3231 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3233 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3234 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3235 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3239 HIMAGELIST ilItemImage
;
3242 LPSFOLDER tmpFolder
;
3243 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
3244 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3245 UINT icon_width
, icon_height
;
3249 if(pDIStruct
->itemID
== -1)
3252 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3253 pDIStruct
->itemID
)))
3257 icon_width
= GetSystemMetrics(SM_CXICON
);
3258 icon_height
= GetSystemMetrics(SM_CYICON
);
3259 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3261 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3262 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3263 shgfi_flags
|= SHGFI_SMALLICON
;
3266 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
3268 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3269 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3273 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3274 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3277 /* Is this item selected ? */
3278 if(pDIStruct
->itemState
& ODS_SELECTED
)
3280 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3281 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3282 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3286 SetTextColor(pDIStruct
->hDC
,crText
);
3287 SetBkColor(pDIStruct
->hDC
,crWin
);
3288 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3291 /* Do not indent item if drawing in the edit of the combo */
3292 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3295 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3296 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3301 iIndentation
= tmpFolder
->m_iIndent
;
3303 /* Draw text and icon */
3305 /* Initialise the icon display area */
3306 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3307 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3308 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3309 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3311 /* Initialise the text display area */
3312 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3313 rectText
.left
= rectIcon
.right
;
3315 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3316 rectText
.right
= pDIStruct
->rcItem
.right
;
3318 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3320 /* Draw the icon from the image list */
3321 ImageList_Draw(ilItemImage
,
3328 /* Draw the associated text */
3329 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3333 /***********************************************************************
3334 * FILEDLG95_LOOKIN_OnCommand
3336 * LookIn combo box WM_COMMAND message handler
3337 * If the function succeeds, the return value is nonzero.
3339 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3341 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3343 TRACE("%p\n", fodInfos
);
3349 LPSFOLDER tmpFolder
;
3352 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3354 if( iItem
== CB_ERR
) return FALSE
;
3356 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3361 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3362 tmpFolder
->pidlItem
,
3365 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3366 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3376 /***********************************************************************
3377 * FILEDLG95_LOOKIN_AddItem
3379 * Adds an absolute pidl item to the lookin combo box
3380 * returns the index of the inserted item
3382 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3384 LPITEMIDLIST pidlNext
;
3387 LookInInfos
*liInfos
;
3389 TRACE("%08x\n", iInsertId
);
3394 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3397 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3398 tmpFolder
->m_iIndent
= 0;
3400 /* Calculate the indentation of the item in the lookin*/
3402 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3404 tmpFolder
->m_iIndent
++;
3407 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3409 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3410 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3412 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3413 SHGetFileInfoW((LPCWSTR
)pidl
,
3417 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3418 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3420 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3422 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3426 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3428 /* Add the item at the end of the list */
3431 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3433 /* Insert the item at the iInsertId position*/
3436 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3439 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3443 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3444 MemFree( tmpFolder
);
3449 /***********************************************************************
3450 * FILEDLG95_LOOKIN_InsertItemAfterParent
3452 * Insert an item below its parent
3454 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3457 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3462 if (pidl
== pidlParent
)
3465 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3469 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3472 /* Free pidlParent memory */
3473 COMDLG32_SHFree(pidlParent
);
3475 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3478 /***********************************************************************
3479 * FILEDLG95_LOOKIN_SelectItem
3481 * Adds an absolute pidl item to the lookin combo box
3482 * returns the index of the inserted item
3484 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3487 LookInInfos
*liInfos
;
3491 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3493 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3497 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3498 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3503 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3504 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3508 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3510 if(iRemovedItem
< iItemPos
)
3515 CBSetCurSel(hwnd
,iItemPos
);
3516 liInfos
->uSelectedItem
= iItemPos
;
3522 /***********************************************************************
3523 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3525 * Remove the item with an expansion level over iExpansionLevel
3527 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3530 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3534 if(liInfos
->iMaxIndentation
<= 2)
3537 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3539 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3540 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3542 CBDeleteString(hwnd
,iItemPos
);
3543 liInfos
->iMaxIndentation
--;
3551 /***********************************************************************
3552 * FILEDLG95_LOOKIN_SearchItem
3554 * Search for pidl in the lookin combo box
3555 * returns the index of the found item
3557 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3560 int iCount
= CBGetCount(hwnd
);
3562 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3564 if (iCount
!= CB_ERR
)
3568 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3570 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3572 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3580 /***********************************************************************
3581 * FILEDLG95_LOOKIN_Clean
3583 * Clean the memory used by the lookin combo box
3585 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3587 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3588 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3590 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3594 /* Delete each string of the combo and their associated data */
3595 if (iCount
!= CB_ERR
)
3597 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3599 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3600 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3602 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3606 /* LookInInfos structure */
3608 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3611 /***********************************************************************
3612 * FILEDLG95_FILENAME_FillFromSelection
3614 * fills the edit box from the cached DataObject
3616 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3618 FileOpenDlgInfos
*fodInfos
;
3620 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3621 WCHAR lpstrTemp
[MAX_PATH
];
3622 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3625 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3627 /* Count how many files we have */
3628 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3630 /* calculate the string length, count files */
3631 if (nFileSelected
>= 1)
3633 nLength
+= 3; /* first and last quotes, trailing \0 */
3634 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3636 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3640 /* get the total length of the selected file names */
3641 lpstrTemp
[0] = '\0';
3642 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3644 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3646 nLength
+= lstrlenW( lpstrTemp
) + 3;
3649 COMDLG32_SHFree( pidl
);
3654 /* allocate the buffer */
3655 if (nFiles
<= 1) nLength
= MAX_PATH
;
3656 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3658 /* Generate the string for the edit control */
3661 lpstrCurrFile
= lpstrAllFile
;
3662 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3664 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3668 /* get the file name */
3669 lpstrTemp
[0] = '\0';
3670 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3672 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3676 *lpstrCurrFile
++ = '\"';
3677 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3678 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3679 *lpstrCurrFile
++ = '\"';
3680 *lpstrCurrFile
++ = ' ';
3685 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3688 COMDLG32_SHFree( pidl
);
3691 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3693 /* Select the file name like Windows does */
3694 if (filename_is_edit( fodInfos
))
3695 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3697 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3701 /* copied from shell32 to avoid linking to it
3702 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3703 * is dependent on whether emulated OS is unicode or not.
3705 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3710 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3711 COMDLG32_SHFree(src
->u
.pOleStr
);
3715 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3720 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3725 FIXME("unknown type %x!\n", src
->uType
);
3726 if (len
) *dest
= '\0';
3732 /***********************************************************************
3733 * FILEDLG95_FILENAME_GetFileNames
3735 * Copies the filenames to a delimited string list.
3737 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3739 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3740 UINT nFileCount
= 0; /* number of files */
3741 UINT nStrLen
= 0; /* length of string in edit control */
3742 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3746 /* get the filenames from the filename control */
3747 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3748 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3749 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3751 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3753 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3758 #define SETDefFormatEtc(fe,cf,med) \
3760 (fe).cfFormat = cf;\
3761 (fe).dwAspect = DVASPECT_CONTENT; \
3768 * DATAOBJECT Helper functions
3771 /***********************************************************************
3772 * COMCTL32_ReleaseStgMedium
3774 * like ReleaseStgMedium from ole32
3776 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3778 if(medium
.pUnkForRelease
)
3780 IUnknown_Release(medium
.pUnkForRelease
);
3784 GlobalUnlock(medium
.u
.hGlobal
);
3785 GlobalFree(medium
.u
.hGlobal
);
3789 /***********************************************************************
3790 * GetPidlFromDataObject
3792 * Return pidl(s) by number from the cached DataObject
3794 * nPidlIndex=0 gets the fully qualified root path
3796 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3800 FORMATETC formatetc
;
3801 LPITEMIDLIST pidl
= NULL
;
3803 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3808 /* Set the FORMATETC structure*/
3809 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3811 /* Get the pidls from IDataObject */
3812 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3814 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3815 if(nPidlIndex
<= cida
->cidl
)
3817 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3819 COMCTL32_ReleaseStgMedium(medium
);
3824 /***********************************************************************
3827 * Return the number of selected items in the DataObject.
3830 static UINT
GetNumSelected( IDataObject
*doSelected
)
3834 FORMATETC formatetc
;
3836 TRACE("sv=%p\n", doSelected
);
3838 if (!doSelected
) return 0;
3840 /* Set the FORMATETC structure*/
3841 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3843 /* Get the pidls from IDataObject */
3844 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3846 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3847 retVal
= cida
->cidl
;
3848 COMCTL32_ReleaseStgMedium(medium
);
3858 /***********************************************************************
3861 * Get the pidl's display name (relative to folder) and
3862 * put it in lpstrFileName.
3864 * Return NOERROR on success,
3868 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3873 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3877 SHGetDesktopFolder(&lpsf
);
3878 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3879 IShellFolder_Release(lpsf
);
3883 /* Get the display name of the pidl relative to the folder */
3884 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3886 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3891 /***********************************************************************
3892 * GetShellFolderFromPidl
3894 * pidlRel is the item pidl relative
3895 * Return the IShellFolder of the absolute pidl
3897 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3899 IShellFolder
*psf
= NULL
,*psfParent
;
3901 TRACE("%p\n", pidlAbs
);
3903 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3906 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3908 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3910 IShellFolder_Release(psfParent
);
3914 /* return the desktop */
3920 /***********************************************************************
3923 * Return the LPITEMIDLIST to the parent of the pidl in the list
3925 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3927 LPITEMIDLIST pidlParent
;
3929 TRACE("%p\n", pidl
);
3931 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3932 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3937 /***********************************************************************
3940 * returns the pidl of the file name relative to folder
3941 * NULL if an error occurred
3943 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3945 LPITEMIDLIST pidl
= NULL
;
3948 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3950 if(!lpcstrFileName
) return NULL
;
3951 if(!*lpcstrFileName
) return NULL
;
3955 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3956 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3957 IShellFolder_Release(lpsf
);
3962 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3969 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3971 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3974 TRACE("%p, %p\n", psf
, pidl
);
3976 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3978 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3979 /* see documentation shell 4.1*/
3980 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3983 /***********************************************************************
3984 * BrowseSelectedFolder
3986 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3988 BOOL bBrowseSelFolder
= FALSE
;
3989 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3993 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3995 LPITEMIDLIST pidlSelection
;
3997 /* get the file selected */
3998 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3999 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4001 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4002 pidlSelection
, SBSP_RELATIVE
) ) )
4004 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
4005 ' ','n','o','t',' ','e','x','i','s','t',0};
4006 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4008 bBrowseSelFolder
= TRUE
;
4009 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4010 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4012 COMDLG32_SHFree( pidlSelection
);
4015 return bBrowseSelFolder
;
4019 * Memory allocation methods */
4020 static void *MemAlloc(UINT size
)
4022 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4025 static void MemFree(void *mem
)
4027 HeapFree(GetProcessHeap(),0,mem
);
4030 static inline BOOL
valid_struct_size( DWORD size
)
4032 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4033 (size
== sizeof( OPENFILENAMEW
));
4036 static inline BOOL
is_win16_looks(DWORD flags
)
4038 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4039 !(flags
& OFN_EXPLORER
));
4042 /* ------------------ APIs ---------------------- */
4044 /***********************************************************************
4045 * GetOpenFileNameA (COMDLG32.@)
4047 * Creates a dialog box for the user to select a file to open.
4050 * TRUE on success: user enters a valid file
4051 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4054 BOOL WINAPI
GetOpenFileNameA(
4055 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4057 TRACE("flags %08x\n", ofn
->Flags
);
4059 if (!valid_struct_size( ofn
->lStructSize
))
4061 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4065 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4066 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4067 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4069 if (is_win16_looks(ofn
->Flags
))
4070 return GetFileName31A(ofn
, OPEN_DIALOG
);
4072 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4075 /***********************************************************************
4076 * GetOpenFileNameW (COMDLG32.@)
4078 * Creates a dialog box for the user to select a file to open.
4081 * TRUE on success: user enters a valid file
4082 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4085 BOOL WINAPI
GetOpenFileNameW(
4086 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4088 TRACE("flags %08x\n", ofn
->Flags
);
4090 if (!valid_struct_size( ofn
->lStructSize
))
4092 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4096 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4097 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4098 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4100 if (is_win16_looks(ofn
->Flags
))
4101 return GetFileName31W(ofn
, OPEN_DIALOG
);
4103 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4107 /***********************************************************************
4108 * GetSaveFileNameA (COMDLG32.@)
4110 * Creates a dialog box for the user to select a file to save.
4113 * TRUE on success: user enters a valid file
4114 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4117 BOOL WINAPI
GetSaveFileNameA(
4118 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4120 if (!valid_struct_size( ofn
->lStructSize
))
4122 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4126 if (is_win16_looks(ofn
->Flags
))
4127 return GetFileName31A(ofn
, SAVE_DIALOG
);
4129 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4132 /***********************************************************************
4133 * GetSaveFileNameW (COMDLG32.@)
4135 * Creates a dialog box for the user to select a file to save.
4138 * TRUE on success: user enters a valid file
4139 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4142 BOOL WINAPI
GetSaveFileNameW(
4143 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4145 if (!valid_struct_size( ofn
->lStructSize
))
4147 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4151 if (is_win16_looks(ofn
->Flags
))
4152 return GetFileName31W(ofn
, SAVE_DIALOG
);
4154 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4157 /***********************************************************************
4158 * GetFileTitleA (COMDLG32.@)
4160 * See GetFileTitleW.
4162 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4165 UNICODE_STRING strWFile
;
4168 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4169 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4170 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4171 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4172 RtlFreeUnicodeString( &strWFile
);
4173 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4178 /***********************************************************************
4179 * GetFileTitleW (COMDLG32.@)
4181 * Get the name of a file.
4184 * lpFile [I] name and location of file
4185 * lpTitle [O] returned file name
4186 * cbBuf [I] buffer size of lpTitle
4190 * Failure: negative number.
4192 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4195 static const WCHAR brkpoint
[] = {'*','[',']',0};
4196 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4198 if(lpFile
== NULL
|| lpTitle
== NULL
)
4201 len
= lstrlenW(lpFile
);
4206 if(strpbrkW(lpFile
, brkpoint
))
4211 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4214 for(i
= len
; i
>= 0; i
--)
4216 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4226 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4228 len
= lstrlenW(lpFile
+i
)+1;
4232 lstrcpyW(lpTitle
, &lpFile
[i
]);