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)
68 #include "filedlgbrowser.h"
71 #include "wine/debug.h"
72 #include "wine/heap.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
76 #define UNIMPLEMENTED_FLAGS \
77 (OFN_DONTADDTORECENT |\
78 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
79 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
81 /***********************************************************************
82 * Data structure and global variables
84 typedef struct SFolder
86 int m_iImageIndex
; /* Index of picture in image list */
88 int m_iIndent
; /* Indentation index */
89 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
93 typedef struct tagLookInInfo
100 /***********************************************************************
101 * Defines and global variables
104 /* Draw item constant */
105 #define XTEXTOFFSET 3
110 /* SearchItem methods */
111 #define SEARCH_PIDL 1
113 #define ITEM_NOTFOUND -1
115 /* Undefined windows message sent by CreateViewObject*/
116 #define WM_GETISHELLBROWSER WM_USER+7
118 #define TBPLACES_CMDID_PLACE0 0xa064
119 #define TBPLACES_CMDID_PLACE1 0xa065
120 #define TBPLACES_CMDID_PLACE2 0xa066
121 #define TBPLACES_CMDID_PLACE3 0xa067
122 #define TBPLACES_CMDID_PLACE4 0xa068
125 * Those macros exist in windowsx.h. However, you can't really use them since
126 * they rely on the UNICODE defines and can't be used inside Wine itself.
129 /* Combo box macros */
130 #define CBGetItemDataPtr(hwnd,iItemId) \
131 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
133 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
134 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
136 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
138 return GetPropW(hwnd
, L
"FileOpenDlgInfos");
141 static BOOL
is_dialog_hooked(const FileOpenDlgInfos
*info
)
143 return (info
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && info
->ofnInfos
->lpfnHook
;
146 static BOOL
filedialog_is_readonly_hidden(const FileOpenDlgInfos
*info
)
148 return (info
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) || (info
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
);
151 /***********************************************************************
155 /* Internal functions used by the dialog */
156 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
157 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
158 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
159 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
160 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
161 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
162 static void FILEDLG95_Clean(HWND hwnd
);
164 /* Functions used by the shell navigation */
165 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
166 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
167 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
168 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
170 /* Functions used by the EDIT box */
171 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
173 /* Functions used by the filetype combo box */
174 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
175 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
176 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
177 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
179 /* Functions used by the Look In combo box */
180 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
181 static LRESULT
FILEDLG95_LOOKIN_DrawItem(HWND hwnd
, LPDRAWITEMSTRUCT pDIStruct
);
182 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
183 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
184 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
185 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
186 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
187 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
188 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
190 /* Functions for dealing with the most-recently-used registry keys */
191 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
192 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
193 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
195 /* Miscellaneous tool functions */
196 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
197 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
198 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
199 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
200 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
201 static UINT
GetNumSelected( IDataObject
*doSelected
);
202 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
204 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
205 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
207 static BOOL
BrowseSelectedFolder(HWND hwnd
);
209 static BOOL
get_config_key_as_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
211 DWORD type
, data
, size
;
214 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
))
223 static BOOL
get_config_key_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
225 DWORD type
, data
, size
;
228 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
237 static BOOL
get_config_key_string(HKEY hkey
, const WCHAR
*name
, WCHAR
**value
)
242 if (RegQueryValueExW(hkey
, name
, 0, &type
, NULL
, &size
))
244 if (type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
)
247 str
= heap_alloc(size
);
248 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)str
, &size
))
258 static BOOL
is_places_bar_enabled(const FileOpenDlgInfos
*fodInfos
)
263 if (fodInfos
->ofnInfos
->lStructSize
!= sizeof(*fodInfos
->ofnInfos
) ||
264 (fodInfos
->ofnInfos
->FlagsEx
& OFN_EX_NOPLACESBAR
) ||
265 !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
))
270 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey
))
274 get_config_key_as_dword(hkey
, L
"NoPlacesBar", &value
);
279 static void filedlg_collect_places_pidls(FileOpenDlgInfos
*fodInfos
)
281 static const int default_places
[] =
290 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
293 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
300 swprintf(nameW
, ARRAY_SIZE(nameW
), L
"Place%d", i
);
301 if (get_config_key_dword(hkey
, nameW
, &value
))
303 hr
= SHGetSpecialFolderLocation(NULL
, value
, &fodInfos
->places
[i
]);
305 WARN("Unrecognized special folder %lu.\n", value
);
307 else if (get_config_key_string(hkey
, nameW
, &str
))
309 hr
= SHParseDisplayName(str
, NULL
, &fodInfos
->places
[i
], 0, NULL
);
311 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str
));
316 /* FIXME: eliminate duplicates. */
322 for (i
= 0; i
< ARRAY_SIZE(default_places
); i
++)
323 SHGetSpecialFolderLocation(NULL
, default_places
[i
], &fodInfos
->places
[i
]);
326 /***********************************************************************
329 * Creates an Open common dialog box that lets the user select
330 * the drive, directory, and the name of a file or set of files to open.
332 * IN : The FileOpenDlgInfos structure associated with the dialog
333 * OUT : TRUE on success
334 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
336 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
344 /* test for missing functionality */
345 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
347 FIXME("Flags 0x%08lx not yet implemented\n",
348 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
351 /* Create the dialog from a template */
353 if (is_places_bar_enabled(fodInfos
))
354 templateid
= NEWFILEOPENV2ORD
;
356 templateid
= NEWFILEOPENORD
;
358 if (!(hRes
= FindResourceW(COMDLG32_hInstance
, MAKEINTRESOURCEW(templateid
), (LPCWSTR
)RT_DIALOG
)))
360 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
363 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
364 !(template = LockResource( hDlgTmpl
)))
366 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
370 /* msdn: explorer style dialogs permit sizing by default.
371 * The OFN_ENABLESIZING flag is only needed when a hook or
372 * custom template is provided */
373 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
374 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
375 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
377 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
379 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
380 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
383 /* old style hook messages */
384 if (is_dialog_hooked(fodInfos
))
386 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
387 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
388 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
389 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
392 if (fodInfos
->unicode
)
393 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
395 fodInfos
->ofnInfos
->hwndOwner
,
399 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
401 fodInfos
->ofnInfos
->hwndOwner
,
404 if (fodInfos
->ole_initialized
)
407 /* Unable to create the dialog */
414 static WCHAR
*heap_strdupAtoW(const char *str
)
422 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
423 ret
= heap_alloc(len
* sizeof(WCHAR
));
424 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
429 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
431 INITCOMMONCONTROLSEX icc
;
433 /* Initialize ComboBoxEx32 */
434 icc
.dwSize
= sizeof(icc
);
435 icc
.dwICC
= ICC_USEREX_CLASSES
;
436 InitCommonControlsEx(&icc
);
438 /* Initialize CommDlgExtendedError() */
439 COMDLG32_SetCommDlgExtendedError(0);
441 memset(info
, 0, sizeof(*info
));
443 /* Pass in the original ofn */
444 info
->ofnInfos
= ofn
;
446 info
->title
= ofn
->lpstrTitle
;
447 info
->defext
= ofn
->lpstrDefExt
;
448 info
->filter
= ofn
->lpstrFilter
;
449 info
->customfilter
= ofn
->lpstrCustomFilter
;
453 info
->filename
= heap_alloc(ofn
->nMaxFile
* sizeof(WCHAR
));
454 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
457 if (ofn
->lpstrInitialDir
)
459 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
462 info
->initdir
= heap_alloc(len
* sizeof(WCHAR
));
463 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
467 info
->unicode
= TRUE
;
470 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
475 ofnW
= *(OPENFILENAMEW
*)ofn
;
477 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
478 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
479 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
483 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
484 ofnW
.lpstrFile
= heap_alloc(len
* sizeof(WCHAR
));
485 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
489 if (ofn
->lpstrFilter
)
494 /* filter is a list... title\0ext\0......\0\0 */
495 s
= ofn
->lpstrFilter
;
496 while (*s
) s
= s
+strlen(s
)+1;
498 n
= s
- ofn
->lpstrFilter
;
499 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
500 ofnW
.lpstrFilter
= heap_alloc(len
* sizeof(WCHAR
));
501 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
504 /* convert lpstrCustomFilter */
505 if (ofn
->lpstrCustomFilter
)
510 /* customfilter contains a pair of strings... title\0ext\0 */
511 s
= ofn
->lpstrCustomFilter
;
512 if (*s
) s
= s
+strlen(s
)+1;
513 if (*s
) s
= s
+strlen(s
)+1;
514 n
= s
- ofn
->lpstrCustomFilter
;
515 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
516 ofnW
.lpstrCustomFilter
= heap_alloc(len
* sizeof(WCHAR
));
517 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
520 init_filedlg_infoW(&ofnW
, info
);
522 /* fixup A-specific fields */
523 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
524 info
->unicode
= FALSE
;
526 /* free what was duplicated */
527 heap_free((void *)ofnW
.lpstrInitialDir
);
528 heap_free(ofnW
.lpstrFile
);
531 /***********************************************************************
534 * Call GetFileName95 with this structure and clean the memory.
536 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
538 WCHAR
*current_dir
= NULL
;
542 /* save current directory */
543 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
545 current_dir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
546 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
552 ret
= GetFileName95(info
);
555 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
556 ret
= GetFileName95(info
);
564 SetCurrentDirectoryW(current_dir
);
565 heap_free(current_dir
);
570 heap_free((void *)info
->defext
);
571 heap_free((void *)info
->title
);
572 heap_free((void *)info
->filter
);
573 heap_free((void *)info
->customfilter
);
576 heap_free(info
->filename
);
577 heap_free(info
->initdir
);
579 for (i
= 0; i
< ARRAY_SIZE(info
->places
); i
++)
580 ILFree(info
->places
[i
]);
585 /******************************************************************************
586 * COMDLG32_GetDisplayNameOf [internal]
588 * Helper function to get the display name for a pidl.
590 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
591 LPSHELLFOLDER psfDesktop
;
594 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
597 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
598 IShellFolder_Release(psfDesktop
);
602 IShellFolder_Release(psfDesktop
);
603 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
606 /******************************************************************************
607 * COMDLG32_GetCanonicalPath [internal]
609 * Helper function to get the canonical path.
611 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
612 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
614 WCHAR lpstrTemp
[MAX_PATH
];
616 /* Get the current directory name */
617 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
620 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
622 PathAddBackslashW(lpstrPathAndFile
);
624 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile
), debugstr_w(lpstrFile
));
626 /* if the user specified a fully qualified path use it */
627 if(PathIsRelativeW(lpstrFile
))
629 lstrcatW(lpstrPathAndFile
, lpstrFile
);
633 /* does the path have a drive letter? */
634 if (PathGetDriveNumberW(lpstrFile
) == -1)
635 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
637 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
640 /* resolve "." and ".." */
641 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
642 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
643 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
646 /***********************************************************************
647 * COMDLG32_SplitFileNames [internal]
649 * Creates a delimited list of filenames.
651 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
653 UINT nStrCharCount
= 0; /* index in src buffer */
654 UINT nFileIndex
= 0; /* index in dest buffer */
655 UINT nFileCount
= 0; /* number of files */
657 /* we might get single filename without any '"',
658 * so we need nStrLen + terminating \0 + end-of-list \0 */
659 *lpstrFileList
= heap_alloc((nStrLen
+ 2) * sizeof(WCHAR
));
662 /* build delimited file list from filenames */
663 while ( nStrCharCount
<= nStrLen
)
665 if ( lpstrEdit
[nStrCharCount
]=='"' )
668 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
670 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
673 (*lpstrFileList
)[nFileIndex
++] = 0;
679 /* single, unquoted string */
680 if ((nStrLen
> 0) && (nFileIndex
== 0) )
682 lstrcpyW(*lpstrFileList
, lpstrEdit
);
683 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
688 (*lpstrFileList
)[nFileIndex
++] = '\0';
690 *sizeUsed
= nFileIndex
;
694 /***********************************************************************
695 * ArrangeCtrlPositions [internal]
697 * NOTE: Make sure to add testcases for any changes made here.
699 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
701 HWND hwndChild
, hwndStc32
;
702 RECT rectParent
, rectChild
, rectStc32
;
706 /* Take into account if open as read only checkbox and help button
711 RECT rectHelp
, rectCancel
;
712 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
713 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
714 /* subtract the height of the help button plus the space between
715 * the help button and the cancel button to the height of the dialog
717 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
721 There are two possibilities to add components to the default file dialog box.
723 By default, all the new components are added below the standard dialog box (the else case).
725 However, if there is a static text component with the stc32 id, a special case happens.
726 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
727 in the window and the cx and cy indicate how to size the window.
728 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
729 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
733 GetClientRect(hwndParentDlg
, &rectParent
);
735 /* when arranging controls we have to use fixed parent size */
736 rectParent
.bottom
-= help_fixup
;
738 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
741 GetWindowRect(hwndStc32
, &rectStc32
);
742 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
744 /* set the size of the stc32 control according to the size of
745 * client area of the parent dialog
747 SetWindowPos(hwndStc32
, 0,
749 rectParent
.right
, rectParent
.bottom
,
750 SWP_NOMOVE
| SWP_NOZORDER
);
753 SetRectEmpty(&rectStc32
);
755 /* this part moves controls of the child dialog */
756 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
759 if (hwndChild
!= hwndStc32
)
761 GetWindowRect(hwndChild
, &rectChild
);
762 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
764 /* move only if stc32 exist */
765 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
767 /* move to the right of visible controls of the parent dialog */
768 rectChild
.left
+= rectParent
.right
;
769 rectChild
.left
-= rectStc32
.right
;
771 /* move even if stc32 doesn't exist */
772 if (rectChild
.top
>= rectStc32
.bottom
)
774 /* move below visible controls of the parent dialog */
775 rectChild
.top
+= rectParent
.bottom
;
776 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
779 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
780 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
782 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
785 /* this part moves controls of the parent dialog */
786 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
789 if (hwndChild
!= hwndChildDlg
)
791 GetWindowRect(hwndChild
, &rectChild
);
792 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
794 /* left,top of stc32 marks the position of controls
795 * from the parent dialog
797 rectChild
.left
+= rectStc32
.left
;
798 rectChild
.top
+= rectStc32
.top
;
800 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
801 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
803 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
806 /* calculate the size of the resulting dialog */
808 /* here we have to use original parent size */
809 GetClientRect(hwndParentDlg
, &rectParent
);
810 GetClientRect(hwndChildDlg
, &rectChild
);
811 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
812 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
817 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
818 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
820 chgx
= rectChild
.right
- rectParent
.right
;
822 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
823 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
825 /* Unconditionally set new dialog
826 * height to that of the child
828 chgy
= rectChild
.bottom
- rectParent
.bottom
;
833 chgy
= rectChild
.bottom
- help_fixup
;
835 /* set the size of the parent dialog */
836 GetWindowRect(hwndParentDlg
, &rectParent
);
837 SetWindowPos(hwndParentDlg
, 0,
839 rectParent
.right
- rectParent
.left
+ chgx
,
840 rectParent
.bottom
- rectParent
.top
+ chgy
,
841 SWP_NOMOVE
| SWP_NOZORDER
);
844 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
853 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
860 TRACE("%p, %p\n", fodInfos
, hwnd
);
863 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
864 * structure's hInstance parameter is not a HINSTANCE, but
865 * instead a pointer to a template resource to use.
867 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
870 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
872 hinst
= COMDLG32_hInstance
;
873 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
875 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
881 hinst
= fodInfos
->ofnInfos
->hInstance
;
882 if(fodInfos
->unicode
)
884 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
885 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
889 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
890 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
894 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
897 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
898 !(template = LockResource( hDlgTmpl
)))
900 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
904 if (fodInfos
->unicode
)
905 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
906 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
907 (LPARAM
)fodInfos
->ofnInfos
);
909 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
910 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
911 (LPARAM
)fodInfos
->ofnInfos
);
914 else if (is_dialog_hooked(fodInfos
))
919 WORD menu
,class,title
;
921 GetClientRect(hwnd
,&rectHwnd
);
922 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
923 temp
.tmplate
.dwExtendedStyle
= 0;
924 temp
.tmplate
.cdit
= 0;
929 temp
.menu
= temp
.class = temp
.title
= 0;
931 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
932 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
939 /***********************************************************************
940 * SendCustomDlgNotificationMessage
942 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
945 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
947 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
951 TRACE("%p %d\n", hwndParentDlg
, uCode
);
953 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
956 TRACE("CALL NOTIFY for %d\n", uCode
);
958 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
959 ofnNotify
.hdr
.idFrom
= 0;
960 ofnNotify
.hdr
.code
= uCode
;
961 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
962 ofnNotify
.pszFile
= NULL
;
964 if (fodInfos
->unicode
)
965 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
967 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
969 TRACE("RET NOTIFY retval %#Ix\n", hook_result
);
974 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
978 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
980 TRACE("CDM_GETFILEPATH:\n");
982 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
985 /* get path and filenames */
986 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
987 buffer
= heap_alloc( (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
988 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
991 p
= buffer
+ lstrlenW(buffer
);
993 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
995 if (fodInfos
->unicode
)
997 total
= lstrlenW( buffer
) + 1;
998 if (result
) lstrcpynW( result
, buffer
, size
);
999 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
1003 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
1004 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
1005 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1007 heap_free( buffer
);
1011 /***********************************************************************
1012 * FILEDLG95_HandleCustomDialogMessages
1014 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1016 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1018 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1019 WCHAR lpstrPath
[MAX_PATH
];
1022 if(!fodInfos
) return FALSE
;
1026 case CDM_GETFILEPATH
:
1027 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1030 case CDM_GETFOLDERPATH
:
1031 TRACE("CDM_GETFOLDERPATH:\n");
1032 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1035 if (fodInfos
->unicode
)
1036 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1038 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1039 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1041 retval
= lstrlenW(lpstrPath
) + 1;
1044 case CDM_GETFOLDERIDLIST
:
1045 retval
= ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1046 if (retval
<= wParam
)
1047 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1051 TRACE("CDM_GETSPEC:\n");
1052 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1055 if (fodInfos
->unicode
)
1056 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1058 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1062 case CDM_SETCONTROLTEXT
:
1063 TRACE("CDM_SETCONTROLTEXT:\n");
1066 if( fodInfos
->unicode
)
1067 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1069 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1074 case CDM_HIDECONTROL
:
1075 /* MSDN states that it should fail for not OFN_EXPLORER case */
1076 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1078 HWND control
= GetDlgItem( hwnd
, wParam
);
1079 if (control
) ShowWindow( control
, SW_HIDE
);
1082 else retval
= FALSE
;
1086 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1087 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1090 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1094 /***********************************************************************
1095 * FILEDLG95_OnWMGetMMI
1097 * WM_GETMINMAXINFO message handler for resizable dialogs
1099 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1101 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1102 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1103 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1105 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1110 /***********************************************************************
1111 * FILEDLG95_OnWMSize
1113 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1115 * FIXME: this could be made more elaborate. Now use a simple scheme
1116 * where the file view is enlarged and the controls are either moved
1117 * vertically or horizontally to get out of the way. Only the "grip"
1118 * is moved in both directions to stay in the corner.
1120 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1126 FileOpenDlgInfos
*fodInfos
;
1128 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1129 fodInfos
= get_filedlg_infoptr(hwnd
);
1130 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1131 /* get the new dialog rectangle */
1132 GetWindowRect( hwnd
, &rc
);
1133 TRACE("%p, size from %ld,%ld to %ld,%ld\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1134 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1135 /* not initialized yet */
1136 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1137 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1138 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1140 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1141 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1142 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1143 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1144 /* change the size of the view window */
1145 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1146 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1147 hdwp
= BeginDeferWindowPos( 10);
1148 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1149 rcview
.right
- rcview
.left
+ chgx
,
1150 rcview
.bottom
- rcview
.top
+ chgy
,
1151 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1152 /* change position and sizes of the controls */
1153 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1155 int ctrlid
= GetDlgCtrlID( ctrl
);
1156 GetWindowRect( ctrl
, &rc
);
1157 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1158 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1160 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1162 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1164 else if( rc
.top
> rcview
.bottom
)
1166 /* if it was below the shell view
1170 /* file name (edit or comboboxex) and file types combo change also width */
1174 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1175 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1176 SWP_NOACTIVATE
| SWP_NOZORDER
);
1178 /* then these buttons must move out of the way */
1182 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1184 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1187 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1189 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1192 else if( rc
.left
> rcview
.right
)
1194 /* if it was to the right of the shell view
1196 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1198 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1205 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1207 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1208 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1209 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1211 case IDC_TOOLBARSTATIC
:
1213 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1215 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1218 /* not resized in windows. Since wine uses this invisible control
1219 * to size the browser view it needs to be resized */
1220 case IDC_SHELLSTATIC
:
1221 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1222 rc
.right
- rc
.left
+ chgx
,
1223 rc
.bottom
- rc
.top
+ chgy
,
1224 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1226 case IDC_TOOLBARPLACES
:
1227 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
+ chgy
,
1228 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1233 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1234 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1236 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1237 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1239 GetWindowRect( ctrl
, &rc
);
1240 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1241 if( rc
.top
> rcview
.bottom
)
1243 /* if it was below the shell view
1245 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1246 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1247 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1249 else if( rc
.left
> rcview
.right
)
1251 /* if it was to the right of the shell view
1253 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1254 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1255 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1258 /* size the custom dialog at the end: some applications do some
1259 * control re-arranging at this point */
1260 GetClientRect(hwnd
, &rc
);
1261 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1262 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1264 EndDeferWindowPos( hdwp
);
1265 /* should not be needed */
1266 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1270 /***********************************************************************
1273 * File open dialog procedure
1275 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1278 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1285 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1287 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1288 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1290 /* Some shell namespace extensions depend on COM being initialized. */
1291 if (SUCCEEDED(OleInitialize(NULL
)))
1292 fodInfos
->ole_initialized
= TRUE
;
1294 SetPropW(hwnd
, L
"FileOpenDlgInfos", fodInfos
);
1296 FILEDLG95_InitControls(hwnd
);
1298 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1300 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1301 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1302 RECT client
, client_adjusted
;
1304 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1306 style
|= WS_SIZEBOX
;
1307 ex_style
|= WS_EX_WINDOWEDGE
;
1310 style
&= ~WS_SIZEBOX
;
1311 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1312 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1314 GetClientRect( hwnd
, &client
);
1315 GetClientRect( hwnd
, &client_adjusted
);
1316 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1318 GetWindowRect( hwnd
, &rc
);
1319 rc
.right
+= client_adjusted
.right
- client
.right
;
1320 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1321 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1322 SWP_NOZORDER
| SWP_NOMOVE
);
1324 GetWindowRect( hwnd
, &rc
);
1325 fodInfos
->DlgInfos
.hwndGrip
=
1326 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1327 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1328 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1329 rc
.right
- gripx
, rc
.bottom
- gripy
,
1330 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1333 fodInfos
->DlgInfos
.hwndCustomDlg
=
1334 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1336 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1337 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1339 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1340 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1342 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1343 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1344 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1347 /* if the app has changed the position of the invisible listbox,
1348 * change that of the listview (browser) as well */
1349 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1350 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1351 if( !EqualRect( &rc
, &rcstc
))
1353 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1354 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1355 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1356 SWP_NOACTIVATE
| SWP_NOZORDER
);
1359 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1361 GetWindowRect( hwnd
, &rc
);
1362 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1363 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1364 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1365 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1366 GetClientRect( hwnd
, &rc
);
1367 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1368 rc
.right
- gripx
, rc
.bottom
- gripy
,
1369 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1370 /* resize the dialog to the previous invocation */
1371 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1372 SetWindowPos( hwnd
, NULL
,
1373 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1374 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1377 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1378 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1383 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1384 case WM_GETMINMAXINFO
:
1385 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1387 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1390 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1393 FILEDLG95_LOOKIN_DrawItem(hwnd
, (LPDRAWITEMSTRUCT
)lParam
);
1399 case WM_GETISHELLBROWSER
:
1400 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1404 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1405 HWND places_bar
= GetDlgItem(hwnd
, IDC_TOOLBARPLACES
);
1408 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1409 MemDialogSize
= fodInfos
->sizedlg
;
1413 himl
= (HIMAGELIST
)SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_GETIMAGELIST
, 0, 0);
1414 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, 0);
1415 ImageList_Destroy(himl
);
1421 RemovePropW(hwnd
, L
"FileOpenDlgInfos");
1426 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1429 /* set up the button tooltips strings */
1430 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1432 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1433 switch(lpnmh
->idFrom
)
1435 /* Up folder button */
1436 case FCIDM_TB_UPFOLDER
:
1437 stringId
= IDS_UPFOLDER
;
1439 /* New folder button */
1440 case FCIDM_TB_NEWFOLDER
:
1441 stringId
= IDS_NEWFOLDER
;
1443 /* List option button */
1444 case FCIDM_TB_SMALLICON
:
1445 stringId
= IDS_LISTVIEW
;
1447 /* Details option button */
1448 case FCIDM_TB_REPORTVIEW
:
1449 stringId
= IDS_REPORTVIEW
;
1451 /* Desktop button */
1452 case FCIDM_TB_DESKTOP
:
1453 stringId
= IDS_TODESKTOP
;
1458 lpdi
->hinst
= COMDLG32_hInstance
;
1459 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1464 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1465 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1470 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1472 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1473 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1476 /***********************************************************************
1477 * FILEDLG95_InitControls
1479 * WM_INITDIALOG message handler (before hook notification)
1481 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1483 BOOL win2000plus
= FALSE
;
1484 BOOL win98plus
= FALSE
;
1485 BOOL handledPath
= FALSE
;
1486 OSVERSIONINFOW osVi
;
1488 static const TBBUTTON tbb
[] =
1490 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1491 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1492 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1493 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1494 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1495 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1496 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1497 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1498 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1500 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1505 HIMAGELIST toolbarImageList
;
1506 ITEMIDLIST
*desktopPidl
;
1507 SHFILEINFOW fileinfo
;
1509 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1511 TRACE("%p\n", fodInfos
);
1513 /* Get windows version emulating */
1514 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1515 GetVersionExW(&osVi
);
1516 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1517 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1518 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1519 win2000plus
= (osVi
.dwMajorVersion
> 4);
1520 if (win2000plus
) win98plus
= TRUE
;
1522 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1525 /* Use either the edit or the comboboxex for the filename control */
1526 if (filename_is_edit( fodInfos
))
1528 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1529 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1533 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1534 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1537 /* Get the hwnd of the controls */
1538 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1539 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1541 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1542 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1544 /* construct the toolbar */
1545 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1546 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1548 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1549 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1550 rectTB
.left
= rectlook
.right
;
1551 rectTB
.top
= rectlook
.top
-1;
1553 if (fodInfos
->unicode
)
1554 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1555 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1556 rectTB
.left
, rectTB
.top
,
1557 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1558 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1560 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1561 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1562 rectTB
.left
, rectTB
.top
,
1563 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1564 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1566 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1568 /* FIXME: use TB_LOADIMAGES when implemented */
1569 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1570 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1571 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1573 /* Retrieve and add desktop icon to the toolbar */
1574 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1575 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1576 SHGetFileInfoW((const WCHAR
*)desktopPidl
, 0, &fileinfo
, sizeof(fileinfo
),
1577 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1578 ImageList_AddIcon(toolbarImageList
, fileinfo
.hIcon
);
1580 DestroyIcon(fileinfo
.hIcon
);
1581 CoTaskMemFree(desktopPidl
);
1583 /* Finish Toolbar Construction */
1584 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1585 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1587 if (is_places_bar_enabled(fodInfos
))
1589 TBBUTTON tb
= { 0 };
1594 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_BUTTONSTRUCTSIZE
, 0, 0);
1595 GetClientRect(GetDlgItem(hwnd
, IDC_TOOLBARPLACES
), &rect
);
1596 cx
= rect
.right
- rect
.left
;
1598 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONWIDTH
, 0, MAKELPARAM(cx
, cx
));
1599 himl
= ImageList_Create(GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), ILC_COLOR32
, 4, 1);
1601 filedlg_collect_places_pidls(fodInfos
);
1602 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
1606 if (!fodInfos
->places
[i
])
1609 memset(&fileinfo
, 0, sizeof(fileinfo
));
1610 SHGetFileInfoW((const WCHAR
*)fodInfos
->places
[i
], 0, &fileinfo
, sizeof(fileinfo
),
1611 SHGFI_PIDL
| SHGFI_DISPLAYNAME
| SHGFI_ICON
);
1612 index
= ImageList_AddIcon(himl
, fileinfo
.hIcon
);
1615 tb
.iString
= (INT_PTR
)fileinfo
.szDisplayName
;
1616 tb
.fsState
= TBSTATE_ENABLED
| TBSTATE_WRAP
;
1617 tb
.idCommand
= TBPLACES_CMDID_PLACE0
+ i
;
1618 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tb
);
1620 DestroyIcon(fileinfo
.hIcon
);
1623 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, (LPARAM
)himl
);
1624 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, cx
* 3 / 4));
1627 /* Set the window text with the text specified in the OPENFILENAME structure */
1630 SetWindowTextW(hwnd
,fodInfos
->title
);
1632 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1635 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, ARRAY_SIZE(buf
));
1636 SetWindowTextW(hwnd
, buf
);
1639 /* Initialise the file name edit control */
1640 handledPath
= FALSE
;
1641 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1643 if(fodInfos
->filename
)
1645 /* 1. If win2000 or higher and filename contains a path, use it
1646 in preference over the lpstrInitialDir */
1647 if (win2000plus
&& *fodInfos
->filename
&& wcspbrk(fodInfos
->filename
, L
"\\")) {
1648 WCHAR tmpBuf
[MAX_PATH
];
1652 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1655 /* nameBit is always shorter than the original filename. It may be NULL
1656 * when the filename contains only a drive name instead of file name */
1659 lstrcpyW(fodInfos
->filename
,nameBit
);
1663 *fodInfos
->filename
= '\0';
1665 heap_free(fodInfos
->initdir
);
1666 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1667 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1669 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1670 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1672 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1675 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1679 /* 2. (All platforms) If initdir is not null, then use it */
1680 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1682 /* Work out the proper path as supplied one might be relative */
1683 /* (Here because supplying '.' as dir browses to My Computer) */
1684 WCHAR tmpBuf
[MAX_PATH
];
1685 WCHAR tmpBuf2
[MAX_PATH
];
1689 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1690 if (PathFileExistsW(tmpBuf
)) {
1691 /* initdir does not have to be a directory. If a file is
1692 * specified, the dir part is taken */
1693 if (PathIsDirectoryW(tmpBuf
)) {
1694 PathAddBackslashW(tmpBuf
);
1695 lstrcatW(tmpBuf
, L
"*");
1697 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1700 heap_free(fodInfos
->initdir
);
1701 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1702 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1704 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1707 else if (fodInfos
->initdir
)
1709 heap_free(fodInfos
->initdir
);
1710 fodInfos
->initdir
= NULL
;
1711 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1715 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1717 /* 3. All except w2k+: if filename contains a path use it */
1718 if (!win2000plus
&& fodInfos
->filename
&& *fodInfos
->filename
&&
1719 wcspbrk(fodInfos
->filename
, L
"\\")) {
1720 WCHAR tmpBuf
[MAX_PATH
];
1724 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1729 /* nameBit is always shorter than the original filename */
1730 lstrcpyW(fodInfos
->filename
, nameBit
);
1733 len
= lstrlenW(tmpBuf
);
1734 heap_free(fodInfos
->initdir
);
1735 fodInfos
->initdir
= heap_alloc((len
+1)*sizeof(WCHAR
));
1736 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1739 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1740 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1742 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1745 /* 4. Win2000+: Recently used */
1746 if (!handledPath
&& win2000plus
) {
1747 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1748 fodInfos
->initdir
[0] = '\0';
1750 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1752 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1755 heap_free(fodInfos
->initdir
);
1756 fodInfos
->initdir
= NULL
;
1760 /* 5. win98+ and win2000+ if any files of specified filter types in
1761 current directory, use it */
1762 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1764 LPCWSTR lpstrPos
= fodInfos
->filter
;
1765 WIN32_FIND_DATAW FindFileData
;
1770 /* filter is a list... title\0ext\0......\0\0 */
1772 /* Skip the title */
1773 if(! *lpstrPos
) break; /* end */
1774 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1776 /* See if any files exist in the current dir with this extension */
1777 if(! *lpstrPos
) break; /* end */
1779 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1781 if (hFind
== INVALID_HANDLE_VALUE
) {
1782 /* None found - continue search */
1783 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1787 heap_free(fodInfos
->initdir
);
1788 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1789 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1792 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1793 debugstr_w(lpstrPos
));
1800 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1801 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1802 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1804 if (SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
) == S_OK
)
1806 if (SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
) == S_OK
)
1809 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1810 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1813 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1816 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1819 } else if (!handledPath
) {
1820 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1821 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1823 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1826 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1827 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1829 /* Must the open as read only check box be checked ?*/
1830 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1832 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1835 /* Must the open as read only check box be hidden? */
1836 if (filedialog_is_readonly_hidden(fodInfos
))
1838 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1839 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1842 /* Must the help button be hidden? */
1843 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1845 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1846 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1849 /* change Open to Save */
1850 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1853 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, ARRAY_SIZE(buf
));
1854 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1855 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, ARRAY_SIZE(buf
));
1856 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1859 /* Initialize the filter combo box */
1860 FILEDLG95_FILETYPE_Init(hwnd
);
1865 /***********************************************************************
1866 * FILEDLG95_ResizeControls
1868 * WM_INITDIALOG message handler (after hook notification)
1870 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1872 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1874 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1877 UINT flags
= SWP_NOACTIVATE
;
1879 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1880 filedialog_is_readonly_hidden(fodInfos
) && !(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
));
1882 /* resize the custom dialog to the parent size */
1883 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1884 GetClientRect(hwnd
, &rc
);
1887 /* our own fake template is zero sized and doesn't have children, so
1888 * there is no need to resize it. Picasa depends on it.
1890 flags
|= SWP_NOSIZE
;
1893 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1894 0, 0, rc
.right
, rc
.bottom
, flags
);
1898 /* Resize the height; if opened as read-only, checkbox and help button are
1899 * hidden and we are not using a custom template nor a customDialog
1901 if (filedialog_is_readonly_hidden(fodInfos
) &&
1902 (!(fodInfos
->ofnInfos
->Flags
&
1903 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1905 RECT rectDlg
, rectHelp
, rectCancel
;
1906 GetWindowRect(hwnd
, &rectDlg
);
1907 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1908 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1909 /* subtract the height of the help button plus the space between the help
1910 * button and the cancel button to the height of the dialog
1912 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1913 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1914 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1920 /***********************************************************************
1921 * FILEDLG95_FillControls
1923 * WM_INITDIALOG message handler (after hook notification)
1925 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1927 LPITEMIDLIST pidlItemId
= NULL
;
1929 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1931 TRACE("dir=%s file=%s\n",
1932 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1934 /* Get the initial directory pidl */
1936 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1938 WCHAR path
[MAX_PATH
];
1940 GetCurrentDirectoryW(MAX_PATH
,path
);
1941 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1944 /* Initialise shell objects */
1945 FILEDLG95_SHELL_Init(hwnd
);
1947 /* Initialize the Look In combo box */
1948 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1950 /* Browse to the initial directory */
1951 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1957 /***********************************************************************
1960 * Regroups all the cleaning functions of the filedlg
1962 void FILEDLG95_Clean(HWND hwnd
)
1964 FILEDLG95_FILETYPE_Clean(hwnd
);
1965 FILEDLG95_LOOKIN_Clean(hwnd
);
1966 FILEDLG95_SHELL_Clean(hwnd
);
1970 /***********************************************************************
1971 * Browse to arbitrary pidl
1973 static void filedlg_browse_to_pidl(const FileOpenDlgInfos
*info
, LPITEMIDLIST pidl
)
1975 TRACE("%p, %p\n", info
->ShellInfos
.hwndOwner
, pidl
);
1977 IShellBrowser_BrowseObject(info
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
1978 if (info
->ofnInfos
->Flags
& OFN_EXPLORER
)
1979 SendCustomDlgNotificationMessage(info
->ShellInfos
.hwndOwner
, CDN_FOLDERCHANGE
);
1982 /***********************************************************************
1983 * FILEDLG95_OnWMCommand
1985 * WM_COMMAND message handler
1987 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1989 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1990 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1991 WORD id
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1997 FILEDLG95_OnOpen(hwnd
);
2001 FILEDLG95_Clean(hwnd
);
2002 EndDialog(hwnd
, FALSE
);
2004 /* Filetype combo box */
2006 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
2008 /* LookIn combo box */
2010 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
2013 /* --- toolbar --- */
2014 /* Up folder button */
2015 case FCIDM_TB_UPFOLDER
:
2016 FILEDLG95_SHELL_UpFolder(hwnd
);
2018 /* New folder button */
2019 case FCIDM_TB_NEWFOLDER
:
2020 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
2022 /* List option button */
2023 case FCIDM_TB_SMALLICON
:
2024 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
2026 /* Details option button */
2027 case FCIDM_TB_REPORTVIEW
:
2028 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
2031 case FCIDM_TB_DESKTOP
:
2035 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP
, &pidl
);
2036 filedlg_browse_to_pidl(fodInfos
, pidl
);
2042 case TBPLACES_CMDID_PLACE0
:
2043 case TBPLACES_CMDID_PLACE1
:
2044 case TBPLACES_CMDID_PLACE2
:
2045 case TBPLACES_CMDID_PLACE3
:
2046 case TBPLACES_CMDID_PLACE4
:
2047 filedlg_browse_to_pidl(fodInfos
, fodInfos
->places
[id
- TBPLACES_CMDID_PLACE0
]);
2055 /* Do not use the listview selection anymore */
2056 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
2060 /***********************************************************************
2061 * FILEDLG95_OnWMGetIShellBrowser
2063 * WM_GETISHELLBROWSER message handler
2065 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
2067 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2071 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
2077 /***********************************************************************
2078 * FILEDLG95_SendFileOK
2080 * Sends the CDN_FILEOK notification if required
2083 * TRUE if the dialog should close
2084 * FALSE if the dialog should not be closed
2086 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
2088 /* ask the hook if we can close */
2089 if (is_dialog_hooked(fodInfos
))
2094 /* First send CDN_FILEOK as MSDN doc says */
2095 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2096 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
2099 TRACE("canceled\n");
2103 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2104 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
2105 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
2108 TRACE("canceled\n");
2115 /***********************************************************************
2116 * FILEDLG95_OnOpenMultipleFiles
2118 * Handles the opening of multiple files.
2121 * check destination buffer size
2123 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2125 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2126 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2127 UINT nCount
, nSizePath
;
2131 if(fodInfos
->unicode
)
2133 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2134 ofn
->lpstrFile
[0] = '\0';
2138 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2139 ofn
->lpstrFile
[0] = '\0';
2142 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2144 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2145 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2146 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2148 LPWSTR lpstrTemp
= lpstrFileList
;
2150 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2154 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2157 WCHAR lpstrNotFound
[100];
2158 WCHAR lpstrMsg
[100];
2161 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2162 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2164 lstrcpyW(tmp
, lpstrTemp
);
2165 lstrcatW(tmp
, L
"\n");
2166 lstrcatW(tmp
, lpstrNotFound
);
2167 lstrcatW(tmp
, L
"\n");
2168 lstrcatW(tmp
, lpstrMsg
);
2170 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2174 /* move to the next file in the list of files */
2175 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2180 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2181 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2183 /* For "oldstyle" dialog the components have to
2184 be separated by blanks (not '\0'!) and short
2185 filenames have to be used! */
2186 FIXME("Components have to be separated by blanks\n");
2188 if(fodInfos
->unicode
)
2190 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2191 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2192 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2196 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2198 if (ofn
->lpstrFile
!= NULL
)
2200 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2201 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2202 if (ofn
->nMaxFile
> nSizePath
)
2204 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2205 ofn
->lpstrFile
+ nSizePath
,
2206 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2211 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2212 fodInfos
->ofnInfos
->nFileExtension
= 0;
2214 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2217 /* clean and exit */
2218 FILEDLG95_Clean(hwnd
);
2219 return EndDialog(hwnd
,TRUE
);
2222 /* Returns the 'slot name' of the given module_name in the registry's
2223 * most-recently-used list. This will be an ASCII value in the
2224 * range ['a','z'). Returns zero on error.
2226 * The slot's value in the registry has the form:
2227 * module_name\0mru_path\0
2229 * If stored_path is given, then stored_path will contain the path name
2230 * stored in the registry's MRU list for the given module_name.
2232 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2233 * MRU list key for the given module_name.
2235 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2237 WCHAR mru_list
[32], *cur_mru_slot
;
2238 BOOL taken
[25] = {0};
2239 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2240 HKEY hkey_tmp
, *hkey
;
2249 *stored_path
= '\0';
2251 ret
= RegCreateKeyW(HKEY_CURRENT_USER
,
2252 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", hkey
);
2254 WARN("Unable to create MRU key: %ld\n", ret
);
2258 ret
= RegGetValueW(*hkey
, NULL
, L
"MRUList", RRF_RT_REG_SZ
, &key_type
,
2259 (LPBYTE
)mru_list
, &mru_list_size
);
2260 if(ret
|| key_type
!= REG_SZ
){
2261 if(ret
== ERROR_FILE_NOT_FOUND
)
2264 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type
, ret
);
2269 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2270 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2271 DWORD value_data_size
= sizeof(value_data
);
2273 *value_name
= *cur_mru_slot
;
2275 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2276 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2277 if(ret
|| key_type
!= REG_BINARY
){
2278 WARN("Error getting MRU slot data: type: %ld, ret: %ld\n", key_type
, ret
);
2282 if(!wcsicmp(module_name
, value_data
)){
2286 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2294 /* the module name isn't in the registry, so find the next open slot */
2295 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2296 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2297 for(i
= 0; i
< 25; ++i
){
2302 /* all slots are taken, so return the last one in MRUList */
2304 return *cur_mru_slot
;
2307 /* save the given filename as most-recently-used path for this module */
2308 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2310 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2314 /* get the current executable's name */
2315 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2317 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2320 module_name
= wcsrchr(module_path
, '\\');
2322 module_name
= module_path
;
2326 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2331 { /* update the slot's info */
2332 WCHAR
*path_ends
, *final
;
2333 DWORD path_len
, final_len
;
2335 /* use only the path segment of `filename' */
2336 path_ends
= wcsrchr(filename
, '\\');
2337 path_len
= path_ends
- filename
;
2339 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2341 final
= heap_alloc(final_len
* sizeof(WCHAR
));
2344 lstrcpyW(final
, module_name
);
2345 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2346 final
[final_len
-1] = '\0';
2348 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2349 final_len
* sizeof(WCHAR
));
2351 WARN("Error saving MRU data to slot %s: %ld\n", wine_dbgstr_w(slot_name
), ret
);
2360 { /* update MRUList value */
2361 WCHAR old_mru_list
[32], new_mru_list
[32];
2362 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2363 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2365 ret
= RegGetValueW(hkey
, NULL
, L
"MRUList", RRF_RT_ANY
, &key_type
,
2366 (LPBYTE
)old_mru_list
, &mru_list_size
);
2367 if(ret
|| key_type
!= REG_SZ
){
2368 if(ret
== ERROR_FILE_NOT_FOUND
){
2369 new_mru_list
[0] = slot
;
2370 new_mru_list
[1] = '\0';
2372 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type
, ret
);
2377 /* copy old list data over so that the new slot is at the start
2379 *new_mru_slot
++ = slot
;
2380 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2381 if(*old_mru_slot
!= slot
)
2382 *new_mru_slot
++ = *old_mru_slot
;
2384 *new_mru_slot
= '\0';
2387 ret
= RegSetValueExW(hkey
, L
"MRUList", 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2388 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2390 WARN("Error saving MRUList data: %ld\n", ret
);
2397 /* load the most-recently-used path for this module */
2398 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2400 WCHAR module_path
[MAX_PATH
], *module_name
;
2402 /* get the current executable's name */
2403 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2405 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2408 module_name
= wcsrchr(module_path
, '\\');
2410 module_name
= module_path
;
2414 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2415 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2418 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2420 WCHAR strMsgTitle
[MAX_PATH
];
2421 WCHAR strMsgText
[MAX_PATH
];
2423 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, ARRAY_SIZE(strMsgTitle
));
2425 strMsgTitle
[0] = '\0';
2426 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, ARRAY_SIZE(strMsgText
));
2427 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2430 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2431 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2433 int nOpenAction
= defAction
;
2434 LPWSTR lpszTemp
, lpszTemp1
;
2435 LPITEMIDLIST pidl
= NULL
;
2437 /* check for invalid chars */
2438 if((wcspbrk(lpstrPathAndFile
+3, L
"/:<>|") != NULL
) && !(flags
& OFN_NOVALIDATE
))
2440 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2444 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2446 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2449 LPSHELLFOLDER lpsfChild
;
2450 WCHAR lpwstrTemp
[MAX_PATH
];
2451 DWORD dwEaten
, dwAttributes
;
2454 lstrcpyW(lpwstrTemp
, lpszTemp
);
2455 if (lpszTemp
== lpstrPathAndFile
&& (p
= PathSkipRootW(lpwstrTemp
)))
2461 p
= PathFindNextComponentW(lpwstrTemp
);
2462 if (!p
) break; /* end of path */
2465 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2467 /* There are no wildcards when OFN_NOVALIDATE is set */
2468 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2470 /* if the last element is a wildcard do a search */
2471 if(wcspbrk(lpszTemp1
, L
"*?") != NULL
)
2473 nOpenAction
= ONOPEN_SEARCH
;
2477 lpszTemp1
= lpszTemp
;
2479 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2481 /* append a backslash to drive letters */
2482 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2483 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2484 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2486 PathAddBackslashW(lpwstrTemp
);
2489 dwAttributes
= SFGAO_FOLDER
;
2490 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2492 /* the path component is valid, we have a pidl of the next path component */
2493 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
2494 if(dwAttributes
& SFGAO_FOLDER
)
2496 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2498 ERR("bind to failed\n"); /* should not fail */
2501 IShellFolder_Release(*ppsf
);
2509 /* end dialog, return value */
2510 nOpenAction
= ONOPEN_OPEN
;
2516 else if (!(flags
& OFN_NOVALIDATE
))
2518 if(*lpszTemp
|| /* points to trailing null for last path element */
2519 (lpwstrTemp
[lstrlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2521 if(flags
& OFN_PATHMUSTEXIST
)
2523 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2529 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2531 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2535 /* change to the current folder */
2536 nOpenAction
= ONOPEN_OPEN
;
2541 nOpenAction
= ONOPEN_OPEN
;
2550 /***********************************************************************
2553 * Ok button WM_COMMAND message handler
2555 * If the function succeeds, the return value is nonzero.
2557 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2559 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2560 LPWSTR lpstrFileList
;
2561 UINT nFileCount
= 0;
2564 WCHAR lpstrPathAndFile
[MAX_PATH
];
2565 LPSHELLFOLDER lpsf
= NULL
;
2568 TRACE("hwnd=%p\n", hwnd
);
2570 /* try to browse the selected item */
2571 if(BrowseSelectedFolder(hwnd
))
2574 /* get the files from the edit control */
2575 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2582 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2586 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2589 Step 1: Build a complete path name from the current folder and
2590 the filename or path in the edit box.
2592 - the path in the edit box is a root path
2593 (with or without drive letter)
2594 - the edit box contains ".." (or a path with ".." in it)
2597 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2598 heap_free(lpstrFileList
);
2601 Step 2: here we have a cleaned up path
2603 We have to parse the path step by step to see if we have to browse
2604 to a folder if the path points to a directory or the last
2605 valid element is a directory.
2608 lpstrPathAndFile: cleaned up path
2612 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2613 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2614 nOpenAction
= ONOPEN_OPEN
;
2616 nOpenAction
= ONOPEN_BROWSE
;
2618 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2619 fodInfos
->ofnInfos
->Flags
,
2620 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2626 Step 3: here we have a cleaned up and validated path
2629 lpsf: ShellFolder bound to the rightmost valid path component
2630 lpstrPathAndFile: cleaned up path
2631 nOpenAction: action to do
2633 TRACE("end validate sf=%p\n", lpsf
);
2637 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2638 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2641 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2644 /* replace the current filter */
2645 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2646 len
= lstrlenW(lpszTemp
)+1;
2647 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc(len
* sizeof(WCHAR
));
2648 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2650 /* set the filter cb to the extension when possible */
2651 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2652 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, iPos
, 0);
2655 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2656 TRACE("ONOPEN_BROWSE\n");
2658 IPersistFolder2
* ppf2
;
2659 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2661 LPITEMIDLIST pidlCurrent
;
2662 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2663 IPersistFolder2_Release(ppf2
);
2664 if (!ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2666 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2667 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2669 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2670 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2673 else if( nOpenAction
== ONOPEN_SEARCH
)
2675 if (fodInfos
->Shell
.FOIShellView
)
2676 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2678 ILFree(pidlCurrent
);
2679 if (filename_is_edit( fodInfos
))
2680 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2685 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2686 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2692 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2693 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2697 /* update READONLY check box flag */
2698 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2699 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2701 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2703 /* Attach the file extension with file name*/
2704 ext
= PathFindExtensionW(lpstrPathAndFile
);
2705 if (! *ext
&& fodInfos
->defext
)
2707 /* if no extension is specified with file name, then */
2708 /* attach the extension from file filter or default one */
2710 WCHAR
*filterExt
= NULL
;
2711 LPWSTR lpstrFilter
= NULL
;
2712 int PathLength
= lstrlenW(lpstrPathAndFile
);
2714 /*Get the file extension from file type filter*/
2715 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2716 fodInfos
->ofnInfos
->nFilterIndex
-1);
2718 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2720 WCHAR
* filterSearchIndex
;
2721 filterExt
= heap_alloc((lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2722 lstrcpyW(filterExt
, lpstrFilter
);
2724 /* if a semicolon-separated list of file extensions was given, do not include the
2725 semicolon or anything after it in the extension.
2726 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2727 filterSearchIndex
= wcschr(filterExt
, ';');
2728 if (filterSearchIndex
)
2730 filterSearchIndex
[0] = '\0';
2733 /* find the file extension by searching for the first dot in filterExt */
2734 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2735 /* if the extension is invalid or contains a glob, ignore it */
2736 filterSearchIndex
= wcschr(filterExt
, '.');
2737 if (filterSearchIndex
++ && !wcschr(filterSearchIndex
, '*') && !wcschr(filterSearchIndex
, '?'))
2739 lstrcpyW(filterExt
, filterSearchIndex
);
2743 heap_free(filterExt
);
2750 /* use the default file extension */
2751 filterExt
= heap_alloc((lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2752 lstrcpyW(filterExt
, fodInfos
->defext
);
2755 if (*filterExt
) /* ignore filterExt="" */
2758 lstrcatW(lpstrPathAndFile
, L
".");
2759 /* Attach the extension */
2760 lstrcatW(lpstrPathAndFile
, filterExt
);
2763 heap_free(filterExt
);
2765 /* In Open dialog: if file does not exist try without extension */
2766 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2767 lpstrPathAndFile
[PathLength
] = '\0';
2769 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2772 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2773 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2775 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2778 /* In Save dialog: check if the file already exists */
2779 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2780 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2781 && PathFileExistsW(lpstrPathAndFile
))
2783 WCHAR lpstrOverwrite
[100];
2786 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2787 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2788 MB_YESNO
| MB_ICONEXCLAMATION
);
2789 if (answer
== IDNO
|| answer
== IDCANCEL
)
2796 /* In Open dialog: check if it should be created if it doesn't exist */
2797 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2798 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2799 && !PathFileExistsW(lpstrPathAndFile
))
2801 WCHAR lpstrCreate
[100];
2804 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2805 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2806 MB_YESNO
| MB_ICONEXCLAMATION
);
2807 if (answer
== IDNO
|| answer
== IDCANCEL
)
2814 /* Check that the size of the file does not exceed buffer size.
2815 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2816 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2817 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2820 /* fill destination buffer */
2821 if (fodInfos
->ofnInfos
->lpstrFile
)
2823 if(fodInfos
->unicode
)
2825 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2827 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2828 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2829 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2833 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2835 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2836 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2837 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2838 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2842 if(fodInfos
->unicode
)
2846 /* set filename offset */
2847 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2848 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2850 /* set extension offset */
2851 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2852 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2857 CHAR tempFileA
[MAX_PATH
];
2859 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2860 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2861 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2863 /* set filename offset */
2864 lpszTemp
= PathFindFileNameA(tempFileA
);
2865 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2867 /* set extension offset */
2868 lpszTemp
= PathFindExtensionA(tempFileA
);
2869 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2872 /* set the lpstrFileTitle */
2873 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2875 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2876 if(fodInfos
->unicode
)
2878 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2879 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2883 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2884 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2885 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2889 /* copy currently selected filter to lpstrCustomFilter */
2890 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2892 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2893 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2894 NULL
, 0, NULL
, NULL
);
2895 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2897 LPSTR s
= ofn
->lpstrCustomFilter
;
2898 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2899 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2900 s
, len
, NULL
, NULL
);
2905 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2908 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2911 FILEDLG95_Clean(hwnd
);
2912 ret
= EndDialog(hwnd
, TRUE
);
2918 size
= lstrlenW(lpstrPathAndFile
) + 1;
2919 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2921 /* return needed size in first two bytes of lpstrFile */
2922 if(fodInfos
->ofnInfos
->lpstrFile
)
2923 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2924 FILEDLG95_Clean(hwnd
);
2925 ret
= EndDialog(hwnd
, FALSE
);
2926 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2933 if(lpsf
) IShellFolder_Release(lpsf
);
2937 /***********************************************************************
2938 * FILEDLG95_SHELL_Init
2940 * Initialisation of the shell objects
2942 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2944 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2946 TRACE("%p\n", hwnd
);
2949 * Initialisation of the FileOpenDialogInfos structure
2955 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2957 /* Disable multi-select if flag not set */
2958 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2960 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2962 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2963 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2965 /* Construct the IShellBrowser interface */
2966 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2971 /***********************************************************************
2972 * FILEDLG95_SHELL_ExecuteCommand
2974 * Change the folder option and refresh the view
2975 * If the function succeeds, the return value is nonzero.
2977 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2979 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2982 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2984 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2989 CMINVOKECOMMANDINFO ci
;
2990 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2991 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2995 IContextMenu_InvokeCommand(pcm
, &ci
);
2996 IContextMenu_Release(pcm
);
3002 /***********************************************************************
3003 * FILEDLG95_SHELL_UpFolder
3005 * Browse to the specified object
3006 * If the function succeeds, the return value is nonzero.
3008 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
3010 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3014 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3018 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3019 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3024 /***********************************************************************
3025 * FILEDLG95_SHELL_Clean
3027 * Cleans the memory used by shell objects
3029 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
3031 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3035 ILFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
3037 /* clean Shell interfaces */
3038 if (fodInfos
->Shell
.FOIShellView
)
3040 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
3041 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
3043 if (fodInfos
->Shell
.FOIShellFolder
)
3044 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
3045 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
3046 if (fodInfos
->Shell
.FOIDataObject
)
3047 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
3050 /***********************************************************************
3051 * FILEDLG95_FILETYPE_Init
3053 * Initialisation of the file type combo box
3055 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
3057 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3058 int nFilters
= 0; /* number of filters */
3061 TRACE("%p\n", hwnd
);
3063 if(fodInfos
->customfilter
)
3065 /* customfilter has one entry... title\0ext\0
3066 * Set first entry of combo box item with customfilter
3069 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
3072 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
3074 /* Copy the extensions */
3075 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
3076 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3077 lstrcpyW(lpstrExt
,lpstrPos
);
3079 /* Add the item at the end of the combo */
3080 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)fodInfos
->customfilter
);
3081 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
, (LPARAM
)lpstrExt
);
3085 if(fodInfos
->filter
)
3087 LPCWSTR lpstrPos
= fodInfos
->filter
;
3091 /* filter is a list... title\0ext\0......\0\0
3092 * Set the combo item text to the title and the item data
3095 LPCWSTR lpstrDisplay
;
3099 if(! *lpstrPos
) break; /* end */
3100 lpstrDisplay
= lpstrPos
;
3101 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3103 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)lpstrDisplay
);
3107 /* Copy the extensions */
3108 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3109 lstrcpyW(lpstrExt
,lpstrPos
);
3110 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3112 /* Add the item at the end of the combo */
3113 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
- 1, (LPARAM
)lpstrExt
);
3115 /* malformed filters are added anyway... */
3116 if (!*lpstrExt
) break;
3121 * Set the current filter to the one specified
3122 * in the initialisation structure
3124 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3128 /* Check to make sure our index isn't out of bounds. */
3129 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3130 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3131 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3133 /* set default filter index */
3134 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3135 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3137 /* calculate index of Combo Box item */
3138 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3139 if (fodInfos
->customfilter
== NULL
)
3142 /* Set the current index selection. */
3143 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, nFilterIndexCB
, 0);
3145 /* Get the corresponding text string from the combo box. */
3146 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3149 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3155 CharLowerW(lpstrFilter
); /* lowercase */
3156 len
= lstrlenW(lpstrFilter
)+1;
3157 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3158 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3161 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3165 /***********************************************************************
3166 * FILEDLG95_FILETYPE_OnCommand
3168 * WM_COMMAND of the file type combo box
3169 * If the function succeeds, the return value is nonzero.
3171 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3173 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3181 /* Get the current item of the filetype combo box */
3182 int iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCURSEL
, 0, 0);
3184 /* set the current filter index */
3185 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3186 (fodInfos
->customfilter
== NULL
? 1 : 0);
3188 /* Set the current filter with the current selection */
3189 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3191 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3193 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3196 CharLowerW(lpstrFilter
); /* lowercase */
3197 len
= lstrlenW(lpstrFilter
)+1;
3198 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3199 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3200 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3201 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3204 /* Refresh the actual view to display the included items*/
3205 if (fodInfos
->Shell
.FOIShellView
)
3206 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3211 /***********************************************************************
3212 * FILEDLG95_FILETYPE_SearchExt
3214 * searches for an extension in the filetype box
3216 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3220 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3222 TRACE("%s\n", debugstr_w(lpstrExt
));
3224 if(iCount
!= CB_ERR
)
3226 for(i
=0;i
<iCount
;i
++)
3228 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3235 /***********************************************************************
3236 * FILEDLG95_FILETYPE_Clean
3238 * Clean the memory used by the filetype combo box
3240 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3242 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3246 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCOUNT
, 0, 0);
3250 /* Delete each string of the combo and their associated data */
3251 if(iCount
!= CB_ERR
)
3253 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3255 heap_free((void *)CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3256 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_DELETESTRING
, iPos
, 0);
3259 /* Current filter */
3260 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3263 /***********************************************************************
3264 * FILEDLG95_LOOKIN_Init
3266 * Initialisation of the look in combo box
3269 /* Small helper function, to determine if the unixfs shell extension is rooted
3270 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3272 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3275 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3276 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3277 "{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3284 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3286 IShellFolder
*psfRoot
, *psfDrives
;
3287 IEnumIDList
*lpeRoot
, *lpeDrives
;
3288 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3291 LookInInfos
*liInfos
= heap_alloc_zero(sizeof(*liInfos
));
3293 TRACE("%p\n", hwndCombo
);
3295 liInfos
->iMaxIndentation
= 0;
3297 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3299 hdc
= GetDC( hwndCombo
);
3300 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3301 GetTextMetricsW( hdc
, &tm
);
3302 ReleaseDC( hwndCombo
, hdc
);
3304 /* set item height for both text field and listbox */
3305 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, -1, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3306 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, 0, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3308 /* Turn on the extended UI for the combo box like Windows does */
3309 SendMessageW(hwndCombo
, CB_SETEXTENDEDUI
, TRUE
, 0);
3311 /* Initialise data of Desktop folder */
3312 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3313 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3316 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3318 SHGetDesktopFolder(&psfRoot
);
3322 /* enumerate the contents of the desktop */
3323 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3325 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3327 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3329 /* If the unixfs extension is rooted, we don't expand the drives by default */
3330 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3332 /* special handling for CSIDL_DRIVES */
3333 if (ILIsEqual(pidlTmp
, pidlDrives
))
3335 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3337 /* enumerate the drives */
3338 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3340 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3342 pidlAbsTmp
= ILCombine(pidlTmp
, pidlTmp1
);
3343 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3347 IEnumIDList_Release(lpeDrives
);
3349 IShellFolder_Release(psfDrives
);
3356 IEnumIDList_Release(lpeRoot
);
3358 IShellFolder_Release(psfRoot
);
3364 /***********************************************************************
3365 * FILEDLG95_LOOKIN_DrawItem
3367 * WM_DRAWITEM message handler
3369 static LRESULT
FILEDLG95_LOOKIN_DrawItem(HWND hwnd
, LPDRAWITEMSTRUCT pDIStruct
)
3371 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3372 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3373 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3374 RECT rectText
, rectIcon
, lookin_rect
;
3376 HIMAGELIST ilItemImage
;
3379 LPSFOLDER tmpFolder
;
3380 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3381 UINT icon_width
, icon_height
;
3382 FileOpenDlgInfos
*dialog
;
3387 if(pDIStruct
->itemID
== -1)
3390 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3391 pDIStruct
->itemID
)))
3395 icon_width
= GetSystemMetrics(SM_CXICON
);
3396 icon_height
= GetSystemMetrics(SM_CYICON
);
3397 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3399 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3400 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3401 shgfi_flags
|= SHGFI_SMALLICON
;
3404 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3405 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3407 /* Is this item selected ? */
3408 if(pDIStruct
->itemState
& ODS_SELECTED
)
3410 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3411 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3412 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3416 SetTextColor(pDIStruct
->hDC
,crText
);
3417 SetBkColor(pDIStruct
->hDC
,crWin
);
3418 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3421 /* Do not indent item if drawing in the edit of the combo */
3422 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3425 iIndentation
= tmpFolder
->m_iIndent
;
3427 /* Draw text and icon */
3429 /* Initialise the icon display area */
3430 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3431 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3432 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3433 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3435 /* Initialise the text display area */
3436 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3437 rectText
.left
= rectIcon
.right
;
3439 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3440 rectText
.right
= pDIStruct
->rcItem
.right
;
3442 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3444 /* Draw the icon from the image list */
3445 ImageList_Draw(ilItemImage
,
3452 /* Draw the associated text */
3453 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3455 dialog
= get_filedlg_infoptr(hwnd
);
3456 GetWindowRect(dialog
->DlgInfos
.hwndLookInCB
, &lookin_rect
);
3457 height
= lookin_rect
.bottom
- lookin_rect
.top
;
3458 SendMessageW(dialog
->DlgInfos
.hwndTB
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(height
, height
));
3463 /***********************************************************************
3464 * FILEDLG95_LOOKIN_OnCommand
3466 * LookIn combo box WM_COMMAND message handler
3467 * If the function succeeds, the return value is nonzero.
3469 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3471 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3473 TRACE("%p\n", fodInfos
);
3479 LPSFOLDER tmpFolder
;
3482 iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCURSEL
, 0, 0);
3484 if( iItem
== CB_ERR
) return FALSE
;
3486 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3491 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3492 tmpFolder
->pidlItem
,
3495 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3496 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3506 /***********************************************************************
3507 * FILEDLG95_LOOKIN_AddItem
3509 * Adds an absolute pidl item to the lookin combo box
3510 * returns the index of the inserted item
3512 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3514 LPITEMIDLIST pidlNext
;
3517 LookInInfos
*liInfos
;
3519 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3524 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3527 tmpFolder
= heap_alloc_zero(sizeof(*tmpFolder
));
3528 tmpFolder
->m_iIndent
= 0;
3530 /* Calculate the indentation of the item in the lookin*/
3532 while ((pidlNext
= ILGetNext(pidlNext
)))
3534 tmpFolder
->m_iIndent
++;
3537 tmpFolder
->pidlItem
= ILClone(pidl
);
3539 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3540 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3542 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3543 SHGetFileInfoW((LPCWSTR
)pidl
,
3547 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3549 TRACE("-- Add %s attr=0x%08lx\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3551 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3555 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3557 /* Add the item at the end of the list */
3560 iItemID
= SendMessageW(hwnd
, CB_ADDSTRING
, 0, (LPARAM
)sfi
.szDisplayName
);
3562 /* Insert the item at the iInsertId position*/
3565 iItemID
= SendMessageW(hwnd
, CB_INSERTSTRING
, iInsertId
, (LPARAM
)sfi
.szDisplayName
);
3568 SendMessageW(hwnd
, CB_SETITEMDATA
, iItemID
, (LPARAM
)tmpFolder
);
3572 ILFree( tmpFolder
->pidlItem
);
3573 heap_free( tmpFolder
);
3578 /***********************************************************************
3579 * FILEDLG95_LOOKIN_InsertItemAfterParent
3581 * Insert an item below its parent
3583 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3586 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3591 if (pidl
== pidlParent
)
3594 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3598 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3603 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3606 /***********************************************************************
3607 * FILEDLG95_LOOKIN_SelectItem
3609 * Adds an absolute pidl item to the lookin combo box
3610 * returns the index of the inserted item
3612 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3615 LookInInfos
*liInfos
;
3617 TRACE("%p, %p\n", hwnd
, pidl
);
3619 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3621 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3625 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3626 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3631 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3632 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3636 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3638 if(iRemovedItem
< iItemPos
)
3643 SendMessageW(hwnd
, CB_SETCURSEL
, iItemPos
, 0);
3644 liInfos
->uSelectedItem
= iItemPos
;
3650 /***********************************************************************
3651 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3653 * Remove the item with an expansion level over iExpansionLevel
3655 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3658 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3662 if(liInfos
->iMaxIndentation
<= 2)
3665 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3667 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3668 ILFree(tmpFolder
->pidlItem
);
3669 heap_free(tmpFolder
);
3670 SendMessageW(hwnd
, CB_DELETESTRING
, iItemPos
, 0);
3671 liInfos
->iMaxIndentation
--;
3679 /***********************************************************************
3680 * FILEDLG95_LOOKIN_SearchItem
3682 * Search for pidl in the lookin combo box
3683 * returns the index of the found item
3685 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3690 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3692 TRACE("0x%08Ix 0x%x\n",searchArg
, iSearchMethod
);
3694 if (iCount
!= CB_ERR
)
3698 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3700 if (iSearchMethod
== SEARCH_PIDL
&& ILIsEqual((LPITEMIDLIST
)searchArg
, tmpFolder
->pidlItem
))
3702 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3710 /***********************************************************************
3711 * FILEDLG95_LOOKIN_Clean
3713 * Clean the memory used by the lookin combo box
3715 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3717 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3718 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3721 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCOUNT
, 0, 0);
3725 /* Delete each string of the combo and their associated data */
3726 if (iCount
!= CB_ERR
)
3728 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3730 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3731 ILFree(tmpFolder
->pidlItem
);
3732 heap_free(tmpFolder
);
3733 SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_DELETESTRING
, iPos
, 0);
3737 /* LookInInfos structure */
3739 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3742 /***********************************************************************
3745 * Fill the FORMATETC used in the shell id list
3747 static FORMATETC
get_def_format(void)
3749 static CLIPFORMAT cfFormat
;
3750 FORMATETC formatetc
;
3752 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3753 formatetc
.cfFormat
= cfFormat
;
3755 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3756 formatetc
.lindex
= -1;
3757 formatetc
.tymed
= TYMED_HGLOBAL
;
3761 /***********************************************************************
3762 * FILEDLG95_FILENAME_FillFromSelection
3764 * fills the edit box from the cached DataObject
3766 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3768 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3770 LPWSTR lpstrAllFiles
, lpstrTmp
;
3771 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3774 FORMATETC formatetc
= get_def_format();
3778 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3781 cida
= GlobalLock(medium
.hGlobal
);
3782 nFileSelected
= cida
->cidl
;
3784 /* Allocate a buffer */
3785 nAllFilesMaxLength
= MAX_PATH
+ 3;
3786 lpstrAllFiles
= heap_alloc_zero(nAllFilesMaxLength
* sizeof(WCHAR
));
3790 /* Loop through the selection, handle only files (not folders) */
3791 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3793 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3796 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3798 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3800 nAllFilesMaxLength
*= 2;
3801 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3804 lpstrAllFiles
= lpstrTmp
;
3807 lpstrAllFiles
[nAllFilesLength
++] = '"';
3808 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3809 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3810 nAllFilesLength
+= nThisFileLength
;
3811 lpstrAllFiles
[nAllFilesLength
++] = '"';
3812 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3819 /* If there's only one file, use the name as-is without quotes */
3820 lpstrTmp
= lpstrAllFiles
;
3824 lpstrTmp
[nThisFileLength
] = 0;
3826 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3827 /* Select the file name like Windows does */
3828 if (filename_is_edit(fodInfos
))
3829 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3833 heap_free(lpstrAllFiles
);
3834 COMCTL32_ReleaseStgMedium(medium
);
3838 /* copied from shell32 to avoid linking to it
3839 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3840 * is dependent on whether emulated OS is unicode or not.
3842 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3847 lstrcpynW(dest
, src
->pOleStr
, len
);
3848 CoTaskMemFree(src
->pOleStr
);
3852 if (!MultiByteToWideChar( CP_ACP
, 0, src
->cStr
, -1, dest
, len
) && len
)
3857 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->uOffset
, -1, dest
, len
) && len
)
3862 FIXME("unknown type %x!\n", src
->uType
);
3863 if (len
) *dest
= '\0';
3869 /***********************************************************************
3870 * FILEDLG95_FILENAME_GetFileNames
3872 * Copies the filenames to a delimited string list.
3874 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3876 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3877 UINT nFileCount
= 0; /* number of files */
3878 UINT nStrLen
= 0; /* length of string in edit control */
3879 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3883 /* get the filenames from the filename control */
3884 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3885 lpstrEdit
= heap_alloc( (nStrLen
+1)*sizeof(WCHAR
) );
3886 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3888 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3890 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3891 heap_free(lpstrEdit
);
3896 * DATAOBJECT Helper functions
3899 /***********************************************************************
3900 * COMCTL32_ReleaseStgMedium
3902 * like ReleaseStgMedium from ole32
3904 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3906 if(medium
.pUnkForRelease
)
3908 IUnknown_Release(medium
.pUnkForRelease
);
3912 GlobalUnlock(medium
.hGlobal
);
3913 GlobalFree(medium
.hGlobal
);
3917 /***********************************************************************
3918 * GetPidlFromDataObject
3920 * Return pidl(s) by number from the cached DataObject
3922 * nPidlIndex=0 gets the fully qualified root path
3924 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3928 FORMATETC formatetc
= get_def_format();
3929 LPITEMIDLIST pidl
= NULL
;
3931 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3936 /* Get the pidls from IDataObject */
3937 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3939 LPIDA cida
= GlobalLock(medium
.hGlobal
);
3940 if(nPidlIndex
<= cida
->cidl
)
3942 pidl
= ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3944 COMCTL32_ReleaseStgMedium(medium
);
3949 /***********************************************************************
3952 * Return the number of selected items in the DataObject.
3955 static UINT
GetNumSelected( IDataObject
*doSelected
)
3959 FORMATETC formatetc
= get_def_format();
3961 TRACE("sv=%p\n", doSelected
);
3963 if (!doSelected
) return 0;
3965 /* Get the pidls from IDataObject */
3966 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3968 LPIDA cida
= GlobalLock(medium
.hGlobal
);
3969 retVal
= cida
->cidl
;
3970 COMCTL32_ReleaseStgMedium(medium
);
3980 /***********************************************************************
3983 * Get the pidl's display name (relative to folder) and
3984 * put it in lpstrFileName.
3986 * Return NOERROR on success,
3990 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3995 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3999 SHGetDesktopFolder(&lpsf
);
4000 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
4001 IShellFolder_Release(lpsf
);
4005 /* Get the display name of the pidl relative to the folder */
4006 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
4008 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
4013 /***********************************************************************
4014 * GetShellFolderFromPidl
4016 * pidlRel is the item pidl relative
4017 * Return the IShellFolder of the absolute pidl
4019 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
4021 IShellFolder
*psf
= NULL
,*psfParent
;
4023 TRACE("%p\n", pidlAbs
);
4025 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
4028 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
4030 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
4032 IShellFolder_Release(psfParent
);
4036 /* return the desktop */
4042 /***********************************************************************
4045 * Return the LPITEMIDLIST to the parent of the pidl in the list
4047 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
4049 LPITEMIDLIST pidlParent
;
4051 TRACE("%p\n", pidl
);
4053 pidlParent
= ILClone(pidl
);
4054 ILRemoveLastID(pidlParent
);
4059 /***********************************************************************
4062 * returns the pidl of the file name relative to folder
4063 * NULL if an error occurred
4065 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
4067 LPITEMIDLIST pidl
= NULL
;
4070 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
4072 if(!lpcstrFileName
) return NULL
;
4073 if(!*lpcstrFileName
) return NULL
;
4077 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
4078 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4079 IShellFolder_Release(lpsf
);
4084 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4091 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
4093 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4096 TRACE("%p, %p\n", psf
, pidl
);
4098 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4100 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
4101 /* see documentation shell 4.1*/
4102 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4105 /***********************************************************************
4106 * BrowseSelectedFolder
4108 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4110 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
4111 BOOL bBrowseSelFolder
= FALSE
;
4115 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4117 LPITEMIDLIST pidlSelection
;
4119 /* get the file selected */
4120 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4121 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4123 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4124 pidlSelection
, SBSP_RELATIVE
) ) )
4127 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, ARRAY_SIZE(buf
));
4128 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4130 bBrowseSelFolder
= TRUE
;
4131 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4132 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4134 ILFree( pidlSelection
);
4137 return bBrowseSelFolder
;
4140 static inline BOOL
valid_struct_size( DWORD size
)
4142 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4143 (size
== sizeof( OPENFILENAMEW
));
4146 static inline BOOL
is_win16_looks(DWORD flags
)
4148 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4149 !(flags
& OFN_EXPLORER
));
4152 /* ------------------ APIs ---------------------- */
4154 /***********************************************************************
4155 * GetOpenFileNameA (COMDLG32.@)
4157 * Creates a dialog box for the user to select a file to open.
4160 * TRUE on success: user enters a valid file
4161 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4164 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4166 TRACE("flags 0x%08lx\n", ofn
->Flags
);
4168 if (!valid_struct_size( ofn
->lStructSize
))
4170 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4174 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4175 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4176 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4178 if (is_win16_looks(ofn
->Flags
))
4179 return GetFileName31A(ofn
, OPEN_DIALOG
);
4182 FileOpenDlgInfos info
;
4184 init_filedlg_infoA(ofn
, &info
);
4185 return GetFileDialog95(&info
, OPEN_DIALOG
);
4189 /***********************************************************************
4190 * GetOpenFileNameW (COMDLG32.@)
4192 * Creates a dialog box for the user to select a file to open.
4195 * TRUE on success: user enters a valid file
4196 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4199 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4201 TRACE("flags 0x%08lx\n", ofn
->Flags
);
4203 if (!valid_struct_size( ofn
->lStructSize
))
4205 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4209 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4210 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4211 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4213 if (is_win16_looks(ofn
->Flags
))
4214 return GetFileName31W(ofn
, OPEN_DIALOG
);
4217 FileOpenDlgInfos info
;
4219 init_filedlg_infoW(ofn
, &info
);
4220 return GetFileDialog95(&info
, OPEN_DIALOG
);
4225 /***********************************************************************
4226 * GetSaveFileNameA (COMDLG32.@)
4228 * Creates a dialog box for the user to select a file to save.
4231 * TRUE on success: user enters a valid file
4232 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4235 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4237 if (!valid_struct_size( ofn
->lStructSize
))
4239 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4243 if (is_win16_looks(ofn
->Flags
))
4244 return GetFileName31A(ofn
, SAVE_DIALOG
);
4247 FileOpenDlgInfos info
;
4249 init_filedlg_infoA(ofn
, &info
);
4250 return GetFileDialog95(&info
, SAVE_DIALOG
);
4254 /***********************************************************************
4255 * GetSaveFileNameW (COMDLG32.@)
4257 * Creates a dialog box for the user to select a file to save.
4260 * TRUE on success: user enters a valid file
4261 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4264 BOOL WINAPI
GetSaveFileNameW(
4265 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4267 if (!valid_struct_size( ofn
->lStructSize
))
4269 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4273 if (is_win16_looks(ofn
->Flags
))
4274 return GetFileName31W(ofn
, SAVE_DIALOG
);
4277 FileOpenDlgInfos info
;
4279 init_filedlg_infoW(ofn
, &info
);
4280 return GetFileDialog95(&info
, SAVE_DIALOG
);
4284 /***********************************************************************
4285 * GetFileTitleA (COMDLG32.@)
4287 * See GetFileTitleW.
4289 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4292 UNICODE_STRING strWFile
;
4295 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4296 lpWTitle
= heap_alloc(cbBuf
* sizeof(WCHAR
));
4297 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4298 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4299 RtlFreeUnicodeString( &strWFile
);
4300 heap_free( lpWTitle
);
4305 /***********************************************************************
4306 * GetFileTitleW (COMDLG32.@)
4308 * Get the name of a file.
4311 * lpFile [I] name and location of file
4312 * lpTitle [O] returned file name
4313 * cbBuf [I] buffer size of lpTitle
4317 * Failure: negative number.
4319 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4322 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4324 if(lpFile
== NULL
|| lpTitle
== NULL
)
4327 len
= lstrlenW(lpFile
);
4332 if(wcspbrk(lpFile
, L
"*[]"))
4337 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4340 for(i
= len
; i
>= 0; i
--)
4342 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4352 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4354 len
= lstrlenW(lpFile
+i
)+1;
4358 lstrcpyW(lpTitle
, &lpFile
[i
]);