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 static const WCHAR LastVisitedMRUW
[] =
139 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
140 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
142 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
143 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
145 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
147 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
149 return GetPropW(hwnd
, filedlg_info_propnameW
);
152 static BOOL
is_dialog_hooked(const FileOpenDlgInfos
*info
)
154 return (info
->ofnInfos
->Flags
& OFN_ENABLEHOOK
) && info
->ofnInfos
->lpfnHook
;
157 static BOOL
filedialog_is_readonly_hidden(const FileOpenDlgInfos
*info
)
159 return (info
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) || (info
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
);
162 /***********************************************************************
166 /* Internal functions used by the dialog */
167 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
168 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
169 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
170 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
171 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
172 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
173 static void FILEDLG95_Clean(HWND hwnd
);
175 /* Functions used by the shell navigation */
176 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
177 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
178 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
179 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
181 /* Functions used by the EDIT box */
182 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
184 /* Functions used by the filetype combo box */
185 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
186 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
187 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
188 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
190 /* Functions used by the Look In combo box */
191 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
192 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
193 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
194 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
195 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
196 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
197 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
198 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
199 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
201 /* Functions for dealing with the most-recently-used registry keys */
202 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
203 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
204 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
206 /* Miscellaneous tool functions */
207 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
208 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
209 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
210 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
211 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
212 static UINT
GetNumSelected( IDataObject
*doSelected
);
213 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
215 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
216 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
217 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
218 static BOOL
BrowseSelectedFolder(HWND hwnd
);
220 static BOOL
get_config_key_as_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
222 DWORD type
, data
, size
;
225 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
))
234 static BOOL
get_config_key_dword(HKEY hkey
, const WCHAR
*name
, DWORD
*value
)
236 DWORD type
, data
, size
;
239 if (hkey
&& !RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
248 static BOOL
get_config_key_string(HKEY hkey
, const WCHAR
*name
, WCHAR
**value
)
253 if (RegQueryValueExW(hkey
, name
, 0, &type
, NULL
, &size
))
255 if (type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
)
258 str
= heap_alloc(size
);
259 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)str
, &size
))
269 static BOOL
is_places_bar_enabled(const FileOpenDlgInfos
*fodInfos
)
271 static const WCHAR noplacesbarW
[] = {'N','o','P','l','a','c','e','s','B','a','r',0};
275 if (fodInfos
->ofnInfos
->lStructSize
!= sizeof(*fodInfos
->ofnInfos
) ||
276 (fodInfos
->ofnInfos
->FlagsEx
& OFN_EX_NOPLACESBAR
) ||
277 !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
))
282 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey
))
286 get_config_key_as_dword(hkey
, noplacesbarW
, &value
);
291 static void filedlg_collect_places_pidls(FileOpenDlgInfos
*fodInfos
)
293 static const int default_places
[] =
302 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
305 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
307 static const WCHAR placeW
[] = {'P','l','a','c','e','%','d',0};
313 swprintf(nameW
, ARRAY_SIZE(nameW
), placeW
, i
);
314 if (get_config_key_dword(hkey
, nameW
, &value
))
316 hr
= SHGetSpecialFolderLocation(NULL
, value
, &fodInfos
->places
[i
]);
318 WARN("Unrecognized special folder %u.\n", value
);
320 else if (get_config_key_string(hkey
, nameW
, &str
))
322 hr
= SHParseDisplayName(str
, NULL
, &fodInfos
->places
[i
], 0, NULL
);
324 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str
));
329 /* FIXME: eliminate duplicates. */
335 for (i
= 0; i
< ARRAY_SIZE(default_places
); i
++)
336 SHGetSpecialFolderLocation(NULL
, default_places
[i
], &fodInfos
->places
[i
]);
339 /***********************************************************************
342 * Creates an Open common dialog box that lets the user select
343 * the drive, directory, and the name of a file or set of files to open.
345 * IN : The FileOpenDlgInfos structure associated with the dialog
346 * OUT : TRUE on success
347 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
349 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
357 /* test for missing functionality */
358 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
360 FIXME("Flags 0x%08x not yet implemented\n",
361 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
364 /* Create the dialog from a template */
366 if (is_places_bar_enabled(fodInfos
))
367 templateid
= NEWFILEOPENV2ORD
;
369 templateid
= NEWFILEOPENORD
;
371 if (!(hRes
= FindResourceW(COMDLG32_hInstance
, MAKEINTRESOURCEW(templateid
), (LPCWSTR
)RT_DIALOG
)))
373 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
376 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
377 !(template = LockResource( hDlgTmpl
)))
379 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
383 /* msdn: explorer style dialogs permit sizing by default.
384 * The OFN_ENABLESIZING flag is only needed when a hook or
385 * custom template is provided */
386 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
387 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
388 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
390 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
392 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
393 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
396 /* old style hook messages */
397 if (is_dialog_hooked(fodInfos
))
399 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
400 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
401 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
402 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
405 if (fodInfos
->unicode
)
406 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
408 fodInfos
->ofnInfos
->hwndOwner
,
412 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
414 fodInfos
->ofnInfos
->hwndOwner
,
417 if (fodInfos
->ole_initialized
)
420 /* Unable to create the dialog */
427 static WCHAR
*heap_strdupAtoW(const char *str
)
435 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
436 ret
= heap_alloc(len
* sizeof(WCHAR
));
437 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
442 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
444 INITCOMMONCONTROLSEX icc
;
446 /* Initialize ComboBoxEx32 */
447 icc
.dwSize
= sizeof(icc
);
448 icc
.dwICC
= ICC_USEREX_CLASSES
;
449 InitCommonControlsEx(&icc
);
451 /* Initialize CommDlgExtendedError() */
452 COMDLG32_SetCommDlgExtendedError(0);
454 memset(info
, 0, sizeof(*info
));
456 /* Pass in the original ofn */
457 info
->ofnInfos
= ofn
;
459 info
->title
= ofn
->lpstrTitle
;
460 info
->defext
= ofn
->lpstrDefExt
;
461 info
->filter
= ofn
->lpstrFilter
;
462 info
->customfilter
= ofn
->lpstrCustomFilter
;
466 info
->filename
= heap_alloc(ofn
->nMaxFile
* sizeof(WCHAR
));
467 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
470 if (ofn
->lpstrInitialDir
)
472 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
475 info
->initdir
= heap_alloc(len
* sizeof(WCHAR
));
476 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
480 info
->unicode
= TRUE
;
483 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
488 ofnW
= *(OPENFILENAMEW
*)ofn
;
490 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
491 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
492 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
496 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
497 ofnW
.lpstrFile
= heap_alloc(len
* sizeof(WCHAR
));
498 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
502 if (ofn
->lpstrFilter
)
507 /* filter is a list... title\0ext\0......\0\0 */
508 s
= ofn
->lpstrFilter
;
509 while (*s
) s
= s
+strlen(s
)+1;
511 n
= s
- ofn
->lpstrFilter
;
512 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
513 ofnW
.lpstrFilter
= heap_alloc(len
* sizeof(WCHAR
));
514 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
517 /* convert lpstrCustomFilter */
518 if (ofn
->lpstrCustomFilter
)
523 /* customfilter contains a pair of strings... title\0ext\0 */
524 s
= ofn
->lpstrCustomFilter
;
525 if (*s
) s
= s
+strlen(s
)+1;
526 if (*s
) s
= s
+strlen(s
)+1;
527 n
= s
- ofn
->lpstrCustomFilter
;
528 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
529 ofnW
.lpstrCustomFilter
= heap_alloc(len
* sizeof(WCHAR
));
530 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
533 init_filedlg_infoW(&ofnW
, info
);
535 /* fixup A-specific fields */
536 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
537 info
->unicode
= FALSE
;
539 /* free what was duplicated */
540 heap_free((void *)ofnW
.lpstrInitialDir
);
541 heap_free(ofnW
.lpstrFile
);
544 /***********************************************************************
547 * Call GetFileName95 with this structure and clean the memory.
549 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
551 WCHAR
*current_dir
= NULL
;
555 /* save current directory */
556 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
558 current_dir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
559 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
565 ret
= GetFileName95(info
);
568 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
569 ret
= GetFileName95(info
);
577 SetCurrentDirectoryW(current_dir
);
578 heap_free(current_dir
);
583 heap_free((void *)info
->defext
);
584 heap_free((void *)info
->title
);
585 heap_free((void *)info
->filter
);
586 heap_free((void *)info
->customfilter
);
589 heap_free(info
->filename
);
590 heap_free(info
->initdir
);
592 for (i
= 0; i
< ARRAY_SIZE(info
->places
); i
++)
593 ILFree(info
->places
[i
]);
598 /******************************************************************************
599 * COMDLG32_GetDisplayNameOf [internal]
601 * Helper function to get the display name for a pidl.
603 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
604 LPSHELLFOLDER psfDesktop
;
607 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
610 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
611 IShellFolder_Release(psfDesktop
);
615 IShellFolder_Release(psfDesktop
);
616 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
619 /******************************************************************************
620 * COMDLG32_GetCanonicalPath [internal]
622 * Helper function to get the canonical path.
624 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
625 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
627 WCHAR lpstrTemp
[MAX_PATH
];
629 /* Get the current directory name */
630 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
633 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
635 PathAddBackslashW(lpstrPathAndFile
);
637 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile
), debugstr_w(lpstrFile
));
639 /* if the user specified a fully qualified path use it */
640 if(PathIsRelativeW(lpstrFile
))
642 lstrcatW(lpstrPathAndFile
, lpstrFile
);
646 /* does the path have a drive letter? */
647 if (PathGetDriveNumberW(lpstrFile
) == -1)
648 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
650 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
653 /* resolve "." and ".." */
654 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
655 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
656 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
659 /***********************************************************************
660 * COMDLG32_SplitFileNames [internal]
662 * Creates a delimited list of filenames.
664 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
666 UINT nStrCharCount
= 0; /* index in src buffer */
667 UINT nFileIndex
= 0; /* index in dest buffer */
668 UINT nFileCount
= 0; /* number of files */
670 /* we might get single filename without any '"',
671 * so we need nStrLen + terminating \0 + end-of-list \0 */
672 *lpstrFileList
= heap_alloc((nStrLen
+ 2) * sizeof(WCHAR
));
675 /* build delimited file list from filenames */
676 while ( nStrCharCount
<= nStrLen
)
678 if ( lpstrEdit
[nStrCharCount
]=='"' )
681 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
683 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
686 (*lpstrFileList
)[nFileIndex
++] = 0;
692 /* single, unquoted string */
693 if ((nStrLen
> 0) && (nFileIndex
== 0) )
695 lstrcpyW(*lpstrFileList
, lpstrEdit
);
696 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
701 (*lpstrFileList
)[nFileIndex
++] = '\0';
703 *sizeUsed
= nFileIndex
;
707 /***********************************************************************
708 * ArrangeCtrlPositions [internal]
710 * NOTE: Make sure to add testcases for any changes made here.
712 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
714 HWND hwndChild
, hwndStc32
;
715 RECT rectParent
, rectChild
, rectStc32
;
719 /* Take into account if open as read only checkbox and help button
724 RECT rectHelp
, rectCancel
;
725 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
726 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
727 /* subtract the height of the help button plus the space between
728 * the help button and the cancel button to the height of the dialog
730 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
734 There are two possibilities to add components to the default file dialog box.
736 By default, all the new components are added below the standard dialog box (the else case).
738 However, if there is a static text component with the stc32 id, a special case happens.
739 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
740 in the window and the cx and cy indicate how to size the window.
741 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
742 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
746 GetClientRect(hwndParentDlg
, &rectParent
);
748 /* when arranging controls we have to use fixed parent size */
749 rectParent
.bottom
-= help_fixup
;
751 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
754 GetWindowRect(hwndStc32
, &rectStc32
);
755 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
757 /* set the size of the stc32 control according to the size of
758 * client area of the parent dialog
760 SetWindowPos(hwndStc32
, 0,
762 rectParent
.right
, rectParent
.bottom
,
763 SWP_NOMOVE
| SWP_NOZORDER
);
766 SetRectEmpty(&rectStc32
);
768 /* this part moves controls of the child dialog */
769 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
772 if (hwndChild
!= hwndStc32
)
774 GetWindowRect(hwndChild
, &rectChild
);
775 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
777 /* move only if stc32 exist */
778 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
780 /* move to the right of visible controls of the parent dialog */
781 rectChild
.left
+= rectParent
.right
;
782 rectChild
.left
-= rectStc32
.right
;
784 /* move even if stc32 doesn't exist */
785 if (rectChild
.top
>= rectStc32
.bottom
)
787 /* move below visible controls of the parent dialog */
788 rectChild
.top
+= rectParent
.bottom
;
789 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
792 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
793 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
795 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
798 /* this part moves controls of the parent dialog */
799 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
802 if (hwndChild
!= hwndChildDlg
)
804 GetWindowRect(hwndChild
, &rectChild
);
805 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
807 /* left,top of stc32 marks the position of controls
808 * from the parent dialog
810 rectChild
.left
+= rectStc32
.left
;
811 rectChild
.top
+= rectStc32
.top
;
813 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
814 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
816 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
819 /* calculate the size of the resulting dialog */
821 /* here we have to use original parent size */
822 GetClientRect(hwndParentDlg
, &rectParent
);
823 GetClientRect(hwndChildDlg
, &rectChild
);
824 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
825 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
830 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
831 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
833 chgx
= rectChild
.right
- rectParent
.right
;
835 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
836 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
838 /* Unconditionally set new dialog
839 * height to that of the child
841 chgy
= rectChild
.bottom
- rectParent
.bottom
;
846 chgy
= rectChild
.bottom
- help_fixup
;
848 /* set the size of the parent dialog */
849 GetWindowRect(hwndParentDlg
, &rectParent
);
850 SetWindowPos(hwndParentDlg
, 0,
852 rectParent
.right
- rectParent
.left
+ chgx
,
853 rectParent
.bottom
- rectParent
.top
+ chgy
,
854 SWP_NOMOVE
| SWP_NOZORDER
);
857 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
866 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
873 TRACE("%p, %p\n", fodInfos
, hwnd
);
876 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
877 * structure's hInstance parameter is not a HINSTANCE, but
878 * instead a pointer to a template resource to use.
880 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
883 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
885 hinst
= COMDLG32_hInstance
;
886 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
888 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
894 hinst
= fodInfos
->ofnInfos
->hInstance
;
895 if(fodInfos
->unicode
)
897 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
898 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
902 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
903 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
907 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
910 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
911 !(template = LockResource( hDlgTmpl
)))
913 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
917 if (fodInfos
->unicode
)
918 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
919 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
920 (LPARAM
)fodInfos
->ofnInfos
);
922 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
923 is_dialog_hooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
924 (LPARAM
)fodInfos
->ofnInfos
);
927 else if (is_dialog_hooked(fodInfos
))
932 WORD menu
,class,title
;
934 GetClientRect(hwnd
,&rectHwnd
);
935 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
936 temp
.tmplate
.dwExtendedStyle
= 0;
937 temp
.tmplate
.cdit
= 0;
942 temp
.menu
= temp
.class = temp
.title
= 0;
944 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
945 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
952 /***********************************************************************
953 * SendCustomDlgNotificationMessage
955 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
958 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
960 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
964 TRACE("%p %d\n", hwndParentDlg
, uCode
);
966 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
969 TRACE("CALL NOTIFY for %d\n", uCode
);
971 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
972 ofnNotify
.hdr
.idFrom
= 0;
973 ofnNotify
.hdr
.code
= uCode
;
974 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
975 ofnNotify
.pszFile
= NULL
;
977 if (fodInfos
->unicode
)
978 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
980 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
982 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
987 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
991 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
993 TRACE("CDM_GETFILEPATH:\n");
995 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
998 /* get path and filenames */
999 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
1000 buffer
= heap_alloc( (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
1001 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
1004 p
= buffer
+ lstrlenW(buffer
);
1006 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
1008 if (fodInfos
->unicode
)
1010 total
= lstrlenW( buffer
) + 1;
1011 if (result
) lstrcpynW( result
, buffer
, size
);
1012 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
1016 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
1017 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
1018 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
1020 heap_free( buffer
);
1024 /***********************************************************************
1025 * FILEDLG95_HandleCustomDialogMessages
1027 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1029 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1031 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1032 WCHAR lpstrPath
[MAX_PATH
];
1035 if(!fodInfos
) return FALSE
;
1039 case CDM_GETFILEPATH
:
1040 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1043 case CDM_GETFOLDERPATH
:
1044 TRACE("CDM_GETFOLDERPATH:\n");
1045 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1048 if (fodInfos
->unicode
)
1049 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1051 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1052 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1054 retval
= lstrlenW(lpstrPath
) + 1;
1057 case CDM_GETFOLDERIDLIST
:
1058 retval
= ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1059 if (retval
<= wParam
)
1060 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1064 TRACE("CDM_GETSPEC:\n");
1065 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1068 if (fodInfos
->unicode
)
1069 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1071 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1075 case CDM_SETCONTROLTEXT
:
1076 TRACE("CDM_SETCONTROLTEXT:\n");
1079 if( fodInfos
->unicode
)
1080 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1082 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1087 case CDM_HIDECONTROL
:
1088 /* MSDN states that it should fail for not OFN_EXPLORER case */
1089 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1091 HWND control
= GetDlgItem( hwnd
, wParam
);
1092 if (control
) ShowWindow( control
, SW_HIDE
);
1095 else retval
= FALSE
;
1099 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1100 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1103 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1107 /***********************************************************************
1108 * FILEDLG95_OnWMGetMMI
1110 * WM_GETMINMAXINFO message handler for resizable dialogs
1112 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1114 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1115 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1116 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1118 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1123 /***********************************************************************
1124 * FILEDLG95_OnWMSize
1126 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1128 * FIXME: this could be made more elaborate. Now use a simple scheme
1129 * where the file view is enlarged and the controls are either moved
1130 * vertically or horizontally to get out of the way. Only the "grip"
1131 * is moved in both directions to stay in the corner.
1133 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1139 FileOpenDlgInfos
*fodInfos
;
1141 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1142 fodInfos
= get_filedlg_infoptr(hwnd
);
1143 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1144 /* get the new dialog rectangle */
1145 GetWindowRect( hwnd
, &rc
);
1146 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1147 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1148 /* not initialized yet */
1149 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1150 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1151 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1153 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1154 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1155 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1156 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1157 /* change the size of the view window */
1158 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1159 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1160 hdwp
= BeginDeferWindowPos( 10);
1161 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1162 rcview
.right
- rcview
.left
+ chgx
,
1163 rcview
.bottom
- rcview
.top
+ chgy
,
1164 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1165 /* change position and sizes of the controls */
1166 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1168 int ctrlid
= GetDlgCtrlID( ctrl
);
1169 GetWindowRect( ctrl
, &rc
);
1170 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1171 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1173 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1175 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1177 else if( rc
.top
> rcview
.bottom
)
1179 /* if it was below the shell view
1183 /* file name (edit or comboboxex) and file types combo change also width */
1187 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1188 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1189 SWP_NOACTIVATE
| SWP_NOZORDER
);
1191 /* then these buttons must move out of the way */
1195 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1197 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1200 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1202 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1205 else if( rc
.left
> rcview
.right
)
1207 /* if it was to the right of the shell view
1209 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1211 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1218 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1220 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1221 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1222 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1224 case IDC_TOOLBARSTATIC
:
1226 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1228 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1231 /* not resized in windows. Since wine uses this invisible control
1232 * to size the browser view it needs to be resized */
1233 case IDC_SHELLSTATIC
:
1234 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1235 rc
.right
- rc
.left
+ chgx
,
1236 rc
.bottom
- rc
.top
+ chgy
,
1237 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1239 case IDC_TOOLBARPLACES
:
1240 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
+ chgy
,
1241 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1246 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1247 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1249 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1250 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1252 GetWindowRect( ctrl
, &rc
);
1253 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1254 if( rc
.top
> rcview
.bottom
)
1256 /* if it was below the shell view
1258 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1259 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1260 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1262 else if( rc
.left
> rcview
.right
)
1264 /* if it was to the right of the shell view
1266 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1267 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1268 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1271 /* size the custom dialog at the end: some applications do some
1272 * control re-arranging at this point */
1273 GetClientRect(hwnd
, &rc
);
1274 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1275 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1277 EndDeferWindowPos( hdwp
);
1278 /* should not be needed */
1279 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1283 /***********************************************************************
1286 * File open dialog procedure
1288 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1291 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1298 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1300 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1301 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1303 /* Some shell namespace extensions depend on COM being initialized. */
1304 if (SUCCEEDED(OleInitialize(NULL
)))
1305 fodInfos
->ole_initialized
= TRUE
;
1307 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1309 FILEDLG95_InitControls(hwnd
);
1311 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1313 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1314 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1315 RECT client
, client_adjusted
;
1317 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1319 style
|= WS_SIZEBOX
;
1320 ex_style
|= WS_EX_WINDOWEDGE
;
1323 style
&= ~WS_SIZEBOX
;
1324 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1325 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1327 GetClientRect( hwnd
, &client
);
1328 GetClientRect( hwnd
, &client_adjusted
);
1329 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1331 GetWindowRect( hwnd
, &rc
);
1332 rc
.right
+= client_adjusted
.right
- client
.right
;
1333 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1334 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1335 SWP_NOZORDER
| SWP_NOMOVE
);
1337 GetWindowRect( hwnd
, &rc
);
1338 fodInfos
->DlgInfos
.hwndGrip
=
1339 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1340 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1341 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1342 rc
.right
- gripx
, rc
.bottom
- gripy
,
1343 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1346 fodInfos
->DlgInfos
.hwndCustomDlg
=
1347 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1349 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1350 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1352 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1353 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1355 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1356 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1357 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1360 /* if the app has changed the position of the invisible listbox,
1361 * change that of the listview (browser) as well */
1362 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1363 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1364 if( !EqualRect( &rc
, &rcstc
))
1366 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1367 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1368 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1369 SWP_NOACTIVATE
| SWP_NOZORDER
);
1372 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1374 GetWindowRect( hwnd
, &rc
);
1375 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1376 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1377 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1378 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1379 GetClientRect( hwnd
, &rc
);
1380 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1381 rc
.right
- gripx
, rc
.bottom
- gripy
,
1382 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1383 /* resize the dialog to the previous invocation */
1384 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1385 SetWindowPos( hwnd
, NULL
,
1386 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1387 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1390 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1391 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1396 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1397 case WM_GETMINMAXINFO
:
1398 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1400 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1403 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1406 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1412 case WM_GETISHELLBROWSER
:
1413 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1417 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1418 HWND places_bar
= GetDlgItem(hwnd
, IDC_TOOLBARPLACES
);
1421 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1422 MemDialogSize
= fodInfos
->sizedlg
;
1426 himl
= (HIMAGELIST
)SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_GETIMAGELIST
, 0, 0);
1427 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, 0);
1428 ImageList_Destroy(himl
);
1434 RemovePropW(hwnd
, filedlg_info_propnameW
);
1439 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1442 /* set up the button tooltips strings */
1443 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1445 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1446 switch(lpnmh
->idFrom
)
1448 /* Up folder button */
1449 case FCIDM_TB_UPFOLDER
:
1450 stringId
= IDS_UPFOLDER
;
1452 /* New folder button */
1453 case FCIDM_TB_NEWFOLDER
:
1454 stringId
= IDS_NEWFOLDER
;
1456 /* List option button */
1457 case FCIDM_TB_SMALLICON
:
1458 stringId
= IDS_LISTVIEW
;
1460 /* Details option button */
1461 case FCIDM_TB_REPORTVIEW
:
1462 stringId
= IDS_REPORTVIEW
;
1464 /* Desktop button */
1465 case FCIDM_TB_DESKTOP
:
1466 stringId
= IDS_TODESKTOP
;
1471 lpdi
->hinst
= COMDLG32_hInstance
;
1472 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1477 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1478 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1483 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1485 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1486 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1489 /***********************************************************************
1490 * FILEDLG95_InitControls
1492 * WM_INITDIALOG message handler (before hook notification)
1494 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1496 BOOL win2000plus
= FALSE
;
1497 BOOL win98plus
= FALSE
;
1498 BOOL handledPath
= FALSE
;
1499 OSVERSIONINFOW osVi
;
1500 static const WCHAR szwSlash
[] = { '\\', 0 };
1501 static const WCHAR szwStar
[] = { '*',0 };
1503 static const TBBUTTON tbb
[] =
1505 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1506 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1507 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1508 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1509 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1510 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1511 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1512 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1513 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1515 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1520 HIMAGELIST toolbarImageList
;
1521 ITEMIDLIST
*desktopPidl
;
1522 SHFILEINFOW fileinfo
;
1524 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1526 TRACE("%p\n", fodInfos
);
1528 /* Get windows version emulating */
1529 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1530 GetVersionExW(&osVi
);
1531 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1532 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1533 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1534 win2000plus
= (osVi
.dwMajorVersion
> 4);
1535 if (win2000plus
) win98plus
= TRUE
;
1537 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1540 /* Use either the edit or the comboboxex for the filename control */
1541 if (filename_is_edit( fodInfos
))
1543 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1544 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1548 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1549 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1552 /* Get the hwnd of the controls */
1553 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1554 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1556 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1557 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1559 /* construct the toolbar */
1560 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1561 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1563 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1564 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1565 rectTB
.left
= rectlook
.right
;
1566 rectTB
.top
= rectlook
.top
-1;
1568 if (fodInfos
->unicode
)
1569 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1570 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1571 rectTB
.left
, rectTB
.top
,
1572 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1573 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1575 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1576 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
| CCS_NODIVIDER
| CCS_NORESIZE
,
1577 rectTB
.left
, rectTB
.top
,
1578 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1579 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1581 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1583 /* FIXME: use TB_LOADIMAGES when implemented */
1584 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1585 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1586 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1588 /* Retrieve and add desktop icon to the toolbar */
1589 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1590 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1591 SHGetFileInfoW((const WCHAR
*)desktopPidl
, 0, &fileinfo
, sizeof(fileinfo
),
1592 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1593 ImageList_AddIcon(toolbarImageList
, fileinfo
.hIcon
);
1595 DestroyIcon(fileinfo
.hIcon
);
1596 CoTaskMemFree(desktopPidl
);
1598 /* Finish Toolbar Construction */
1599 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1600 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1602 if (is_places_bar_enabled(fodInfos
))
1604 TBBUTTON tb
= { 0 };
1609 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_BUTTONSTRUCTSIZE
, 0, 0);
1610 GetClientRect(GetDlgItem(hwnd
, IDC_TOOLBARPLACES
), &rect
);
1611 cx
= rect
.right
- rect
.left
;
1613 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONWIDTH
, 0, MAKELPARAM(cx
, cx
));
1614 himl
= ImageList_Create(GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), ILC_COLOR32
, 4, 1);
1616 filedlg_collect_places_pidls(fodInfos
);
1617 for (i
= 0; i
< ARRAY_SIZE(fodInfos
->places
); i
++)
1621 if (!fodInfos
->places
[i
])
1624 memset(&fileinfo
, 0, sizeof(fileinfo
));
1625 SHGetFileInfoW((const WCHAR
*)fodInfos
->places
[i
], 0, &fileinfo
, sizeof(fileinfo
),
1626 SHGFI_PIDL
| SHGFI_DISPLAYNAME
| SHGFI_ICON
);
1627 index
= ImageList_AddIcon(himl
, fileinfo
.hIcon
);
1630 tb
.iString
= (INT_PTR
)fileinfo
.szDisplayName
;
1631 tb
.fsState
= TBSTATE_ENABLED
| TBSTATE_WRAP
;
1632 tb
.idCommand
= TBPLACES_CMDID_PLACE0
+ i
;
1633 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tb
);
1635 DestroyIcon(fileinfo
.hIcon
);
1638 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETIMAGELIST
, 0, (LPARAM
)himl
);
1639 SendDlgItemMessageW(hwnd
, IDC_TOOLBARPLACES
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, cx
* 3 / 4));
1642 /* Set the window text with the text specified in the OPENFILENAME structure */
1645 SetWindowTextW(hwnd
,fodInfos
->title
);
1647 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1650 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, ARRAY_SIZE(buf
));
1651 SetWindowTextW(hwnd
, buf
);
1654 /* Initialise the file name edit control */
1655 handledPath
= FALSE
;
1656 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1658 if(fodInfos
->filename
)
1660 /* 1. If win2000 or higher and filename contains a path, use it
1661 in preference over the lpstrInitialDir */
1662 if (win2000plus
&& *fodInfos
->filename
&& wcspbrk(fodInfos
->filename
, szwSlash
)) {
1663 WCHAR tmpBuf
[MAX_PATH
];
1667 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1670 /* nameBit is always shorter than the original filename. It may be NULL
1671 * when the filename contains only a drive name instead of file name */
1674 lstrcpyW(fodInfos
->filename
,nameBit
);
1678 *fodInfos
->filename
= '\0';
1680 heap_free(fodInfos
->initdir
);
1681 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1682 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1684 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1685 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1687 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1690 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1694 /* 2. (All platforms) If initdir is not null, then use it */
1695 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1697 /* Work out the proper path as supplied one might be relative */
1698 /* (Here because supplying '.' as dir browses to My Computer) */
1699 WCHAR tmpBuf
[MAX_PATH
];
1700 WCHAR tmpBuf2
[MAX_PATH
];
1704 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1705 if (PathFileExistsW(tmpBuf
)) {
1706 /* initdir does not have to be a directory. If a file is
1707 * specified, the dir part is taken */
1708 if (PathIsDirectoryW(tmpBuf
)) {
1709 PathAddBackslashW(tmpBuf
);
1710 lstrcatW(tmpBuf
, szwStar
);
1712 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1715 heap_free(fodInfos
->initdir
);
1716 fodInfos
->initdir
= heap_alloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1717 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1719 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1722 else if (fodInfos
->initdir
)
1724 heap_free(fodInfos
->initdir
);
1725 fodInfos
->initdir
= NULL
;
1726 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1730 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1732 /* 3. All except w2k+: if filename contains a path use it */
1733 if (!win2000plus
&& fodInfos
->filename
&&
1734 *fodInfos
->filename
&&
1735 wcspbrk(fodInfos
->filename
, szwSlash
)) {
1736 WCHAR tmpBuf
[MAX_PATH
];
1740 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1745 /* nameBit is always shorter than the original filename */
1746 lstrcpyW(fodInfos
->filename
, nameBit
);
1749 len
= lstrlenW(tmpBuf
);
1750 heap_free(fodInfos
->initdir
);
1751 fodInfos
->initdir
= heap_alloc((len
+1)*sizeof(WCHAR
));
1752 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1755 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1756 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1758 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1761 /* 4. Win2000+: Recently used */
1762 if (!handledPath
&& win2000plus
) {
1763 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1764 fodInfos
->initdir
[0] = '\0';
1766 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1768 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1771 heap_free(fodInfos
->initdir
);
1772 fodInfos
->initdir
= NULL
;
1776 /* 5. win98+ and win2000+ if any files of specified filter types in
1777 current directory, use it */
1778 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1780 LPCWSTR lpstrPos
= fodInfos
->filter
;
1781 WIN32_FIND_DATAW FindFileData
;
1786 /* filter is a list... title\0ext\0......\0\0 */
1788 /* Skip the title */
1789 if(! *lpstrPos
) break; /* end */
1790 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1792 /* See if any files exist in the current dir with this extension */
1793 if(! *lpstrPos
) break; /* end */
1795 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1797 if (hFind
== INVALID_HANDLE_VALUE
) {
1798 /* None found - continue search */
1799 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1803 heap_free(fodInfos
->initdir
);
1804 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1805 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1808 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1809 debugstr_w(lpstrPos
));
1816 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1817 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1818 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1820 if (SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
) == S_OK
)
1822 if (SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
) == S_OK
)
1825 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1826 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1829 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1832 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1835 } else if (!handledPath
) {
1836 fodInfos
->initdir
= heap_alloc(MAX_PATH
* sizeof(WCHAR
));
1837 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1839 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1842 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1843 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1845 /* Must the open as read only check box be checked ?*/
1846 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1848 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1851 /* Must the open as read only check box be hidden? */
1852 if (filedialog_is_readonly_hidden(fodInfos
))
1854 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1855 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1858 /* Must the help button be hidden? */
1859 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1861 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1862 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1865 /* change Open to Save */
1866 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1869 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, ARRAY_SIZE(buf
));
1870 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1871 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, ARRAY_SIZE(buf
));
1872 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1875 /* Initialize the filter combo box */
1876 FILEDLG95_FILETYPE_Init(hwnd
);
1881 /***********************************************************************
1882 * FILEDLG95_ResizeControls
1884 * WM_INITDIALOG message handler (after hook notification)
1886 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1888 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1890 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1893 UINT flags
= SWP_NOACTIVATE
;
1895 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1896 filedialog_is_readonly_hidden(fodInfos
) && !(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
));
1898 /* resize the custom dialog to the parent size */
1899 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1900 GetClientRect(hwnd
, &rc
);
1903 /* our own fake template is zero sized and doesn't have children, so
1904 * there is no need to resize it. Picasa depends on it.
1906 flags
|= SWP_NOSIZE
;
1909 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1910 0, 0, rc
.right
, rc
.bottom
, flags
);
1914 /* Resize the height; if opened as read-only, checkbox and help button are
1915 * hidden and we are not using a custom template nor a customDialog
1917 if (filedialog_is_readonly_hidden(fodInfos
) &&
1918 (!(fodInfos
->ofnInfos
->Flags
&
1919 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1921 RECT rectDlg
, rectHelp
, rectCancel
;
1922 GetWindowRect(hwnd
, &rectDlg
);
1923 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1924 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1925 /* subtract the height of the help button plus the space between the help
1926 * button and the cancel button to the height of the dialog
1928 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1929 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1930 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1936 /***********************************************************************
1937 * FILEDLG95_FillControls
1939 * WM_INITDIALOG message handler (after hook notification)
1941 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1943 LPITEMIDLIST pidlItemId
= NULL
;
1945 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1947 TRACE("dir=%s file=%s\n",
1948 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1950 /* Get the initial directory pidl */
1952 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1954 WCHAR path
[MAX_PATH
];
1956 GetCurrentDirectoryW(MAX_PATH
,path
);
1957 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1960 /* Initialise shell objects */
1961 FILEDLG95_SHELL_Init(hwnd
);
1963 /* Initialize the Look In combo box */
1964 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1966 /* Browse to the initial directory */
1967 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1973 /***********************************************************************
1976 * Regroups all the cleaning functions of the filedlg
1978 void FILEDLG95_Clean(HWND hwnd
)
1980 FILEDLG95_FILETYPE_Clean(hwnd
);
1981 FILEDLG95_LOOKIN_Clean(hwnd
);
1982 FILEDLG95_SHELL_Clean(hwnd
);
1986 /***********************************************************************
1987 * Browse to arbitrary pidl
1989 static void filedlg_browse_to_pidl(const FileOpenDlgInfos
*info
, LPITEMIDLIST pidl
)
1991 TRACE("%p, %p\n", info
->ShellInfos
.hwndOwner
, pidl
);
1993 IShellBrowser_BrowseObject(info
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
1994 if (info
->ofnInfos
->Flags
& OFN_EXPLORER
)
1995 SendCustomDlgNotificationMessage(info
->ShellInfos
.hwndOwner
, CDN_FOLDERCHANGE
);
1998 /***********************************************************************
1999 * FILEDLG95_OnWMCommand
2001 * WM_COMMAND message handler
2003 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
2005 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2006 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
2007 WORD id
= LOWORD(wParam
); /* item, control, or accelerator identifier */
2013 FILEDLG95_OnOpen(hwnd
);
2017 FILEDLG95_Clean(hwnd
);
2018 EndDialog(hwnd
, FALSE
);
2020 /* Filetype combo box */
2022 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
2024 /* LookIn combo box */
2026 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
2029 /* --- toolbar --- */
2030 /* Up folder button */
2031 case FCIDM_TB_UPFOLDER
:
2032 FILEDLG95_SHELL_UpFolder(hwnd
);
2034 /* New folder button */
2035 case FCIDM_TB_NEWFOLDER
:
2036 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
2038 /* List option button */
2039 case FCIDM_TB_SMALLICON
:
2040 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
2042 /* Details option button */
2043 case FCIDM_TB_REPORTVIEW
:
2044 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
2047 case FCIDM_TB_DESKTOP
:
2051 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP
, &pidl
);
2052 filedlg_browse_to_pidl(fodInfos
, pidl
);
2058 case TBPLACES_CMDID_PLACE0
:
2059 case TBPLACES_CMDID_PLACE1
:
2060 case TBPLACES_CMDID_PLACE2
:
2061 case TBPLACES_CMDID_PLACE3
:
2062 case TBPLACES_CMDID_PLACE4
:
2063 filedlg_browse_to_pidl(fodInfos
, fodInfos
->places
[id
- TBPLACES_CMDID_PLACE0
]);
2071 /* Do not use the listview selection anymore */
2072 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
2076 /***********************************************************************
2077 * FILEDLG95_OnWMGetIShellBrowser
2079 * WM_GETISHELLBROWSER message handler
2081 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
2083 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2087 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
2093 /***********************************************************************
2094 * FILEDLG95_SendFileOK
2096 * Sends the CDN_FILEOK notification if required
2099 * TRUE if the dialog should close
2100 * FALSE if the dialog should not be closed
2102 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
2104 /* ask the hook if we can close */
2105 if (is_dialog_hooked(fodInfos
))
2110 /* First send CDN_FILEOK as MSDN doc says */
2111 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2112 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
2115 TRACE("canceled\n");
2119 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2120 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
2121 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
2124 TRACE("canceled\n");
2131 /***********************************************************************
2132 * FILEDLG95_OnOpenMultipleFiles
2134 * Handles the opening of multiple files.
2137 * check destination buffer size
2139 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2141 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2142 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2143 UINT nCount
, nSizePath
;
2147 if(fodInfos
->unicode
)
2149 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2150 ofn
->lpstrFile
[0] = '\0';
2154 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2155 ofn
->lpstrFile
[0] = '\0';
2158 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2160 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2161 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2162 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2164 LPWSTR lpstrTemp
= lpstrFileList
;
2166 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2170 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2173 WCHAR lpstrNotFound
[100];
2174 WCHAR lpstrMsg
[100];
2176 static const WCHAR nl
[] = {'\n',0};
2178 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2179 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2181 lstrcpyW(tmp
, lpstrTemp
);
2183 lstrcatW(tmp
, lpstrNotFound
);
2185 lstrcatW(tmp
, lpstrMsg
);
2187 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2191 /* move to the next file in the list of files */
2192 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2197 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2198 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2200 /* For "oldstyle" dialog the components have to
2201 be separated by blanks (not '\0'!) and short
2202 filenames have to be used! */
2203 FIXME("Components have to be separated by blanks\n");
2205 if(fodInfos
->unicode
)
2207 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2208 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2209 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2213 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2215 if (ofn
->lpstrFile
!= NULL
)
2217 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2218 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2219 if (ofn
->nMaxFile
> nSizePath
)
2221 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2222 ofn
->lpstrFile
+ nSizePath
,
2223 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2228 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2229 fodInfos
->ofnInfos
->nFileExtension
= 0;
2231 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2234 /* clean and exit */
2235 FILEDLG95_Clean(hwnd
);
2236 return EndDialog(hwnd
,TRUE
);
2239 /* Returns the 'slot name' of the given module_name in the registry's
2240 * most-recently-used list. This will be an ASCII value in the
2241 * range ['a','z'). Returns zero on error.
2243 * The slot's value in the registry has the form:
2244 * module_name\0mru_path\0
2246 * If stored_path is given, then stored_path will contain the path name
2247 * stored in the registry's MRU list for the given module_name.
2249 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2250 * MRU list key for the given module_name.
2252 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2254 WCHAR mru_list
[32], *cur_mru_slot
;
2255 BOOL taken
[25] = {0};
2256 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2257 HKEY hkey_tmp
, *hkey
;
2266 *stored_path
= '\0';
2268 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2270 WARN("Unable to create MRU key: %d\n", ret
);
2274 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2275 (LPBYTE
)mru_list
, &mru_list_size
);
2276 if(ret
|| key_type
!= REG_SZ
){
2277 if(ret
== ERROR_FILE_NOT_FOUND
)
2280 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2285 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2286 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2287 DWORD value_data_size
= sizeof(value_data
);
2289 *value_name
= *cur_mru_slot
;
2291 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2292 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2293 if(ret
|| key_type
!= REG_BINARY
){
2294 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2298 if(!wcsicmp(module_name
, value_data
)){
2302 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2310 /* the module name isn't in the registry, so find the next open slot */
2311 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2312 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2313 for(i
= 0; i
< 25; ++i
){
2318 /* all slots are taken, so return the last one in MRUList */
2320 return *cur_mru_slot
;
2323 /* save the given filename as most-recently-used path for this module */
2324 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2326 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2330 /* get the current executable's name */
2331 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2333 WARN("GotModuleFileName failed: %d\n", GetLastError());
2336 module_name
= wcsrchr(module_path
, '\\');
2338 module_name
= module_path
;
2342 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2347 { /* update the slot's info */
2348 WCHAR
*path_ends
, *final
;
2349 DWORD path_len
, final_len
;
2351 /* use only the path segment of `filename' */
2352 path_ends
= wcsrchr(filename
, '\\');
2353 path_len
= path_ends
- filename
;
2355 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2357 final
= heap_alloc(final_len
* sizeof(WCHAR
));
2360 lstrcpyW(final
, module_name
);
2361 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2362 final
[final_len
-1] = '\0';
2364 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2365 final_len
* sizeof(WCHAR
));
2367 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2376 { /* update MRUList value */
2377 WCHAR old_mru_list
[32], new_mru_list
[32];
2378 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2379 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2381 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2382 (LPBYTE
)old_mru_list
, &mru_list_size
);
2383 if(ret
|| key_type
!= REG_SZ
){
2384 if(ret
== ERROR_FILE_NOT_FOUND
){
2385 new_mru_list
[0] = slot
;
2386 new_mru_list
[1] = '\0';
2388 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2393 /* copy old list data over so that the new slot is at the start
2395 *new_mru_slot
++ = slot
;
2396 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2397 if(*old_mru_slot
!= slot
)
2398 *new_mru_slot
++ = *old_mru_slot
;
2400 *new_mru_slot
= '\0';
2403 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2404 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2406 WARN("Error saving MRUList data: %d\n", ret
);
2413 /* load the most-recently-used path for this module */
2414 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2416 WCHAR module_path
[MAX_PATH
], *module_name
;
2418 /* get the current executable's name */
2419 if (!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, ARRAY_SIZE(module_path
)))
2421 WARN("GotModuleFileName failed: %d\n", GetLastError());
2424 module_name
= wcsrchr(module_path
, '\\');
2426 module_name
= module_path
;
2430 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2431 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2434 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2436 WCHAR strMsgTitle
[MAX_PATH
];
2437 WCHAR strMsgText
[MAX_PATH
];
2439 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, ARRAY_SIZE(strMsgTitle
));
2441 strMsgTitle
[0] = '\0';
2442 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, ARRAY_SIZE(strMsgText
));
2443 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2446 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2447 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2449 int nOpenAction
= defAction
;
2450 LPWSTR lpszTemp
, lpszTemp1
;
2451 LPITEMIDLIST pidl
= NULL
;
2452 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2454 /* check for invalid chars */
2455 if((wcspbrk(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2457 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2461 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2463 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2466 LPSHELLFOLDER lpsfChild
;
2467 WCHAR lpwstrTemp
[MAX_PATH
];
2468 DWORD dwEaten
, dwAttributes
;
2471 lstrcpyW(lpwstrTemp
, lpszTemp
);
2472 p
= PathFindNextComponentW(lpwstrTemp
);
2474 if (!p
) break; /* end of path */
2477 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2479 /* There are no wildcards when OFN_NOVALIDATE is set */
2480 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2482 static const WCHAR wszWild
[] = { '*', '?', 0 };
2483 /* if the last element is a wildcard do a search */
2484 if(wcspbrk(lpszTemp1
, wszWild
) != NULL
)
2486 nOpenAction
= ONOPEN_SEARCH
;
2490 lpszTemp1
= lpszTemp
;
2492 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2494 /* append a backslash to drive letters */
2495 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2496 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2497 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2499 PathAddBackslashW(lpwstrTemp
);
2502 dwAttributes
= SFGAO_FOLDER
;
2503 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2505 /* the path component is valid, we have a pidl of the next path component */
2506 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2507 if(dwAttributes
& SFGAO_FOLDER
)
2509 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2511 ERR("bind to failed\n"); /* should not fail */
2514 IShellFolder_Release(*ppsf
);
2522 /* end dialog, return value */
2523 nOpenAction
= ONOPEN_OPEN
;
2529 else if (!(flags
& OFN_NOVALIDATE
))
2531 if(*lpszTemp
|| /* points to trailing null for last path element */
2532 (lpwstrTemp
[lstrlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2534 if(flags
& OFN_PATHMUSTEXIST
)
2536 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2542 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2544 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2548 /* change to the current folder */
2549 nOpenAction
= ONOPEN_OPEN
;
2554 nOpenAction
= ONOPEN_OPEN
;
2563 /***********************************************************************
2566 * Ok button WM_COMMAND message handler
2568 * If the function succeeds, the return value is nonzero.
2570 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2572 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2573 LPWSTR lpstrFileList
;
2574 UINT nFileCount
= 0;
2577 WCHAR lpstrPathAndFile
[MAX_PATH
];
2578 LPSHELLFOLDER lpsf
= NULL
;
2581 TRACE("hwnd=%p\n", hwnd
);
2583 /* try to browse the selected item */
2584 if(BrowseSelectedFolder(hwnd
))
2587 /* get the files from the edit control */
2588 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2595 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2599 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2602 Step 1: Build a complete path name from the current folder and
2603 the filename or path in the edit box.
2605 - the path in the edit box is a root path
2606 (with or without drive letter)
2607 - the edit box contains ".." (or a path with ".." in it)
2610 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2611 heap_free(lpstrFileList
);
2614 Step 2: here we have a cleaned up path
2616 We have to parse the path step by step to see if we have to browse
2617 to a folder if the path points to a directory or the last
2618 valid element is a directory.
2621 lpstrPathAndFile: cleaned up path
2625 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2626 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2627 nOpenAction
= ONOPEN_OPEN
;
2629 nOpenAction
= ONOPEN_BROWSE
;
2631 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2632 fodInfos
->ofnInfos
->Flags
,
2633 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2639 Step 3: here we have a cleaned up and validated path
2642 lpsf: ShellFolder bound to the rightmost valid path component
2643 lpstrPathAndFile: cleaned up path
2644 nOpenAction: action to do
2646 TRACE("end validate sf=%p\n", lpsf
);
2650 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2651 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2654 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2657 /* replace the current filter */
2658 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2659 len
= lstrlenW(lpszTemp
)+1;
2660 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc(len
* sizeof(WCHAR
));
2661 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2663 /* set the filter cb to the extension when possible */
2664 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2665 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, iPos
, 0);
2668 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2669 TRACE("ONOPEN_BROWSE\n");
2671 IPersistFolder2
* ppf2
;
2672 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2674 LPITEMIDLIST pidlCurrent
;
2675 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2676 IPersistFolder2_Release(ppf2
);
2677 if (!ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2679 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2680 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2682 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2683 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2686 else if( nOpenAction
== ONOPEN_SEARCH
)
2688 if (fodInfos
->Shell
.FOIShellView
)
2689 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2691 ILFree(pidlCurrent
);
2692 if (filename_is_edit( fodInfos
))
2693 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2698 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2699 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2705 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2706 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2710 /* update READONLY check box flag */
2711 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2712 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2714 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2716 /* Attach the file extension with file name*/
2717 ext
= PathFindExtensionW(lpstrPathAndFile
);
2718 if (! *ext
&& fodInfos
->defext
)
2720 /* if no extension is specified with file name, then */
2721 /* attach the extension from file filter or default one */
2723 WCHAR
*filterExt
= NULL
;
2724 LPWSTR lpstrFilter
= NULL
;
2725 static const WCHAR szwDot
[] = {'.',0};
2726 int PathLength
= lstrlenW(lpstrPathAndFile
);
2728 /*Get the file extension from file type filter*/
2729 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2730 fodInfos
->ofnInfos
->nFilterIndex
-1);
2732 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2734 WCHAR
* filterSearchIndex
;
2735 filterExt
= heap_alloc((lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2736 lstrcpyW(filterExt
, lpstrFilter
);
2738 /* if a semicolon-separated list of file extensions was given, do not include the
2739 semicolon or anything after it in the extension.
2740 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2741 filterSearchIndex
= wcschr(filterExt
, ';');
2742 if (filterSearchIndex
)
2744 filterSearchIndex
[0] = '\0';
2747 /* find the file extension by searching for the first dot in filterExt */
2748 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2749 /* if the extension is invalid or contains a glob, ignore it */
2750 filterSearchIndex
= wcschr(filterExt
, '.');
2751 if (filterSearchIndex
++ && !wcschr(filterSearchIndex
, '*') && !wcschr(filterSearchIndex
, '?'))
2753 lstrcpyW(filterExt
, filterSearchIndex
);
2757 heap_free(filterExt
);
2764 /* use the default file extension */
2765 filterExt
= heap_alloc((lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2766 lstrcpyW(filterExt
, fodInfos
->defext
);
2769 if (*filterExt
) /* ignore filterExt="" */
2772 lstrcatW(lpstrPathAndFile
, szwDot
);
2773 /* Attach the extension */
2774 lstrcatW(lpstrPathAndFile
, filterExt
);
2777 heap_free(filterExt
);
2779 /* In Open dialog: if file does not exist try without extension */
2780 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2781 lpstrPathAndFile
[PathLength
] = '\0';
2783 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2786 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2787 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2789 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2792 /* In Save dialog: check if the file already exists */
2793 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2794 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2795 && PathFileExistsW(lpstrPathAndFile
))
2797 WCHAR lpstrOverwrite
[100];
2800 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2801 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2802 MB_YESNO
| MB_ICONEXCLAMATION
);
2803 if (answer
== IDNO
|| answer
== IDCANCEL
)
2810 /* In Open dialog: check if it should be created if it doesn't exist */
2811 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2812 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2813 && !PathFileExistsW(lpstrPathAndFile
))
2815 WCHAR lpstrCreate
[100];
2818 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2819 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2820 MB_YESNO
| MB_ICONEXCLAMATION
);
2821 if (answer
== IDNO
|| answer
== IDCANCEL
)
2828 /* Check that the size of the file does not exceed buffer size.
2829 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2830 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2831 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2834 /* fill destination buffer */
2835 if (fodInfos
->ofnInfos
->lpstrFile
)
2837 if(fodInfos
->unicode
)
2839 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2841 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2842 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2843 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2847 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2849 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2850 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2851 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2852 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2856 if(fodInfos
->unicode
)
2860 /* set filename offset */
2861 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2862 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2864 /* set extension offset */
2865 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2866 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2871 CHAR tempFileA
[MAX_PATH
];
2873 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2874 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2875 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2877 /* set filename offset */
2878 lpszTemp
= PathFindFileNameA(tempFileA
);
2879 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2881 /* set extension offset */
2882 lpszTemp
= PathFindExtensionA(tempFileA
);
2883 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2886 /* set the lpstrFileTitle */
2887 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2889 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2890 if(fodInfos
->unicode
)
2892 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2893 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2897 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2898 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2899 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2903 /* copy currently selected filter to lpstrCustomFilter */
2904 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2906 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2907 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2908 NULL
, 0, NULL
, NULL
);
2909 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2911 LPSTR s
= ofn
->lpstrCustomFilter
;
2912 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2913 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2914 s
, len
, NULL
, NULL
);
2919 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2922 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2925 FILEDLG95_Clean(hwnd
);
2926 ret
= EndDialog(hwnd
, TRUE
);
2932 size
= lstrlenW(lpstrPathAndFile
) + 1;
2933 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2935 /* return needed size in first two bytes of lpstrFile */
2936 if(fodInfos
->ofnInfos
->lpstrFile
)
2937 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2938 FILEDLG95_Clean(hwnd
);
2939 ret
= EndDialog(hwnd
, FALSE
);
2940 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2947 if(lpsf
) IShellFolder_Release(lpsf
);
2951 /***********************************************************************
2952 * FILEDLG95_SHELL_Init
2954 * Initialisation of the shell objects
2956 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2958 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2960 TRACE("%p\n", hwnd
);
2963 * Initialisation of the FileOpenDialogInfos structure
2969 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2971 /* Disable multi-select if flag not set */
2972 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2974 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2976 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2977 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2979 /* Construct the IShellBrowser interface */
2980 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2985 /***********************************************************************
2986 * FILEDLG95_SHELL_ExecuteCommand
2988 * Change the folder option and refresh the view
2989 * If the function succeeds, the return value is nonzero.
2991 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2993 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2996 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2998 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
3003 CMINVOKECOMMANDINFO ci
;
3004 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
3005 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
3009 IContextMenu_InvokeCommand(pcm
, &ci
);
3010 IContextMenu_Release(pcm
);
3016 /***********************************************************************
3017 * FILEDLG95_SHELL_UpFolder
3019 * Browse to the specified object
3020 * If the function succeeds, the return value is nonzero.
3022 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
3024 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3028 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3032 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3033 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3038 /***********************************************************************
3039 * FILEDLG95_SHELL_Clean
3041 * Cleans the memory used by shell objects
3043 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
3045 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3049 ILFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
3051 /* clean Shell interfaces */
3052 if (fodInfos
->Shell
.FOIShellView
)
3054 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
3055 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
3057 if (fodInfos
->Shell
.FOIShellFolder
)
3058 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
3059 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
3060 if (fodInfos
->Shell
.FOIDataObject
)
3061 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
3064 /***********************************************************************
3065 * FILEDLG95_FILETYPE_Init
3067 * Initialisation of the file type combo box
3069 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
3071 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3072 int nFilters
= 0; /* number of filters */
3075 TRACE("%p\n", hwnd
);
3077 if(fodInfos
->customfilter
)
3079 /* customfilter has one entry... title\0ext\0
3080 * Set first entry of combo box item with customfilter
3083 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
3086 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
3088 /* Copy the extensions */
3089 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
3090 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3091 lstrcpyW(lpstrExt
,lpstrPos
);
3093 /* Add the item at the end of the combo */
3094 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)fodInfos
->customfilter
);
3095 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
, (LPARAM
)lpstrExt
);
3099 if(fodInfos
->filter
)
3101 LPCWSTR lpstrPos
= fodInfos
->filter
;
3105 /* filter is a list... title\0ext\0......\0\0
3106 * Set the combo item text to the title and the item data
3109 LPCWSTR lpstrDisplay
;
3113 if(! *lpstrPos
) break; /* end */
3114 lpstrDisplay
= lpstrPos
;
3115 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3117 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_ADDSTRING
, 0, (LPARAM
)lpstrDisplay
);
3121 /* Copy the extensions */
3122 if (!(lpstrExt
= heap_alloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
3123 lstrcpyW(lpstrExt
,lpstrPos
);
3124 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
3126 /* Add the item at the end of the combo */
3127 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETITEMDATA
, nFilters
- 1, (LPARAM
)lpstrExt
);
3129 /* malformed filters are added anyway... */
3130 if (!*lpstrExt
) break;
3135 * Set the current filter to the one specified
3136 * in the initialisation structure
3138 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3142 /* Check to make sure our index isn't out of bounds. */
3143 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3144 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3145 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3147 /* set default filter index */
3148 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3149 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3151 /* calculate index of Combo Box item */
3152 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3153 if (fodInfos
->customfilter
== NULL
)
3156 /* Set the current index selection. */
3157 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_SETCURSEL
, nFilterIndexCB
, 0);
3159 /* Get the corresponding text string from the combo box. */
3160 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3163 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3169 CharLowerW(lpstrFilter
); /* lowercase */
3170 len
= lstrlenW(lpstrFilter
)+1;
3171 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3172 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3175 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3179 /***********************************************************************
3180 * FILEDLG95_FILETYPE_OnCommand
3182 * WM_COMMAND of the file type combo box
3183 * If the function succeeds, the return value is nonzero.
3185 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3187 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3195 /* Get the current item of the filetype combo box */
3196 int iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCURSEL
, 0, 0);
3198 /* set the current filter index */
3199 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3200 (fodInfos
->customfilter
== NULL
? 1 : 0);
3202 /* Set the current filter with the current selection */
3203 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3205 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3207 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3210 CharLowerW(lpstrFilter
); /* lowercase */
3211 len
= lstrlenW(lpstrFilter
)+1;
3212 fodInfos
->ShellInfos
.lpstrCurrentFilter
= heap_alloc( len
* sizeof(WCHAR
) );
3213 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3214 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3215 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3218 /* Refresh the actual view to display the included items*/
3219 if (fodInfos
->Shell
.FOIShellView
)
3220 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3225 /***********************************************************************
3226 * FILEDLG95_FILETYPE_SearchExt
3228 * searches for an extension in the filetype box
3230 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3234 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3236 TRACE("%s\n", debugstr_w(lpstrExt
));
3238 if(iCount
!= CB_ERR
)
3240 for(i
=0;i
<iCount
;i
++)
3242 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3249 /***********************************************************************
3250 * FILEDLG95_FILETYPE_Clean
3252 * Clean the memory used by the filetype combo box
3254 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3256 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3260 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_GETCOUNT
, 0, 0);
3264 /* Delete each string of the combo and their associated data */
3265 if(iCount
!= CB_ERR
)
3267 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3269 heap_free((void *)CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3270 SendMessageW(fodInfos
->DlgInfos
.hwndFileTypeCB
, CB_DELETESTRING
, iPos
, 0);
3273 /* Current filter */
3274 heap_free(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3277 /***********************************************************************
3278 * FILEDLG95_LOOKIN_Init
3280 * Initialisation of the look in combo box
3283 /* Small helper function, to determine if the unixfs shell extension is rooted
3284 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3286 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3288 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3289 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3290 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3291 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3292 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3293 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3294 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3296 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3303 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3305 IShellFolder
*psfRoot
, *psfDrives
;
3306 IEnumIDList
*lpeRoot
, *lpeDrives
;
3307 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3310 LookInInfos
*liInfos
= heap_alloc_zero(sizeof(*liInfos
));
3312 TRACE("%p\n", hwndCombo
);
3314 liInfos
->iMaxIndentation
= 0;
3316 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3318 hdc
= GetDC( hwndCombo
);
3319 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3320 GetTextMetricsW( hdc
, &tm
);
3321 ReleaseDC( hwndCombo
, hdc
);
3323 /* set item height for both text field and listbox */
3324 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, -1, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3325 SendMessageW(hwndCombo
, CB_SETITEMHEIGHT
, 0, max(tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
)));
3327 /* Turn on the extended UI for the combo box like Windows does */
3328 SendMessageW(hwndCombo
, CB_SETEXTENDEDUI
, TRUE
, 0);
3330 /* Initialise data of Desktop folder */
3331 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3332 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3335 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3337 SHGetDesktopFolder(&psfRoot
);
3341 /* enumerate the contents of the desktop */
3342 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3344 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3346 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3348 /* If the unixfs extension is rooted, we don't expand the drives by default */
3349 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3351 /* special handling for CSIDL_DRIVES */
3352 if (ILIsEqual(pidlTmp
, pidlDrives
))
3354 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3356 /* enumerate the drives */
3357 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3359 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3361 pidlAbsTmp
= ILCombine(pidlTmp
, pidlTmp1
);
3362 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3366 IEnumIDList_Release(lpeDrives
);
3368 IShellFolder_Release(psfDrives
);
3375 IEnumIDList_Release(lpeRoot
);
3377 IShellFolder_Release(psfRoot
);
3383 /***********************************************************************
3384 * FILEDLG95_LOOKIN_DrawItem
3386 * WM_DRAWITEM message handler
3388 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3390 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3391 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3392 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3396 HIMAGELIST ilItemImage
;
3399 LPSFOLDER tmpFolder
;
3400 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3401 UINT icon_width
, icon_height
;
3405 if(pDIStruct
->itemID
== -1)
3408 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3409 pDIStruct
->itemID
)))
3413 icon_width
= GetSystemMetrics(SM_CXICON
);
3414 icon_height
= GetSystemMetrics(SM_CYICON
);
3415 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3417 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3418 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3419 shgfi_flags
|= SHGFI_SMALLICON
;
3422 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3423 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3425 /* Is this item selected ? */
3426 if(pDIStruct
->itemState
& ODS_SELECTED
)
3428 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3429 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3430 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3434 SetTextColor(pDIStruct
->hDC
,crText
);
3435 SetBkColor(pDIStruct
->hDC
,crWin
);
3436 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3439 /* Do not indent item if drawing in the edit of the combo */
3440 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3443 iIndentation
= tmpFolder
->m_iIndent
;
3445 /* Draw text and icon */
3447 /* Initialise the icon display area */
3448 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3449 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3450 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3451 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3453 /* Initialise the text display area */
3454 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3455 rectText
.left
= rectIcon
.right
;
3457 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3458 rectText
.right
= pDIStruct
->rcItem
.right
;
3460 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3462 /* Draw the icon from the image list */
3463 ImageList_Draw(ilItemImage
,
3470 /* Draw the associated text */
3471 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3475 /***********************************************************************
3476 * FILEDLG95_LOOKIN_OnCommand
3478 * LookIn combo box WM_COMMAND message handler
3479 * If the function succeeds, the return value is nonzero.
3481 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3483 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3485 TRACE("%p\n", fodInfos
);
3491 LPSFOLDER tmpFolder
;
3494 iItem
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCURSEL
, 0, 0);
3496 if( iItem
== CB_ERR
) return FALSE
;
3498 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3503 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3504 tmpFolder
->pidlItem
,
3507 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3508 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3518 /***********************************************************************
3519 * FILEDLG95_LOOKIN_AddItem
3521 * Adds an absolute pidl item to the lookin combo box
3522 * returns the index of the inserted item
3524 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3526 LPITEMIDLIST pidlNext
;
3529 LookInInfos
*liInfos
;
3531 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3536 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3539 tmpFolder
= heap_alloc_zero(sizeof(*tmpFolder
));
3540 tmpFolder
->m_iIndent
= 0;
3542 /* Calculate the indentation of the item in the lookin*/
3544 while ((pidlNext
= ILGetNext(pidlNext
)))
3546 tmpFolder
->m_iIndent
++;
3549 tmpFolder
->pidlItem
= ILClone(pidl
);
3551 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3552 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3554 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3555 SHGetFileInfoW((LPCWSTR
)pidl
,
3559 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3561 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3563 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3567 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3569 /* Add the item at the end of the list */
3572 iItemID
= SendMessageW(hwnd
, CB_ADDSTRING
, 0, (LPARAM
)sfi
.szDisplayName
);
3574 /* Insert the item at the iInsertId position*/
3577 iItemID
= SendMessageW(hwnd
, CB_INSERTSTRING
, iInsertId
, (LPARAM
)sfi
.szDisplayName
);
3580 SendMessageW(hwnd
, CB_SETITEMDATA
, iItemID
, (LPARAM
)tmpFolder
);
3584 ILFree( tmpFolder
->pidlItem
);
3585 heap_free( tmpFolder
);
3590 /***********************************************************************
3591 * FILEDLG95_LOOKIN_InsertItemAfterParent
3593 * Insert an item below its parent
3595 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3598 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3603 if (pidl
== pidlParent
)
3606 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3610 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3615 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3618 /***********************************************************************
3619 * FILEDLG95_LOOKIN_SelectItem
3621 * Adds an absolute pidl item to the lookin combo box
3622 * returns the index of the inserted item
3624 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3627 LookInInfos
*liInfos
;
3629 TRACE("%p, %p\n", hwnd
, pidl
);
3631 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3633 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3637 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3638 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3643 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3644 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3648 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3650 if(iRemovedItem
< iItemPos
)
3655 SendMessageW(hwnd
, CB_SETCURSEL
, iItemPos
, 0);
3656 liInfos
->uSelectedItem
= iItemPos
;
3662 /***********************************************************************
3663 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3665 * Remove the item with an expansion level over iExpansionLevel
3667 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3670 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3674 if(liInfos
->iMaxIndentation
<= 2)
3677 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3679 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3680 ILFree(tmpFolder
->pidlItem
);
3681 heap_free(tmpFolder
);
3682 SendMessageW(hwnd
, CB_DELETESTRING
, iItemPos
, 0);
3683 liInfos
->iMaxIndentation
--;
3691 /***********************************************************************
3692 * FILEDLG95_LOOKIN_SearchItem
3694 * Search for pidl in the lookin combo box
3695 * returns the index of the found item
3697 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3702 iCount
= SendMessageW(hwnd
, CB_GETCOUNT
, 0, 0);
3704 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3706 if (iCount
!= CB_ERR
)
3710 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3712 if (iSearchMethod
== SEARCH_PIDL
&& ILIsEqual((LPITEMIDLIST
)searchArg
, tmpFolder
->pidlItem
))
3714 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3722 /***********************************************************************
3723 * FILEDLG95_LOOKIN_Clean
3725 * Clean the memory used by the lookin combo box
3727 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3729 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3730 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3733 iCount
= SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_GETCOUNT
, 0, 0);
3737 /* Delete each string of the combo and their associated data */
3738 if (iCount
!= CB_ERR
)
3740 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3742 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3743 ILFree(tmpFolder
->pidlItem
);
3744 heap_free(tmpFolder
);
3745 SendMessageW(fodInfos
->DlgInfos
.hwndLookInCB
, CB_DELETESTRING
, iPos
, 0);
3749 /* LookInInfos structure */
3751 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3754 /***********************************************************************
3757 * Fill the FORMATETC used in the shell id list
3759 static FORMATETC
get_def_format(void)
3761 static CLIPFORMAT cfFormat
;
3762 FORMATETC formatetc
;
3764 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3765 formatetc
.cfFormat
= cfFormat
;
3767 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3768 formatetc
.lindex
= -1;
3769 formatetc
.tymed
= TYMED_HGLOBAL
;
3773 /***********************************************************************
3774 * FILEDLG95_FILENAME_FillFromSelection
3776 * fills the edit box from the cached DataObject
3778 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3780 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3782 LPWSTR lpstrAllFiles
, lpstrTmp
;
3783 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3786 FORMATETC formatetc
= get_def_format();
3790 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3793 cida
= GlobalLock(medium
.u
.hGlobal
);
3794 nFileSelected
= cida
->cidl
;
3796 /* Allocate a buffer */
3797 nAllFilesMaxLength
= MAX_PATH
+ 3;
3798 lpstrAllFiles
= heap_alloc_zero(nAllFilesMaxLength
* sizeof(WCHAR
));
3802 /* Loop through the selection, handle only files (not folders) */
3803 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3805 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3808 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3810 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3812 nAllFilesMaxLength
*= 2;
3813 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3816 lpstrAllFiles
= lpstrTmp
;
3819 lpstrAllFiles
[nAllFilesLength
++] = '"';
3820 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3821 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3822 nAllFilesLength
+= nThisFileLength
;
3823 lpstrAllFiles
[nAllFilesLength
++] = '"';
3824 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3831 /* If there's only one file, use the name as-is without quotes */
3832 lpstrTmp
= lpstrAllFiles
;
3836 lpstrTmp
[nThisFileLength
] = 0;
3838 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3839 /* Select the file name like Windows does */
3840 if (filename_is_edit(fodInfos
))
3841 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3845 heap_free(lpstrAllFiles
);
3846 COMCTL32_ReleaseStgMedium(medium
);
3850 /* copied from shell32 to avoid linking to it
3851 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3852 * is dependent on whether emulated OS is unicode or not.
3854 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3859 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3860 CoTaskMemFree(src
->u
.pOleStr
);
3864 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3869 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3874 FIXME("unknown type %x!\n", src
->uType
);
3875 if (len
) *dest
= '\0';
3881 /***********************************************************************
3882 * FILEDLG95_FILENAME_GetFileNames
3884 * Copies the filenames to a delimited string list.
3886 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3888 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3889 UINT nFileCount
= 0; /* number of files */
3890 UINT nStrLen
= 0; /* length of string in edit control */
3891 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3895 /* get the filenames from the filename control */
3896 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3897 lpstrEdit
= heap_alloc( (nStrLen
+1)*sizeof(WCHAR
) );
3898 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3900 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3902 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3903 heap_free(lpstrEdit
);
3908 * DATAOBJECT Helper functions
3911 /***********************************************************************
3912 * COMCTL32_ReleaseStgMedium
3914 * like ReleaseStgMedium from ole32
3916 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3918 if(medium
.pUnkForRelease
)
3920 IUnknown_Release(medium
.pUnkForRelease
);
3924 GlobalUnlock(medium
.u
.hGlobal
);
3925 GlobalFree(medium
.u
.hGlobal
);
3929 /***********************************************************************
3930 * GetPidlFromDataObject
3932 * Return pidl(s) by number from the cached DataObject
3934 * nPidlIndex=0 gets the fully qualified root path
3936 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3940 FORMATETC formatetc
= get_def_format();
3941 LPITEMIDLIST pidl
= NULL
;
3943 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3948 /* Get the pidls from IDataObject */
3949 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3951 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3952 if(nPidlIndex
<= cida
->cidl
)
3954 pidl
= ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3956 COMCTL32_ReleaseStgMedium(medium
);
3961 /***********************************************************************
3964 * Return the number of selected items in the DataObject.
3967 static UINT
GetNumSelected( IDataObject
*doSelected
)
3971 FORMATETC formatetc
= get_def_format();
3973 TRACE("sv=%p\n", doSelected
);
3975 if (!doSelected
) return 0;
3977 /* Get the pidls from IDataObject */
3978 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3980 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3981 retVal
= cida
->cidl
;
3982 COMCTL32_ReleaseStgMedium(medium
);
3992 /***********************************************************************
3995 * Get the pidl's display name (relative to folder) and
3996 * put it in lpstrFileName.
3998 * Return NOERROR on success,
4002 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
4007 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
4011 SHGetDesktopFolder(&lpsf
);
4012 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
4013 IShellFolder_Release(lpsf
);
4017 /* Get the display name of the pidl relative to the folder */
4018 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
4020 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
4025 /***********************************************************************
4026 * GetShellFolderFromPidl
4028 * pidlRel is the item pidl relative
4029 * Return the IShellFolder of the absolute pidl
4031 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
4033 IShellFolder
*psf
= NULL
,*psfParent
;
4035 TRACE("%p\n", pidlAbs
);
4037 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
4040 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
4042 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
4044 IShellFolder_Release(psfParent
);
4048 /* return the desktop */
4054 /***********************************************************************
4057 * Return the LPITEMIDLIST to the parent of the pidl in the list
4059 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
4061 LPITEMIDLIST pidlParent
;
4063 TRACE("%p\n", pidl
);
4065 pidlParent
= ILClone(pidl
);
4066 ILRemoveLastID(pidlParent
);
4071 /***********************************************************************
4074 * returns the pidl of the file name relative to folder
4075 * NULL if an error occurred
4077 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
4079 LPITEMIDLIST pidl
= NULL
;
4082 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
4084 if(!lpcstrFileName
) return NULL
;
4085 if(!*lpcstrFileName
) return NULL
;
4089 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
4090 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4091 IShellFolder_Release(lpsf
);
4096 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
4103 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
4105 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
4108 TRACE("%p, %p\n", psf
, pidl
);
4110 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
4112 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
4113 /* see documentation shell 4.1*/
4114 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4117 /***********************************************************************
4118 * BrowseSelectedFolder
4120 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4122 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
4123 BOOL bBrowseSelFolder
= FALSE
;
4127 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4129 LPITEMIDLIST pidlSelection
;
4131 /* get the file selected */
4132 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4133 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4135 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4136 pidlSelection
, SBSP_RELATIVE
) ) )
4139 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, ARRAY_SIZE(buf
));
4140 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4142 bBrowseSelFolder
= TRUE
;
4143 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4144 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4146 ILFree( pidlSelection
);
4149 return bBrowseSelFolder
;
4152 static inline BOOL
valid_struct_size( DWORD size
)
4154 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4155 (size
== sizeof( OPENFILENAMEW
));
4158 static inline BOOL
is_win16_looks(DWORD flags
)
4160 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4161 !(flags
& OFN_EXPLORER
));
4164 /* ------------------ APIs ---------------------- */
4166 /***********************************************************************
4167 * GetOpenFileNameA (COMDLG32.@)
4169 * Creates a dialog box for the user to select a file to open.
4172 * TRUE on success: user enters a valid file
4173 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4176 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4178 TRACE("flags 0x%08x\n", ofn
->Flags
);
4180 if (!valid_struct_size( ofn
->lStructSize
))
4182 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4186 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4187 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4188 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4190 if (is_win16_looks(ofn
->Flags
))
4191 return GetFileName31A(ofn
, OPEN_DIALOG
);
4194 FileOpenDlgInfos info
;
4196 init_filedlg_infoA(ofn
, &info
);
4197 return GetFileDialog95(&info
, OPEN_DIALOG
);
4201 /***********************************************************************
4202 * GetOpenFileNameW (COMDLG32.@)
4204 * Creates a dialog box for the user to select a file to open.
4207 * TRUE on success: user enters a valid file
4208 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4211 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4213 TRACE("flags 0x%08x\n", ofn
->Flags
);
4215 if (!valid_struct_size( ofn
->lStructSize
))
4217 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4221 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4222 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4223 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4225 if (is_win16_looks(ofn
->Flags
))
4226 return GetFileName31W(ofn
, OPEN_DIALOG
);
4229 FileOpenDlgInfos info
;
4231 init_filedlg_infoW(ofn
, &info
);
4232 return GetFileDialog95(&info
, OPEN_DIALOG
);
4237 /***********************************************************************
4238 * GetSaveFileNameA (COMDLG32.@)
4240 * Creates a dialog box for the user to select a file to save.
4243 * TRUE on success: user enters a valid file
4244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4247 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4249 if (!valid_struct_size( ofn
->lStructSize
))
4251 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4255 if (is_win16_looks(ofn
->Flags
))
4256 return GetFileName31A(ofn
, SAVE_DIALOG
);
4259 FileOpenDlgInfos info
;
4261 init_filedlg_infoA(ofn
, &info
);
4262 return GetFileDialog95(&info
, SAVE_DIALOG
);
4266 /***********************************************************************
4267 * GetSaveFileNameW (COMDLG32.@)
4269 * Creates a dialog box for the user to select a file to save.
4272 * TRUE on success: user enters a valid file
4273 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4276 BOOL WINAPI
GetSaveFileNameW(
4277 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4279 if (!valid_struct_size( ofn
->lStructSize
))
4281 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4285 if (is_win16_looks(ofn
->Flags
))
4286 return GetFileName31W(ofn
, SAVE_DIALOG
);
4289 FileOpenDlgInfos info
;
4291 init_filedlg_infoW(ofn
, &info
);
4292 return GetFileDialog95(&info
, SAVE_DIALOG
);
4296 /***********************************************************************
4297 * GetFileTitleA (COMDLG32.@)
4299 * See GetFileTitleW.
4301 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4304 UNICODE_STRING strWFile
;
4307 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4308 lpWTitle
= heap_alloc(cbBuf
* sizeof(WCHAR
));
4309 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4310 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4311 RtlFreeUnicodeString( &strWFile
);
4312 heap_free( lpWTitle
);
4317 /***********************************************************************
4318 * GetFileTitleW (COMDLG32.@)
4320 * Get the name of a file.
4323 * lpFile [I] name and location of file
4324 * lpTitle [O] returned file name
4325 * cbBuf [I] buffer size of lpTitle
4329 * Failure: negative number.
4331 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4334 static const WCHAR brkpoint
[] = {'*','[',']',0};
4335 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4337 if(lpFile
== NULL
|| lpTitle
== NULL
)
4340 len
= lstrlenW(lpFile
);
4345 if(wcspbrk(lpFile
, brkpoint
))
4350 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4353 for(i
= len
; i
>= 0; i
--)
4355 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4365 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4367 len
= lstrlenW(lpFile
+i
)+1;
4371 lstrcpyW(lpTitle
, &lpFile
[i
]);