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 %lu.\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%08lx 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 %#Ix\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 %ld,%ld to %ld,%ld\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: %ld\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: %ld, ret: %ld\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: %ld, ret: %ld\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: %ld\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: %ld\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: %ld, ret: %ld\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: %ld\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: %ld\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 if (lpszTemp
== lpstrPathAndFile
&& (p
= PathSkipRootW(lpwstrTemp
)))
2463 p
= PathFindNextComponentW(lpwstrTemp
);
2464 if (!p
) break; /* end of path */
2467 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2469 /* There are no wildcards when OFN_NOVALIDATE is set */
2470 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2472 /* if the last element is a wildcard do a search */
2473 if(wcspbrk(lpszTemp1
, L
"*?") != NULL
)
2475 nOpenAction
= ONOPEN_SEARCH
;
2479 lpszTemp1
= lpszTemp
;
2481 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2483 /* append a backslash to drive letters */
2484 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2485 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2486 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2488 PathAddBackslashW(lpwstrTemp
);
2491 dwAttributes
= SFGAO_FOLDER
;
2492 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2494 /* the path component is valid, we have a pidl of the next path component */
2495 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
2496 if(dwAttributes
& SFGAO_FOLDER
)
2498 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2500 ERR("bind to failed\n"); /* should not fail */
2503 IShellFolder_Release(*ppsf
);
2511 /* end dialog, return value */
2512 nOpenAction
= ONOPEN_OPEN
;
2518 else if (!(flags
& OFN_NOVALIDATE
))
2520 if(*lpszTemp
|| /* points to trailing null for last path element */
2521 (lpwstrTemp
[lstrlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2523 if(flags
& OFN_PATHMUSTEXIST
)
2525 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2531 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2533 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2537 /* change to the current folder */
2538 nOpenAction
= ONOPEN_OPEN
;
2543 nOpenAction
= ONOPEN_OPEN
;
2552 /***********************************************************************
2555 * Ok button WM_COMMAND message handler
2557 * If the function succeeds, the return value is nonzero.
2559 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2561 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2562 LPWSTR lpstrFileList
;
2563 UINT nFileCount
= 0;
2566 WCHAR lpstrPathAndFile
[MAX_PATH
];
2567 LPSHELLFOLDER lpsf
= NULL
;
2570 TRACE("hwnd=%p\n", hwnd
);
2572 /* try to browse the selected item */
2573 if(BrowseSelectedFolder(hwnd
))
2576 /* get the files from the edit control */
2577 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2584 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2588 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2591 Step 1: Build a complete path name from the current folder and
2592 the filename or path in the edit box.
2594 - the path in the edit box is a root path
2595 (with or without drive letter)
2596 - the edit box contains ".." (or a path with ".." in it)
2599 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2600 heap_free(lpstrFileList
);
2603 Step 2: here we have a cleaned up path
2605 We have to parse the path step by step to see if we have to browse
2606 to a folder if the path points to a directory or the last
2607 valid element is a directory.
2610 lpstrPathAndFile: cleaned up path
2614 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2615 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2616 nOpenAction
= ONOPEN_OPEN
;
2618 nOpenAction
= ONOPEN_BROWSE
;
2620 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2621 fodInfos
->ofnInfos
->Flags
,
2622 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2628 Step 3: here we have a cleaned up and validated path
2631 lpsf: ShellFolder bound to the rightmost valid path component
2632 lpstrPathAndFile: cleaned up path
2633 nOpenAction: action to do
2635 TRACE("end validate sf=%p\n", lpsf
);
2639 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2640 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2643 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2646 /* replace the current filter */
2647 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2648 len
= lstrlenW(lpszTemp
)+1;
2649 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc(len
* sizeof(WCHAR
));
2650 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2652 /* set the filter cb to the extension when possible */
2653 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2654 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, iPos
, 0);
2657 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2658 TRACE("ONOPEN_BROWSE\n");
2660 IPersistFolder2
* ppf2
;
2661 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2663 LPITEMIDLIST pidlCurrent
;
2664 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2665 IPersistFolder2_Release(ppf2
);
2666 if (!ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2668 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2669 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2671 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2672 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2675 else if( nOpenAction
== ONOPEN_SEARCH
)
2677 if (fodInfos
->Shell
.FOIShellView
)
2678 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2680 ILFree(pidlCurrent
);
2681 if (filename_is_edit( fodInfos
))
2682 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2687 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2688 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2694 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2695 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2699 /* update READONLY check box flag */
2700 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2701 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2703 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2705 /* Attach the file extension with file name*/
2706 ext
= PathFindExtensionW(lpstrPathAndFile
);
2707 if (! *ext
&& fodInfos
->defext
)
2709 /* if no extension is specified with file name, then */
2710 /* attach the extension from file filter or default one */
2712 WCHAR
*filterExt
= NULL
;
2713 LPWSTR lpstrFilter
= NULL
;
2714 int PathLength
= lstrlenW(lpstrPathAndFile
);
2716 /*Get the file extension from file type filter*/
2717 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2718 fodInfos
->ofnInfos
->nFilterIndex
-1);
2720 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2722 WCHAR
* filterSearchIndex
;
2723 filterExt
= heap_alloc((lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2724 lstrcpyW(filterExt
, lpstrFilter
);
2726 /* if a semicolon-separated list of file extensions was given, do not include the
2727 semicolon or anything after it in the extension.
2728 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2729 filterSearchIndex
= wcschr(filterExt
, ';');
2730 if (filterSearchIndex
)
2732 filterSearchIndex
[0] = '\0';
2735 /* find the file extension by searching for the first dot in filterExt */
2736 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2737 /* if the extension is invalid or contains a glob, ignore it */
2738 filterSearchIndex
= wcschr(filterExt
, '.');
2739 if (filterSearchIndex
++ && !wcschr(filterSearchIndex
, '*') && !wcschr(filterSearchIndex
, '?'))
2741 lstrcpyW(filterExt
, filterSearchIndex
);
2745 heap_free(filterExt
);
2752 /* use the default file extension */
2753 filterExt
= heap_alloc((lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2754 lstrcpyW(filterExt
, fodInfos
->defext
);
2757 if (*filterExt
) /* ignore filterExt="" */
2760 lstrcatW(lpstrPathAndFile
, L
".");
2761 /* Attach the extension */
2762 lstrcatW(lpstrPathAndFile
, filterExt
);
2765 heap_free(filterExt
);
2767 /* In Open dialog: if file does not exist try without extension */
2768 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2769 lpstrPathAndFile
[PathLength
] = '\0';
2771 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2774 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2775 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2777 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2780 /* In Save dialog: check if the file already exists */
2781 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2782 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2783 && PathFileExistsW(lpstrPathAndFile
))
2785 WCHAR lpstrOverwrite
[100];
2788 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2789 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2790 MB_YESNO
| MB_ICONEXCLAMATION
);
2791 if (answer
== IDNO
|| answer
== IDCANCEL
)
2798 /* In Open dialog: check if it should be created if it doesn't exist */
2799 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2800 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2801 && !PathFileExistsW(lpstrPathAndFile
))
2803 WCHAR lpstrCreate
[100];
2806 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2807 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2808 MB_YESNO
| MB_ICONEXCLAMATION
);
2809 if (answer
== IDNO
|| answer
== IDCANCEL
)
2816 /* Check that the size of the file does not exceed buffer size.
2817 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2818 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2819 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2822 /* fill destination buffer */
2823 if (fodInfos
->ofnInfos
->lpstrFile
)
2825 if(fodInfos
->unicode
)
2827 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2829 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2830 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2831 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2835 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2837 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2838 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2839 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2840 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2844 if(fodInfos
->unicode
)
2848 /* set filename offset */
2849 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2850 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2852 /* set extension offset */
2853 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2854 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2859 CHAR tempFileA
[MAX_PATH
];
2861 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2862 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2863 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2865 /* set filename offset */
2866 lpszTemp
= PathFindFileNameA(tempFileA
);
2867 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2869 /* set extension offset */
2870 lpszTemp
= PathFindExtensionA(tempFileA
);
2871 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2874 /* set the lpstrFileTitle */
2875 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2877 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2878 if(fodInfos
->unicode
)
2880 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2881 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2885 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2886 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2887 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2891 /* copy currently selected filter to lpstrCustomFilter */
2892 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2894 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2895 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2896 NULL
, 0, NULL
, NULL
);
2897 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2899 LPSTR s
= ofn
->lpstrCustomFilter
;
2900 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2901 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2902 s
, len
, NULL
, NULL
);
2907 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2910 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2913 FILEDLG95_Clean(hwnd
);
2914 ret
= EndDialog(hwnd
, TRUE
);
2920 size
= lstrlenW(lpstrPathAndFile
) + 1;
2921 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2923 /* return needed size in first two bytes of lpstrFile */
2924 if(fodInfos
->ofnInfos
->lpstrFile
)
2925 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2926 FILEDLG95_Clean(hwnd
);
2927 ret
= EndDialog(hwnd
, FALSE
);
2928 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2935 if(lpsf
) IShellFolder_Release(lpsf
);
2939 /***********************************************************************
2940 * FILEDLG95_SHELL_Init
2942 * Initialisation of the shell objects
2944 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2946 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2948 TRACE("%p\n", hwnd
);
2951 * Initialisation of the FileOpenDialogInfos structure
2957 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2959 /* Disable multi-select if flag not set */
2960 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2962 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2964 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2965 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2967 /* Construct the IShellBrowser interface */
2968 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2973 /***********************************************************************
2974 * FILEDLG95_SHELL_ExecuteCommand
2976 * Change the folder option and refresh the view
2977 * If the function succeeds, the return value is nonzero.
2979 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2981 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2984 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2986 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2991 CMINVOKECOMMANDINFO ci
;
2992 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2993 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2997 IContextMenu_InvokeCommand(pcm
, &ci
);
2998 IContextMenu_Release(pcm
);
3004 /***********************************************************************
3005 * FILEDLG95_SHELL_UpFolder
3007 * Browse to the specified object
3008 * If the function succeeds, the return value is nonzero.
3010 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
3012 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3016 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3020 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3021 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3026 /***********************************************************************
3027 * FILEDLG95_SHELL_Clean
3029 * Cleans the memory used by shell objects
3031 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
3033 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3037 ILFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
3039 /* clean Shell interfaces */
3040 if (fodInfos
->Shell
.FOIShellView
)
3042 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
3043 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
3045 if (fodInfos
->Shell
.FOIShellFolder
)
3046 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
3047 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
3048 if (fodInfos
->Shell
.FOIDataObject
)
3049 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
3052 /***********************************************************************
3053 * FILEDLG95_FILETYPE_Init
3055 * Initialisation of the file type combo box
3057 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
3059 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3060 int nFilters
= 0; /* number of filters */
3063 TRACE("%p\n", hwnd
);
3065 if(fodInfos
->customfilter
)
3067 /* customfilter has one entry... title\0ext\0
3068 * Set first entry of combo box item with customfilter
3071 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
3074 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
3076 /* Copy the extensions */
3077 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
3078 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3079 lstrcpyW(lpstrExt
,lpstrPos
);
3081 /* Add the item at the end of the combo */
3082 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)fodInfos
->customfilter
);
3083 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
, (LPARAM
)lpstrExt
);
3087 if(fodInfos
->filter
)
3089 LPCWSTR lpstrPos
= fodInfos
->filter
;
3093 /* filter is a list... title\0ext\0......\0\0
3094 * Set the combo item text to the title and the item data
3097 LPCWSTR lpstrDisplay
;
3101 if(! *lpstrPos
) break; /* end */
3102 lpstrDisplay
= lpstrPos
;
3103 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3105 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)lpstrDisplay
);
3109 /* Copy the extensions */
3110 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3111 lstrcpyW(lpstrExt
,lpstrPos
);
3112 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3114 /* Add the item at the end of the combo */
3115 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
- 1, (LPARAM
)lpstrExt
);
3117 /* malformed filters are added anyway... */
3118 if (!*lpstrExt
) break;
3123 * Set the current filter to the one specified
3124 * in the initialisation structure
3126 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3130 /* Check to make sure our index isn't out of bounds. */
3131 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3132 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3133 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3135 /* set default filter index */
3136 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3137 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3139 /* calculate index of Combo Box item */
3140 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3141 if (fodInfos
->customfilter
== NULL
)
3144 /* Set the current index selection. */
3145 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, nFilterIndexCB
, 0);
3147 /* Get the corresponding text string from the combo box. */
3148 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3151 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3157 CharLowerW(lpstrFilter
); /* lowercase */
3158 len
= lstrlenW(lpstrFilter
)+1;
3159 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3160 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3163 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3167 /***********************************************************************
3168 * FILEDLG95_FILETYPE_OnCommand
3170 * WM_COMMAND of the file type combo box
3171 * If the function succeeds, the return value is nonzero.
3173 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3175 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3183 /* Get the current item of the filetype combo box */
3184 int iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCURSEL
, 0, 0);
3186 /* set the current filter index */
3187 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3188 (fodInfos
->customfilter
== NULL
? 1 : 0);
3190 /* Set the current filter with the current selection */
3191 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3193 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3195 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3198 CharLowerW(lpstrFilter
); /* lowercase */
3199 len
= lstrlenW(lpstrFilter
)+1;
3200 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3201 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3202 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3203 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3206 /* Refresh the actual view to display the included items*/
3207 if (fodInfos
->Shell
.FOIShellView
)
3208 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3213 /***********************************************************************
3214 * FILEDLG95_FILETYPE_SearchExt
3216 * searches for an extension in the filetype box
3218 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3222 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3224 TRACE("%s\n", debugstr_w(lpstrExt
));
3226 if(iCount
!= CB_ERR
)
3228 for(i
=0;i
<iCount
;i
++)
3230 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3237 /***********************************************************************
3238 * FILEDLG95_FILETYPE_Clean
3240 * Clean the memory used by the filetype combo box
3242 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3244 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3248 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCOUNT
, 0, 0);
3252 /* Delete each string of the combo and their associated data */
3253 if(iCount
!= CB_ERR
)
3255 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3257 heap_free((void *)CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3258 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_DELETESTRING
, iPos
, 0);
3261 /* Current filter */
3262 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3265 /***********************************************************************
3266 * FILEDLG95_LOOKIN_Init
3268 * Initialisation of the look in combo box
3271 /* Small helper function, to determine if the unixfs shell extension is rooted
3272 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3274 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3277 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3278 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3279 "{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3286 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3288 IShellFolder
*psfRoot
, *psfDrives
;
3289 IEnumIDList
*lpeRoot
, *lpeDrives
;
3290 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3293 LookInInfos
*liInfos
= heap_alloc_zero(sizeof(*liInfos
));
3295 TRACE("%p\n", hwndCombo
);
3297 liInfos
->iMaxIndentation
= 0;
3299 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3301 hdc
= GetDC( hwndCombo
);
3302 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3303 GetTextMetricsW( hdc
, &tm
);
3304 ReleaseDC( hwndCombo
, hdc
);
3306 /* set item height for both text field and listbox */
3307 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, -1, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3308 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, 0, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3310 /* Turn on the extended UI for the combo box like Windows does */
3311 SendMessageW(hwndCombo
, CB_SETEXTENDEDUI
, TRUE
, 0);
3313 /* Initialise data of Desktop folder */
3314 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3315 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3318 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3320 SHGetDesktopFolder(&psfRoot
);
3324 /* enumerate the contents of the desktop */
3325 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3327 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3329 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3331 /* If the unixfs extension is rooted, we don't expand the drives by default */
3332 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3334 /* special handling for CSIDL_DRIVES */
3335 if (ILIsEqual(pidlTmp
, pidlDrives
))
3337 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3339 /* enumerate the drives */
3340 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3342 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3344 pidlAbsTmp
= ILCombine(pidlTmp
, pidlTmp1
);
3345 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3349 IEnumIDList_Release(lpeDrives
);
3351 IShellFolder_Release(psfDrives
);
3358 IEnumIDList_Release(lpeRoot
);
3360 IShellFolder_Release(psfRoot
);
3366 /***********************************************************************
3367 * FILEDLG95_LOOKIN_DrawItem
3369 * WM_DRAWITEM message handler
3371 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3373 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3374 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3375 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3379 HIMAGELIST ilItemImage
;
3382 LPSFOLDER tmpFolder
;
3383 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3384 UINT icon_width
, icon_height
;
3388 if(pDIStruct
->itemID
== -1)
3391 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3392 pDIStruct
->itemID
)))
3396 icon_width
= GetSystemMetrics(SM_CXICON
);
3397 icon_height
= GetSystemMetrics(SM_CYICON
);
3398 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3400 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3401 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3402 shgfi_flags
|= SHGFI_SMALLICON
;
3405 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3406 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3408 /* Is this item selected ? */
3409 if(pDIStruct
->itemState
& ODS_SELECTED
)
3411 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3412 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3413 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3417 SetTextColor(pDIStruct
->hDC
,crText
);
3418 SetBkColor(pDIStruct
->hDC
,crWin
);
3419 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3422 /* Do not indent item if drawing in the edit of the combo */
3423 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3426 iIndentation
= tmpFolder
->m_iIndent
;
3428 /* Draw text and icon */
3430 /* Initialise the icon display area */
3431 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3432 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3433 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3434 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3436 /* Initialise the text display area */
3437 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3438 rectText
.left
= rectIcon
.right
;
3440 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3441 rectText
.right
= pDIStruct
->rcItem
.right
;
3443 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3445 /* Draw the icon from the image list */
3446 ImageList_Draw(ilItemImage
,
3453 /* Draw the associated text */
3454 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3458 /***********************************************************************
3459 * FILEDLG95_LOOKIN_OnCommand
3461 * LookIn combo box WM_COMMAND message handler
3462 * If the function succeeds, the return value is nonzero.
3464 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3466 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3468 TRACE("%p\n", fodInfos
);
3474 LPSFOLDER tmpFolder
;
3477 iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCURSEL
, 0, 0);
3479 if( iItem
== CB_ERR
) return FALSE
;
3481 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3486 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3487 tmpFolder
->pidlItem
,
3490 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3491 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3501 /***********************************************************************
3502 * FILEDLG95_LOOKIN_AddItem
3504 * Adds an absolute pidl item to the lookin combo box
3505 * returns the index of the inserted item
3507 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3509 LPITEMIDLIST pidlNext
;
3512 LookInInfos
*liInfos
;
3514 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3519 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3522 tmpFolder
= heap_alloc_zero(sizeof(*tmpFolder
));
3523 tmpFolder
->m_iIndent
= 0;
3525 /* Calculate the indentation of the item in the lookin*/
3527 while ((pidlNext
= ILGetNext(pidlNext
)))
3529 tmpFolder
->m_iIndent
++;
3532 tmpFolder
->pidlItem
= ILClone(pidl
);
3534 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3535 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3537 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3538 SHGetFileInfoW((LPCWSTR
)pidl
,
3542 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3544 TRACE("-- Add %s attr=0x%08lx\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3546 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3550 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3552 /* Add the item at the end of the list */
3555 iItemID
= SendMessageW(hwnd
, CB_ADDSTRING
, 0, (LPARAM
)sfi
.szDisplayName
);
3557 /* Insert the item at the iInsertId position*/
3560 iItemID
= SendMessageW(hwnd
, CB_INSERTSTRING
, iInsertId
, (LPARAM
)sfi
.szDisplayName
);
3563 SendMessageW(hwnd
, CB_SETITEMDATA
, iItemID
, (LPARAM
)tmpFolder
);
3567 ILFree( tmpFolder
->pidlItem
);
3568 heap_free( tmpFolder
);
3573 /***********************************************************************
3574 * FILEDLG95_LOOKIN_InsertItemAfterParent
3576 * Insert an item below its parent
3578 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3581 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3586 if (pidl
== pidlParent
)
3589 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3593 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3598 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3601 /***********************************************************************
3602 * FILEDLG95_LOOKIN_SelectItem
3604 * Adds an absolute pidl item to the lookin combo box
3605 * returns the index of the inserted item
3607 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3610 LookInInfos
*liInfos
;
3612 TRACE("%p, %p\n", hwnd
, pidl
);
3614 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3616 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3620 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3621 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3626 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3627 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3631 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3633 if(iRemovedItem
< iItemPos
)
3638 SendMessageW(hwnd
, CB_SETCURSEL
, iItemPos
, 0);
3639 liInfos
->uSelectedItem
= iItemPos
;
3645 /***********************************************************************
3646 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3648 * Remove the item with an expansion level over iExpansionLevel
3650 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3653 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3657 if(liInfos
->iMaxIndentation
<= 2)
3660 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3662 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3663 ILFree(tmpFolder
->pidlItem
);
3664 heap_free(tmpFolder
);
3665 SendMessageW(hwnd
, CB_DELETESTRING
, iItemPos
, 0);
3666 liInfos
->iMaxIndentation
--;
3674 /***********************************************************************
3675 * FILEDLG95_LOOKIN_SearchItem
3677 * Search for pidl in the lookin combo box
3678 * returns the index of the found item
3680 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3685 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3687 TRACE("0x%08Ix 0x%x\n",searchArg
, iSearchMethod
);
3689 if (iCount
!= CB_ERR
)
3693 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3695 if (iSearchMethod
== SEARCH_PIDL
&& ILIsEqual((LPITEMIDLIST
)searchArg
, tmpFolder
->pidlItem
))
3697 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3705 /***********************************************************************
3706 * FILEDLG95_LOOKIN_Clean
3708 * Clean the memory used by the lookin combo box
3710 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3712 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3713 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3716 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCOUNT
, 0, 0);
3720 /* Delete each string of the combo and their associated data */
3721 if (iCount
!= CB_ERR
)
3723 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3725 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3726 ILFree(tmpFolder
->pidlItem
);
3727 heap_free(tmpFolder
);
3728 SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_DELETESTRING
, iPos
, 0);
3732 /* LookInInfos structure */
3734 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3737 /***********************************************************************
3740 * Fill the FORMATETC used in the shell id list
3742 static FORMATETC
get_def_format(void)
3744 static CLIPFORMAT cfFormat
;
3745 FORMATETC formatetc
;
3747 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3748 formatetc
.cfFormat
= cfFormat
;
3750 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3751 formatetc
.lindex
= -1;
3752 formatetc
.tymed
= TYMED_HGLOBAL
;
3756 /***********************************************************************
3757 * FILEDLG95_FILENAME_FillFromSelection
3759 * fills the edit box from the cached DataObject
3761 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3763 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3765 LPWSTR lpstrAllFiles
, lpstrTmp
;
3766 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3769 FORMATETC formatetc
= get_def_format();
3773 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3776 cida
= GlobalLock(medium
.u
.hGlobal
);
3777 nFileSelected
= cida
->cidl
;
3779 /* Allocate a buffer */
3780 nAllFilesMaxLength
= MAX_PATH
+ 3;
3781 lpstrAllFiles
= heap_alloc_zero(nAllFilesMaxLength
* sizeof(WCHAR
));
3785 /* Loop through the selection, handle only files (not folders) */
3786 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3788 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3791 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3793 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3795 nAllFilesMaxLength
*= 2;
3796 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3799 lpstrAllFiles
= lpstrTmp
;
3802 lpstrAllFiles
[nAllFilesLength
++] = '"';
3803 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3804 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3805 nAllFilesLength
+= nThisFileLength
;
3806 lpstrAllFiles
[nAllFilesLength
++] = '"';
3807 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3814 /* If there's only one file, use the name as-is without quotes */
3815 lpstrTmp
= lpstrAllFiles
;
3819 lpstrTmp
[nThisFileLength
] = 0;
3821 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3822 /* Select the file name like Windows does */
3823 if (filename_is_edit(fodInfos
))
3824 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3828 heap_free(lpstrAllFiles
);
3829 COMCTL32_ReleaseStgMedium(medium
);
3833 /* copied from shell32 to avoid linking to it
3834 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3835 * is dependent on whether emulated OS is unicode or not.
3837 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3842 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3843 CoTaskMemFree(src
->u
.pOleStr
);
3847 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3852 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3857 FIXME("unknown type %x!\n", src
->uType
);
3858 if (len
) *dest
= '\0';
3864 /***********************************************************************
3865 * FILEDLG95_FILENAME_GetFileNames
3867 * Copies the filenames to a delimited string list.
3869 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3871 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3872 UINT nFileCount
= 0; /* number of files */
3873 UINT nStrLen
= 0; /* length of string in edit control */
3874 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3878 /* get the filenames from the filename control */
3879 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3880 lpstrEdit
= heap_alloc( (nStrLen
+1)*sizeof(WCHAR
) );
3881 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3883 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3885 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3886 heap_free(lpstrEdit
);
3891 * DATAOBJECT Helper functions
3894 /***********************************************************************
3895 * COMCTL32_ReleaseStgMedium
3897 * like ReleaseStgMedium from ole32
3899 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3901 if(medium
.pUnkForRelease
)
3903 IUnknown_Release(medium
.pUnkForRelease
);
3907 GlobalUnlock(medium
.u
.hGlobal
);
3908 GlobalFree(medium
.u
.hGlobal
);
3912 /***********************************************************************
3913 * GetPidlFromDataObject
3915 * Return pidl(s) by number from the cached DataObject
3917 * nPidlIndex=0 gets the fully qualified root path
3919 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3923 FORMATETC formatetc
= get_def_format();
3924 LPITEMIDLIST pidl
= NULL
;
3926 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3931 /* Get the pidls from IDataObject */
3932 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3934 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3935 if(nPidlIndex
<= cida
->cidl
)
3937 pidl
= ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3939 COMCTL32_ReleaseStgMedium(medium
);
3944 /***********************************************************************
3947 * Return the number of selected items in the DataObject.
3950 static UINT
GetNumSelected( IDataObject
*doSelected
)
3954 FORMATETC formatetc
= get_def_format();
3956 TRACE("sv=%p\n", doSelected
);
3958 if (!doSelected
) return 0;
3960 /* Get the pidls from IDataObject */
3961 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3963 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3964 retVal
= cida
->cidl
;
3965 COMCTL32_ReleaseStgMedium(medium
);
3975 /***********************************************************************
3978 * Get the pidl's display name (relative to folder) and
3979 * put it in lpstrFileName.
3981 * Return NOERROR on success,
3985 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3990 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3994 SHGetDesktopFolder(&lpsf
);
3995 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3996 IShellFolder_Release(lpsf
);
4000 /* Get the display name of the pidl relative to the folder */
4001 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
4003 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
4008 /***********************************************************************
4009 * GetShellFolderFromPidl
4011 * pidlRel is the item pidl relative
4012 * Return the IShellFolder of the absolute pidl
4014 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
4016 IShellFolder
*psf
= NULL
,*psfParent
;
4018 TRACE("%p\n", pidlAbs
);
4020 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
4023 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
4025 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
4027 IShellFolder_Release(psfParent
);
4031 /* return the desktop */
4037 /***********************************************************************
4040 * Return the LPITEMIDLIST to the parent of the pidl in the list
4042 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
4044 LPITEMIDLIST pidlParent
;
4046 TRACE("%p\n", pidl
);
4048 pidlParent
= ILClone(pidl
);
4049 ILRemoveLastID(pidlParent
);
4054 /***********************************************************************
4057 * returns the pidl of the file name relative to folder
4058 * NULL if an error occurred
4060 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
4062 LPITEMIDLIST pidl
= NULL
;
4065 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
4067 if(!lpcstrFileName
) return NULL
;
4068 if(!*lpcstrFileName
) return NULL
;
4072 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
4073 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4074 IShellFolder_Release(lpsf
);
4079 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4086 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
4088 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4091 TRACE("%p, %p\n", psf
, pidl
);
4093 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4095 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
4096 /* see documentation shell 4.1*/
4097 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4100 /***********************************************************************
4101 * BrowseSelectedFolder
4103 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4105 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
4106 BOOL bBrowseSelFolder
= FALSE
;
4110 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4112 LPITEMIDLIST pidlSelection
;
4114 /* get the file selected */
4115 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4116 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4118 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4119 pidlSelection
, SBSP_RELATIVE
) ) )
4122 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, ARRAY_SIZE(buf
));
4123 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4125 bBrowseSelFolder
= TRUE
;
4126 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4127 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4129 ILFree( pidlSelection
);
4132 return bBrowseSelFolder
;
4135 static inline BOOL
valid_struct_size( DWORD size
)
4137 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4138 (size
== sizeof( OPENFILENAMEW
));
4141 static inline BOOL
is_win16_looks(DWORD flags
)
4143 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4144 !(flags
& OFN_EXPLORER
));
4147 /* ------------------ APIs ---------------------- */
4149 /***********************************************************************
4150 * GetOpenFileNameA (COMDLG32.@)
4152 * Creates a dialog box for the user to select a file to open.
4155 * TRUE on success: user enters a valid file
4156 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4159 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4161 TRACE("flags 0x%08lx\n", ofn
->Flags
);
4163 if (!valid_struct_size( ofn
->lStructSize
))
4165 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4169 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4170 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4171 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4173 if (is_win16_looks(ofn
->Flags
))
4174 return GetFileName31A(ofn
, OPEN_DIALOG
);
4177 FileOpenDlgInfos info
;
4179 init_filedlg_infoA(ofn
, &info
);
4180 return GetFileDialog95(&info
, OPEN_DIALOG
);
4184 /***********************************************************************
4185 * GetOpenFileNameW (COMDLG32.@)
4187 * Creates a dialog box for the user to select a file to open.
4190 * TRUE on success: user enters a valid file
4191 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4194 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4196 TRACE("flags 0x%08lx\n", ofn
->Flags
);
4198 if (!valid_struct_size( ofn
->lStructSize
))
4200 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4204 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4205 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4206 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4208 if (is_win16_looks(ofn
->Flags
))
4209 return GetFileName31W(ofn
, OPEN_DIALOG
);
4212 FileOpenDlgInfos info
;
4214 init_filedlg_infoW(ofn
, &info
);
4215 return GetFileDialog95(&info
, OPEN_DIALOG
);
4220 /***********************************************************************
4221 * GetSaveFileNameA (COMDLG32.@)
4223 * Creates a dialog box for the user to select a file to save.
4226 * TRUE on success: user enters a valid file
4227 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4230 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4232 if (!valid_struct_size( ofn
->lStructSize
))
4234 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4238 if (is_win16_looks(ofn
->Flags
))
4239 return GetFileName31A(ofn
, SAVE_DIALOG
);
4242 FileOpenDlgInfos info
;
4244 init_filedlg_infoA(ofn
, &info
);
4245 return GetFileDialog95(&info
, SAVE_DIALOG
);
4249 /***********************************************************************
4250 * GetSaveFileNameW (COMDLG32.@)
4252 * Creates a dialog box for the user to select a file to save.
4255 * TRUE on success: user enters a valid file
4256 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4259 BOOL WINAPI
GetSaveFileNameW(
4260 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4262 if (!valid_struct_size( ofn
->lStructSize
))
4264 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4268 if (is_win16_looks(ofn
->Flags
))
4269 return GetFileName31W(ofn
, SAVE_DIALOG
);
4272 FileOpenDlgInfos info
;
4274 init_filedlg_infoW(ofn
, &info
);
4275 return GetFileDialog95(&info
, SAVE_DIALOG
);
4279 /***********************************************************************
4280 * GetFileTitleA (COMDLG32.@)
4282 * See GetFileTitleW.
4284 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4287 UNICODE_STRING strWFile
;
4290 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4291 lpWTitle
= heap_alloc(cbBuf
* sizeof(WCHAR
));
4292 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4293 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4294 RtlFreeUnicodeString( &strWFile
);
4295 heap_free( lpWTitle
);
4300 /***********************************************************************
4301 * GetFileTitleW (COMDLG32.@)
4303 * Get the name of a file.
4306 * lpFile [I] name and location of file
4307 * lpTitle [O] returned file name
4308 * cbBuf [I] buffer size of lpTitle
4312 * Failure: negative number.
4314 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4317 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4319 if(lpFile
== NULL
|| lpTitle
== NULL
)
4322 len
= lstrlenW(lpFile
);
4327 if(wcspbrk(lpFile
, L
"*[]"))
4332 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4335 for(i
= len
; i
>= 0; i
--)
4337 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4347 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4349 len
= lstrlenW(lpFile
+i
)+1;
4353 lstrcpyW(lpTitle
, &lpFile
[i
]);