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)
55 #define NONAMELESSUNION
70 #include "filedlgbrowser.h"
73 #include "wine/debug.h"
74 #include "wine/heap.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
78 #define UNIMPLEMENTED_FLAGS \
79 (OFN_DONTADDTORECENT |\
80 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
81 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
83 /***********************************************************************
84 * Data structure and global variables
86 typedef struct SFolder
88 int m_iImageIndex
; /* Index of picture in image list */
90 int m_iIndent
; /* Indentation index */
91 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
95 typedef struct tagLookInInfo
102 /***********************************************************************
103 * Defines and global variables
106 /* Draw item constant */
107 #define XTEXTOFFSET 3
112 /* SearchItem methods */
113 #define SEARCH_PIDL 1
115 #define ITEM_NOTFOUND -1
117 /* Undefined windows message sent by CreateViewObject*/
118 #define WM_GETISHELLBROWSER WM_USER+7
120 #define TBPLACES_CMDID_PLACE0 0xa064
121 #define TBPLACES_CMDID_PLACE1 0xa065
122 #define TBPLACES_CMDID_PLACE2 0xa066
123 #define TBPLACES_CMDID_PLACE3 0xa067
124 #define TBPLACES_CMDID_PLACE4 0xa068
127 * Those macros exist in windowsx.h. However, you can't really use them since
128 * they rely on the UNICODE defines and can't be used inside Wine itself.
131 /* Combo box macros */
132 #define CBGetItemDataPtr(hwnd,iItemId) \
133 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
135 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
136 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
138 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
140 return GetPropW(hwnd
, L
"FileOpenDlgInfos");
143 static BOOL
is_dialog_hooked(const FileOpenDlgInfos
*info
)
145 return (info
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && info
->ofnInfos
->lpfnHook
;
148 static BOOL
filedialog_is_readonly_hidden(const FileOpenDlgInfos
*info
)
150 return (info
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) || (info
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
);
153 /***********************************************************************
157 /* Internal functions used by the dialog */
158 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
159 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
160 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
161 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
162 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
163 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
164 static void FILEDLG95_Clean(HWND hwnd
);
166 /* Functions used by the shell navigation */
167 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
168 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
169 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
170 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
172 /* Functions used by the EDIT box */
173 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
175 /* Functions used by the filetype combo box */
176 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
177 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
178 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
179 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
181 /* Functions used by the Look In combo box */
182 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
183 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
184 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
185 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
186 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
187 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
188 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
189 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
190 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
192 /* Functions for dealing with the most-recently-used registry keys */
193 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
194 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
195 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
197 /* Miscellaneous tool functions */
198 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
199 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
200 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
201 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
202 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
203 static UINT
GetNumSelected( IDataObject
*doSelected
);
204 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
206 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
207 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
208 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
209 static BOOL
BrowseSelectedFolder(HWND hwnd
);
211 static BOOL
get_config_key_as_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
213 DWORD type
, data
, size
;
216 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
))
225 static BOOL
get_config_key_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
227 DWORD type
, data
, size
;
230 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
239 static BOOL
get_config_key_string(HKEY hkey
, const WCHAR
*name
, WCHAR
**value
)
244 if (RegQueryValueExW(hkey
, name
, 0, &type
, NULL
, &size
))
246 if (type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
)
249 str
= heap_alloc(size
);
250 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)str
, &size
))
260 static BOOL
is_places_bar_enabled(const FileOpenDlgInfos
*fodInfos
)
265 if (fodInfos
->ofnInfos
->lStructSize
!= sizeof(*fodInfos
->ofnInfos
) ||
266 (fodInfos
->ofnInfos
->FlagsEx
& OFN_EX_NOPLACESBAR
) ||
267 !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
))
272 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey
))
276 get_config_key_as_dword(hkey
, L
"NoPlacesBar", &value
);
281 static void filedlg_collect_places_pidls(FileOpenDlgInfos
*fodInfos
)
283 static const int default_places
[] =
292 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
295 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
302 swprintf(nameW
, ARRAY_SIZE(nameW
), L
"Place%d", i
);
303 if (get_config_key_dword(hkey
, nameW
, &value
))
305 hr
= SHGetSpecialFolderLocation(NULL
, value
, &fodInfos
->places
[i
]);
307 WARN("Unrecognized special folder %u.\n", value
);
309 else if (get_config_key_string(hkey
, nameW
, &str
))
311 hr
= SHParseDisplayName(str
, NULL
, &fodInfos
->places
[i
], 0, NULL
);
313 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str
));
318 /* FIXME: eliminate duplicates. */
324 for (i
= 0; i
< ARRAY_SIZE(default_places
); i
++)
325 SHGetSpecialFolderLocation(NULL
, default_places
[i
], &fodInfos
->places
[i
]);
328 /***********************************************************************
331 * Creates an Open common dialog box that lets the user select
332 * the drive, directory, and the name of a file or set of files to open.
334 * IN : The FileOpenDlgInfos structure associated with the dialog
335 * OUT : TRUE on success
336 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
338 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
346 /* test for missing functionality */
347 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
349 FIXME("Flags 0x%08x not yet implemented\n",
350 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
353 /* Create the dialog from a template */
355 if (is_places_bar_enabled(fodInfos
))
356 templateid
= NEWFILEOPENV2ORD
;
358 templateid
= NEWFILEOPENORD
;
360 if (!(hRes
= FindResourceW(COMDLG32_hInstance
, MAKEINTRESOURCEW(templateid
), (LPCWSTR
)RT_DIALOG
)))
362 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
365 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
366 !(template = LockResource( hDlgTmpl
)))
368 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
372 /* msdn: explorer style dialogs permit sizing by default.
373 * The OFN_ENABLESIZING flag is only needed when a hook or
374 * custom template is provided */
375 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
376 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
377 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
379 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
381 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
382 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
385 /* old style hook messages */
386 if (is_dialog_hooked(fodInfos
))
388 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
389 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
390 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
391 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
394 if (fodInfos
->unicode
)
395 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
397 fodInfos
->ofnInfos
->hwndOwner
,
401 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
403 fodInfos
->ofnInfos
->hwndOwner
,
406 if (fodInfos
->ole_initialized
)
409 /* Unable to create the dialog */
416 static WCHAR
*heap_strdupAtoW(const char *str
)
424 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
425 ret
= heap_alloc(len
* sizeof(WCHAR
));
426 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
431 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
433 INITCOMMONCONTROLSEX icc
;
435 /* Initialize ComboBoxEx32 */
436 icc
.dwSize
= sizeof(icc
);
437 icc
.dwICC
= ICC_USEREX_CLASSES
;
438 InitCommonControlsEx(&icc
);
440 /* Initialize CommDlgExtendedError() */
441 COMDLG32_SetCommDlgExtendedError(0);
443 memset(info
, 0, sizeof(*info
));
445 /* Pass in the original ofn */
446 info
->ofnInfos
= ofn
;
448 info
->title
= ofn
->lpstrTitle
;
449 info
->defext
= ofn
->lpstrDefExt
;
450 info
->filter
= ofn
->lpstrFilter
;
451 info
->customfilter
= ofn
->lpstrCustomFilter
;
455 info
->filename
= heap_alloc(ofn
->nMaxFile
* sizeof(WCHAR
));
456 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
459 if (ofn
->lpstrInitialDir
)
461 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
464 info
->initdir
= heap_alloc(len
* sizeof(WCHAR
));
465 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
469 info
->unicode
= TRUE
;
472 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
477 ofnW
= *(OPENFILENAMEW
*)ofn
;
479 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
480 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
481 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
485 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
486 ofnW
.lpstrFile
= heap_alloc(len
* sizeof(WCHAR
));
487 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
491 if (ofn
->lpstrFilter
)
496 /* filter is a list... title\0ext\0......\0\0 */
497 s
= ofn
->lpstrFilter
;
498 while (*s
) s
= s
+strlen(s
)+1;
500 n
= s
- ofn
->lpstrFilter
;
501 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
502 ofnW
.lpstrFilter
= heap_alloc(len
* sizeof(WCHAR
));
503 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
506 /* convert lpstrCustomFilter */
507 if (ofn
->lpstrCustomFilter
)
512 /* customfilter contains a pair of strings... title\0ext\0 */
513 s
= ofn
->lpstrCustomFilter
;
514 if (*s
) s
= s
+strlen(s
)+1;
515 if (*s
) s
= s
+strlen(s
)+1;
516 n
= s
- ofn
->lpstrCustomFilter
;
517 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
518 ofnW
.lpstrCustomFilter
= heap_alloc(len
* sizeof(WCHAR
));
519 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
522 init_filedlg_infoW(&ofnW
, info
);
524 /* fixup A-specific fields */
525 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
526 info
->unicode
= FALSE
;
528 /* free what was duplicated */
529 heap_free((void *)ofnW
.lpstrInitialDir
);
530 heap_free(ofnW
.lpstrFile
);
533 /***********************************************************************
536 * Call GetFileName95 with this structure and clean the memory.
538 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
540 WCHAR
*current_dir
= NULL
;
544 /* save current directory */
545 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
547 current_dir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
548 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
554 ret
= GetFileName95(info
);
557 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
558 ret
= GetFileName95(info
);
566 SetCurrentDirectoryW(current_dir
);
567 heap_free(current_dir
);
572 heap_free((void *)info
->defext
);
573 heap_free((void *)info
->title
);
574 heap_free((void *)info
->filter
);
575 heap_free((void *)info
->customfilter
);
578 heap_free(info
->filename
);
579 heap_free(info
->initdir
);
581 for (i
= 0; i
< ARRAY_SIZE(info
->places
); i
++)
582 ILFree(info
->places
[i
]);
587 /******************************************************************************
588 * COMDLG32_GetDisplayNameOf [internal]
590 * Helper function to get the display name for a pidl.
592 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
593 LPSHELLFOLDER psfDesktop
;
596 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
599 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
600 IShellFolder_Release(psfDesktop
);
604 IShellFolder_Release(psfDesktop
);
605 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
608 /******************************************************************************
609 * COMDLG32_GetCanonicalPath [internal]
611 * Helper function to get the canonical path.
613 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
614 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
616 WCHAR lpstrTemp
[MAX_PATH
];
618 /* Get the current directory name */
619 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
622 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
624 PathAddBackslashW(lpstrPathAndFile
);
626 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile
), debugstr_w(lpstrFile
));
628 /* if the user specified a fully qualified path use it */
629 if(PathIsRelativeW(lpstrFile
))
631 lstrcatW(lpstrPathAndFile
, lpstrFile
);
635 /* does the path have a drive letter? */
636 if (PathGetDriveNumberW(lpstrFile
) == -1)
637 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
639 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
642 /* resolve "." and ".." */
643 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
644 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
645 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
648 /***********************************************************************
649 * COMDLG32_SplitFileNames [internal]
651 * Creates a delimited list of filenames.
653 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
655 UINT nStrCharCount
= 0; /* index in src buffer */
656 UINT nFileIndex
= 0; /* index in dest buffer */
657 UINT nFileCount
= 0; /* number of files */
659 /* we might get single filename without any '"',
660 * so we need nStrLen + terminating \0 + end-of-list \0 */
661 *lpstrFileList
= heap_alloc((nStrLen
+ 2) * sizeof(WCHAR
));
664 /* build delimited file list from filenames */
665 while ( nStrCharCount
<= nStrLen
)
667 if ( lpstrEdit
[nStrCharCount
]=='"' )
670 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
672 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
675 (*lpstrFileList
)[nFileIndex
++] = 0;
681 /* single, unquoted string */
682 if ((nStrLen
> 0) && (nFileIndex
== 0) )
684 lstrcpyW(*lpstrFileList
, lpstrEdit
);
685 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
690 (*lpstrFileList
)[nFileIndex
++] = '\0';
692 *sizeUsed
= nFileIndex
;
696 /***********************************************************************
697 * ArrangeCtrlPositions [internal]
699 * NOTE: Make sure to add testcases for any changes made here.
701 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
703 HWND hwndChild
, hwndStc32
;
704 RECT rectParent
, rectChild
, rectStc32
;
708 /* Take into account if open as read only checkbox and help button
713 RECT rectHelp
, rectCancel
;
714 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
715 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
716 /* subtract the height of the help button plus the space between
717 * the help button and the cancel button to the height of the dialog
719 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
723 There are two possibilities to add components to the default file dialog box.
725 By default, all the new components are added below the standard dialog box (the else case).
727 However, if there is a static text component with the stc32 id, a special case happens.
728 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
729 in the window and the cx and cy indicate how to size the window.
730 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
731 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
735 GetClientRect(hwndParentDlg
, &rectParent
);
737 /* when arranging controls we have to use fixed parent size */
738 rectParent
.bottom
-= help_fixup
;
740 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
743 GetWindowRect(hwndStc32
, &rectStc32
);
744 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
746 /* set the size of the stc32 control according to the size of
747 * client area of the parent dialog
749 SetWindowPos(hwndStc32
, 0,
751 rectParent
.right
, rectParent
.bottom
,
752 SWP_NOMOVE
| SWP_NOZORDER
);
755 SetRectEmpty(&rectStc32
);
757 /* this part moves controls of the child dialog */
758 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
761 if (hwndChild
!= hwndStc32
)
763 GetWindowRect(hwndChild
, &rectChild
);
764 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
766 /* move only if stc32 exist */
767 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
769 /* move to the right of visible controls of the parent dialog */
770 rectChild
.left
+= rectParent
.right
;
771 rectChild
.left
-= rectStc32
.right
;
773 /* move even if stc32 doesn't exist */
774 if (rectChild
.top
>= rectStc32
.bottom
)
776 /* move below visible controls of the parent dialog */
777 rectChild
.top
+= rectParent
.bottom
;
778 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
781 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
782 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
784 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
787 /* this part moves controls of the parent dialog */
788 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
791 if (hwndChild
!= hwndChildDlg
)
793 GetWindowRect(hwndChild
, &rectChild
);
794 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
796 /* left,top of stc32 marks the position of controls
797 * from the parent dialog
799 rectChild
.left
+= rectStc32
.left
;
800 rectChild
.top
+= rectStc32
.top
;
802 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
803 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
805 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
808 /* calculate the size of the resulting dialog */
810 /* here we have to use original parent size */
811 GetClientRect(hwndParentDlg
, &rectParent
);
812 GetClientRect(hwndChildDlg
, &rectChild
);
813 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
814 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
819 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
820 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
822 chgx
= rectChild
.right
- rectParent
.right
;
824 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
825 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
827 /* Unconditionally set new dialog
828 * height to that of the child
830 chgy
= rectChild
.bottom
- rectParent
.bottom
;
835 chgy
= rectChild
.bottom
- help_fixup
;
837 /* set the size of the parent dialog */
838 GetWindowRect(hwndParentDlg
, &rectParent
);
839 SetWindowPos(hwndParentDlg
, 0,
841 rectParent
.right
- rectParent
.left
+ chgx
,
842 rectParent
.bottom
- rectParent
.top
+ chgy
,
843 SWP_NOMOVE
| SWP_NOZORDER
);
846 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
855 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
862 TRACE("%p, %p\n", fodInfos
, hwnd
);
865 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
866 * structure's hInstance parameter is not a HINSTANCE, but
867 * instead a pointer to a template resource to use.
869 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
872 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
874 hinst
= COMDLG32_hInstance
;
875 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
877 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
883 hinst
= fodInfos
->ofnInfos
->hInstance
;
884 if(fodInfos
->unicode
)
886 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
887 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
891 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
892 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
896 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
899 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
900 !(template = LockResource( hDlgTmpl
)))
902 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
906 if (fodInfos
->unicode
)
907 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
908 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
909 (LPARAM
)fodInfos
->ofnInfos
);
911 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
912 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
913 (LPARAM
)fodInfos
->ofnInfos
);
916 else if (is_dialog_hooked(fodInfos
))
921 WORD menu
,class,title
;
923 GetClientRect(hwnd
,&rectHwnd
);
924 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
925 temp
.tmplate
.dwExtendedStyle
= 0;
926 temp
.tmplate
.cdit
= 0;
931 temp
.menu
= temp
.class = temp
.title
= 0;
933 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
934 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
941 /***********************************************************************
942 * SendCustomDlgNotificationMessage
944 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
947 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
949 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
953 TRACE("%p %d\n", hwndParentDlg
, uCode
);
955 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
958 TRACE("CALL NOTIFY for %d\n", uCode
);
960 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
961 ofnNotify
.hdr
.idFrom
= 0;
962 ofnNotify
.hdr
.code
= uCode
;
963 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
964 ofnNotify
.pszFile
= NULL
;
966 if (fodInfos
->unicode
)
967 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
969 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
971 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
976 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
980 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
982 TRACE("CDM_GETFILEPATH:\n");
984 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
987 /* get path and filenames */
988 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
989 buffer
= heap_alloc( (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
990 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
993 p
= buffer
+ lstrlenW(buffer
);
995 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
997 if (fodInfos
->unicode
)
999 total
= lstrlenW( buffer
) + 1;
1000 if (result
) lstrcpynW( result
, buffer
, size
);
1001 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
1005 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
1006 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
1007 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1009 heap_free( buffer
);
1013 /***********************************************************************
1014 * FILEDLG95_HandleCustomDialogMessages
1016 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1018 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1020 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1021 WCHAR lpstrPath
[MAX_PATH
];
1024 if(!fodInfos
) return FALSE
;
1028 case CDM_GETFILEPATH
:
1029 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1032 case CDM_GETFOLDERPATH
:
1033 TRACE("CDM_GETFOLDERPATH:\n");
1034 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1037 if (fodInfos
->unicode
)
1038 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1040 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1041 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1043 retval
= lstrlenW(lpstrPath
) + 1;
1046 case CDM_GETFOLDERIDLIST
:
1047 retval
= ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1048 if (retval
<= wParam
)
1049 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1053 TRACE("CDM_GETSPEC:\n");
1054 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1057 if (fodInfos
->unicode
)
1058 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1060 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1064 case CDM_SETCONTROLTEXT
:
1065 TRACE("CDM_SETCONTROLTEXT:\n");
1068 if( fodInfos
->unicode
)
1069 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1071 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1076 case CDM_HIDECONTROL
:
1077 /* MSDN states that it should fail for not OFN_EXPLORER case */
1078 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1080 HWND control
= GetDlgItem( hwnd
, wParam
);
1081 if (control
) ShowWindow( control
, SW_HIDE
);
1084 else retval
= FALSE
;
1088 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1089 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1092 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1096 /***********************************************************************
1097 * FILEDLG95_OnWMGetMMI
1099 * WM_GETMINMAXINFO message handler for resizable dialogs
1101 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1103 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1104 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1105 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1107 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1112 /***********************************************************************
1113 * FILEDLG95_OnWMSize
1115 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1117 * FIXME: this could be made more elaborate. Now use a simple scheme
1118 * where the file view is enlarged and the controls are either moved
1119 * vertically or horizontally to get out of the way. Only the "grip"
1120 * is moved in both directions to stay in the corner.
1122 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1128 FileOpenDlgInfos
*fodInfos
;
1130 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1131 fodInfos
= get_filedlg_infoptr(hwnd
);
1132 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1133 /* get the new dialog rectangle */
1134 GetWindowRect( hwnd
, &rc
);
1135 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1136 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1137 /* not initialized yet */
1138 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1139 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1140 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1142 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1143 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1144 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1145 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1146 /* change the size of the view window */
1147 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1148 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1149 hdwp
= BeginDeferWindowPos( 10);
1150 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1151 rcview
.right
- rcview
.left
+ chgx
,
1152 rcview
.bottom
- rcview
.top
+ chgy
,
1153 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1154 /* change position and sizes of the controls */
1155 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1157 int ctrlid
= GetDlgCtrlID( ctrl
);
1158 GetWindowRect( ctrl
, &rc
);
1159 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1160 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1162 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1164 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1166 else if( rc
.top
> rcview
.bottom
)
1168 /* if it was below the shell view
1172 /* file name (edit or comboboxex) and file types combo change also width */
1176 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1177 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1178 SWP_NOACTIVATE
| SWP_NOZORDER
);
1180 /* then these buttons must move out of the way */
1184 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1186 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1189 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1191 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1194 else if( rc
.left
> rcview
.right
)
1196 /* if it was to the right of the shell view
1198 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1200 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1207 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1209 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1210 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1211 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1213 case IDC_TOOLBARSTATIC
:
1215 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1217 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1220 /* not resized in windows. Since wine uses this invisible control
1221 * to size the browser view it needs to be resized */
1222 case IDC_SHELLSTATIC
:
1223 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1224 rc
.right
- rc
.left
+ chgx
,
1225 rc
.bottom
- rc
.top
+ chgy
,
1226 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1228 case IDC_TOOLBARPLACES
:
1229 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
+ chgy
,
1230 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1235 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1236 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1238 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1239 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1241 GetWindowRect( ctrl
, &rc
);
1242 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1243 if( rc
.top
> rcview
.bottom
)
1245 /* if it was below the shell view
1247 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1248 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1249 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1251 else if( rc
.left
> rcview
.right
)
1253 /* if it was to the right of the shell view
1255 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1256 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1257 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1260 /* size the custom dialog at the end: some applications do some
1261 * control re-arranging at this point */
1262 GetClientRect(hwnd
, &rc
);
1263 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1264 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1266 EndDeferWindowPos( hdwp
);
1267 /* should not be needed */
1268 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1272 /***********************************************************************
1275 * File open dialog procedure
1277 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1280 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1287 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1289 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1290 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1292 /* Some shell namespace extensions depend on COM being initialized. */
1293 if (SUCCEEDED(OleInitialize(NULL
)))
1294 fodInfos
->ole_initialized
= TRUE
;
1296 SetPropW(hwnd
, L
"FileOpenDlgInfos", fodInfos
);
1298 FILEDLG95_InitControls(hwnd
);
1300 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1302 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1303 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1304 RECT client
, client_adjusted
;
1306 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1308 style
|= WS_SIZEBOX
;
1309 ex_style
|= WS_EX_WINDOWEDGE
;
1312 style
&= ~WS_SIZEBOX
;
1313 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1314 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1316 GetClientRect( hwnd
, &client
);
1317 GetClientRect( hwnd
, &client_adjusted
);
1318 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1320 GetWindowRect( hwnd
, &rc
);
1321 rc
.right
+= client_adjusted
.right
- client
.right
;
1322 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1323 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1324 SWP_NOZORDER
| SWP_NOMOVE
);
1326 GetWindowRect( hwnd
, &rc
);
1327 fodInfos
->DlgInfos
.hwndGrip
=
1328 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1329 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1330 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1331 rc
.right
- gripx
, rc
.bottom
- gripy
,
1332 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1335 fodInfos
->DlgInfos
.hwndCustomDlg
=
1336 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1338 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1339 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1341 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1342 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1344 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1345 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1346 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1349 /* if the app has changed the position of the invisible listbox,
1350 * change that of the listview (browser) as well */
1351 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1352 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1353 if( !EqualRect( &rc
, &rcstc
))
1355 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1356 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1357 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1358 SWP_NOACTIVATE
| SWP_NOZORDER
);
1361 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1363 GetWindowRect( hwnd
, &rc
);
1364 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1365 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1366 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1367 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1368 GetClientRect( hwnd
, &rc
);
1369 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1370 rc
.right
- gripx
, rc
.bottom
- gripy
,
1371 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1372 /* resize the dialog to the previous invocation */
1373 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1374 SetWindowPos( hwnd
, NULL
,
1375 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1376 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1379 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1380 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1385 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1386 case WM_GETMINMAXINFO
:
1387 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1389 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1392 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1395 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1401 case WM_GETISHELLBROWSER
:
1402 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1406 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1407 HWND places_bar
= GetDlgItem(hwnd
, IDC_TOOLBARPLACES
);
1410 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1411 MemDialogSize
= fodInfos
->sizedlg
;
1415 himl
= (HIMAGELIST
)SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_GETIMAGELIST
, 0, 0);
1416 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, 0);
1417 ImageList_Destroy(himl
);
1423 RemovePropW(hwnd
, L
"FileOpenDlgInfos");
1428 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1431 /* set up the button tooltips strings */
1432 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1434 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1435 switch(lpnmh
->idFrom
)
1437 /* Up folder button */
1438 case FCIDM_TB_UPFOLDER
:
1439 stringId
= IDS_UPFOLDER
;
1441 /* New folder button */
1442 case FCIDM_TB_NEWFOLDER
:
1443 stringId
= IDS_NEWFOLDER
;
1445 /* List option button */
1446 case FCIDM_TB_SMALLICON
:
1447 stringId
= IDS_LISTVIEW
;
1449 /* Details option button */
1450 case FCIDM_TB_REPORTVIEW
:
1451 stringId
= IDS_REPORTVIEW
;
1453 /* Desktop button */
1454 case FCIDM_TB_DESKTOP
:
1455 stringId
= IDS_TODESKTOP
;
1460 lpdi
->hinst
= COMDLG32_hInstance
;
1461 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1466 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1467 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1472 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1474 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1475 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1478 /***********************************************************************
1479 * FILEDLG95_InitControls
1481 * WM_INITDIALOG message handler (before hook notification)
1483 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1485 BOOL win2000plus
= FALSE
;
1486 BOOL win98plus
= FALSE
;
1487 BOOL handledPath
= FALSE
;
1488 OSVERSIONINFOW osVi
;
1490 static const TBBUTTON tbb
[] =
1492 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1493 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1494 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1495 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1496 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1497 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1498 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1499 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1500 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1502 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1507 HIMAGELIST toolbarImageList
;
1508 ITEMIDLIST
*desktopPidl
;
1509 SHFILEINFOW fileinfo
;
1511 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1513 TRACE("%p\n", fodInfos
);
1515 /* Get windows version emulating */
1516 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1517 GetVersionExW(&osVi
);
1518 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1519 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1520 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1521 win2000plus
= (osVi
.dwMajorVersion
> 4);
1522 if (win2000plus
) win98plus
= TRUE
;
1524 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1527 /* Use either the edit or the comboboxex for the filename control */
1528 if (filename_is_edit( fodInfos
))
1530 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1531 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1535 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1536 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1539 /* Get the hwnd of the controls */
1540 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1541 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1543 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1544 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1546 /* construct the toolbar */
1547 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1548 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1550 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1551 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1552 rectTB
.left
= rectlook
.right
;
1553 rectTB
.top
= rectlook
.top
-1;
1555 if (fodInfos
->unicode
)
1556 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1557 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1558 rectTB
.left
, rectTB
.top
,
1559 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1560 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1562 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1563 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1564 rectTB
.left
, rectTB
.top
,
1565 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1566 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1568 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1570 /* FIXME: use TB_LOADIMAGES when implemented */
1571 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1572 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1573 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1575 /* Retrieve and add desktop icon to the toolbar */
1576 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1577 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1578 SHGetFileInfoW((const WCHAR
*)desktopPidl
, 0, &fileinfo
, sizeof(fileinfo
),
1579 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1580 ImageList_AddIcon(toolbarImageList
, fileinfo
.hIcon
);
1582 DestroyIcon(fileinfo
.hIcon
);
1583 CoTaskMemFree(desktopPidl
);
1585 /* Finish Toolbar Construction */
1586 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1587 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1589 if (is_places_bar_enabled(fodInfos
))
1591 TBBUTTON tb
= { 0 };
1596 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_BUTTONSTRUCTSIZE
, 0, 0);
1597 GetClientRect(GetDlgItem(hwnd
, IDC_TOOLBARPLACES
), &rect
);
1598 cx
= rect
.right
- rect
.left
;
1600 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONWIDTH
, 0, MAKELPARAM(cx
, cx
));
1601 himl
= ImageList_Create(GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), ILC_COLOR32
, 4, 1);
1603 filedlg_collect_places_pidls(fodInfos
);
1604 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
1608 if (!fodInfos
->places
[i
])
1611 memset(&fileinfo
, 0, sizeof(fileinfo
));
1612 SHGetFileInfoW((const WCHAR
*)fodInfos
->places
[i
], 0, &fileinfo
, sizeof(fileinfo
),
1613 SHGFI_PIDL
| SHGFI_DISPLAYNAME
| SHGFI_ICON
);
1614 index
= ImageList_AddIcon(himl
, fileinfo
.hIcon
);
1617 tb
.iString
= (INT_PTR
)fileinfo
.szDisplayName
;
1618 tb
.fsState
= TBSTATE_ENABLED
| TBSTATE_WRAP
;
1619 tb
.idCommand
= TBPLACES_CMDID_PLACE0
+ i
;
1620 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tb
);
1622 DestroyIcon(fileinfo
.hIcon
);
1625 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, (LPARAM
)himl
);
1626 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, cx
* 3 / 4));
1629 /* Set the window text with the text specified in the OPENFILENAME structure */
1632 SetWindowTextW(hwnd
,fodInfos
->title
);
1634 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1637 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, ARRAY_SIZE(buf
));
1638 SetWindowTextW(hwnd
, buf
);
1641 /* Initialise the file name edit control */
1642 handledPath
= FALSE
;
1643 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1645 if(fodInfos
->filename
)
1647 /* 1. If win2000 or higher and filename contains a path, use it
1648 in preference over the lpstrInitialDir */
1649 if (win2000plus
&& *fodInfos
->filename
&& wcspbrk(fodInfos
->filename
, L
"\\")) {
1650 WCHAR tmpBuf
[MAX_PATH
];
1654 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1657 /* nameBit is always shorter than the original filename. It may be NULL
1658 * when the filename contains only a drive name instead of file name */
1661 lstrcpyW(fodInfos
->filename
,nameBit
);
1665 *fodInfos
->filename
= '\0';
1667 heap_free(fodInfos
->initdir
);
1668 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1669 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1671 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1672 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1674 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1677 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1681 /* 2. (All platforms) If initdir is not null, then use it */
1682 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1684 /* Work out the proper path as supplied one might be relative */
1685 /* (Here because supplying '.' as dir browses to My Computer) */
1686 WCHAR tmpBuf
[MAX_PATH
];
1687 WCHAR tmpBuf2
[MAX_PATH
];
1691 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1692 if (PathFileExistsW(tmpBuf
)) {
1693 /* initdir does not have to be a directory. If a file is
1694 * specified, the dir part is taken */
1695 if (PathIsDirectoryW(tmpBuf
)) {
1696 PathAddBackslashW(tmpBuf
);
1697 lstrcatW(tmpBuf
, L
"*");
1699 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1702 heap_free(fodInfos
->initdir
);
1703 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1704 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1706 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1709 else if (fodInfos
->initdir
)
1711 heap_free(fodInfos
->initdir
);
1712 fodInfos
->initdir
= NULL
;
1713 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1717 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1719 /* 3. All except w2k+: if filename contains a path use it */
1720 if (!win2000plus
&& fodInfos
->filename
&& *fodInfos
->filename
&&
1721 wcspbrk(fodInfos
->filename
, L
"\\")) {
1722 WCHAR tmpBuf
[MAX_PATH
];
1726 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1731 /* nameBit is always shorter than the original filename */
1732 lstrcpyW(fodInfos
->filename
, nameBit
);
1735 len
= lstrlenW(tmpBuf
);
1736 heap_free(fodInfos
->initdir
);
1737 fodInfos
->initdir
= heap_alloc((len
+1)*sizeof(WCHAR
));
1738 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1741 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1742 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1744 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1747 /* 4. Win2000+: Recently used */
1748 if (!handledPath
&& win2000plus
) {
1749 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1750 fodInfos
->initdir
[0] = '\0';
1752 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1754 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1757 heap_free(fodInfos
->initdir
);
1758 fodInfos
->initdir
= NULL
;
1762 /* 5. win98+ and win2000+ if any files of specified filter types in
1763 current directory, use it */
1764 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1766 LPCWSTR lpstrPos
= fodInfos
->filter
;
1767 WIN32_FIND_DATAW FindFileData
;
1772 /* filter is a list... title\0ext\0......\0\0 */
1774 /* Skip the title */
1775 if(! *lpstrPos
) break; /* end */
1776 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1778 /* See if any files exist in the current dir with this extension */
1779 if(! *lpstrPos
) break; /* end */
1781 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1783 if (hFind
== INVALID_HANDLE_VALUE
) {
1784 /* None found - continue search */
1785 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1789 heap_free(fodInfos
->initdir
);
1790 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1791 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1794 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1795 debugstr_w(lpstrPos
));
1802 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1803 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1804 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1806 if (SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
) == S_OK
)
1808 if (SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
) == S_OK
)
1811 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1812 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1815 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1818 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1821 } else if (!handledPath
) {
1822 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1823 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1825 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1828 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1829 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1831 /* Must the open as read only check box be checked ?*/
1832 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1834 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1837 /* Must the open as read only check box be hidden? */
1838 if (filedialog_is_readonly_hidden(fodInfos
))
1840 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1841 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1844 /* Must the help button be hidden? */
1845 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1847 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1848 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1851 /* change Open to Save */
1852 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1855 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, ARRAY_SIZE(buf
));
1856 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1857 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, ARRAY_SIZE(buf
));
1858 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1861 /* Initialize the filter combo box */
1862 FILEDLG95_FILETYPE_Init(hwnd
);
1867 /***********************************************************************
1868 * FILEDLG95_ResizeControls
1870 * WM_INITDIALOG message handler (after hook notification)
1872 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1874 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1876 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1879 UINT flags
= SWP_NOACTIVATE
;
1881 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1882 filedialog_is_readonly_hidden(fodInfos
) && !(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
));
1884 /* resize the custom dialog to the parent size */
1885 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1886 GetClientRect(hwnd
, &rc
);
1889 /* our own fake template is zero sized and doesn't have children, so
1890 * there is no need to resize it. Picasa depends on it.
1892 flags
|= SWP_NOSIZE
;
1895 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1896 0, 0, rc
.right
, rc
.bottom
, flags
);
1900 /* Resize the height; if opened as read-only, checkbox and help button are
1901 * hidden and we are not using a custom template nor a customDialog
1903 if (filedialog_is_readonly_hidden(fodInfos
) &&
1904 (!(fodInfos
->ofnInfos
->Flags
&
1905 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1907 RECT rectDlg
, rectHelp
, rectCancel
;
1908 GetWindowRect(hwnd
, &rectDlg
);
1909 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1910 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1911 /* subtract the height of the help button plus the space between the help
1912 * button and the cancel button to the height of the dialog
1914 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1915 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1916 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1922 /***********************************************************************
1923 * FILEDLG95_FillControls
1925 * WM_INITDIALOG message handler (after hook notification)
1927 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1929 LPITEMIDLIST pidlItemId
= NULL
;
1931 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1933 TRACE("dir=%s file=%s\n",
1934 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1936 /* Get the initial directory pidl */
1938 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1940 WCHAR path
[MAX_PATH
];
1942 GetCurrentDirectoryW(MAX_PATH
,path
);
1943 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1946 /* Initialise shell objects */
1947 FILEDLG95_SHELL_Init(hwnd
);
1949 /* Initialize the Look In combo box */
1950 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1952 /* Browse to the initial directory */
1953 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1959 /***********************************************************************
1962 * Regroups all the cleaning functions of the filedlg
1964 void FILEDLG95_Clean(HWND hwnd
)
1966 FILEDLG95_FILETYPE_Clean(hwnd
);
1967 FILEDLG95_LOOKIN_Clean(hwnd
);
1968 FILEDLG95_SHELL_Clean(hwnd
);
1972 /***********************************************************************
1973 * Browse to arbitrary pidl
1975 static void filedlg_browse_to_pidl(const FileOpenDlgInfos
*info
, LPITEMIDLIST pidl
)
1977 TRACE("%p, %p\n", info
->ShellInfos
.hwndOwner
, pidl
);
1979 IShellBrowser_BrowseObject(info
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
1980 if (info
->ofnInfos
->Flags
& OFN_EXPLORER
)
1981 SendCustomDlgNotificationMessage(info
->ShellInfos
.hwndOwner
, CDN_FOLDERCHANGE
);
1984 /***********************************************************************
1985 * FILEDLG95_OnWMCommand
1987 * WM_COMMAND message handler
1989 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1991 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1992 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1993 WORD id
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1999 FILEDLG95_OnOpen(hwnd
);
2003 FILEDLG95_Clean(hwnd
);
2004 EndDialog(hwnd
, FALSE
);
2006 /* Filetype combo box */
2008 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
2010 /* LookIn combo box */
2012 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
2015 /* --- toolbar --- */
2016 /* Up folder button */
2017 case FCIDM_TB_UPFOLDER
:
2018 FILEDLG95_SHELL_UpFolder(hwnd
);
2020 /* New folder button */
2021 case FCIDM_TB_NEWFOLDER
:
2022 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
2024 /* List option button */
2025 case FCIDM_TB_SMALLICON
:
2026 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
2028 /* Details option button */
2029 case FCIDM_TB_REPORTVIEW
:
2030 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
2033 case FCIDM_TB_DESKTOP
:
2037 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP
, &pidl
);
2038 filedlg_browse_to_pidl(fodInfos
, pidl
);
2044 case TBPLACES_CMDID_PLACE0
:
2045 case TBPLACES_CMDID_PLACE1
:
2046 case TBPLACES_CMDID_PLACE2
:
2047 case TBPLACES_CMDID_PLACE3
:
2048 case TBPLACES_CMDID_PLACE4
:
2049 filedlg_browse_to_pidl(fodInfos
, fodInfos
->places
[id
- TBPLACES_CMDID_PLACE0
]);
2057 /* Do not use the listview selection anymore */
2058 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
2062 /***********************************************************************
2063 * FILEDLG95_OnWMGetIShellBrowser
2065 * WM_GETISHELLBROWSER message handler
2067 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
2069 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2073 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
2079 /***********************************************************************
2080 * FILEDLG95_SendFileOK
2082 * Sends the CDN_FILEOK notification if required
2085 * TRUE if the dialog should close
2086 * FALSE if the dialog should not be closed
2088 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
2090 /* ask the hook if we can close */
2091 if (is_dialog_hooked(fodInfos
))
2096 /* First send CDN_FILEOK as MSDN doc says */
2097 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2098 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
2101 TRACE("canceled\n");
2105 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2106 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
2107 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
2110 TRACE("canceled\n");
2117 /***********************************************************************
2118 * FILEDLG95_OnOpenMultipleFiles
2120 * Handles the opening of multiple files.
2123 * check destination buffer size
2125 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2127 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2128 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2129 UINT nCount
, nSizePath
;
2133 if(fodInfos
->unicode
)
2135 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2136 ofn
->lpstrFile
[0] = '\0';
2140 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2141 ofn
->lpstrFile
[0] = '\0';
2144 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2146 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2147 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2148 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2150 LPWSTR lpstrTemp
= lpstrFileList
;
2152 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2156 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2159 WCHAR lpstrNotFound
[100];
2160 WCHAR lpstrMsg
[100];
2163 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2164 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2166 lstrcpyW(tmp
, lpstrTemp
);
2167 lstrcatW(tmp
, L
"\n");
2168 lstrcatW(tmp
, lpstrNotFound
);
2169 lstrcatW(tmp
, L
"\n");
2170 lstrcatW(tmp
, lpstrMsg
);
2172 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2176 /* move to the next file in the list of files */
2177 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2182 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2183 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2185 /* For "oldstyle" dialog the components have to
2186 be separated by blanks (not '\0'!) and short
2187 filenames have to be used! */
2188 FIXME("Components have to be separated by blanks\n");
2190 if(fodInfos
->unicode
)
2192 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2193 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2194 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2198 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2200 if (ofn
->lpstrFile
!= NULL
)
2202 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2203 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2204 if (ofn
->nMaxFile
> nSizePath
)
2206 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2207 ofn
->lpstrFile
+ nSizePath
,
2208 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2213 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2214 fodInfos
->ofnInfos
->nFileExtension
= 0;
2216 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2219 /* clean and exit */
2220 FILEDLG95_Clean(hwnd
);
2221 return EndDialog(hwnd
,TRUE
);
2224 /* Returns the 'slot name' of the given module_name in the registry's
2225 * most-recently-used list. This will be an ASCII value in the
2226 * range ['a','z'). Returns zero on error.
2228 * The slot's value in the registry has the form:
2229 * module_name\0mru_path\0
2231 * If stored_path is given, then stored_path will contain the path name
2232 * stored in the registry's MRU list for the given module_name.
2234 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2235 * MRU list key for the given module_name.
2237 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2239 WCHAR mru_list
[32], *cur_mru_slot
;
2240 BOOL taken
[25] = {0};
2241 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2242 HKEY hkey_tmp
, *hkey
;
2251 *stored_path
= '\0';
2253 ret
= RegCreateKeyW(HKEY_CURRENT_USER
,
2254 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", hkey
);
2256 WARN("Unable to create MRU key: %d\n", ret
);
2260 ret
= RegGetValueW(*hkey
, NULL
, L
"MRUList", RRF_RT_REG_SZ
, &key_type
,
2261 (LPBYTE
)mru_list
, &mru_list_size
);
2262 if(ret
|| key_type
!= REG_SZ
){
2263 if(ret
== ERROR_FILE_NOT_FOUND
)
2266 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2271 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2272 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2273 DWORD value_data_size
= sizeof(value_data
);
2275 *value_name
= *cur_mru_slot
;
2277 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2278 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2279 if(ret
|| key_type
!= REG_BINARY
){
2280 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2284 if(!wcsicmp(module_name
, value_data
)){
2288 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2296 /* the module name isn't in the registry, so find the next open slot */
2297 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2298 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2299 for(i
= 0; i
< 25; ++i
){
2304 /* all slots are taken, so return the last one in MRUList */
2306 return *cur_mru_slot
;
2309 /* save the given filename as most-recently-used path for this module */
2310 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2312 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2316 /* get the current executable's name */
2317 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2319 WARN("GotModuleFileName failed: %d\n", GetLastError());
2322 module_name
= wcsrchr(module_path
, '\\');
2324 module_name
= module_path
;
2328 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2333 { /* update the slot's info */
2334 WCHAR
*path_ends
, *final
;
2335 DWORD path_len
, final_len
;
2337 /* use only the path segment of `filename' */
2338 path_ends
= wcsrchr(filename
, '\\');
2339 path_len
= path_ends
- filename
;
2341 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2343 final
= heap_alloc(final_len
* sizeof(WCHAR
));
2346 lstrcpyW(final
, module_name
);
2347 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2348 final
[final_len
-1] = '\0';
2350 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2351 final_len
* sizeof(WCHAR
));
2353 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2362 { /* update MRUList value */
2363 WCHAR old_mru_list
[32], new_mru_list
[32];
2364 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2365 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2367 ret
= RegGetValueW(hkey
, NULL
, L
"MRUList", RRF_RT_ANY
, &key_type
,
2368 (LPBYTE
)old_mru_list
, &mru_list_size
);
2369 if(ret
|| key_type
!= REG_SZ
){
2370 if(ret
== ERROR_FILE_NOT_FOUND
){
2371 new_mru_list
[0] = slot
;
2372 new_mru_list
[1] = '\0';
2374 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2379 /* copy old list data over so that the new slot is at the start
2381 *new_mru_slot
++ = slot
;
2382 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2383 if(*old_mru_slot
!= slot
)
2384 *new_mru_slot
++ = *old_mru_slot
;
2386 *new_mru_slot
= '\0';
2389 ret
= RegSetValueExW(hkey
, L
"MRUList", 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2390 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2392 WARN("Error saving MRUList data: %d\n", ret
);
2399 /* load the most-recently-used path for this module */
2400 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2402 WCHAR module_path
[MAX_PATH
], *module_name
;
2404 /* get the current executable's name */
2405 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2407 WARN("GotModuleFileName failed: %d\n", GetLastError());
2410 module_name
= wcsrchr(module_path
, '\\');
2412 module_name
= module_path
;
2416 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2417 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2420 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2422 WCHAR strMsgTitle
[MAX_PATH
];
2423 WCHAR strMsgText
[MAX_PATH
];
2425 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, ARRAY_SIZE(strMsgTitle
));
2427 strMsgTitle
[0] = '\0';
2428 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, ARRAY_SIZE(strMsgText
));
2429 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2432 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2433 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2435 int nOpenAction
= defAction
;
2436 LPWSTR lpszTemp
, lpszTemp1
;
2437 LPITEMIDLIST pidl
= NULL
;
2439 /* check for invalid chars */
2440 if((wcspbrk(lpstrPathAndFile
+3, L
"/:<>|") != NULL
) && !(flags
& OFN_NOVALIDATE
))
2442 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2446 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2448 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2451 LPSHELLFOLDER lpsfChild
;
2452 WCHAR lpwstrTemp
[MAX_PATH
];
2453 DWORD dwEaten
, dwAttributes
;
2456 lstrcpyW(lpwstrTemp
, lpszTemp
);
2457 p
= PathFindNextComponentW(lpwstrTemp
);
2459 if (!p
) break; /* end of path */
2462 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2464 /* There are no wildcards when OFN_NOVALIDATE is set */
2465 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2467 /* if the last element is a wildcard do a search */
2468 if(wcspbrk(lpszTemp1
, L
"*?") != NULL
)
2470 nOpenAction
= ONOPEN_SEARCH
;
2474 lpszTemp1
= lpszTemp
;
2476 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2478 /* append a backslash to drive letters */
2479 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2480 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2481 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2483 PathAddBackslashW(lpwstrTemp
);
2486 dwAttributes
= SFGAO_FOLDER
;
2487 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2489 /* the path component is valid, we have a pidl of the next path component */
2490 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2491 if(dwAttributes
& SFGAO_FOLDER
)
2493 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2495 ERR("bind to failed\n"); /* should not fail */
2498 IShellFolder_Release(*ppsf
);
2506 /* end dialog, return value */
2507 nOpenAction
= ONOPEN_OPEN
;
2513 else if (!(flags
& OFN_NOVALIDATE
))
2515 if(*lpszTemp
|| /* points to trailing null for last path element */
2516 (lpwstrTemp
[lstrlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2518 if(flags
& OFN_PATHMUSTEXIST
)
2520 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2526 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2528 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2532 /* change to the current folder */
2533 nOpenAction
= ONOPEN_OPEN
;
2538 nOpenAction
= ONOPEN_OPEN
;
2547 /***********************************************************************
2550 * Ok button WM_COMMAND message handler
2552 * If the function succeeds, the return value is nonzero.
2554 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2556 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2557 LPWSTR lpstrFileList
;
2558 UINT nFileCount
= 0;
2561 WCHAR lpstrPathAndFile
[MAX_PATH
];
2562 LPSHELLFOLDER lpsf
= NULL
;
2565 TRACE("hwnd=%p\n", hwnd
);
2567 /* try to browse the selected item */
2568 if(BrowseSelectedFolder(hwnd
))
2571 /* get the files from the edit control */
2572 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2579 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2583 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2586 Step 1: Build a complete path name from the current folder and
2587 the filename or path in the edit box.
2589 - the path in the edit box is a root path
2590 (with or without drive letter)
2591 - the edit box contains ".." (or a path with ".." in it)
2594 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2595 heap_free(lpstrFileList
);
2598 Step 2: here we have a cleaned up path
2600 We have to parse the path step by step to see if we have to browse
2601 to a folder if the path points to a directory or the last
2602 valid element is a directory.
2605 lpstrPathAndFile: cleaned up path
2609 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2610 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2611 nOpenAction
= ONOPEN_OPEN
;
2613 nOpenAction
= ONOPEN_BROWSE
;
2615 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2616 fodInfos
->ofnInfos
->Flags
,
2617 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2623 Step 3: here we have a cleaned up and validated path
2626 lpsf: ShellFolder bound to the rightmost valid path component
2627 lpstrPathAndFile: cleaned up path
2628 nOpenAction: action to do
2630 TRACE("end validate sf=%p\n", lpsf
);
2634 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2635 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2638 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2641 /* replace the current filter */
2642 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2643 len
= lstrlenW(lpszTemp
)+1;
2644 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc(len
* sizeof(WCHAR
));
2645 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2647 /* set the filter cb to the extension when possible */
2648 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2649 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, iPos
, 0);
2652 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2653 TRACE("ONOPEN_BROWSE\n");
2655 IPersistFolder2
* ppf2
;
2656 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2658 LPITEMIDLIST pidlCurrent
;
2659 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2660 IPersistFolder2_Release(ppf2
);
2661 if (!ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2663 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2664 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2666 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2667 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2670 else if( nOpenAction
== ONOPEN_SEARCH
)
2672 if (fodInfos
->Shell
.FOIShellView
)
2673 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2675 ILFree(pidlCurrent
);
2676 if (filename_is_edit( fodInfos
))
2677 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2682 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2683 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2689 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2690 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2694 /* update READONLY check box flag */
2695 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2696 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2698 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2700 /* Attach the file extension with file name*/
2701 ext
= PathFindExtensionW(lpstrPathAndFile
);
2702 if (! *ext
&& fodInfos
->defext
)
2704 /* if no extension is specified with file name, then */
2705 /* attach the extension from file filter or default one */
2707 WCHAR
*filterExt
= NULL
;
2708 LPWSTR lpstrFilter
= NULL
;
2709 int PathLength
= lstrlenW(lpstrPathAndFile
);
2711 /*Get the file extension from file type filter*/
2712 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2713 fodInfos
->ofnInfos
->nFilterIndex
-1);
2715 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2717 WCHAR
* filterSearchIndex
;
2718 filterExt
= heap_alloc((lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2719 lstrcpyW(filterExt
, lpstrFilter
);
2721 /* if a semicolon-separated list of file extensions was given, do not include the
2722 semicolon or anything after it in the extension.
2723 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2724 filterSearchIndex
= wcschr(filterExt
, ';');
2725 if (filterSearchIndex
)
2727 filterSearchIndex
[0] = '\0';
2730 /* find the file extension by searching for the first dot in filterExt */
2731 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2732 /* if the extension is invalid or contains a glob, ignore it */
2733 filterSearchIndex
= wcschr(filterExt
, '.');
2734 if (filterSearchIndex
++ && !wcschr(filterSearchIndex
, '*') && !wcschr(filterSearchIndex
, '?'))
2736 lstrcpyW(filterExt
, filterSearchIndex
);
2740 heap_free(filterExt
);
2747 /* use the default file extension */
2748 filterExt
= heap_alloc((lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2749 lstrcpyW(filterExt
, fodInfos
->defext
);
2752 if (*filterExt
) /* ignore filterExt="" */
2755 lstrcatW(lpstrPathAndFile
, L
".");
2756 /* Attach the extension */
2757 lstrcatW(lpstrPathAndFile
, filterExt
);
2760 heap_free(filterExt
);
2762 /* In Open dialog: if file does not exist try without extension */
2763 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2764 lpstrPathAndFile
[PathLength
] = '\0';
2766 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2769 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2770 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2772 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2775 /* In Save dialog: check if the file already exists */
2776 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2777 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2778 && PathFileExistsW(lpstrPathAndFile
))
2780 WCHAR lpstrOverwrite
[100];
2783 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2784 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2785 MB_YESNO
| MB_ICONEXCLAMATION
);
2786 if (answer
== IDNO
|| answer
== IDCANCEL
)
2793 /* In Open dialog: check if it should be created if it doesn't exist */
2794 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2795 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2796 && !PathFileExistsW(lpstrPathAndFile
))
2798 WCHAR lpstrCreate
[100];
2801 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2802 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2803 MB_YESNO
| MB_ICONEXCLAMATION
);
2804 if (answer
== IDNO
|| answer
== IDCANCEL
)
2811 /* Check that the size of the file does not exceed buffer size.
2812 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2813 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2814 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2817 /* fill destination buffer */
2818 if (fodInfos
->ofnInfos
->lpstrFile
)
2820 if(fodInfos
->unicode
)
2822 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2824 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2825 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2826 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2830 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2832 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2833 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2834 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2835 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2839 if(fodInfos
->unicode
)
2843 /* set filename offset */
2844 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2845 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2847 /* set extension offset */
2848 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2849 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2854 CHAR tempFileA
[MAX_PATH
];
2856 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2857 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2858 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2860 /* set filename offset */
2861 lpszTemp
= PathFindFileNameA(tempFileA
);
2862 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2864 /* set extension offset */
2865 lpszTemp
= PathFindExtensionA(tempFileA
);
2866 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2869 /* set the lpstrFileTitle */
2870 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2872 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2873 if(fodInfos
->unicode
)
2875 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2876 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2880 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2881 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2882 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2886 /* copy currently selected filter to lpstrCustomFilter */
2887 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2889 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2890 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2891 NULL
, 0, NULL
, NULL
);
2892 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2894 LPSTR s
= ofn
->lpstrCustomFilter
;
2895 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2896 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2897 s
, len
, NULL
, NULL
);
2902 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2905 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2908 FILEDLG95_Clean(hwnd
);
2909 ret
= EndDialog(hwnd
, TRUE
);
2915 size
= lstrlenW(lpstrPathAndFile
) + 1;
2916 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2918 /* return needed size in first two bytes of lpstrFile */
2919 if(fodInfos
->ofnInfos
->lpstrFile
)
2920 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2921 FILEDLG95_Clean(hwnd
);
2922 ret
= EndDialog(hwnd
, FALSE
);
2923 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2930 if(lpsf
) IShellFolder_Release(lpsf
);
2934 /***********************************************************************
2935 * FILEDLG95_SHELL_Init
2937 * Initialisation of the shell objects
2939 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2941 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2943 TRACE("%p\n", hwnd
);
2946 * Initialisation of the FileOpenDialogInfos structure
2952 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2954 /* Disable multi-select if flag not set */
2955 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2957 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2959 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2960 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2962 /* Construct the IShellBrowser interface */
2963 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2968 /***********************************************************************
2969 * FILEDLG95_SHELL_ExecuteCommand
2971 * Change the folder option and refresh the view
2972 * If the function succeeds, the return value is nonzero.
2974 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2976 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2979 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2981 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2986 CMINVOKECOMMANDINFO ci
;
2987 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2988 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2992 IContextMenu_InvokeCommand(pcm
, &ci
);
2993 IContextMenu_Release(pcm
);
2999 /***********************************************************************
3000 * FILEDLG95_SHELL_UpFolder
3002 * Browse to the specified object
3003 * If the function succeeds, the return value is nonzero.
3005 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
3007 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3011 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3015 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3016 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3021 /***********************************************************************
3022 * FILEDLG95_SHELL_Clean
3024 * Cleans the memory used by shell objects
3026 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
3028 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3032 ILFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
3034 /* clean Shell interfaces */
3035 if (fodInfos
->Shell
.FOIShellView
)
3037 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
3038 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
3040 if (fodInfos
->Shell
.FOIShellFolder
)
3041 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
3042 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
3043 if (fodInfos
->Shell
.FOIDataObject
)
3044 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
3047 /***********************************************************************
3048 * FILEDLG95_FILETYPE_Init
3050 * Initialisation of the file type combo box
3052 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
3054 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3055 int nFilters
= 0; /* number of filters */
3058 TRACE("%p\n", hwnd
);
3060 if(fodInfos
->customfilter
)
3062 /* customfilter has one entry... title\0ext\0
3063 * Set first entry of combo box item with customfilter
3066 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
3069 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
3071 /* Copy the extensions */
3072 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
3073 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3074 lstrcpyW(lpstrExt
,lpstrPos
);
3076 /* Add the item at the end of the combo */
3077 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)fodInfos
->customfilter
);
3078 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
, (LPARAM
)lpstrExt
);
3082 if(fodInfos
->filter
)
3084 LPCWSTR lpstrPos
= fodInfos
->filter
;
3088 /* filter is a list... title\0ext\0......\0\0
3089 * Set the combo item text to the title and the item data
3092 LPCWSTR lpstrDisplay
;
3096 if(! *lpstrPos
) break; /* end */
3097 lpstrDisplay
= lpstrPos
;
3098 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3100 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)lpstrDisplay
);
3104 /* Copy the extensions */
3105 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3106 lstrcpyW(lpstrExt
,lpstrPos
);
3107 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3109 /* Add the item at the end of the combo */
3110 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
- 1, (LPARAM
)lpstrExt
);
3112 /* malformed filters are added anyway... */
3113 if (!*lpstrExt
) break;
3118 * Set the current filter to the one specified
3119 * in the initialisation structure
3121 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3125 /* Check to make sure our index isn't out of bounds. */
3126 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3127 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3128 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3130 /* set default filter index */
3131 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3132 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3134 /* calculate index of Combo Box item */
3135 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3136 if (fodInfos
->customfilter
== NULL
)
3139 /* Set the current index selection. */
3140 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, nFilterIndexCB
, 0);
3142 /* Get the corresponding text string from the combo box. */
3143 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3146 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3152 CharLowerW(lpstrFilter
); /* lowercase */
3153 len
= lstrlenW(lpstrFilter
)+1;
3154 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3155 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3158 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3162 /***********************************************************************
3163 * FILEDLG95_FILETYPE_OnCommand
3165 * WM_COMMAND of the file type combo box
3166 * If the function succeeds, the return value is nonzero.
3168 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3170 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3178 /* Get the current item of the filetype combo box */
3179 int iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCURSEL
, 0, 0);
3181 /* set the current filter index */
3182 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3183 (fodInfos
->customfilter
== NULL
? 1 : 0);
3185 /* Set the current filter with the current selection */
3186 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3188 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3190 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3193 CharLowerW(lpstrFilter
); /* lowercase */
3194 len
= lstrlenW(lpstrFilter
)+1;
3195 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3196 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3197 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3198 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3201 /* Refresh the actual view to display the included items*/
3202 if (fodInfos
->Shell
.FOIShellView
)
3203 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3208 /***********************************************************************
3209 * FILEDLG95_FILETYPE_SearchExt
3211 * searches for an extension in the filetype box
3213 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3217 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3219 TRACE("%s\n", debugstr_w(lpstrExt
));
3221 if(iCount
!= CB_ERR
)
3223 for(i
=0;i
<iCount
;i
++)
3225 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3232 /***********************************************************************
3233 * FILEDLG95_FILETYPE_Clean
3235 * Clean the memory used by the filetype combo box
3237 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3239 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3243 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCOUNT
, 0, 0);
3247 /* Delete each string of the combo and their associated data */
3248 if(iCount
!= CB_ERR
)
3250 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3252 heap_free((void *)CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3253 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_DELETESTRING
, iPos
, 0);
3256 /* Current filter */
3257 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3260 /***********************************************************************
3261 * FILEDLG95_LOOKIN_Init
3263 * Initialisation of the look in combo box
3266 /* Small helper function, to determine if the unixfs shell extension is rooted
3267 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3269 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3272 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3273 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3274 "{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3281 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3283 IShellFolder
*psfRoot
, *psfDrives
;
3284 IEnumIDList
*lpeRoot
, *lpeDrives
;
3285 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3288 LookInInfos
*liInfos
= heap_alloc_zero(sizeof(*liInfos
));
3290 TRACE("%p\n", hwndCombo
);
3292 liInfos
->iMaxIndentation
= 0;
3294 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3296 hdc
= GetDC( hwndCombo
);
3297 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3298 GetTextMetricsW( hdc
, &tm
);
3299 ReleaseDC( hwndCombo
, hdc
);
3301 /* set item height for both text field and listbox */
3302 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, -1, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3303 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, 0, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3305 /* Turn on the extended UI for the combo box like Windows does */
3306 SendMessageW(hwndCombo
, CB_SETEXTENDEDUI
, TRUE
, 0);
3308 /* Initialise data of Desktop folder */
3309 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3310 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3313 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3315 SHGetDesktopFolder(&psfRoot
);
3319 /* enumerate the contents of the desktop */
3320 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3322 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3324 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3326 /* If the unixfs extension is rooted, we don't expand the drives by default */
3327 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3329 /* special handling for CSIDL_DRIVES */
3330 if (ILIsEqual(pidlTmp
, pidlDrives
))
3332 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3334 /* enumerate the drives */
3335 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3337 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3339 pidlAbsTmp
= ILCombine(pidlTmp
, pidlTmp1
);
3340 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3344 IEnumIDList_Release(lpeDrives
);
3346 IShellFolder_Release(psfDrives
);
3353 IEnumIDList_Release(lpeRoot
);
3355 IShellFolder_Release(psfRoot
);
3361 /***********************************************************************
3362 * FILEDLG95_LOOKIN_DrawItem
3364 * WM_DRAWITEM message handler
3366 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3368 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3369 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3370 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3374 HIMAGELIST ilItemImage
;
3377 LPSFOLDER tmpFolder
;
3378 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3379 UINT icon_width
, icon_height
;
3383 if(pDIStruct
->itemID
== -1)
3386 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3387 pDIStruct
->itemID
)))
3391 icon_width
= GetSystemMetrics(SM_CXICON
);
3392 icon_height
= GetSystemMetrics(SM_CYICON
);
3393 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3395 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3396 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3397 shgfi_flags
|= SHGFI_SMALLICON
;
3400 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3401 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3403 /* Is this item selected ? */
3404 if(pDIStruct
->itemState
& ODS_SELECTED
)
3406 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3407 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3408 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3412 SetTextColor(pDIStruct
->hDC
,crText
);
3413 SetBkColor(pDIStruct
->hDC
,crWin
);
3414 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3417 /* Do not indent item if drawing in the edit of the combo */
3418 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3421 iIndentation
= tmpFolder
->m_iIndent
;
3423 /* Draw text and icon */
3425 /* Initialise the icon display area */
3426 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3427 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3428 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3429 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3431 /* Initialise the text display area */
3432 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3433 rectText
.left
= rectIcon
.right
;
3435 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3436 rectText
.right
= pDIStruct
->rcItem
.right
;
3438 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3440 /* Draw the icon from the image list */
3441 ImageList_Draw(ilItemImage
,
3448 /* Draw the associated text */
3449 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3453 /***********************************************************************
3454 * FILEDLG95_LOOKIN_OnCommand
3456 * LookIn combo box WM_COMMAND message handler
3457 * If the function succeeds, the return value is nonzero.
3459 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3461 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3463 TRACE("%p\n", fodInfos
);
3469 LPSFOLDER tmpFolder
;
3472 iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCURSEL
, 0, 0);
3474 if( iItem
== CB_ERR
) return FALSE
;
3476 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3481 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3482 tmpFolder
->pidlItem
,
3485 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3486 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3496 /***********************************************************************
3497 * FILEDLG95_LOOKIN_AddItem
3499 * Adds an absolute pidl item to the lookin combo box
3500 * returns the index of the inserted item
3502 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3504 LPITEMIDLIST pidlNext
;
3507 LookInInfos
*liInfos
;
3509 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3514 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3517 tmpFolder
= heap_alloc_zero(sizeof(*tmpFolder
));
3518 tmpFolder
->m_iIndent
= 0;
3520 /* Calculate the indentation of the item in the lookin*/
3522 while ((pidlNext
= ILGetNext(pidlNext
)))
3524 tmpFolder
->m_iIndent
++;
3527 tmpFolder
->pidlItem
= ILClone(pidl
);
3529 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3530 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3532 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3533 SHGetFileInfoW((LPCWSTR
)pidl
,
3537 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3539 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3541 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3545 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3547 /* Add the item at the end of the list */
3550 iItemID
= SendMessageW(hwnd
, CB_ADDSTRING
, 0, (LPARAM
)sfi
.szDisplayName
);
3552 /* Insert the item at the iInsertId position*/
3555 iItemID
= SendMessageW(hwnd
, CB_INSERTSTRING
, iInsertId
, (LPARAM
)sfi
.szDisplayName
);
3558 SendMessageW(hwnd
, CB_SETITEMDATA
, iItemID
, (LPARAM
)tmpFolder
);
3562 ILFree( tmpFolder
->pidlItem
);
3563 heap_free( tmpFolder
);
3568 /***********************************************************************
3569 * FILEDLG95_LOOKIN_InsertItemAfterParent
3571 * Insert an item below its parent
3573 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3576 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3581 if (pidl
== pidlParent
)
3584 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3588 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3593 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3596 /***********************************************************************
3597 * FILEDLG95_LOOKIN_SelectItem
3599 * Adds an absolute pidl item to the lookin combo box
3600 * returns the index of the inserted item
3602 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3605 LookInInfos
*liInfos
;
3607 TRACE("%p, %p\n", hwnd
, pidl
);
3609 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3611 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3615 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3616 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3621 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3622 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3626 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3628 if(iRemovedItem
< iItemPos
)
3633 SendMessageW(hwnd
, CB_SETCURSEL
, iItemPos
, 0);
3634 liInfos
->uSelectedItem
= iItemPos
;
3640 /***********************************************************************
3641 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3643 * Remove the item with an expansion level over iExpansionLevel
3645 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3648 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3652 if(liInfos
->iMaxIndentation
<= 2)
3655 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3657 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3658 ILFree(tmpFolder
->pidlItem
);
3659 heap_free(tmpFolder
);
3660 SendMessageW(hwnd
, CB_DELETESTRING
, iItemPos
, 0);
3661 liInfos
->iMaxIndentation
--;
3669 /***********************************************************************
3670 * FILEDLG95_LOOKIN_SearchItem
3672 * Search for pidl in the lookin combo box
3673 * returns the index of the found item
3675 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3680 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3682 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3684 if (iCount
!= CB_ERR
)
3688 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3690 if (iSearchMethod
== SEARCH_PIDL
&& ILIsEqual((LPITEMIDLIST
)searchArg
, tmpFolder
->pidlItem
))
3692 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3700 /***********************************************************************
3701 * FILEDLG95_LOOKIN_Clean
3703 * Clean the memory used by the lookin combo box
3705 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3707 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3708 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3711 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCOUNT
, 0, 0);
3715 /* Delete each string of the combo and their associated data */
3716 if (iCount
!= CB_ERR
)
3718 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3720 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3721 ILFree(tmpFolder
->pidlItem
);
3722 heap_free(tmpFolder
);
3723 SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_DELETESTRING
, iPos
, 0);
3727 /* LookInInfos structure */
3729 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3732 /***********************************************************************
3735 * Fill the FORMATETC used in the shell id list
3737 static FORMATETC
get_def_format(void)
3739 static CLIPFORMAT cfFormat
;
3740 FORMATETC formatetc
;
3742 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3743 formatetc
.cfFormat
= cfFormat
;
3745 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3746 formatetc
.lindex
= -1;
3747 formatetc
.tymed
= TYMED_HGLOBAL
;
3751 /***********************************************************************
3752 * FILEDLG95_FILENAME_FillFromSelection
3754 * fills the edit box from the cached DataObject
3756 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3758 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3760 LPWSTR lpstrAllFiles
, lpstrTmp
;
3761 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3764 FORMATETC formatetc
= get_def_format();
3768 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3771 cida
= GlobalLock(medium
.u
.hGlobal
);
3772 nFileSelected
= cida
->cidl
;
3774 /* Allocate a buffer */
3775 nAllFilesMaxLength
= MAX_PATH
+ 3;
3776 lpstrAllFiles
= heap_alloc_zero(nAllFilesMaxLength
* sizeof(WCHAR
));
3780 /* Loop through the selection, handle only files (not folders) */
3781 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3783 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3786 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3788 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3790 nAllFilesMaxLength
*= 2;
3791 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3794 lpstrAllFiles
= lpstrTmp
;
3797 lpstrAllFiles
[nAllFilesLength
++] = '"';
3798 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3799 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3800 nAllFilesLength
+= nThisFileLength
;
3801 lpstrAllFiles
[nAllFilesLength
++] = '"';
3802 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3809 /* If there's only one file, use the name as-is without quotes */
3810 lpstrTmp
= lpstrAllFiles
;
3814 lpstrTmp
[nThisFileLength
] = 0;
3816 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3817 /* Select the file name like Windows does */
3818 if (filename_is_edit(fodInfos
))
3819 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3823 heap_free(lpstrAllFiles
);
3824 COMCTL32_ReleaseStgMedium(medium
);
3828 /* copied from shell32 to avoid linking to it
3829 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3830 * is dependent on whether emulated OS is unicode or not.
3832 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3837 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3838 CoTaskMemFree(src
->u
.pOleStr
);
3842 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3847 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3852 FIXME("unknown type %x!\n", src
->uType
);
3853 if (len
) *dest
= '\0';
3859 /***********************************************************************
3860 * FILEDLG95_FILENAME_GetFileNames
3862 * Copies the filenames to a delimited string list.
3864 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3866 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3867 UINT nFileCount
= 0; /* number of files */
3868 UINT nStrLen
= 0; /* length of string in edit control */
3869 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3873 /* get the filenames from the filename control */
3874 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3875 lpstrEdit
= heap_alloc( (nStrLen
+1)*sizeof(WCHAR
) );
3876 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3878 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3880 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3881 heap_free(lpstrEdit
);
3886 * DATAOBJECT Helper functions
3889 /***********************************************************************
3890 * COMCTL32_ReleaseStgMedium
3892 * like ReleaseStgMedium from ole32
3894 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3896 if(medium
.pUnkForRelease
)
3898 IUnknown_Release(medium
.pUnkForRelease
);
3902 GlobalUnlock(medium
.u
.hGlobal
);
3903 GlobalFree(medium
.u
.hGlobal
);
3907 /***********************************************************************
3908 * GetPidlFromDataObject
3910 * Return pidl(s) by number from the cached DataObject
3912 * nPidlIndex=0 gets the fully qualified root path
3914 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3918 FORMATETC formatetc
= get_def_format();
3919 LPITEMIDLIST pidl
= NULL
;
3921 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3926 /* Get the pidls from IDataObject */
3927 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3929 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3930 if(nPidlIndex
<= cida
->cidl
)
3932 pidl
= ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3934 COMCTL32_ReleaseStgMedium(medium
);
3939 /***********************************************************************
3942 * Return the number of selected items in the DataObject.
3945 static UINT
GetNumSelected( IDataObject
*doSelected
)
3949 FORMATETC formatetc
= get_def_format();
3951 TRACE("sv=%p\n", doSelected
);
3953 if (!doSelected
) return 0;
3955 /* Get the pidls from IDataObject */
3956 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3958 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3959 retVal
= cida
->cidl
;
3960 COMCTL32_ReleaseStgMedium(medium
);
3970 /***********************************************************************
3973 * Get the pidl's display name (relative to folder) and
3974 * put it in lpstrFileName.
3976 * Return NOERROR on success,
3980 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3985 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3989 SHGetDesktopFolder(&lpsf
);
3990 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3991 IShellFolder_Release(lpsf
);
3995 /* Get the display name of the pidl relative to the folder */
3996 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3998 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
4003 /***********************************************************************
4004 * GetShellFolderFromPidl
4006 * pidlRel is the item pidl relative
4007 * Return the IShellFolder of the absolute pidl
4009 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
4011 IShellFolder
*psf
= NULL
,*psfParent
;
4013 TRACE("%p\n", pidlAbs
);
4015 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
4018 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
4020 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
4022 IShellFolder_Release(psfParent
);
4026 /* return the desktop */
4032 /***********************************************************************
4035 * Return the LPITEMIDLIST to the parent of the pidl in the list
4037 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
4039 LPITEMIDLIST pidlParent
;
4041 TRACE("%p\n", pidl
);
4043 pidlParent
= ILClone(pidl
);
4044 ILRemoveLastID(pidlParent
);
4049 /***********************************************************************
4052 * returns the pidl of the file name relative to folder
4053 * NULL if an error occurred
4055 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
4057 LPITEMIDLIST pidl
= NULL
;
4060 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
4062 if(!lpcstrFileName
) return NULL
;
4063 if(!*lpcstrFileName
) return NULL
;
4067 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
4068 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4069 IShellFolder_Release(lpsf
);
4074 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4081 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
4083 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4086 TRACE("%p, %p\n", psf
, pidl
);
4088 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4090 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
4091 /* see documentation shell 4.1*/
4092 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4095 /***********************************************************************
4096 * BrowseSelectedFolder
4098 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4100 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
4101 BOOL bBrowseSelFolder
= FALSE
;
4105 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4107 LPITEMIDLIST pidlSelection
;
4109 /* get the file selected */
4110 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4111 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4113 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4114 pidlSelection
, SBSP_RELATIVE
) ) )
4117 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, ARRAY_SIZE(buf
));
4118 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4120 bBrowseSelFolder
= TRUE
;
4121 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4122 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4124 ILFree( pidlSelection
);
4127 return bBrowseSelFolder
;
4130 static inline BOOL
valid_struct_size( DWORD size
)
4132 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4133 (size
== sizeof( OPENFILENAMEW
));
4136 static inline BOOL
is_win16_looks(DWORD flags
)
4138 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4139 !(flags
& OFN_EXPLORER
));
4142 /* ------------------ APIs ---------------------- */
4144 /***********************************************************************
4145 * GetOpenFileNameA (COMDLG32.@)
4147 * Creates a dialog box for the user to select a file to open.
4150 * TRUE on success: user enters a valid file
4151 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4154 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4156 TRACE("flags 0x%08x\n", ofn
->Flags
);
4158 if (!valid_struct_size( ofn
->lStructSize
))
4160 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4164 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4165 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4166 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4168 if (is_win16_looks(ofn
->Flags
))
4169 return GetFileName31A(ofn
, OPEN_DIALOG
);
4172 FileOpenDlgInfos info
;
4174 init_filedlg_infoA(ofn
, &info
);
4175 return GetFileDialog95(&info
, OPEN_DIALOG
);
4179 /***********************************************************************
4180 * GetOpenFileNameW (COMDLG32.@)
4182 * Creates a dialog box for the user to select a file to open.
4185 * TRUE on success: user enters a valid file
4186 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4189 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4191 TRACE("flags 0x%08x\n", ofn
->Flags
);
4193 if (!valid_struct_size( ofn
->lStructSize
))
4195 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4199 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4200 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4201 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4203 if (is_win16_looks(ofn
->Flags
))
4204 return GetFileName31W(ofn
, OPEN_DIALOG
);
4207 FileOpenDlgInfos info
;
4209 init_filedlg_infoW(ofn
, &info
);
4210 return GetFileDialog95(&info
, OPEN_DIALOG
);
4215 /***********************************************************************
4216 * GetSaveFileNameA (COMDLG32.@)
4218 * Creates a dialog box for the user to select a file to save.
4221 * TRUE on success: user enters a valid file
4222 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4225 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4227 if (!valid_struct_size( ofn
->lStructSize
))
4229 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4233 if (is_win16_looks(ofn
->Flags
))
4234 return GetFileName31A(ofn
, SAVE_DIALOG
);
4237 FileOpenDlgInfos info
;
4239 init_filedlg_infoA(ofn
, &info
);
4240 return GetFileDialog95(&info
, SAVE_DIALOG
);
4244 /***********************************************************************
4245 * GetSaveFileNameW (COMDLG32.@)
4247 * Creates a dialog box for the user to select a file to save.
4250 * TRUE on success: user enters a valid file
4251 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4254 BOOL WINAPI
GetSaveFileNameW(
4255 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4257 if (!valid_struct_size( ofn
->lStructSize
))
4259 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4263 if (is_win16_looks(ofn
->Flags
))
4264 return GetFileName31W(ofn
, SAVE_DIALOG
);
4267 FileOpenDlgInfos info
;
4269 init_filedlg_infoW(ofn
, &info
);
4270 return GetFileDialog95(&info
, SAVE_DIALOG
);
4274 /***********************************************************************
4275 * GetFileTitleA (COMDLG32.@)
4277 * See GetFileTitleW.
4279 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4282 UNICODE_STRING strWFile
;
4285 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4286 lpWTitle
= heap_alloc(cbBuf
* sizeof(WCHAR
));
4287 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4288 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4289 RtlFreeUnicodeString( &strWFile
);
4290 heap_free( lpWTitle
);
4295 /***********************************************************************
4296 * GetFileTitleW (COMDLG32.@)
4298 * Get the name of a file.
4301 * lpFile [I] name and location of file
4302 * lpTitle [O] returned file name
4303 * cbBuf [I] buffer size of lpTitle
4307 * Failure: negative number.
4309 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4312 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4314 if(lpFile
== NULL
|| lpTitle
== NULL
)
4317 len
= lstrlenW(lpFile
);
4322 if(wcspbrk(lpFile
, L
"*[]"))
4327 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4330 for(i
= len
; i
>= 0; i
--)
4332 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4342 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4344 len
= lstrlenW(lpFile
+i
)+1;
4348 lstrcpyW(lpTitle
, &lpFile
[i
]);