2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
73 #include "filedlgbrowser.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex
; /* Index of picture in image list */
95 int m_iIndent
; /* Indentation index */
96 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
100 typedef struct tagLookInInfo
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
166 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
168 static const WCHAR LastVisitedMRUW
[] =
169 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
172 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
173 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
175 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
177 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
179 return GetPropW(hwnd
, filedlg_info_propnameW
);
182 /***********************************************************************
186 /* Internal functions used by the dialog */
187 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
188 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
189 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
190 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
191 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
192 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
193 static void FILEDLG95_Clean(HWND hwnd
);
195 /* Functions used by the shell navigation */
196 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
197 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
198 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
199 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
200 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
202 /* Functions used by the EDIT box */
203 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
205 /* Functions used by the filetype combo box */
206 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
207 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
208 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
209 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
211 /* Functions used by the Look In combo box */
212 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
213 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
214 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
215 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
216 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
217 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
218 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
219 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
220 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
222 /* Functions for dealing with the most-recently-used registry keys */
223 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
224 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
225 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
227 /* Miscellaneous tool functions */
228 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
229 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
230 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
231 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
232 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
233 static UINT
GetNumSelected( IDataObject
*doSelected
);
234 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
236 /* Shell memory allocation */
237 static void *MemAlloc(UINT size
);
238 static void MemFree(void *mem
);
240 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
241 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
242 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
243 static BOOL
BrowseSelectedFolder(HWND hwnd
);
245 /***********************************************************************
248 * Creates an Open common dialog box that lets the user select
249 * the drive, directory, and the name of a file or set of files to open.
251 * IN : The FileOpenDlgInfos structure associated with the dialog
252 * OUT : TRUE on success
253 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
255 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
262 /* test for missing functionality */
263 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
265 FIXME("Flags 0x%08x not yet implemented\n",
266 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
269 /* Create the dialog from a template */
271 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
273 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
276 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
277 !(template = LockResource( hDlgTmpl
)))
279 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
283 /* msdn: explorer style dialogs permit sizing by default.
284 * The OFN_ENABLESIZING flag is only needed when a hook or
285 * custom template is provided */
286 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
287 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
288 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
290 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
292 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
293 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
296 /* old style hook messages */
297 if (IsHooked(fodInfos
))
299 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
300 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
301 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
302 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
305 if (fodInfos
->unicode
)
306 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
308 fodInfos
->ofnInfos
->hwndOwner
,
312 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
314 fodInfos
->ofnInfos
->hwndOwner
,
317 if (fodInfos
->ole_initialized
)
320 /* Unable to create the dialog */
327 static WCHAR
*heap_strdupAtoW(const char *str
)
335 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
336 ret
= MemAlloc(len
* sizeof(WCHAR
));
337 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
342 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
344 INITCOMMONCONTROLSEX icc
;
346 /* Initialize ComboBoxEx32 */
347 icc
.dwSize
= sizeof(icc
);
348 icc
.dwICC
= ICC_USEREX_CLASSES
;
349 InitCommonControlsEx(&icc
);
351 /* Initialize CommDlgExtendedError() */
352 COMDLG32_SetCommDlgExtendedError(0);
354 memset(info
, 0, sizeof(*info
));
356 /* Pass in the original ofn */
357 info
->ofnInfos
= ofn
;
359 info
->title
= ofn
->lpstrTitle
;
360 info
->defext
= ofn
->lpstrDefExt
;
361 info
->filter
= ofn
->lpstrFilter
;
362 info
->customfilter
= ofn
->lpstrCustomFilter
;
366 info
->filename
= MemAlloc(ofn
->nMaxFile
* sizeof(WCHAR
));
367 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
370 if (ofn
->lpstrInitialDir
)
372 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
375 info
->initdir
= MemAlloc(len
* sizeof(WCHAR
));
376 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
380 info
->unicode
= TRUE
;
383 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
388 ofnW
= *(OPENFILENAMEW
*)ofn
;
390 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
391 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
392 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
396 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
397 ofnW
.lpstrFile
= MemAlloc(len
* sizeof(WCHAR
));
398 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
402 if (ofn
->lpstrFilter
)
407 /* filter is a list... title\0ext\0......\0\0 */
408 s
= ofn
->lpstrFilter
;
409 while (*s
) s
= s
+strlen(s
)+1;
411 n
= s
- ofn
->lpstrFilter
;
412 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
413 ofnW
.lpstrFilter
= MemAlloc(len
* sizeof(WCHAR
));
414 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
417 /* convert lpstrCustomFilter */
418 if (ofn
->lpstrCustomFilter
)
423 /* customfilter contains a pair of strings... title\0ext\0 */
424 s
= ofn
->lpstrCustomFilter
;
425 if (*s
) s
= s
+strlen(s
)+1;
426 if (*s
) s
= s
+strlen(s
)+1;
427 n
= s
- ofn
->lpstrCustomFilter
;
428 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
429 ofnW
.lpstrCustomFilter
= MemAlloc(len
* sizeof(WCHAR
));
430 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
433 init_filedlg_infoW(&ofnW
, info
);
435 /* fixup A-specific fields */
436 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
437 info
->unicode
= FALSE
;
439 /* free what was duplicated */
440 MemFree((WCHAR
*)ofnW
.lpstrInitialDir
);
441 MemFree((WCHAR
*)ofnW
.lpstrFile
);
444 /***********************************************************************
447 * Call GetFileName95 with this structure and clean the memory.
449 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
451 WCHAR
*current_dir
= NULL
;
454 /* save current directory */
455 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
457 current_dir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
458 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
464 ret
= GetFileName95(info
);
467 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
468 ret
= GetFileName95(info
);
476 SetCurrentDirectoryW(current_dir
);
477 MemFree(current_dir
);
482 MemFree((WCHAR
*)info
->defext
);
483 MemFree((WCHAR
*)info
->title
);
484 MemFree((WCHAR
*)info
->filter
);
485 MemFree((WCHAR
*)info
->customfilter
);
488 MemFree(info
->filename
);
489 MemFree(info
->initdir
);
493 /******************************************************************************
494 * COMDLG32_GetDisplayNameOf [internal]
496 * Helper function to get the display name for a pidl.
498 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
499 LPSHELLFOLDER psfDesktop
;
502 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
505 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
506 IShellFolder_Release(psfDesktop
);
510 IShellFolder_Release(psfDesktop
);
511 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
514 /******************************************************************************
515 * COMDLG32_GetCanonicalPath [internal]
517 * Helper function to get the canonical path.
519 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
520 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
522 WCHAR lpstrTemp
[MAX_PATH
];
524 /* Get the current directory name */
525 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
528 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
530 PathAddBackslashW(lpstrPathAndFile
);
532 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
534 /* if the user specified a fully qualified path use it */
535 if(PathIsRelativeW(lpstrFile
))
537 lstrcatW(lpstrPathAndFile
, lpstrFile
);
541 /* does the path have a drive letter? */
542 if (PathGetDriveNumberW(lpstrFile
) == -1)
543 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
545 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
548 /* resolve "." and ".." */
549 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
550 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
551 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
554 /***********************************************************************
555 * COMDLG32_SplitFileNames [internal]
557 * Creates a delimited list of filenames.
559 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
561 UINT nStrCharCount
= 0; /* index in src buffer */
562 UINT nFileIndex
= 0; /* index in dest buffer */
563 UINT nFileCount
= 0; /* number of files */
565 /* we might get single filename without any '"',
566 * so we need nStrLen + terminating \0 + end-of-list \0 */
567 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
570 /* build delimited file list from filenames */
571 while ( nStrCharCount
<= nStrLen
)
573 if ( lpstrEdit
[nStrCharCount
]=='"' )
576 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
578 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
581 (*lpstrFileList
)[nFileIndex
++] = 0;
587 /* single, unquoted string */
588 if ((nStrLen
> 0) && (nFileIndex
== 0) )
590 lstrcpyW(*lpstrFileList
, lpstrEdit
);
591 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
596 (*lpstrFileList
)[nFileIndex
++] = '\0';
598 *sizeUsed
= nFileIndex
;
602 /***********************************************************************
603 * ArrangeCtrlPositions [internal]
605 * NOTE: Make sure to add testcases for any changes made here.
607 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
609 HWND hwndChild
, hwndStc32
;
610 RECT rectParent
, rectChild
, rectStc32
;
614 /* Take into account if open as read only checkbox and help button
619 RECT rectHelp
, rectCancel
;
620 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
621 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
622 /* subtract the height of the help button plus the space between
623 * the help button and the cancel button to the height of the dialog
625 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
629 There are two possibilities to add components to the default file dialog box.
631 By default, all the new components are added below the standard dialog box (the else case).
633 However, if there is a static text component with the stc32 id, a special case happens.
634 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
635 in the window and the cx and cy indicate how to size the window.
636 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
637 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
641 GetClientRect(hwndParentDlg
, &rectParent
);
643 /* when arranging controls we have to use fixed parent size */
644 rectParent
.bottom
-= help_fixup
;
646 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
649 GetWindowRect(hwndStc32
, &rectStc32
);
650 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
652 /* set the size of the stc32 control according to the size of
653 * client area of the parent dialog
655 SetWindowPos(hwndStc32
, 0,
657 rectParent
.right
, rectParent
.bottom
,
658 SWP_NOMOVE
| SWP_NOZORDER
);
661 SetRectEmpty(&rectStc32
);
663 /* this part moves controls of the child dialog */
664 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
667 if (hwndChild
!= hwndStc32
)
669 GetWindowRect(hwndChild
, &rectChild
);
670 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
672 /* move only if stc32 exist */
673 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
675 /* move to the right of visible controls of the parent dialog */
676 rectChild
.left
+= rectParent
.right
;
677 rectChild
.left
-= rectStc32
.right
;
679 /* move even if stc32 doesn't exist */
680 if (rectChild
.top
>= rectStc32
.bottom
)
682 /* move below visible controls of the parent dialog */
683 rectChild
.top
+= rectParent
.bottom
;
684 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
687 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
688 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
690 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
693 /* this part moves controls of the parent dialog */
694 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
697 if (hwndChild
!= hwndChildDlg
)
699 GetWindowRect(hwndChild
, &rectChild
);
700 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
702 /* left,top of stc32 marks the position of controls
703 * from the parent dialog
705 rectChild
.left
+= rectStc32
.left
;
706 rectChild
.top
+= rectStc32
.top
;
708 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
709 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
711 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
714 /* calculate the size of the resulting dialog */
716 /* here we have to use original parent size */
717 GetClientRect(hwndParentDlg
, &rectParent
);
718 GetClientRect(hwndChildDlg
, &rectChild
);
719 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
720 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
725 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
726 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
728 chgx
= rectChild
.right
- rectParent
.right
;
730 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
731 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
733 /* Unconditionally set new dialog
734 * height to that of the child
736 chgy
= rectChild
.bottom
- rectParent
.bottom
;
741 chgy
= rectChild
.bottom
- help_fixup
;
743 /* set the size of the parent dialog */
744 GetWindowRect(hwndParentDlg
, &rectParent
);
745 SetWindowPos(hwndParentDlg
, 0,
747 rectParent
.right
- rectParent
.left
+ chgx
,
748 rectParent
.bottom
- rectParent
.top
+ chgy
,
749 SWP_NOMOVE
| SWP_NOZORDER
);
752 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
761 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
768 TRACE("%p, %p\n", fodInfos
, hwnd
);
771 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
772 * structure's hInstance parameter is not a HINSTANCE, but
773 * instead a pointer to a template resource to use.
775 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
778 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
780 hinst
= COMDLG32_hInstance
;
781 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
783 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
789 hinst
= fodInfos
->ofnInfos
->hInstance
;
790 if(fodInfos
->unicode
)
792 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
793 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
797 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
798 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
802 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
805 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
806 !(template = LockResource( hDlgTmpl
)))
808 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
812 if (fodInfos
->unicode
)
813 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
814 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
815 (LPARAM
)fodInfos
->ofnInfos
);
817 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
818 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
819 (LPARAM
)fodInfos
->ofnInfos
);
822 else if( IsHooked(fodInfos
))
827 WORD menu
,class,title
;
829 GetClientRect(hwnd
,&rectHwnd
);
830 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
831 temp
.tmplate
.dwExtendedStyle
= 0;
832 temp
.tmplate
.cdit
= 0;
837 temp
.menu
= temp
.class = temp
.title
= 0;
839 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
840 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
847 /***********************************************************************
848 * SendCustomDlgNotificationMessage
850 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
853 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
855 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
859 TRACE("%p %d\n", hwndParentDlg
, uCode
);
861 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
864 TRACE("CALL NOTIFY for %d\n", uCode
);
866 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
867 ofnNotify
.hdr
.idFrom
= 0;
868 ofnNotify
.hdr
.code
= uCode
;
869 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
870 ofnNotify
.pszFile
= NULL
;
872 if (fodInfos
->unicode
)
873 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
875 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
877 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
882 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
886 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
888 TRACE("CDM_GETFILEPATH:\n");
890 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
893 /* get path and filenames */
894 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
895 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
896 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
899 p
= buffer
+ strlenW(buffer
);
901 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
903 if (fodInfos
->unicode
)
905 total
= strlenW( buffer
) + 1;
906 if (result
) lstrcpynW( result
, buffer
, size
);
907 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
911 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
912 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
913 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
915 HeapFree( GetProcessHeap(), 0, buffer
);
919 /***********************************************************************
920 * FILEDLG95_HandleCustomDialogMessages
922 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
924 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
926 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
927 WCHAR lpstrPath
[MAX_PATH
];
930 if(!fodInfos
) return FALSE
;
934 case CDM_GETFILEPATH
:
935 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
938 case CDM_GETFOLDERPATH
:
939 TRACE("CDM_GETFOLDERPATH:\n");
940 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
943 if (fodInfos
->unicode
)
944 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
946 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
947 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
949 retval
= lstrlenW(lpstrPath
) + 1;
952 case CDM_GETFOLDERIDLIST
:
953 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
954 if (retval
<= wParam
)
955 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
959 TRACE("CDM_GETSPEC:\n");
960 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
963 if (fodInfos
->unicode
)
964 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
966 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
970 case CDM_SETCONTROLTEXT
:
971 TRACE("CDM_SETCONTROLTEXT:\n");
974 if( fodInfos
->unicode
)
975 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
977 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
982 case CDM_HIDECONTROL
:
983 /* MSDN states that it should fail for not OFN_EXPLORER case */
984 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
986 HWND control
= GetDlgItem( hwnd
, wParam
);
987 if (control
) ShowWindow( control
, SW_HIDE
);
994 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
995 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
998 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1002 /***********************************************************************
1003 * FILEDLG95_OnWMGetMMI
1005 * WM_GETMINMAXINFO message handler for resizable dialogs
1007 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1009 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1010 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1011 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1013 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1018 /***********************************************************************
1019 * FILEDLG95_OnWMSize
1021 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1023 * FIXME: this could be made more elaborate. Now use a simple scheme
1024 * where the file view is enlarged and the controls are either moved
1025 * vertically or horizontally to get out of the way. Only the "grip"
1026 * is moved in both directions to stay in the corner.
1028 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1034 FileOpenDlgInfos
*fodInfos
;
1036 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1037 fodInfos
= get_filedlg_infoptr(hwnd
);
1038 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1039 /* get the new dialog rectangle */
1040 GetWindowRect( hwnd
, &rc
);
1041 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1042 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1043 /* not initialized yet */
1044 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1045 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1046 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1048 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1049 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1050 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1051 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1052 /* change the size of the view window */
1053 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1054 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1055 hdwp
= BeginDeferWindowPos( 10);
1056 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1057 rcview
.right
- rcview
.left
+ chgx
,
1058 rcview
.bottom
- rcview
.top
+ chgy
,
1059 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1060 /* change position and sizes of the controls */
1061 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1063 int ctrlid
= GetDlgCtrlID( ctrl
);
1064 GetWindowRect( ctrl
, &rc
);
1065 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1066 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1068 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1070 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1072 else if( rc
.top
> rcview
.bottom
)
1074 /* if it was below the shell view
1078 /* file name (edit or comboboxex) and file types combo change also width */
1082 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1083 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1084 SWP_NOACTIVATE
| SWP_NOZORDER
);
1086 /* then these buttons must move out of the way */
1090 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1092 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1095 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1097 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1100 else if( rc
.left
> rcview
.right
)
1102 /* if it was to the right of the shell view
1104 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1106 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1113 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1115 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1116 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1117 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1119 case IDC_TOOLBARSTATIC
:
1121 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1123 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1126 /* not resized in windows. Since wine uses this invisible control
1127 * to size the browser view it needs to be resized */
1128 case IDC_SHELLSTATIC
:
1129 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1130 rc
.right
- rc
.left
+ chgx
,
1131 rc
.bottom
- rc
.top
+ chgy
,
1132 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1137 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1138 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1140 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1141 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1143 GetWindowRect( ctrl
, &rc
);
1144 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1145 if( rc
.top
> rcview
.bottom
)
1147 /* if it was below the shell view
1149 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1150 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1151 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1153 else if( rc
.left
> rcview
.right
)
1155 /* if it was to the right of the shell view
1157 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1158 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1159 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1162 /* size the custom dialog at the end: some applications do some
1163 * control re-arranging at this point */
1164 GetClientRect(hwnd
, &rc
);
1165 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1166 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1168 EndDeferWindowPos( hdwp
);
1169 /* should not be needed */
1170 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1174 /***********************************************************************
1177 * File open dialog procedure
1179 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1182 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1189 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1191 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1192 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1194 /* Some shell namespace extensions depend on COM being initialized. */
1195 if (SUCCEEDED(OleInitialize(NULL
)))
1196 fodInfos
->ole_initialized
= TRUE
;
1198 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1200 FILEDLG95_InitControls(hwnd
);
1202 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1204 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1205 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1206 RECT client
, client_adjusted
;
1208 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1210 style
|= WS_SIZEBOX
;
1211 ex_style
|= WS_EX_WINDOWEDGE
;
1214 style
&= ~WS_SIZEBOX
;
1215 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1216 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1218 GetClientRect( hwnd
, &client
);
1219 GetClientRect( hwnd
, &client_adjusted
);
1220 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1222 GetWindowRect( hwnd
, &rc
);
1223 rc
.right
+= client_adjusted
.right
- client
.right
;
1224 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1225 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1226 SWP_NOZORDER
| SWP_NOMOVE
);
1228 GetWindowRect( hwnd
, &rc
);
1229 fodInfos
->DlgInfos
.hwndGrip
=
1230 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1231 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1232 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1233 rc
.right
- gripx
, rc
.bottom
- gripy
,
1234 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1237 fodInfos
->DlgInfos
.hwndCustomDlg
=
1238 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1240 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1241 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1243 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1244 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1246 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1247 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1248 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1251 /* if the app has changed the position of the invisible listbox,
1252 * change that of the listview (browser) as well */
1253 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1254 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1255 if( !EqualRect( &rc
, &rcstc
))
1257 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1258 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1259 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1260 SWP_NOACTIVATE
| SWP_NOZORDER
);
1263 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1265 GetWindowRect( hwnd
, &rc
);
1266 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1267 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1268 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1269 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1270 GetClientRect( hwnd
, &rc
);
1271 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1272 rc
.right
- gripx
, rc
.bottom
- gripy
,
1273 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1274 /* resize the dialog to the previous invocation */
1275 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1276 SetWindowPos( hwnd
, NULL
,
1277 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1278 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1281 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1282 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1287 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1288 case WM_GETMINMAXINFO
:
1289 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1291 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1294 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1297 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1303 case WM_GETISHELLBROWSER
:
1304 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1308 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1309 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1310 MemDialogSize
= fodInfos
->sizedlg
;
1311 RemovePropW(hwnd
, filedlg_info_propnameW
);
1316 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1319 /* set up the button tooltips strings */
1320 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1322 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1323 switch(lpnmh
->idFrom
)
1325 /* Up folder button */
1326 case FCIDM_TB_UPFOLDER
:
1327 stringId
= IDS_UPFOLDER
;
1329 /* New folder button */
1330 case FCIDM_TB_NEWFOLDER
:
1331 stringId
= IDS_NEWFOLDER
;
1333 /* List option button */
1334 case FCIDM_TB_SMALLICON
:
1335 stringId
= IDS_LISTVIEW
;
1337 /* Details option button */
1338 case FCIDM_TB_REPORTVIEW
:
1339 stringId
= IDS_REPORTVIEW
;
1341 /* Desktop button */
1342 case FCIDM_TB_DESKTOP
:
1343 stringId
= IDS_TODESKTOP
;
1348 lpdi
->hinst
= COMDLG32_hInstance
;
1349 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1354 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1355 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1360 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1362 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1363 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1366 /***********************************************************************
1367 * FILEDLG95_InitControls
1369 * WM_INITDIALOG message handler (before hook notification)
1371 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1373 BOOL win2000plus
= FALSE
;
1374 BOOL win98plus
= FALSE
;
1375 BOOL handledPath
= FALSE
;
1376 OSVERSIONINFOW osVi
;
1377 static const WCHAR szwSlash
[] = { '\\', 0 };
1378 static const WCHAR szwStar
[] = { '*',0 };
1380 static const TBBUTTON tbb
[] =
1382 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1383 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1384 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1385 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1386 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1387 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1388 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1389 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1390 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1392 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1397 HIMAGELIST toolbarImageList
;
1398 SHFILEINFOA shFileInfo
;
1399 ITEMIDLIST
*desktopPidl
;
1401 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1403 TRACE("%p\n", fodInfos
);
1405 /* Get windows version emulating */
1406 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1407 GetVersionExW(&osVi
);
1408 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1409 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1410 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1411 win2000plus
= (osVi
.dwMajorVersion
> 4);
1412 if (win2000plus
) win98plus
= TRUE
;
1414 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1417 /* Use either the edit or the comboboxex for the filename control */
1418 if (filename_is_edit( fodInfos
))
1420 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1421 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1425 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1426 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1429 /* Get the hwnd of the controls */
1430 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1431 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1433 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1434 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1436 /* construct the toolbar */
1437 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1438 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1440 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1441 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1442 rectTB
.left
= rectlook
.right
;
1443 rectTB
.top
= rectlook
.top
-1;
1445 if (fodInfos
->unicode
)
1446 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1447 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1448 rectTB
.left
, rectTB
.top
,
1449 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1450 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1452 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1453 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1454 rectTB
.left
, rectTB
.top
,
1455 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1456 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1458 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1460 /* FIXME: use TB_LOADIMAGES when implemented */
1461 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1462 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1463 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1465 /* Retrieve and add desktop icon to the toolbar */
1466 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1467 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1468 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1469 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1470 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1472 DestroyIcon(shFileInfo
.hIcon
);
1473 CoTaskMemFree(desktopPidl
);
1475 /* Finish Toolbar Construction */
1476 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1477 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1479 /* Set the window text with the text specified in the OPENFILENAME structure */
1482 SetWindowTextW(hwnd
,fodInfos
->title
);
1484 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1487 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1488 SetWindowTextW(hwnd
, buf
);
1491 /* Initialise the file name edit control */
1492 handledPath
= FALSE
;
1493 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1495 if(fodInfos
->filename
)
1497 /* 1. If win2000 or higher and filename contains a path, use it
1498 in preference over the lpstrInitialDir */
1499 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1500 WCHAR tmpBuf
[MAX_PATH
];
1504 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1507 /* nameBit is always shorter than the original filename. It may be NULL
1508 * when the filename contains only a drive name instead of file name */
1511 lstrcpyW(fodInfos
->filename
,nameBit
);
1515 *fodInfos
->filename
= '\0';
1517 MemFree(fodInfos
->initdir
);
1518 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1519 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1521 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1522 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1524 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1527 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1531 /* 2. (All platforms) If initdir is not null, then use it */
1532 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1534 /* Work out the proper path as supplied one might be relative */
1535 /* (Here because supplying '.' as dir browses to My Computer) */
1536 WCHAR tmpBuf
[MAX_PATH
];
1537 WCHAR tmpBuf2
[MAX_PATH
];
1541 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1542 if (PathFileExistsW(tmpBuf
)) {
1543 /* initdir does not have to be a directory. If a file is
1544 * specified, the dir part is taken */
1545 if (PathIsDirectoryW(tmpBuf
)) {
1546 PathAddBackslashW(tmpBuf
);
1547 lstrcatW(tmpBuf
, szwStar
);
1549 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1552 MemFree(fodInfos
->initdir
);
1553 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1554 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1556 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1559 else if (fodInfos
->initdir
)
1561 MemFree(fodInfos
->initdir
);
1562 fodInfos
->initdir
= NULL
;
1563 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1567 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1569 /* 3. All except w2k+: if filename contains a path use it */
1570 if (!win2000plus
&& fodInfos
->filename
&&
1571 *fodInfos
->filename
&&
1572 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1573 WCHAR tmpBuf
[MAX_PATH
];
1577 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1582 /* nameBit is always shorter than the original filename */
1583 lstrcpyW(fodInfos
->filename
, nameBit
);
1586 len
= lstrlenW(tmpBuf
);
1587 MemFree(fodInfos
->initdir
);
1588 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1589 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1592 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1593 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1595 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1598 /* 4. Win2000+: Recently used */
1599 if (!handledPath
&& win2000plus
) {
1600 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1601 fodInfos
->initdir
[0] = '\0';
1603 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1605 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1608 MemFree(fodInfos
->initdir
);
1609 fodInfos
->initdir
= NULL
;
1613 /* 5. win98+ and win2000+ if any files of specified filter types in
1614 current directory, use it */
1615 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1617 LPCWSTR lpstrPos
= fodInfos
->filter
;
1618 WIN32_FIND_DATAW FindFileData
;
1623 /* filter is a list... title\0ext\0......\0\0 */
1625 /* Skip the title */
1626 if(! *lpstrPos
) break; /* end */
1627 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1629 /* See if any files exist in the current dir with this extension */
1630 if(! *lpstrPos
) break; /* end */
1632 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1634 if (hFind
== INVALID_HANDLE_VALUE
) {
1635 /* None found - continue search */
1636 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1640 MemFree(fodInfos
->initdir
);
1641 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1642 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1645 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1646 debugstr_w(lpstrPos
));
1653 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1654 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1655 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1657 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1659 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1662 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1663 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1665 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1668 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1671 } else if (!handledPath
) {
1672 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1673 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1675 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1678 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1679 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1681 /* Must the open as read only check box be checked ?*/
1682 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1684 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1687 /* Must the open as read only check box be hidden? */
1688 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1690 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1691 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1694 /* Must the help button be hidden? */
1695 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1697 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1698 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1701 /* change Open to Save */
1702 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1705 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1706 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1707 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1708 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1711 /* Initialize the filter combo box */
1712 FILEDLG95_FILETYPE_Init(hwnd
);
1717 /***********************************************************************
1718 * FILEDLG95_ResizeControls
1720 * WM_INITDIALOG message handler (after hook notification)
1722 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1724 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1726 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1729 UINT flags
= SWP_NOACTIVATE
;
1731 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1732 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1734 /* resize the custom dialog to the parent size */
1735 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1736 GetClientRect(hwnd
, &rc
);
1739 /* our own fake template is zero sized and doesn't have children, so
1740 * there is no need to resize it. Picasa depends on it.
1742 flags
|= SWP_NOSIZE
;
1745 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1746 0, 0, rc
.right
, rc
.bottom
, flags
);
1750 /* Resize the height; if opened as read-only, checkbox and help button are
1751 * hidden and we are not using a custom template nor a customDialog
1753 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1754 (!(fodInfos
->ofnInfos
->Flags
&
1755 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1757 RECT rectDlg
, rectHelp
, rectCancel
;
1758 GetWindowRect(hwnd
, &rectDlg
);
1759 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1760 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1761 /* subtract the height of the help button plus the space between the help
1762 * button and the cancel button to the height of the dialog
1764 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1765 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1766 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1772 /***********************************************************************
1773 * FILEDLG95_FillControls
1775 * WM_INITDIALOG message handler (after hook notification)
1777 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1779 LPITEMIDLIST pidlItemId
= NULL
;
1781 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1783 TRACE("dir=%s file=%s\n",
1784 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1786 /* Get the initial directory pidl */
1788 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1790 WCHAR path
[MAX_PATH
];
1792 GetCurrentDirectoryW(MAX_PATH
,path
);
1793 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1796 /* Initialise shell objects */
1797 FILEDLG95_SHELL_Init(hwnd
);
1799 /* Initialize the Look In combo box */
1800 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1802 /* Browse to the initial directory */
1803 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1805 /* Free pidlItem memory */
1806 COMDLG32_SHFree(pidlItemId
);
1810 /***********************************************************************
1813 * Regroups all the cleaning functions of the filedlg
1815 void FILEDLG95_Clean(HWND hwnd
)
1817 FILEDLG95_FILETYPE_Clean(hwnd
);
1818 FILEDLG95_LOOKIN_Clean(hwnd
);
1819 FILEDLG95_SHELL_Clean(hwnd
);
1821 /***********************************************************************
1822 * FILEDLG95_OnWMCommand
1824 * WM_COMMAND message handler
1826 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1828 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1829 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1830 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1836 FILEDLG95_OnOpen(hwnd
);
1840 FILEDLG95_Clean(hwnd
);
1841 EndDialog(hwnd
, FALSE
);
1843 /* Filetype combo box */
1845 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1847 /* LookIn combo box */
1849 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1852 /* --- toolbar --- */
1853 /* Up folder button */
1854 case FCIDM_TB_UPFOLDER
:
1855 FILEDLG95_SHELL_UpFolder(hwnd
);
1857 /* New folder button */
1858 case FCIDM_TB_NEWFOLDER
:
1859 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1861 /* List option button */
1862 case FCIDM_TB_SMALLICON
:
1863 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1865 /* Details option button */
1866 case FCIDM_TB_REPORTVIEW
:
1867 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1869 /* Details option button */
1870 case FCIDM_TB_DESKTOP
:
1871 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1879 /* Do not use the listview selection anymore */
1880 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1884 /***********************************************************************
1885 * FILEDLG95_OnWMGetIShellBrowser
1887 * WM_GETISHELLBROWSER message handler
1889 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1891 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1895 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1901 /***********************************************************************
1902 * FILEDLG95_SendFileOK
1904 * Sends the CDN_FILEOK notification if required
1907 * TRUE if the dialog should close
1908 * FALSE if the dialog should not be closed
1910 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1912 /* ask the hook if we can close */
1913 if(IsHooked(fodInfos
))
1918 /* First send CDN_FILEOK as MSDN doc says */
1919 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1920 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1923 TRACE("canceled\n");
1927 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1928 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1929 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1932 TRACE("canceled\n");
1939 /***********************************************************************
1940 * FILEDLG95_OnOpenMultipleFiles
1942 * Handles the opening of multiple files.
1945 * check destination buffer size
1947 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1949 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1950 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1951 UINT nCount
, nSizePath
;
1955 if(fodInfos
->unicode
)
1957 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1958 ofn
->lpstrFile
[0] = '\0';
1962 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1963 ofn
->lpstrFile
[0] = '\0';
1966 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1968 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1969 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1970 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1972 LPWSTR lpstrTemp
= lpstrFileList
;
1974 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1978 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1981 WCHAR lpstrNotFound
[100];
1982 WCHAR lpstrMsg
[100];
1984 static const WCHAR nl
[] = {'\n',0};
1986 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1987 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1989 lstrcpyW(tmp
, lpstrTemp
);
1991 lstrcatW(tmp
, lpstrNotFound
);
1993 lstrcatW(tmp
, lpstrMsg
);
1995 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1999 /* move to the next file in the list of files */
2000 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2001 COMDLG32_SHFree(pidl
);
2005 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2006 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2008 /* For "oldstyle" dialog the components have to
2009 be separated by blanks (not '\0'!) and short
2010 filenames have to be used! */
2011 FIXME("Components have to be separated by blanks\n");
2013 if(fodInfos
->unicode
)
2015 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2016 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2017 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2021 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2023 if (ofn
->lpstrFile
!= NULL
)
2025 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2026 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2027 if (ofn
->nMaxFile
> nSizePath
)
2029 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2030 ofn
->lpstrFile
+ nSizePath
,
2031 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2036 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2037 fodInfos
->ofnInfos
->nFileExtension
= 0;
2039 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2042 /* clean and exit */
2043 FILEDLG95_Clean(hwnd
);
2044 return EndDialog(hwnd
,TRUE
);
2047 /* Returns the 'slot name' of the given module_name in the registry's
2048 * most-recently-used list. This will be an ASCII value in the
2049 * range ['a','z'). Returns zero on error.
2051 * The slot's value in the registry has the form:
2052 * module_name\0mru_path\0
2054 * If stored_path is given, then stored_path will contain the path name
2055 * stored in the registry's MRU list for the given module_name.
2057 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2058 * MRU list key for the given module_name.
2060 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2062 WCHAR mru_list
[32], *cur_mru_slot
;
2063 BOOL taken
[25] = {0};
2064 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2065 HKEY hkey_tmp
, *hkey
;
2074 *stored_path
= '\0';
2076 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2078 WARN("Unable to create MRU key: %d\n", ret
);
2082 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2083 (LPBYTE
)mru_list
, &mru_list_size
);
2084 if(ret
|| key_type
!= REG_SZ
){
2085 if(ret
== ERROR_FILE_NOT_FOUND
)
2088 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2093 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2094 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2095 DWORD value_data_size
= sizeof(value_data
);
2097 *value_name
= *cur_mru_slot
;
2099 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2100 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2101 if(ret
|| key_type
!= REG_BINARY
){
2102 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2106 if(!strcmpiW(module_name
, value_data
)){
2110 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2118 /* the module name isn't in the registry, so find the next open slot */
2119 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2120 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2121 for(i
= 0; i
< 25; ++i
){
2126 /* all slots are taken, so return the last one in MRUList */
2128 return *cur_mru_slot
;
2131 /* save the given filename as most-recently-used path for this module */
2132 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2134 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2138 /* get the current executable's name */
2139 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2140 WARN("GotModuleFileName failed: %d\n", GetLastError());
2143 module_name
= strrchrW(module_path
, '\\');
2145 module_name
= module_path
;
2149 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2154 { /* update the slot's info */
2155 WCHAR
*path_ends
, *final
;
2156 DWORD path_len
, final_len
;
2158 /* use only the path segment of `filename' */
2159 path_ends
= strrchrW(filename
, '\\');
2160 path_len
= path_ends
- filename
;
2162 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2164 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2167 lstrcpyW(final
, module_name
);
2168 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2169 final
[final_len
-1] = '\0';
2171 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2172 final_len
* sizeof(WCHAR
));
2174 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2183 { /* update MRUList value */
2184 WCHAR old_mru_list
[32], new_mru_list
[32];
2185 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2186 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2188 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2189 (LPBYTE
)old_mru_list
, &mru_list_size
);
2190 if(ret
|| key_type
!= REG_SZ
){
2191 if(ret
== ERROR_FILE_NOT_FOUND
){
2192 new_mru_list
[0] = slot
;
2193 new_mru_list
[1] = '\0';
2195 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2200 /* copy old list data over so that the new slot is at the start
2202 *new_mru_slot
++ = slot
;
2203 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2204 if(*old_mru_slot
!= slot
)
2205 *new_mru_slot
++ = *old_mru_slot
;
2207 *new_mru_slot
= '\0';
2210 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2211 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2213 WARN("Error saving MRUList data: %d\n", ret
);
2220 /* load the most-recently-used path for this module */
2221 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2223 WCHAR module_path
[MAX_PATH
], *module_name
;
2225 /* get the current executable's name */
2226 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2227 WARN("GotModuleFileName failed: %d\n", GetLastError());
2230 module_name
= strrchrW(module_path
, '\\');
2232 module_name
= module_path
;
2236 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2237 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2240 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2242 WCHAR strMsgTitle
[MAX_PATH
];
2243 WCHAR strMsgText
[MAX_PATH
];
2245 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2247 strMsgTitle
[0] = '\0';
2248 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2249 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2252 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2253 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2255 int nOpenAction
= defAction
;
2256 LPWSTR lpszTemp
, lpszTemp1
;
2257 LPITEMIDLIST pidl
= NULL
;
2258 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2260 /* check for invalid chars */
2261 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2263 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2267 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2269 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2272 LPSHELLFOLDER lpsfChild
;
2273 WCHAR lpwstrTemp
[MAX_PATH
];
2274 DWORD dwEaten
, dwAttributes
;
2277 lstrcpyW(lpwstrTemp
, lpszTemp
);
2278 p
= PathFindNextComponentW(lpwstrTemp
);
2280 if (!p
) break; /* end of path */
2283 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2285 /* There are no wildcards when OFN_NOVALIDATE is set */
2286 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2288 static const WCHAR wszWild
[] = { '*', '?', 0 };
2289 /* if the last element is a wildcard do a search */
2290 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2292 nOpenAction
= ONOPEN_SEARCH
;
2296 lpszTemp1
= lpszTemp
;
2298 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2300 /* append a backslash to drive letters */
2301 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2302 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2303 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2305 PathAddBackslashW(lpwstrTemp
);
2308 dwAttributes
= SFGAO_FOLDER
;
2309 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2311 /* the path component is valid, we have a pidl of the next path component */
2312 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2313 if(dwAttributes
& SFGAO_FOLDER
)
2315 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2317 ERR("bind to failed\n"); /* should not fail */
2320 IShellFolder_Release(*ppsf
);
2328 /* end dialog, return value */
2329 nOpenAction
= ONOPEN_OPEN
;
2332 COMDLG32_SHFree(pidl
);
2335 else if (!(flags
& OFN_NOVALIDATE
))
2337 if(*lpszTemp
|| /* points to trailing null for last path element */
2338 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2340 if(flags
& OFN_PATHMUSTEXIST
)
2342 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2348 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2350 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2354 /* change to the current folder */
2355 nOpenAction
= ONOPEN_OPEN
;
2360 nOpenAction
= ONOPEN_OPEN
;
2364 if(pidl
) COMDLG32_SHFree(pidl
);
2369 /***********************************************************************
2372 * Ok button WM_COMMAND message handler
2374 * If the function succeeds, the return value is nonzero.
2376 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2378 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2379 LPWSTR lpstrFileList
;
2380 UINT nFileCount
= 0;
2383 WCHAR lpstrPathAndFile
[MAX_PATH
];
2384 LPSHELLFOLDER lpsf
= NULL
;
2387 TRACE("hwnd=%p\n", hwnd
);
2389 /* try to browse the selected item */
2390 if(BrowseSelectedFolder(hwnd
))
2393 /* get the files from the edit control */
2394 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2401 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2405 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2408 Step 1: Build a complete path name from the current folder and
2409 the filename or path in the edit box.
2411 - the path in the edit box is a root path
2412 (with or without drive letter)
2413 - the edit box contains ".." (or a path with ".." in it)
2416 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2417 MemFree(lpstrFileList
);
2420 Step 2: here we have a cleaned up path
2422 We have to parse the path step by step to see if we have to browse
2423 to a folder if the path points to a directory or the last
2424 valid element is a directory.
2427 lpstrPathAndFile: cleaned up path
2431 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2432 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2433 nOpenAction
= ONOPEN_OPEN
;
2435 nOpenAction
= ONOPEN_BROWSE
;
2437 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2438 fodInfos
->ofnInfos
->Flags
,
2439 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2445 Step 3: here we have a cleaned up and validated path
2448 lpsf: ShellFolder bound to the rightmost valid path component
2449 lpstrPathAndFile: cleaned up path
2450 nOpenAction: action to do
2452 TRACE("end validate sf=%p\n", lpsf
);
2456 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2457 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2460 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2463 /* replace the current filter */
2464 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2465 len
= lstrlenW(lpszTemp
)+1;
2466 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2467 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2469 /* set the filter cb to the extension when possible */
2470 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2471 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2474 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2475 TRACE("ONOPEN_BROWSE\n");
2477 IPersistFolder2
* ppf2
;
2478 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2480 LPITEMIDLIST pidlCurrent
;
2481 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2482 IPersistFolder2_Release(ppf2
);
2483 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2485 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2486 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2488 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2489 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2492 else if( nOpenAction
== ONOPEN_SEARCH
)
2494 if (fodInfos
->Shell
.FOIShellView
)
2495 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2497 COMDLG32_SHFree(pidlCurrent
);
2498 if (filename_is_edit( fodInfos
))
2499 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2504 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2505 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2511 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2512 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2516 /* update READONLY check box flag */
2517 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2518 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2520 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2522 /* Attach the file extension with file name*/
2523 ext
= PathFindExtensionW(lpstrPathAndFile
);
2524 if (! *ext
&& fodInfos
->defext
)
2526 /* if no extension is specified with file name, then */
2527 /* attach the extension from file filter or default one */
2529 WCHAR
*filterExt
= NULL
;
2530 LPWSTR lpstrFilter
= NULL
;
2531 static const WCHAR szwDot
[] = {'.',0};
2532 int PathLength
= lstrlenW(lpstrPathAndFile
);
2534 /*Get the file extension from file type filter*/
2535 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2536 fodInfos
->ofnInfos
->nFilterIndex
-1);
2538 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2540 WCHAR
* filterSearchIndex
;
2541 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2542 strcpyW(filterExt
, lpstrFilter
);
2544 /* if a semicolon-separated list of file extensions was given, do not include the
2545 semicolon or anything after it in the extension.
2546 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2547 filterSearchIndex
= strchrW(filterExt
, ';');
2548 if (filterSearchIndex
)
2550 filterSearchIndex
[0] = '\0';
2553 /* find the file extension by searching for the first dot in filterExt */
2554 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2555 /* if the extension is invalid or contains a glob, ignore it */
2556 filterSearchIndex
= strchrW(filterExt
, '.');
2557 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2559 strcpyW(filterExt
, filterSearchIndex
);
2563 HeapFree(GetProcessHeap(), 0, filterExt
);
2570 /* use the default file extension */
2571 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2572 strcpyW(filterExt
, fodInfos
->defext
);
2575 if (*filterExt
) /* ignore filterExt="" */
2578 lstrcatW(lpstrPathAndFile
, szwDot
);
2579 /* Attach the extension */
2580 lstrcatW(lpstrPathAndFile
, filterExt
);
2583 HeapFree(GetProcessHeap(), 0, filterExt
);
2585 /* In Open dialog: if file does not exist try without extension */
2586 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2587 lpstrPathAndFile
[PathLength
] = '\0';
2589 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2592 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2593 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2595 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2598 /* In Save dialog: check if the file already exists */
2599 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2600 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2601 && PathFileExistsW(lpstrPathAndFile
))
2603 WCHAR lpstrOverwrite
[100];
2606 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2607 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2608 MB_YESNO
| MB_ICONEXCLAMATION
);
2609 if (answer
== IDNO
|| answer
== IDCANCEL
)
2616 /* In Open dialog: check if it should be created if it doesn't exist */
2617 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2618 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2619 && !PathFileExistsW(lpstrPathAndFile
))
2621 WCHAR lpstrCreate
[100];
2624 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2625 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2626 MB_YESNO
| MB_ICONEXCLAMATION
);
2627 if (answer
== IDNO
|| answer
== IDCANCEL
)
2634 /* Check that the size of the file does not exceed buffer size.
2635 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2636 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2637 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2640 /* fill destination buffer */
2641 if (fodInfos
->ofnInfos
->lpstrFile
)
2643 if(fodInfos
->unicode
)
2645 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2647 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2648 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2649 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2653 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2655 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2656 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2657 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2658 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2662 if(fodInfos
->unicode
)
2666 /* set filename offset */
2667 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2668 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2670 /* set extension offset */
2671 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2672 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2677 CHAR tempFileA
[MAX_PATH
];
2679 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2680 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2681 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2683 /* set filename offset */
2684 lpszTemp
= PathFindFileNameA(tempFileA
);
2685 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2687 /* set extension offset */
2688 lpszTemp
= PathFindExtensionA(tempFileA
);
2689 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2692 /* set the lpstrFileTitle */
2693 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2695 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2696 if(fodInfos
->unicode
)
2698 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2699 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2703 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2704 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2705 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2709 /* copy currently selected filter to lpstrCustomFilter */
2710 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2712 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2713 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2714 NULL
, 0, NULL
, NULL
);
2715 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2717 LPSTR s
= ofn
->lpstrCustomFilter
;
2718 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2719 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2720 s
, len
, NULL
, NULL
);
2725 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2728 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2731 FILEDLG95_Clean(hwnd
);
2732 ret
= EndDialog(hwnd
, TRUE
);
2738 size
= lstrlenW(lpstrPathAndFile
) + 1;
2739 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2741 /* return needed size in first two bytes of lpstrFile */
2742 if(fodInfos
->ofnInfos
->lpstrFile
)
2743 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2744 FILEDLG95_Clean(hwnd
);
2745 ret
= EndDialog(hwnd
, FALSE
);
2746 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2753 if(lpsf
) IShellFolder_Release(lpsf
);
2757 /***********************************************************************
2758 * FILEDLG95_SHELL_Init
2760 * Initialisation of the shell objects
2762 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2764 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2766 TRACE("%p\n", hwnd
);
2769 * Initialisation of the FileOpenDialogInfos structure
2775 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2777 /* Disable multi-select if flag not set */
2778 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2780 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2782 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2783 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2785 /* Construct the IShellBrowser interface */
2786 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2791 /***********************************************************************
2792 * FILEDLG95_SHELL_ExecuteCommand
2794 * Change the folder option and refresh the view
2795 * If the function succeeds, the return value is nonzero.
2797 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2799 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2802 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2804 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2809 CMINVOKECOMMANDINFO ci
;
2810 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2811 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2815 IContextMenu_InvokeCommand(pcm
, &ci
);
2816 IContextMenu_Release(pcm
);
2822 /***********************************************************************
2823 * FILEDLG95_SHELL_UpFolder
2825 * Browse to the specified object
2826 * If the function succeeds, the return value is nonzero.
2828 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2830 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2834 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2838 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2839 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2845 /***********************************************************************
2846 * FILEDLG95_SHELL_BrowseToDesktop
2848 * Browse to the Desktop
2849 * If the function succeeds, the return value is nonzero.
2851 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2853 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2859 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2860 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2861 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2862 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2863 COMDLG32_SHFree(pidl
);
2864 return SUCCEEDED(hres
);
2866 /***********************************************************************
2867 * FILEDLG95_SHELL_Clean
2869 * Cleans the memory used by shell objects
2871 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2873 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2877 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2879 /* clean Shell interfaces */
2880 if (fodInfos
->Shell
.FOIShellView
)
2882 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2883 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2885 if (fodInfos
->Shell
.FOIShellFolder
)
2886 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2887 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2888 if (fodInfos
->Shell
.FOIDataObject
)
2889 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2892 /***********************************************************************
2893 * FILEDLG95_FILETYPE_Init
2895 * Initialisation of the file type combo box
2897 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2899 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2900 int nFilters
= 0; /* number of filters */
2903 TRACE("%p\n", hwnd
);
2905 if(fodInfos
->customfilter
)
2907 /* customfilter has one entry... title\0ext\0
2908 * Set first entry of combo box item with customfilter
2911 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2914 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2916 /* Copy the extensions */
2917 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2918 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2919 lstrcpyW(lpstrExt
,lpstrPos
);
2921 /* Add the item at the end of the combo */
2922 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2923 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2926 if(fodInfos
->filter
)
2928 LPCWSTR lpstrPos
= fodInfos
->filter
;
2932 /* filter is a list... title\0ext\0......\0\0
2933 * Set the combo item text to the title and the item data
2936 LPCWSTR lpstrDisplay
;
2940 if(! *lpstrPos
) break; /* end */
2941 lpstrDisplay
= lpstrPos
;
2942 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2944 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2948 /* Copy the extensions */
2949 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2950 lstrcpyW(lpstrExt
,lpstrPos
);
2951 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2953 /* Add the item at the end of the combo */
2954 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2956 /* malformed filters are added anyway... */
2957 if (!*lpstrExt
) break;
2962 * Set the current filter to the one specified
2963 * in the initialisation structure
2965 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2969 /* Check to make sure our index isn't out of bounds. */
2970 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2971 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2972 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2974 /* set default filter index */
2975 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2976 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2978 /* calculate index of Combo Box item */
2979 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2980 if (fodInfos
->customfilter
== NULL
)
2983 /* Set the current index selection. */
2984 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2986 /* Get the corresponding text string from the combo box. */
2987 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2990 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2996 CharLowerW(lpstrFilter
); /* lowercase */
2997 len
= lstrlenW(lpstrFilter
)+1;
2998 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2999 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3002 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3006 /***********************************************************************
3007 * FILEDLG95_FILETYPE_OnCommand
3009 * WM_COMMAND of the file type combo box
3010 * If the function succeeds, the return value is nonzero.
3012 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3014 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3022 /* Get the current item of the filetype combo box */
3023 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3025 /* set the current filter index */
3026 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3027 (fodInfos
->customfilter
== NULL
? 1 : 0);
3029 /* Set the current filter with the current selection */
3030 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3032 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3034 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3037 CharLowerW(lpstrFilter
); /* lowercase */
3038 len
= lstrlenW(lpstrFilter
)+1;
3039 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3040 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3041 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3042 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3045 /* Refresh the actual view to display the included items*/
3046 if (fodInfos
->Shell
.FOIShellView
)
3047 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3052 /***********************************************************************
3053 * FILEDLG95_FILETYPE_SearchExt
3055 * searches for an extension in the filetype box
3057 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3059 int i
, iCount
= CBGetCount(hwnd
);
3061 TRACE("%s\n", debugstr_w(lpstrExt
));
3063 if(iCount
!= CB_ERR
)
3065 for(i
=0;i
<iCount
;i
++)
3067 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3074 /***********************************************************************
3075 * FILEDLG95_FILETYPE_Clean
3077 * Clean the memory used by the filetype combo box
3079 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3081 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3083 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3087 /* Delete each string of the combo and their associated data */
3088 if(iCount
!= CB_ERR
)
3090 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3092 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3093 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3096 /* Current filter */
3097 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3101 /***********************************************************************
3102 * FILEDLG95_LOOKIN_Init
3104 * Initialisation of the look in combo box
3107 /* Small helper function, to determine if the unixfs shell extension is rooted
3108 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3110 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3112 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3113 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3114 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3115 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3116 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3117 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3118 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3120 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3127 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3129 IShellFolder
*psfRoot
, *psfDrives
;
3130 IEnumIDList
*lpeRoot
, *lpeDrives
;
3131 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3134 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3136 TRACE("%p\n", hwndCombo
);
3138 liInfos
->iMaxIndentation
= 0;
3140 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3142 hdc
= GetDC( hwndCombo
);
3143 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3144 GetTextMetricsW( hdc
, &tm
);
3145 ReleaseDC( hwndCombo
, hdc
);
3147 /* set item height for both text field and listbox */
3148 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3149 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3151 /* Turn on the extended UI for the combo box like Windows does */
3152 CBSetExtendedUI(hwndCombo
, TRUE
);
3154 /* Initialise data of Desktop folder */
3155 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3156 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3157 COMDLG32_SHFree(pidlTmp
);
3159 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3161 SHGetDesktopFolder(&psfRoot
);
3165 /* enumerate the contents of the desktop */
3166 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3168 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3170 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3172 /* If the unixfs extension is rooted, we don't expand the drives by default */
3173 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3175 /* special handling for CSIDL_DRIVES */
3176 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3178 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3180 /* enumerate the drives */
3181 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3183 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3185 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3186 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3187 COMDLG32_SHFree(pidlAbsTmp
);
3188 COMDLG32_SHFree(pidlTmp1
);
3190 IEnumIDList_Release(lpeDrives
);
3192 IShellFolder_Release(psfDrives
);
3197 COMDLG32_SHFree(pidlTmp
);
3199 IEnumIDList_Release(lpeRoot
);
3201 IShellFolder_Release(psfRoot
);
3204 COMDLG32_SHFree(pidlDrives
);
3207 /***********************************************************************
3208 * FILEDLG95_LOOKIN_DrawItem
3210 * WM_DRAWITEM message handler
3212 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3214 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3215 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3216 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3220 HIMAGELIST ilItemImage
;
3223 LPSFOLDER tmpFolder
;
3224 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3225 UINT icon_width
, icon_height
;
3229 if(pDIStruct
->itemID
== -1)
3232 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3233 pDIStruct
->itemID
)))
3237 icon_width
= GetSystemMetrics(SM_CXICON
);
3238 icon_height
= GetSystemMetrics(SM_CYICON
);
3239 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3241 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3242 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3243 shgfi_flags
|= SHGFI_SMALLICON
;
3246 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3247 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3249 /* Is this item selected ? */
3250 if(pDIStruct
->itemState
& ODS_SELECTED
)
3252 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3253 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3254 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3258 SetTextColor(pDIStruct
->hDC
,crText
);
3259 SetBkColor(pDIStruct
->hDC
,crWin
);
3260 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3263 /* Do not indent item if drawing in the edit of the combo */
3264 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3267 iIndentation
= tmpFolder
->m_iIndent
;
3269 /* Draw text and icon */
3271 /* Initialise the icon display area */
3272 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3273 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3274 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3275 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3277 /* Initialise the text display area */
3278 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3279 rectText
.left
= rectIcon
.right
;
3281 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3282 rectText
.right
= pDIStruct
->rcItem
.right
;
3284 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3286 /* Draw the icon from the image list */
3287 ImageList_Draw(ilItemImage
,
3294 /* Draw the associated text */
3295 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3299 /***********************************************************************
3300 * FILEDLG95_LOOKIN_OnCommand
3302 * LookIn combo box WM_COMMAND message handler
3303 * If the function succeeds, the return value is nonzero.
3305 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3307 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3309 TRACE("%p\n", fodInfos
);
3315 LPSFOLDER tmpFolder
;
3318 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3320 if( iItem
== CB_ERR
) return FALSE
;
3322 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3327 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3328 tmpFolder
->pidlItem
,
3331 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3332 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3342 /***********************************************************************
3343 * FILEDLG95_LOOKIN_AddItem
3345 * Adds an absolute pidl item to the lookin combo box
3346 * returns the index of the inserted item
3348 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3350 LPITEMIDLIST pidlNext
;
3353 LookInInfos
*liInfos
;
3355 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3360 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3363 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3364 tmpFolder
->m_iIndent
= 0;
3366 /* Calculate the indentation of the item in the lookin*/
3368 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3370 tmpFolder
->m_iIndent
++;
3373 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3375 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3376 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3378 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3379 SHGetFileInfoW((LPCWSTR
)pidl
,
3383 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3385 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3387 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3391 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3393 /* Add the item at the end of the list */
3396 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3398 /* Insert the item at the iInsertId position*/
3401 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3404 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3408 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3409 MemFree( tmpFolder
);
3414 /***********************************************************************
3415 * FILEDLG95_LOOKIN_InsertItemAfterParent
3417 * Insert an item below its parent
3419 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3422 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3427 if (pidl
== pidlParent
)
3430 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3434 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3437 /* Free pidlParent memory */
3438 COMDLG32_SHFree(pidlParent
);
3440 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3443 /***********************************************************************
3444 * FILEDLG95_LOOKIN_SelectItem
3446 * Adds an absolute pidl item to the lookin combo box
3447 * returns the index of the inserted item
3449 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3452 LookInInfos
*liInfos
;
3454 TRACE("%p, %p\n", hwnd
, pidl
);
3456 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3458 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3462 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3463 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3468 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3469 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3473 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3475 if(iRemovedItem
< iItemPos
)
3480 CBSetCurSel(hwnd
,iItemPos
);
3481 liInfos
->uSelectedItem
= iItemPos
;
3487 /***********************************************************************
3488 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3490 * Remove the item with an expansion level over iExpansionLevel
3492 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3495 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3499 if(liInfos
->iMaxIndentation
<= 2)
3502 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3504 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3505 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3507 CBDeleteString(hwnd
,iItemPos
);
3508 liInfos
->iMaxIndentation
--;
3516 /***********************************************************************
3517 * FILEDLG95_LOOKIN_SearchItem
3519 * Search for pidl in the lookin combo box
3520 * returns the index of the found item
3522 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3525 int iCount
= CBGetCount(hwnd
);
3527 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3529 if (iCount
!= CB_ERR
)
3533 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3535 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3537 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3545 /***********************************************************************
3546 * FILEDLG95_LOOKIN_Clean
3548 * Clean the memory used by the lookin combo box
3550 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3552 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3553 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3555 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3559 /* Delete each string of the combo and their associated data */
3560 if (iCount
!= CB_ERR
)
3562 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3564 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3565 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3567 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3571 /* LookInInfos structure */
3573 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3576 /***********************************************************************
3579 * Fill the FORMATETC used in the shell id list
3581 static FORMATETC
get_def_format(void)
3583 static CLIPFORMAT cfFormat
;
3584 FORMATETC formatetc
;
3586 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3587 formatetc
.cfFormat
= cfFormat
;
3589 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3590 formatetc
.lindex
= -1;
3591 formatetc
.tymed
= TYMED_HGLOBAL
;
3595 /***********************************************************************
3596 * FILEDLG95_FILENAME_FillFromSelection
3598 * fills the edit box from the cached DataObject
3600 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3602 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3604 LPWSTR lpstrAllFiles
, lpstrTmp
;
3605 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3608 FORMATETC formatetc
= get_def_format();
3612 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3615 cida
= GlobalLock(medium
.u
.hGlobal
);
3616 nFileSelected
= cida
->cidl
;
3618 /* Allocate a buffer */
3619 nAllFilesMaxLength
= MAX_PATH
+ 3;
3620 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3624 /* Loop through the selection, handle only files (not folders) */
3625 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3627 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3630 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3632 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3634 nAllFilesMaxLength
*= 2;
3635 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3638 lpstrAllFiles
= lpstrTmp
;
3641 lpstrAllFiles
[nAllFilesLength
++] = '"';
3642 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3643 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3644 nAllFilesLength
+= nThisFileLength
;
3645 lpstrAllFiles
[nAllFilesLength
++] = '"';
3646 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3653 /* If there's only one file, use the name as-is without quotes */
3654 lpstrTmp
= lpstrAllFiles
;
3658 lpstrTmp
[nThisFileLength
] = 0;
3660 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3661 /* Select the file name like Windows does */
3662 if (filename_is_edit(fodInfos
))
3663 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3667 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3668 COMCTL32_ReleaseStgMedium(medium
);
3672 /* copied from shell32 to avoid linking to it
3673 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3674 * is dependent on whether emulated OS is unicode or not.
3676 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3681 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3682 COMDLG32_SHFree(src
->u
.pOleStr
);
3686 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3691 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3696 FIXME("unknown type %x!\n", src
->uType
);
3697 if (len
) *dest
= '\0';
3703 /***********************************************************************
3704 * FILEDLG95_FILENAME_GetFileNames
3706 * Copies the filenames to a delimited string list.
3708 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3710 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3711 UINT nFileCount
= 0; /* number of files */
3712 UINT nStrLen
= 0; /* length of string in edit control */
3713 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3717 /* get the filenames from the filename control */
3718 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3719 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3720 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3722 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3724 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3730 * DATAOBJECT Helper functions
3733 /***********************************************************************
3734 * COMCTL32_ReleaseStgMedium
3736 * like ReleaseStgMedium from ole32
3738 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3740 if(medium
.pUnkForRelease
)
3742 IUnknown_Release(medium
.pUnkForRelease
);
3746 GlobalUnlock(medium
.u
.hGlobal
);
3747 GlobalFree(medium
.u
.hGlobal
);
3751 /***********************************************************************
3752 * GetPidlFromDataObject
3754 * Return pidl(s) by number from the cached DataObject
3756 * nPidlIndex=0 gets the fully qualified root path
3758 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3762 FORMATETC formatetc
= get_def_format();
3763 LPITEMIDLIST pidl
= NULL
;
3765 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3770 /* Get the pidls from IDataObject */
3771 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3773 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3774 if(nPidlIndex
<= cida
->cidl
)
3776 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3778 COMCTL32_ReleaseStgMedium(medium
);
3783 /***********************************************************************
3786 * Return the number of selected items in the DataObject.
3789 static UINT
GetNumSelected( IDataObject
*doSelected
)
3793 FORMATETC formatetc
= get_def_format();
3795 TRACE("sv=%p\n", doSelected
);
3797 if (!doSelected
) return 0;
3799 /* Get the pidls from IDataObject */
3800 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3802 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3803 retVal
= cida
->cidl
;
3804 COMCTL32_ReleaseStgMedium(medium
);
3814 /***********************************************************************
3817 * Get the pidl's display name (relative to folder) and
3818 * put it in lpstrFileName.
3820 * Return NOERROR on success,
3824 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3829 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3833 SHGetDesktopFolder(&lpsf
);
3834 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3835 IShellFolder_Release(lpsf
);
3839 /* Get the display name of the pidl relative to the folder */
3840 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3842 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3847 /***********************************************************************
3848 * GetShellFolderFromPidl
3850 * pidlRel is the item pidl relative
3851 * Return the IShellFolder of the absolute pidl
3853 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3855 IShellFolder
*psf
= NULL
,*psfParent
;
3857 TRACE("%p\n", pidlAbs
);
3859 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3862 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3864 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3866 IShellFolder_Release(psfParent
);
3870 /* return the desktop */
3876 /***********************************************************************
3879 * Return the LPITEMIDLIST to the parent of the pidl in the list
3881 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3883 LPITEMIDLIST pidlParent
;
3885 TRACE("%p\n", pidl
);
3887 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3888 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3893 /***********************************************************************
3896 * returns the pidl of the file name relative to folder
3897 * NULL if an error occurred
3899 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3901 LPITEMIDLIST pidl
= NULL
;
3904 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3906 if(!lpcstrFileName
) return NULL
;
3907 if(!*lpcstrFileName
) return NULL
;
3911 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3912 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3913 IShellFolder_Release(lpsf
);
3918 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3925 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3927 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3930 TRACE("%p, %p\n", psf
, pidl
);
3932 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3934 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3935 /* see documentation shell 4.1*/
3936 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3939 /***********************************************************************
3940 * BrowseSelectedFolder
3942 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3944 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3945 BOOL bBrowseSelFolder
= FALSE
;
3949 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3951 LPITEMIDLIST pidlSelection
;
3953 /* get the file selected */
3954 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3955 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3957 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3958 pidlSelection
, SBSP_RELATIVE
) ) )
3961 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
3962 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3964 bBrowseSelFolder
= TRUE
;
3965 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3966 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3968 COMDLG32_SHFree( pidlSelection
);
3971 return bBrowseSelFolder
;
3975 * Memory allocation methods */
3976 static void *MemAlloc(UINT size
)
3978 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3981 static void MemFree(void *mem
)
3983 HeapFree(GetProcessHeap(),0,mem
);
3986 static inline BOOL
valid_struct_size( DWORD size
)
3988 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
3989 (size
== sizeof( OPENFILENAMEW
));
3992 static inline BOOL
is_win16_looks(DWORD flags
)
3994 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
3995 !(flags
& OFN_EXPLORER
));
3998 /* ------------------ APIs ---------------------- */
4000 /***********************************************************************
4001 * GetOpenFileNameA (COMDLG32.@)
4003 * Creates a dialog box for the user to select a file to open.
4006 * TRUE on success: user enters a valid file
4007 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4010 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4012 TRACE("flags 0x%08x\n", ofn
->Flags
);
4014 if (!valid_struct_size( ofn
->lStructSize
))
4016 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4020 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4021 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4022 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4024 if (is_win16_looks(ofn
->Flags
))
4025 return GetFileName31A(ofn
, OPEN_DIALOG
);
4028 FileOpenDlgInfos info
;
4030 init_filedlg_infoA(ofn
, &info
);
4031 return GetFileDialog95(&info
, OPEN_DIALOG
);
4035 /***********************************************************************
4036 * GetOpenFileNameW (COMDLG32.@)
4038 * Creates a dialog box for the user to select a file to open.
4041 * TRUE on success: user enters a valid file
4042 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4045 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4047 TRACE("flags 0x%08x\n", ofn
->Flags
);
4049 if (!valid_struct_size( ofn
->lStructSize
))
4051 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4055 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4056 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4057 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4059 if (is_win16_looks(ofn
->Flags
))
4060 return GetFileName31W(ofn
, OPEN_DIALOG
);
4063 FileOpenDlgInfos info
;
4065 init_filedlg_infoW(ofn
, &info
);
4066 return GetFileDialog95(&info
, OPEN_DIALOG
);
4071 /***********************************************************************
4072 * GetSaveFileNameA (COMDLG32.@)
4074 * Creates a dialog box for the user to select a file to save.
4077 * TRUE on success: user enters a valid file
4078 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4081 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4083 if (!valid_struct_size( ofn
->lStructSize
))
4085 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4089 if (is_win16_looks(ofn
->Flags
))
4090 return GetFileName31A(ofn
, SAVE_DIALOG
);
4093 FileOpenDlgInfos info
;
4095 init_filedlg_infoA(ofn
, &info
);
4096 return GetFileDialog95(&info
, SAVE_DIALOG
);
4100 /***********************************************************************
4101 * GetSaveFileNameW (COMDLG32.@)
4103 * Creates a dialog box for the user to select a file to save.
4106 * TRUE on success: user enters a valid file
4107 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4110 BOOL WINAPI
GetSaveFileNameW(
4111 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4113 if (!valid_struct_size( ofn
->lStructSize
))
4115 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4119 if (is_win16_looks(ofn
->Flags
))
4120 return GetFileName31W(ofn
, SAVE_DIALOG
);
4123 FileOpenDlgInfos info
;
4125 init_filedlg_infoW(ofn
, &info
);
4126 return GetFileDialog95(&info
, SAVE_DIALOG
);
4130 /***********************************************************************
4131 * GetFileTitleA (COMDLG32.@)
4133 * See GetFileTitleW.
4135 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4138 UNICODE_STRING strWFile
;
4141 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4142 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4143 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4144 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4145 RtlFreeUnicodeString( &strWFile
);
4146 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4151 /***********************************************************************
4152 * GetFileTitleW (COMDLG32.@)
4154 * Get the name of a file.
4157 * lpFile [I] name and location of file
4158 * lpTitle [O] returned file name
4159 * cbBuf [I] buffer size of lpTitle
4163 * Failure: negative number.
4165 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4168 static const WCHAR brkpoint
[] = {'*','[',']',0};
4169 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4171 if(lpFile
== NULL
|| lpTitle
== NULL
)
4174 len
= lstrlenW(lpFile
);
4179 if(strpbrkW(lpFile
, brkpoint
))
4184 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4187 for(i
= len
; i
>= 0; i
--)
4189 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4199 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4201 len
= lstrlenW(lpFile
+i
)+1;
4205 lstrcpyW(lpTitle
, &lpFile
[i
]);