2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
73 #include "filedlgbrowser.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex
; /* Index of picture in image list */
95 int m_iIndent
; /* Indentation index */
96 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
100 typedef struct tagLookInInfo
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
166 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
168 static const WCHAR LastVisitedMRUW
[] =
169 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
172 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
173 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
175 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
177 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
179 return GetPropW(hwnd
, filedlg_info_propnameW
);
182 /***********************************************************************
186 /* Internal functions used by the dialog */
187 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
188 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
189 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
190 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
191 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
192 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
193 static void FILEDLG95_Clean(HWND hwnd
);
195 /* Functions used by the shell navigation */
196 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
197 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
198 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
199 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
200 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
202 /* Functions used by the EDIT box */
203 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
205 /* Functions used by the filetype combo box */
206 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
207 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
208 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
209 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
211 /* Functions used by the Look In combo box */
212 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
213 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
214 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
215 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
216 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
217 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
218 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
219 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
220 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
222 /* Functions for dealing with the most-recently-used registry keys */
223 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
224 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
225 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
227 /* Miscellaneous tool functions */
228 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
229 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
230 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
231 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
232 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
233 static UINT
GetNumSelected( IDataObject
*doSelected
);
234 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
236 /* Shell memory allocation */
237 static void *MemAlloc(UINT size
);
238 static void MemFree(void *mem
);
240 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
241 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
242 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
243 static BOOL
BrowseSelectedFolder(HWND hwnd
);
245 /***********************************************************************
248 * Creates an Open common dialog box that lets the user select
249 * the drive, directory, and the name of a file or set of files to open.
251 * IN : The FileOpenDlgInfos structure associated with the dialog
252 * OUT : TRUE on success
253 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
255 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
262 /* test for missing functionality */
263 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
265 FIXME("Flags 0x%08x not yet implemented\n",
266 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
269 /* Create the dialog from a template */
271 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
273 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
276 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
277 !(template = LockResource( hDlgTmpl
)))
279 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
283 /* msdn: explorer style dialogs permit sizing by default.
284 * The OFN_ENABLESIZING flag is only needed when a hook or
285 * custom template is provided */
286 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
287 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
288 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
290 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
292 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
293 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
296 /* old style hook messages */
297 if (IsHooked(fodInfos
))
299 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
300 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
301 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
302 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
305 if (fodInfos
->unicode
)
306 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
308 fodInfos
->ofnInfos
->hwndOwner
,
312 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
314 fodInfos
->ofnInfos
->hwndOwner
,
317 if (fodInfos
->ole_initialized
)
320 /* Unable to create the dialog */
327 static WCHAR
*heap_strdupAtoW(const char *str
)
335 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
336 ret
= MemAlloc(len
* sizeof(WCHAR
));
337 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
342 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
344 INITCOMMONCONTROLSEX icc
;
346 /* Initialize ComboBoxEx32 */
347 icc
.dwSize
= sizeof(icc
);
348 icc
.dwICC
= ICC_USEREX_CLASSES
;
349 InitCommonControlsEx(&icc
);
351 /* Initialize CommDlgExtendedError() */
352 COMDLG32_SetCommDlgExtendedError(0);
354 memset(info
, 0, sizeof(*info
));
356 /* Pass in the original ofn */
357 info
->ofnInfos
= ofn
;
359 info
->title
= ofn
->lpstrTitle
;
360 info
->defext
= ofn
->lpstrDefExt
;
361 info
->filter
= ofn
->lpstrFilter
;
362 info
->customfilter
= ofn
->lpstrCustomFilter
;
366 info
->filename
= MemAlloc(ofn
->nMaxFile
* sizeof(WCHAR
));
367 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
370 if (ofn
->lpstrInitialDir
)
372 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
375 info
->initdir
= MemAlloc(len
* sizeof(WCHAR
));
376 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
380 info
->unicode
= TRUE
;
383 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
388 ofnW
= *(OPENFILENAMEW
*)ofn
;
390 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
391 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
392 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
396 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
397 ofnW
.lpstrFile
= MemAlloc(len
* sizeof(WCHAR
));
398 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
402 if (ofn
->lpstrFilter
)
407 /* filter is a list... title\0ext\0......\0\0 */
408 s
= ofn
->lpstrFilter
;
409 while (*s
) s
= s
+strlen(s
)+1;
411 n
= s
- ofn
->lpstrFilter
;
412 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
413 ofnW
.lpstrFilter
= MemAlloc(len
* sizeof(WCHAR
));
414 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
417 /* convert lpstrCustomFilter */
418 if (ofn
->lpstrCustomFilter
)
423 /* customfilter contains a pair of strings... title\0ext\0 */
424 s
= ofn
->lpstrCustomFilter
;
425 if (*s
) s
= s
+strlen(s
)+1;
426 if (*s
) s
= s
+strlen(s
)+1;
427 n
= s
- ofn
->lpstrCustomFilter
;
428 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
429 ofnW
.lpstrCustomFilter
= MemAlloc(len
* sizeof(WCHAR
));
430 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
433 init_filedlg_infoW(&ofnW
, info
);
435 /* fixup A-specific fields */
436 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
437 info
->unicode
= FALSE
;
439 /* free what was duplicated */
440 MemFree((WCHAR
*)ofnW
.lpstrInitialDir
);
441 MemFree((WCHAR
*)ofnW
.lpstrFile
);
444 /***********************************************************************
447 * Call GetFileName95 with this structure and clean the memory.
449 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
451 WCHAR
*current_dir
= NULL
;
454 /* save current directory */
455 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
457 current_dir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
458 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
464 ret
= GetFileName95(info
);
467 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
468 ret
= GetFileName95(info
);
476 SetCurrentDirectoryW(current_dir
);
477 MemFree(current_dir
);
482 MemFree((WCHAR
*)info
->defext
);
483 MemFree((WCHAR
*)info
->title
);
484 MemFree((WCHAR
*)info
->filter
);
485 MemFree((WCHAR
*)info
->customfilter
);
488 MemFree(info
->filename
);
489 MemFree(info
->initdir
);
493 /******************************************************************************
494 * COMDLG32_GetDisplayNameOf [internal]
496 * Helper function to get the display name for a pidl.
498 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
499 LPSHELLFOLDER psfDesktop
;
502 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
505 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
506 IShellFolder_Release(psfDesktop
);
510 IShellFolder_Release(psfDesktop
);
511 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
514 /******************************************************************************
515 * COMDLG32_GetCanonicalPath [internal]
517 * Helper function to get the canonical path.
519 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
520 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
522 WCHAR lpstrTemp
[MAX_PATH
];
524 /* Get the current directory name */
525 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
528 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
530 PathAddBackslashW(lpstrPathAndFile
);
532 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
534 /* if the user specified a fully qualified path use it */
535 if(PathIsRelativeW(lpstrFile
))
537 lstrcatW(lpstrPathAndFile
, lpstrFile
);
541 /* does the path have a drive letter? */
542 if (PathGetDriveNumberW(lpstrFile
) == -1)
543 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
545 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
548 /* resolve "." and ".." */
549 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
550 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
551 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
554 /***********************************************************************
555 * COMDLG32_SplitFileNames [internal]
557 * Creates a delimited list of filenames.
559 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
561 UINT nStrCharCount
= 0; /* index in src buffer */
562 UINT nFileIndex
= 0; /* index in dest buffer */
563 UINT nFileCount
= 0; /* number of files */
565 /* we might get single filename without any '"',
566 * so we need nStrLen + terminating \0 + end-of-list \0 */
567 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
570 /* build delimited file list from filenames */
571 while ( nStrCharCount
<= nStrLen
)
573 if ( lpstrEdit
[nStrCharCount
]=='"' )
576 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
578 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
581 (*lpstrFileList
)[nFileIndex
++] = 0;
587 /* single, unquoted string */
588 if ((nStrLen
> 0) && (nFileIndex
== 0) )
590 lstrcpyW(*lpstrFileList
, lpstrEdit
);
591 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
596 (*lpstrFileList
)[nFileIndex
++] = '\0';
598 *sizeUsed
= nFileIndex
;
602 /***********************************************************************
603 * ArrangeCtrlPositions [internal]
605 * NOTE: Make sure to add testcases for any changes made here.
607 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
609 HWND hwndChild
, hwndStc32
;
610 RECT rectParent
, rectChild
, rectStc32
;
614 /* Take into account if open as read only checkbox and help button
619 RECT rectHelp
, rectCancel
;
620 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
621 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
622 /* subtract the height of the help button plus the space between
623 * the help button and the cancel button to the height of the dialog
625 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
629 There are two possibilities to add components to the default file dialog box.
631 By default, all the new components are added below the standard dialog box (the else case).
633 However, if there is a static text component with the stc32 id, a special case happens.
634 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
635 in the window and the cx and cy indicate how to size the window.
636 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
637 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
641 GetClientRect(hwndParentDlg
, &rectParent
);
643 /* when arranging controls we have to use fixed parent size */
644 rectParent
.bottom
-= help_fixup
;
646 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
649 GetWindowRect(hwndStc32
, &rectStc32
);
650 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
652 /* set the size of the stc32 control according to the size of
653 * client area of the parent dialog
655 SetWindowPos(hwndStc32
, 0,
657 rectParent
.right
, rectParent
.bottom
,
658 SWP_NOMOVE
| SWP_NOZORDER
);
661 SetRectEmpty(&rectStc32
);
663 /* this part moves controls of the child dialog */
664 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
667 if (hwndChild
!= hwndStc32
)
669 GetWindowRect(hwndChild
, &rectChild
);
670 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
672 /* move only if stc32 exist */
673 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
675 /* move to the right of visible controls of the parent dialog */
676 rectChild
.left
+= rectParent
.right
;
677 rectChild
.left
-= rectStc32
.right
;
679 /* move even if stc32 doesn't exist */
680 if (rectChild
.top
>= rectStc32
.bottom
)
682 /* move below visible controls of the parent dialog */
683 rectChild
.top
+= rectParent
.bottom
;
684 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
687 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
688 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
690 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
693 /* this part moves controls of the parent dialog */
694 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
697 if (hwndChild
!= hwndChildDlg
)
699 GetWindowRect(hwndChild
, &rectChild
);
700 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
702 /* left,top of stc32 marks the position of controls
703 * from the parent dialog
705 rectChild
.left
+= rectStc32
.left
;
706 rectChild
.top
+= rectStc32
.top
;
708 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
709 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
711 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
714 /* calculate the size of the resulting dialog */
716 /* here we have to use original parent size */
717 GetClientRect(hwndParentDlg
, &rectParent
);
718 GetClientRect(hwndChildDlg
, &rectChild
);
719 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
720 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
725 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
726 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
728 chgx
= rectChild
.right
- rectParent
.right
;
730 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
731 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
733 /* Unconditionally set new dialog
734 * height to that of the child
736 chgy
= rectChild
.bottom
- rectParent
.bottom
;
741 chgy
= rectChild
.bottom
- help_fixup
;
743 /* set the size of the parent dialog */
744 GetWindowRect(hwndParentDlg
, &rectParent
);
745 SetWindowPos(hwndParentDlg
, 0,
747 rectParent
.right
- rectParent
.left
+ chgx
,
748 rectParent
.bottom
- rectParent
.top
+ chgy
,
749 SWP_NOMOVE
| SWP_NOZORDER
);
752 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
761 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
771 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
772 * structure's hInstance parameter is not a HINSTANCE, but
773 * instead a pointer to a template resource to use.
775 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
778 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
780 hinst
= COMDLG32_hInstance
;
781 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
783 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
789 hinst
= fodInfos
->ofnInfos
->hInstance
;
790 if(fodInfos
->unicode
)
792 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
793 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
797 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
798 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
802 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
805 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
806 !(template = LockResource( hDlgTmpl
)))
808 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
812 if (fodInfos
->unicode
)
813 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
814 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
815 (LPARAM
)fodInfos
->ofnInfos
);
817 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
818 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
819 (LPARAM
)fodInfos
->ofnInfos
);
822 else if( IsHooked(fodInfos
))
827 WORD menu
,class,title
;
829 GetClientRect(hwnd
,&rectHwnd
);
830 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
831 temp
.tmplate
.dwExtendedStyle
= 0;
832 temp
.tmplate
.cdit
= 0;
837 temp
.menu
= temp
.class = temp
.title
= 0;
839 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
840 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
847 /***********************************************************************
848 * SendCustomDlgNotificationMessage
850 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
853 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
855 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
856 LRESULT hook_result
= 0;
858 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
860 if(!fodInfos
) return 0;
862 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
864 TRACE("CALL NOTIFY for %x\n", uCode
);
865 if(fodInfos
->unicode
)
868 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
869 ofnNotify
.hdr
.idFrom
=0;
870 ofnNotify
.hdr
.code
= uCode
;
871 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
872 ofnNotify
.pszFile
= NULL
;
873 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
878 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
879 ofnNotify
.hdr
.idFrom
=0;
880 ofnNotify
.hdr
.code
= uCode
;
881 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
882 ofnNotify
.pszFile
= NULL
;
883 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
885 TRACE("RET NOTIFY\n");
887 TRACE("Retval: 0x%08lx\n", hook_result
);
891 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
895 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
897 TRACE("CDM_GETFILEPATH:\n");
899 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
902 /* get path and filenames */
903 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
904 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
905 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
908 p
= buffer
+ strlenW(buffer
);
910 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
912 if (fodInfos
->unicode
)
914 total
= strlenW( buffer
) + 1;
915 if (result
) lstrcpynW( result
, buffer
, size
);
916 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
920 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
921 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
922 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
924 HeapFree( GetProcessHeap(), 0, buffer
);
928 /***********************************************************************
929 * FILEDLG95_HandleCustomDialogMessages
931 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
933 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
935 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
936 WCHAR lpstrPath
[MAX_PATH
];
939 if(!fodInfos
) return FALSE
;
943 case CDM_GETFILEPATH
:
944 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
947 case CDM_GETFOLDERPATH
:
948 TRACE("CDM_GETFOLDERPATH:\n");
949 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
952 if (fodInfos
->unicode
)
953 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
955 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
956 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
958 retval
= lstrlenW(lpstrPath
) + 1;
961 case CDM_GETFOLDERIDLIST
:
962 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
963 if (retval
<= wParam
)
964 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
968 TRACE("CDM_GETSPEC:\n");
969 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
972 if (fodInfos
->unicode
)
973 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
975 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
979 case CDM_SETCONTROLTEXT
:
980 TRACE("CDM_SETCONTROLTEXT:\n");
983 if( fodInfos
->unicode
)
984 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
986 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
991 case CDM_HIDECONTROL
:
992 /* MSDN states that it should fail for not OFN_EXPLORER case */
993 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
995 HWND control
= GetDlgItem( hwnd
, wParam
);
996 if (control
) ShowWindow( control
, SW_HIDE
);
1003 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1004 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1007 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1011 /***********************************************************************
1012 * FILEDLG95_OnWMGetMMI
1014 * WM_GETMINMAXINFO message handler for resizable dialogs
1016 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1018 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1019 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1020 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1022 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1027 /***********************************************************************
1028 * FILEDLG95_OnWMSize
1030 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1032 * FIXME: this could be made more elaborate. Now use a simple scheme
1033 * where the file view is enlarged and the controls are either moved
1034 * vertically or horizontally to get out of the way. Only the "grip"
1035 * is moved in both directions to stay in the corner.
1037 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1043 FileOpenDlgInfos
*fodInfos
;
1045 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1046 fodInfos
= get_filedlg_infoptr(hwnd
);
1047 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1048 /* get the new dialog rectangle */
1049 GetWindowRect( hwnd
, &rc
);
1050 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1051 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1052 /* not initialized yet */
1053 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1054 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1055 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1057 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1058 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1059 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1060 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1061 /* change the size of the view window */
1062 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1063 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1064 hdwp
= BeginDeferWindowPos( 10);
1065 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1066 rcview
.right
- rcview
.left
+ chgx
,
1067 rcview
.bottom
- rcview
.top
+ chgy
,
1068 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1069 /* change position and sizes of the controls */
1070 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1072 int ctrlid
= GetDlgCtrlID( ctrl
);
1073 GetWindowRect( ctrl
, &rc
);
1074 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1075 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1077 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1079 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1081 else if( rc
.top
> rcview
.bottom
)
1083 /* if it was below the shell view
1087 /* file name (edit or comboboxex) and file types combo change also width */
1091 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1092 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1093 SWP_NOACTIVATE
| SWP_NOZORDER
);
1095 /* then these buttons must move out of the way */
1099 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1101 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1104 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1106 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1109 else if( rc
.left
> rcview
.right
)
1111 /* if it was to the right of the shell view
1113 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1115 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1122 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1124 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1125 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1126 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1128 case IDC_TOOLBARSTATIC
:
1130 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1132 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1135 /* not resized in windows. Since wine uses this invisible control
1136 * to size the browser view it needs to be resized */
1137 case IDC_SHELLSTATIC
:
1138 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1139 rc
.right
- rc
.left
+ chgx
,
1140 rc
.bottom
- rc
.top
+ chgy
,
1141 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1146 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1147 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1149 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1150 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1152 GetWindowRect( ctrl
, &rc
);
1153 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1154 if( rc
.top
> rcview
.bottom
)
1156 /* if it was below the shell view
1158 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1159 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1160 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1162 else if( rc
.left
> rcview
.right
)
1164 /* if it was to the right of the shell view
1166 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1167 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1168 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1171 /* size the custom dialog at the end: some applications do some
1172 * control re-arranging at this point */
1173 GetClientRect(hwnd
, &rc
);
1174 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1175 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1177 EndDeferWindowPos( hdwp
);
1178 /* should not be needed */
1179 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1183 /***********************************************************************
1186 * File open dialog procedure
1188 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1191 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1198 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1200 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1201 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1203 /* Some shell namespace extensions depend on COM being initialized. */
1204 if (SUCCEEDED(OleInitialize(NULL
)))
1205 fodInfos
->ole_initialized
= TRUE
;
1207 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1209 FILEDLG95_InitControls(hwnd
);
1211 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1213 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1214 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1215 RECT client
, client_adjusted
;
1217 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1219 style
|= WS_SIZEBOX
;
1220 ex_style
|= WS_EX_WINDOWEDGE
;
1223 style
&= ~WS_SIZEBOX
;
1224 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1225 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1227 GetClientRect( hwnd
, &client
);
1228 GetClientRect( hwnd
, &client_adjusted
);
1229 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1231 GetWindowRect( hwnd
, &rc
);
1232 rc
.right
+= client_adjusted
.right
- client
.right
;
1233 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1234 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1235 SWP_NOZORDER
| SWP_NOMOVE
);
1237 GetWindowRect( hwnd
, &rc
);
1238 fodInfos
->DlgInfos
.hwndGrip
=
1239 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1240 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1241 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1242 rc
.right
- gripx
, rc
.bottom
- gripy
,
1243 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1246 fodInfos
->DlgInfos
.hwndCustomDlg
=
1247 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1249 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1250 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1252 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1253 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1255 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1256 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1257 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1260 /* if the app has changed the position of the invisible listbox,
1261 * change that of the listview (browser) as well */
1262 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1263 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1264 if( !EqualRect( &rc
, &rcstc
))
1266 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1267 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1268 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1269 SWP_NOACTIVATE
| SWP_NOZORDER
);
1272 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1274 GetWindowRect( hwnd
, &rc
);
1275 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1276 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1277 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1278 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1279 GetClientRect( hwnd
, &rc
);
1280 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1281 rc
.right
- gripx
, rc
.bottom
- gripy
,
1282 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1283 /* resize the dialog to the previous invocation */
1284 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1285 SetWindowPos( hwnd
, NULL
,
1286 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1287 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1290 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1291 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1296 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1297 case WM_GETMINMAXINFO
:
1298 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1300 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1303 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1306 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1312 case WM_GETISHELLBROWSER
:
1313 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1317 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1318 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1319 MemDialogSize
= fodInfos
->sizedlg
;
1320 RemovePropW(hwnd
, filedlg_info_propnameW
);
1325 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1328 /* set up the button tooltips strings */
1329 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1331 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1332 switch(lpnmh
->idFrom
)
1334 /* Up folder button */
1335 case FCIDM_TB_UPFOLDER
:
1336 stringId
= IDS_UPFOLDER
;
1338 /* New folder button */
1339 case FCIDM_TB_NEWFOLDER
:
1340 stringId
= IDS_NEWFOLDER
;
1342 /* List option button */
1343 case FCIDM_TB_SMALLICON
:
1344 stringId
= IDS_LISTVIEW
;
1346 /* Details option button */
1347 case FCIDM_TB_REPORTVIEW
:
1348 stringId
= IDS_REPORTVIEW
;
1350 /* Desktop button */
1351 case FCIDM_TB_DESKTOP
:
1352 stringId
= IDS_TODESKTOP
;
1357 lpdi
->hinst
= COMDLG32_hInstance
;
1358 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1363 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1364 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1369 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1371 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1372 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1375 /***********************************************************************
1376 * FILEDLG95_InitControls
1378 * WM_INITDIALOG message handler (before hook notification)
1380 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1382 BOOL win2000plus
= FALSE
;
1383 BOOL win98plus
= FALSE
;
1384 BOOL handledPath
= FALSE
;
1385 OSVERSIONINFOW osVi
;
1386 static const WCHAR szwSlash
[] = { '\\', 0 };
1387 static const WCHAR szwStar
[] = { '*',0 };
1389 static const TBBUTTON tbb
[] =
1391 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1392 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1393 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1394 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1395 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1396 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1397 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1398 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1399 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1401 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1406 HIMAGELIST toolbarImageList
;
1407 SHFILEINFOA shFileInfo
;
1408 ITEMIDLIST
*desktopPidl
;
1410 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1412 TRACE("%p\n", fodInfos
);
1414 /* Get windows version emulating */
1415 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1416 GetVersionExW(&osVi
);
1417 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1418 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1419 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1420 win2000plus
= (osVi
.dwMajorVersion
> 4);
1421 if (win2000plus
) win98plus
= TRUE
;
1423 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1426 /* Use either the edit or the comboboxex for the filename control */
1427 if (filename_is_edit( fodInfos
))
1429 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1430 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1434 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1435 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1438 /* Get the hwnd of the controls */
1439 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1440 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1442 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1443 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1445 /* construct the toolbar */
1446 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1447 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1449 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1450 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1451 rectTB
.left
= rectlook
.right
;
1452 rectTB
.top
= rectlook
.top
-1;
1454 if (fodInfos
->unicode
)
1455 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1456 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1457 rectTB
.left
, rectTB
.top
,
1458 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1459 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1461 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1462 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1463 rectTB
.left
, rectTB
.top
,
1464 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1465 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1467 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1469 /* FIXME: use TB_LOADIMAGES when implemented */
1470 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1471 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1472 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1474 /* Retrieve and add desktop icon to the toolbar */
1475 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1476 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1477 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1478 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1479 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1481 DestroyIcon(shFileInfo
.hIcon
);
1482 CoTaskMemFree(desktopPidl
);
1484 /* Finish Toolbar Construction */
1485 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1486 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1488 /* Set the window text with the text specified in the OPENFILENAME structure */
1491 SetWindowTextW(hwnd
,fodInfos
->title
);
1493 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1496 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1497 SetWindowTextW(hwnd
, buf
);
1500 /* Initialise the file name edit control */
1501 handledPath
= FALSE
;
1502 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1504 if(fodInfos
->filename
)
1506 /* 1. If win2000 or higher and filename contains a path, use it
1507 in preference over the lpstrInitialDir */
1508 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1509 WCHAR tmpBuf
[MAX_PATH
];
1513 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1516 /* nameBit is always shorter than the original filename. It may be NULL
1517 * when the filename contains only a drive name instead of file name */
1520 lstrcpyW(fodInfos
->filename
,nameBit
);
1524 *fodInfos
->filename
= '\0';
1526 MemFree(fodInfos
->initdir
);
1527 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1528 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1530 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1531 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1533 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1536 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1540 /* 2. (All platforms) If initdir is not null, then use it */
1541 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1543 /* Work out the proper path as supplied one might be relative */
1544 /* (Here because supplying '.' as dir browses to My Computer) */
1545 WCHAR tmpBuf
[MAX_PATH
];
1546 WCHAR tmpBuf2
[MAX_PATH
];
1550 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1551 if (PathFileExistsW(tmpBuf
)) {
1552 /* initdir does not have to be a directory. If a file is
1553 * specified, the dir part is taken */
1554 if (PathIsDirectoryW(tmpBuf
)) {
1555 PathAddBackslashW(tmpBuf
);
1556 lstrcatW(tmpBuf
, szwStar
);
1558 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1561 MemFree(fodInfos
->initdir
);
1562 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1563 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1565 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1568 else if (fodInfos
->initdir
)
1570 MemFree(fodInfos
->initdir
);
1571 fodInfos
->initdir
= NULL
;
1572 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1576 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1578 /* 3. All except w2k+: if filename contains a path use it */
1579 if (!win2000plus
&& fodInfos
->filename
&&
1580 *fodInfos
->filename
&&
1581 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1582 WCHAR tmpBuf
[MAX_PATH
];
1586 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1591 /* nameBit is always shorter than the original filename */
1592 lstrcpyW(fodInfos
->filename
, nameBit
);
1595 len
= lstrlenW(tmpBuf
);
1596 MemFree(fodInfos
->initdir
);
1597 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1598 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1601 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1602 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1604 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1607 /* 4. Win2000+: Recently used */
1608 if (!handledPath
&& win2000plus
) {
1609 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1610 fodInfos
->initdir
[0] = '\0';
1612 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1614 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1617 MemFree(fodInfos
->initdir
);
1618 fodInfos
->initdir
= NULL
;
1622 /* 5. win98+ and win2000+ if any files of specified filter types in
1623 current directory, use it */
1624 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1626 LPCWSTR lpstrPos
= fodInfos
->filter
;
1627 WIN32_FIND_DATAW FindFileData
;
1632 /* filter is a list... title\0ext\0......\0\0 */
1634 /* Skip the title */
1635 if(! *lpstrPos
) break; /* end */
1636 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1638 /* See if any files exist in the current dir with this extension */
1639 if(! *lpstrPos
) break; /* end */
1641 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1643 if (hFind
== INVALID_HANDLE_VALUE
) {
1644 /* None found - continue search */
1645 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1649 MemFree(fodInfos
->initdir
);
1650 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1651 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1654 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1655 debugstr_w(lpstrPos
));
1662 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1663 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1664 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1666 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1668 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1671 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1672 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1674 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1677 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1680 } else if (!handledPath
) {
1681 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1682 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1684 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1687 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1688 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1690 /* Must the open as read only check box be checked ?*/
1691 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1693 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1696 /* Must the open as read only check box be hidden? */
1697 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1699 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1700 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1703 /* Must the help button be hidden? */
1704 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1706 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1707 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1710 /* change Open to Save */
1711 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1714 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1715 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1716 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1717 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1720 /* Initialize the filter combo box */
1721 FILEDLG95_FILETYPE_Init(hwnd
);
1726 /***********************************************************************
1727 * FILEDLG95_ResizeControls
1729 * WM_INITDIALOG message handler (after hook notification)
1731 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1733 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1735 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1738 UINT flags
= SWP_NOACTIVATE
;
1740 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1741 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1743 /* resize the custom dialog to the parent size */
1744 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1745 GetClientRect(hwnd
, &rc
);
1748 /* our own fake template is zero sized and doesn't have children, so
1749 * there is no need to resize it. Picasa depends on it.
1751 flags
|= SWP_NOSIZE
;
1754 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1755 0, 0, rc
.right
, rc
.bottom
, flags
);
1759 /* Resize the height; if opened as read-only, checkbox and help button are
1760 * hidden and we are not using a custom template nor a customDialog
1762 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1763 (!(fodInfos
->ofnInfos
->Flags
&
1764 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1766 RECT rectDlg
, rectHelp
, rectCancel
;
1767 GetWindowRect(hwnd
, &rectDlg
);
1768 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1769 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1770 /* subtract the height of the help button plus the space between the help
1771 * button and the cancel button to the height of the dialog
1773 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1774 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1775 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1781 /***********************************************************************
1782 * FILEDLG95_FillControls
1784 * WM_INITDIALOG message handler (after hook notification)
1786 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1788 LPITEMIDLIST pidlItemId
= NULL
;
1790 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1792 TRACE("dir=%s file=%s\n",
1793 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1795 /* Get the initial directory pidl */
1797 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1799 WCHAR path
[MAX_PATH
];
1801 GetCurrentDirectoryW(MAX_PATH
,path
);
1802 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1805 /* Initialise shell objects */
1806 FILEDLG95_SHELL_Init(hwnd
);
1808 /* Initialize the Look In combo box */
1809 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1811 /* Browse to the initial directory */
1812 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1814 /* Free pidlItem memory */
1815 COMDLG32_SHFree(pidlItemId
);
1819 /***********************************************************************
1822 * Regroups all the cleaning functions of the filedlg
1824 void FILEDLG95_Clean(HWND hwnd
)
1826 FILEDLG95_FILETYPE_Clean(hwnd
);
1827 FILEDLG95_LOOKIN_Clean(hwnd
);
1828 FILEDLG95_SHELL_Clean(hwnd
);
1830 /***********************************************************************
1831 * FILEDLG95_OnWMCommand
1833 * WM_COMMAND message handler
1835 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1837 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1838 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1839 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1845 FILEDLG95_OnOpen(hwnd
);
1849 FILEDLG95_Clean(hwnd
);
1850 EndDialog(hwnd
, FALSE
);
1852 /* Filetype combo box */
1854 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1856 /* LookIn combo box */
1858 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1861 /* --- toolbar --- */
1862 /* Up folder button */
1863 case FCIDM_TB_UPFOLDER
:
1864 FILEDLG95_SHELL_UpFolder(hwnd
);
1866 /* New folder button */
1867 case FCIDM_TB_NEWFOLDER
:
1868 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1870 /* List option button */
1871 case FCIDM_TB_SMALLICON
:
1872 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1874 /* Details option button */
1875 case FCIDM_TB_REPORTVIEW
:
1876 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1878 /* Details option button */
1879 case FCIDM_TB_DESKTOP
:
1880 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1888 /* Do not use the listview selection anymore */
1889 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1893 /***********************************************************************
1894 * FILEDLG95_OnWMGetIShellBrowser
1896 * WM_GETISHELLBROWSER message handler
1898 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1900 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1904 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1910 /***********************************************************************
1911 * FILEDLG95_SendFileOK
1913 * Sends the CDN_FILEOK notification if required
1916 * TRUE if the dialog should close
1917 * FALSE if the dialog should not be closed
1919 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1921 /* ask the hook if we can close */
1922 if(IsHooked(fodInfos
))
1927 /* First send CDN_FILEOK as MSDN doc says */
1928 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1929 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1932 TRACE("canceled\n");
1936 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1937 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1938 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1941 TRACE("canceled\n");
1948 /***********************************************************************
1949 * FILEDLG95_OnOpenMultipleFiles
1951 * Handles the opening of multiple files.
1954 * check destination buffer size
1956 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1958 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1959 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1960 UINT nCount
, nSizePath
;
1964 if(fodInfos
->unicode
)
1966 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1967 ofn
->lpstrFile
[0] = '\0';
1971 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1972 ofn
->lpstrFile
[0] = '\0';
1975 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1977 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1978 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1979 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1981 LPWSTR lpstrTemp
= lpstrFileList
;
1983 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1987 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1990 WCHAR lpstrNotFound
[100];
1991 WCHAR lpstrMsg
[100];
1993 static const WCHAR nl
[] = {'\n',0};
1995 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1996 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1998 lstrcpyW(tmp
, lpstrTemp
);
2000 lstrcatW(tmp
, lpstrNotFound
);
2002 lstrcatW(tmp
, lpstrMsg
);
2004 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2008 /* move to the next file in the list of files */
2009 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2010 COMDLG32_SHFree(pidl
);
2014 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2015 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2017 /* For "oldstyle" dialog the components have to
2018 be separated by blanks (not '\0'!) and short
2019 filenames have to be used! */
2020 FIXME("Components have to be separated by blanks\n");
2022 if(fodInfos
->unicode
)
2024 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2025 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2026 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2030 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2032 if (ofn
->lpstrFile
!= NULL
)
2034 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2035 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2036 if (ofn
->nMaxFile
> nSizePath
)
2038 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2039 ofn
->lpstrFile
+ nSizePath
,
2040 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2045 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2046 fodInfos
->ofnInfos
->nFileExtension
= 0;
2048 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2051 /* clean and exit */
2052 FILEDLG95_Clean(hwnd
);
2053 return EndDialog(hwnd
,TRUE
);
2056 /* Returns the 'slot name' of the given module_name in the registry's
2057 * most-recently-used list. This will be an ASCII value in the
2058 * range ['a','z'). Returns zero on error.
2060 * The slot's value in the registry has the form:
2061 * module_name\0mru_path\0
2063 * If stored_path is given, then stored_path will contain the path name
2064 * stored in the registry's MRU list for the given module_name.
2066 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2067 * MRU list key for the given module_name.
2069 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2071 WCHAR mru_list
[32], *cur_mru_slot
;
2072 BOOL taken
[25] = {0};
2073 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2074 HKEY hkey_tmp
, *hkey
;
2083 *stored_path
= '\0';
2085 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2087 WARN("Unable to create MRU key: %d\n", ret
);
2091 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2092 (LPBYTE
)mru_list
, &mru_list_size
);
2093 if(ret
|| key_type
!= REG_SZ
){
2094 if(ret
== ERROR_FILE_NOT_FOUND
)
2097 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2102 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2103 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2104 DWORD value_data_size
= sizeof(value_data
);
2106 *value_name
= *cur_mru_slot
;
2108 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2109 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2110 if(ret
|| key_type
!= REG_BINARY
){
2111 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2115 if(!strcmpiW(module_name
, value_data
)){
2119 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2127 /* the module name isn't in the registry, so find the next open slot */
2128 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2129 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2130 for(i
= 0; i
< 25; ++i
){
2135 /* all slots are taken, so return the last one in MRUList */
2137 return *cur_mru_slot
;
2140 /* save the given filename as most-recently-used path for this module */
2141 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2143 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2147 /* get the current executable's name */
2148 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2149 WARN("GotModuleFileName failed: %d\n", GetLastError());
2152 module_name
= strrchrW(module_path
, '\\');
2154 module_name
= module_path
;
2158 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2163 { /* update the slot's info */
2164 WCHAR
*path_ends
, *final
;
2165 DWORD path_len
, final_len
;
2167 /* use only the path segment of `filename' */
2168 path_ends
= strrchrW(filename
, '\\');
2169 path_len
= path_ends
- filename
;
2171 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2173 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2176 lstrcpyW(final
, module_name
);
2177 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2178 final
[final_len
-1] = '\0';
2180 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2181 final_len
* sizeof(WCHAR
));
2183 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2192 { /* update MRUList value */
2193 WCHAR old_mru_list
[32], new_mru_list
[32];
2194 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2195 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2197 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2198 (LPBYTE
)old_mru_list
, &mru_list_size
);
2199 if(ret
|| key_type
!= REG_SZ
){
2200 if(ret
== ERROR_FILE_NOT_FOUND
){
2201 new_mru_list
[0] = slot
;
2202 new_mru_list
[1] = '\0';
2204 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2209 /* copy old list data over so that the new slot is at the start
2211 *new_mru_slot
++ = slot
;
2212 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2213 if(*old_mru_slot
!= slot
)
2214 *new_mru_slot
++ = *old_mru_slot
;
2216 *new_mru_slot
= '\0';
2219 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2220 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2222 WARN("Error saving MRUList data: %d\n", ret
);
2229 /* load the most-recently-used path for this module */
2230 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2232 WCHAR module_path
[MAX_PATH
], *module_name
;
2234 /* get the current executable's name */
2235 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2236 WARN("GotModuleFileName failed: %d\n", GetLastError());
2239 module_name
= strrchrW(module_path
, '\\');
2241 module_name
= module_path
;
2245 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2246 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2249 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2251 WCHAR strMsgTitle
[MAX_PATH
];
2252 WCHAR strMsgText
[MAX_PATH
];
2254 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2256 strMsgTitle
[0] = '\0';
2257 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2258 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2261 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2262 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2264 int nOpenAction
= defAction
;
2265 LPWSTR lpszTemp
, lpszTemp1
;
2266 LPITEMIDLIST pidl
= NULL
;
2267 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2269 /* check for invalid chars */
2270 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2272 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2276 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2278 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2281 LPSHELLFOLDER lpsfChild
;
2282 WCHAR lpwstrTemp
[MAX_PATH
];
2283 DWORD dwEaten
, dwAttributes
;
2286 lstrcpyW(lpwstrTemp
, lpszTemp
);
2287 p
= PathFindNextComponentW(lpwstrTemp
);
2289 if (!p
) break; /* end of path */
2292 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2294 /* There are no wildcards when OFN_NOVALIDATE is set */
2295 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2297 static const WCHAR wszWild
[] = { '*', '?', 0 };
2298 /* if the last element is a wildcard do a search */
2299 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2301 nOpenAction
= ONOPEN_SEARCH
;
2305 lpszTemp1
= lpszTemp
;
2307 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2309 /* append a backslash to drive letters */
2310 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2311 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2312 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2314 PathAddBackslashW(lpwstrTemp
);
2317 dwAttributes
= SFGAO_FOLDER
;
2318 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2320 /* the path component is valid, we have a pidl of the next path component */
2321 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2322 if(dwAttributes
& SFGAO_FOLDER
)
2324 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2326 ERR("bind to failed\n"); /* should not fail */
2329 IShellFolder_Release(*ppsf
);
2337 /* end dialog, return value */
2338 nOpenAction
= ONOPEN_OPEN
;
2341 COMDLG32_SHFree(pidl
);
2344 else if (!(flags
& OFN_NOVALIDATE
))
2346 if(*lpszTemp
|| /* points to trailing null for last path element */
2347 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2349 if(flags
& OFN_PATHMUSTEXIST
)
2351 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2357 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2359 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2363 /* change to the current folder */
2364 nOpenAction
= ONOPEN_OPEN
;
2369 nOpenAction
= ONOPEN_OPEN
;
2373 if(pidl
) COMDLG32_SHFree(pidl
);
2378 /***********************************************************************
2381 * Ok button WM_COMMAND message handler
2383 * If the function succeeds, the return value is nonzero.
2385 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2387 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2388 LPWSTR lpstrFileList
;
2389 UINT nFileCount
= 0;
2392 WCHAR lpstrPathAndFile
[MAX_PATH
];
2393 LPSHELLFOLDER lpsf
= NULL
;
2396 TRACE("hwnd=%p\n", hwnd
);
2398 /* try to browse the selected item */
2399 if(BrowseSelectedFolder(hwnd
))
2402 /* get the files from the edit control */
2403 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2410 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2414 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2417 Step 1: Build a complete path name from the current folder and
2418 the filename or path in the edit box.
2420 - the path in the edit box is a root path
2421 (with or without drive letter)
2422 - the edit box contains ".." (or a path with ".." in it)
2425 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2426 MemFree(lpstrFileList
);
2429 Step 2: here we have a cleaned up path
2431 We have to parse the path step by step to see if we have to browse
2432 to a folder if the path points to a directory or the last
2433 valid element is a directory.
2436 lpstrPathAndFile: cleaned up path
2440 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2441 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2442 nOpenAction
= ONOPEN_OPEN
;
2444 nOpenAction
= ONOPEN_BROWSE
;
2446 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2447 fodInfos
->ofnInfos
->Flags
,
2448 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2454 Step 3: here we have a cleaned up and validated path
2457 lpsf: ShellFolder bound to the rightmost valid path component
2458 lpstrPathAndFile: cleaned up path
2459 nOpenAction: action to do
2461 TRACE("end validate sf=%p\n", lpsf
);
2465 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2466 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2469 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2472 /* replace the current filter */
2473 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2474 len
= lstrlenW(lpszTemp
)+1;
2475 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2476 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2478 /* set the filter cb to the extension when possible */
2479 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2480 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2483 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2484 TRACE("ONOPEN_BROWSE\n");
2486 IPersistFolder2
* ppf2
;
2487 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2489 LPITEMIDLIST pidlCurrent
;
2490 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2491 IPersistFolder2_Release(ppf2
);
2492 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2494 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2495 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2497 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2498 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2501 else if( nOpenAction
== ONOPEN_SEARCH
)
2503 if (fodInfos
->Shell
.FOIShellView
)
2504 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2506 COMDLG32_SHFree(pidlCurrent
);
2507 if (filename_is_edit( fodInfos
))
2508 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2513 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2514 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2520 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2521 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2525 /* update READONLY check box flag */
2526 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2527 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2529 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2531 /* Attach the file extension with file name*/
2532 ext
= PathFindExtensionW(lpstrPathAndFile
);
2533 if (! *ext
&& fodInfos
->defext
)
2535 /* if no extension is specified with file name, then */
2536 /* attach the extension from file filter or default one */
2538 WCHAR
*filterExt
= NULL
;
2539 LPWSTR lpstrFilter
= NULL
;
2540 static const WCHAR szwDot
[] = {'.',0};
2541 int PathLength
= lstrlenW(lpstrPathAndFile
);
2543 /*Get the file extension from file type filter*/
2544 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2545 fodInfos
->ofnInfos
->nFilterIndex
-1);
2547 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2549 WCHAR
* filterSearchIndex
;
2550 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2551 strcpyW(filterExt
, lpstrFilter
);
2553 /* if a semicolon-separated list of file extensions was given, do not include the
2554 semicolon or anything after it in the extension.
2555 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2556 filterSearchIndex
= strchrW(filterExt
, ';');
2557 if (filterSearchIndex
)
2559 filterSearchIndex
[0] = '\0';
2562 /* find the file extension by searching for the first dot in filterExt */
2563 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2564 /* if the extension is invalid or contains a glob, ignore it */
2565 filterSearchIndex
= strchrW(filterExt
, '.');
2566 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2568 strcpyW(filterExt
, filterSearchIndex
);
2572 HeapFree(GetProcessHeap(), 0, filterExt
);
2579 /* use the default file extension */
2580 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2581 strcpyW(filterExt
, fodInfos
->defext
);
2584 if (*filterExt
) /* ignore filterExt="" */
2587 lstrcatW(lpstrPathAndFile
, szwDot
);
2588 /* Attach the extension */
2589 lstrcatW(lpstrPathAndFile
, filterExt
);
2592 HeapFree(GetProcessHeap(), 0, filterExt
);
2594 /* In Open dialog: if file does not exist try without extension */
2595 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2596 lpstrPathAndFile
[PathLength
] = '\0';
2598 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2601 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2602 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2604 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2607 /* In Save dialog: check if the file already exists */
2608 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2609 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2610 && PathFileExistsW(lpstrPathAndFile
))
2612 WCHAR lpstrOverwrite
[100];
2615 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2616 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2617 MB_YESNO
| MB_ICONEXCLAMATION
);
2618 if (answer
== IDNO
|| answer
== IDCANCEL
)
2625 /* In Open dialog: check if it should be created if it doesn't exist */
2626 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2627 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2628 && !PathFileExistsW(lpstrPathAndFile
))
2630 WCHAR lpstrCreate
[100];
2633 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2634 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2635 MB_YESNO
| MB_ICONEXCLAMATION
);
2636 if (answer
== IDNO
|| answer
== IDCANCEL
)
2643 /* Check that the size of the file does not exceed buffer size.
2644 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2645 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2646 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2649 /* fill destination buffer */
2650 if (fodInfos
->ofnInfos
->lpstrFile
)
2652 if(fodInfos
->unicode
)
2654 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2656 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2657 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2658 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2662 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2664 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2665 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2666 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2667 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2671 if(fodInfos
->unicode
)
2675 /* set filename offset */
2676 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2677 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2679 /* set extension offset */
2680 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2681 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2686 CHAR tempFileA
[MAX_PATH
];
2688 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2689 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2690 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2692 /* set filename offset */
2693 lpszTemp
= PathFindFileNameA(tempFileA
);
2694 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2696 /* set extension offset */
2697 lpszTemp
= PathFindExtensionA(tempFileA
);
2698 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2701 /* set the lpstrFileTitle */
2702 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2704 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2705 if(fodInfos
->unicode
)
2707 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2708 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2712 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2713 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2714 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2718 /* copy currently selected filter to lpstrCustomFilter */
2719 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2721 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2722 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2723 NULL
, 0, NULL
, NULL
);
2724 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2726 LPSTR s
= ofn
->lpstrCustomFilter
;
2727 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2728 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2729 s
, len
, NULL
, NULL
);
2734 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2737 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2740 FILEDLG95_Clean(hwnd
);
2741 ret
= EndDialog(hwnd
, TRUE
);
2747 size
= lstrlenW(lpstrPathAndFile
) + 1;
2748 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2750 /* return needed size in first two bytes of lpstrFile */
2751 if(fodInfos
->ofnInfos
->lpstrFile
)
2752 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2753 FILEDLG95_Clean(hwnd
);
2754 ret
= EndDialog(hwnd
, FALSE
);
2755 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2762 if(lpsf
) IShellFolder_Release(lpsf
);
2766 /***********************************************************************
2767 * FILEDLG95_SHELL_Init
2769 * Initialisation of the shell objects
2771 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2773 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2778 * Initialisation of the FileOpenDialogInfos structure
2784 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2786 /* Disable multi-select if flag not set */
2787 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2789 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2791 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2792 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2794 /* Construct the IShellBrowser interface */
2795 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2800 /***********************************************************************
2801 * FILEDLG95_SHELL_ExecuteCommand
2803 * Change the folder option and refresh the view
2804 * If the function succeeds, the return value is nonzero.
2806 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2808 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2811 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2813 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2818 CMINVOKECOMMANDINFO ci
;
2819 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2820 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2824 IContextMenu_InvokeCommand(pcm
, &ci
);
2825 IContextMenu_Release(pcm
);
2831 /***********************************************************************
2832 * FILEDLG95_SHELL_UpFolder
2834 * Browse to the specified object
2835 * If the function succeeds, the return value is nonzero.
2837 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2839 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2843 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2847 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2848 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2854 /***********************************************************************
2855 * FILEDLG95_SHELL_BrowseToDesktop
2857 * Browse to the Desktop
2858 * If the function succeeds, the return value is nonzero.
2860 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2862 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2868 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2869 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2870 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2871 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2872 COMDLG32_SHFree(pidl
);
2873 return SUCCEEDED(hres
);
2875 /***********************************************************************
2876 * FILEDLG95_SHELL_Clean
2878 * Cleans the memory used by shell objects
2880 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2882 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2886 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2888 /* clean Shell interfaces */
2889 if (fodInfos
->Shell
.FOIShellView
)
2891 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2892 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2894 if (fodInfos
->Shell
.FOIShellFolder
)
2895 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2896 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2897 if (fodInfos
->Shell
.FOIDataObject
)
2898 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2901 /***********************************************************************
2902 * FILEDLG95_FILETYPE_Init
2904 * Initialisation of the file type combo box
2906 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2908 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2909 int nFilters
= 0; /* number of filters */
2914 if(fodInfos
->customfilter
)
2916 /* customfilter has one entry... title\0ext\0
2917 * Set first entry of combo box item with customfilter
2920 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2923 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2925 /* Copy the extensions */
2926 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2927 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2928 lstrcpyW(lpstrExt
,lpstrPos
);
2930 /* Add the item at the end of the combo */
2931 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2932 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2935 if(fodInfos
->filter
)
2937 LPCWSTR lpstrPos
= fodInfos
->filter
;
2941 /* filter is a list... title\0ext\0......\0\0
2942 * Set the combo item text to the title and the item data
2945 LPCWSTR lpstrDisplay
;
2949 if(! *lpstrPos
) break; /* end */
2950 lpstrDisplay
= lpstrPos
;
2951 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2953 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2957 /* Copy the extensions */
2958 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2959 lstrcpyW(lpstrExt
,lpstrPos
);
2960 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2962 /* Add the item at the end of the combo */
2963 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2965 /* malformed filters are added anyway... */
2966 if (!*lpstrExt
) break;
2971 * Set the current filter to the one specified
2972 * in the initialisation structure
2974 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2978 /* Check to make sure our index isn't out of bounds. */
2979 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2980 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2981 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2983 /* set default filter index */
2984 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2985 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2987 /* calculate index of Combo Box item */
2988 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2989 if (fodInfos
->customfilter
== NULL
)
2992 /* Set the current index selection. */
2993 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2995 /* Get the corresponding text string from the combo box. */
2996 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2999 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3005 CharLowerW(lpstrFilter
); /* lowercase */
3006 len
= lstrlenW(lpstrFilter
)+1;
3007 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3008 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3011 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3015 /***********************************************************************
3016 * FILEDLG95_FILETYPE_OnCommand
3018 * WM_COMMAND of the file type combo box
3019 * If the function succeeds, the return value is nonzero.
3021 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3023 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3031 /* Get the current item of the filetype combo box */
3032 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3034 /* set the current filter index */
3035 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3036 (fodInfos
->customfilter
== NULL
? 1 : 0);
3038 /* Set the current filter with the current selection */
3039 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3041 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3043 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3046 CharLowerW(lpstrFilter
); /* lowercase */
3047 len
= lstrlenW(lpstrFilter
)+1;
3048 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3049 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3050 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3051 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3054 /* Refresh the actual view to display the included items*/
3055 if (fodInfos
->Shell
.FOIShellView
)
3056 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3061 /***********************************************************************
3062 * FILEDLG95_FILETYPE_SearchExt
3064 * searches for an extension in the filetype box
3066 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3068 int i
, iCount
= CBGetCount(hwnd
);
3070 TRACE("%s\n", debugstr_w(lpstrExt
));
3072 if(iCount
!= CB_ERR
)
3074 for(i
=0;i
<iCount
;i
++)
3076 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3083 /***********************************************************************
3084 * FILEDLG95_FILETYPE_Clean
3086 * Clean the memory used by the filetype combo box
3088 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3090 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3092 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3096 /* Delete each string of the combo and their associated data */
3097 if(iCount
!= CB_ERR
)
3099 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3101 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3102 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3105 /* Current filter */
3106 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3110 /***********************************************************************
3111 * FILEDLG95_LOOKIN_Init
3113 * Initialisation of the look in combo box
3116 /* Small helper function, to determine if the unixfs shell extension is rooted
3117 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3119 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3121 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3122 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3123 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3124 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3125 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3126 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3127 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3136 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3138 IShellFolder
*psfRoot
, *psfDrives
;
3139 IEnumIDList
*lpeRoot
, *lpeDrives
;
3140 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3143 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3147 liInfos
->iMaxIndentation
= 0;
3149 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3151 hdc
= GetDC( hwndCombo
);
3152 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3153 GetTextMetricsW( hdc
, &tm
);
3154 ReleaseDC( hwndCombo
, hdc
);
3156 /* set item height for both text field and listbox */
3157 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3158 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3160 /* Turn on the extended UI for the combo box like Windows does */
3161 CBSetExtendedUI(hwndCombo
, TRUE
);
3163 /* Initialise data of Desktop folder */
3164 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3165 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3166 COMDLG32_SHFree(pidlTmp
);
3168 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3170 SHGetDesktopFolder(&psfRoot
);
3174 /* enumerate the contents of the desktop */
3175 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3177 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3179 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3181 /* If the unixfs extension is rooted, we don't expand the drives by default */
3182 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3184 /* special handling for CSIDL_DRIVES */
3185 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3187 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3189 /* enumerate the drives */
3190 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3192 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3194 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3195 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3196 COMDLG32_SHFree(pidlAbsTmp
);
3197 COMDLG32_SHFree(pidlTmp1
);
3199 IEnumIDList_Release(lpeDrives
);
3201 IShellFolder_Release(psfDrives
);
3206 COMDLG32_SHFree(pidlTmp
);
3208 IEnumIDList_Release(lpeRoot
);
3210 IShellFolder_Release(psfRoot
);
3213 COMDLG32_SHFree(pidlDrives
);
3216 /***********************************************************************
3217 * FILEDLG95_LOOKIN_DrawItem
3219 * WM_DRAWITEM message handler
3221 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3223 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3224 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3225 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3229 HIMAGELIST ilItemImage
;
3232 LPSFOLDER tmpFolder
;
3233 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3234 UINT icon_width
, icon_height
;
3238 if(pDIStruct
->itemID
== -1)
3241 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3242 pDIStruct
->itemID
)))
3246 icon_width
= GetSystemMetrics(SM_CXICON
);
3247 icon_height
= GetSystemMetrics(SM_CYICON
);
3248 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3250 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3251 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3252 shgfi_flags
|= SHGFI_SMALLICON
;
3255 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3256 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3258 /* Is this item selected ? */
3259 if(pDIStruct
->itemState
& ODS_SELECTED
)
3261 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3262 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3263 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3267 SetTextColor(pDIStruct
->hDC
,crText
);
3268 SetBkColor(pDIStruct
->hDC
,crWin
);
3269 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3272 /* Do not indent item if drawing in the edit of the combo */
3273 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3276 iIndentation
= tmpFolder
->m_iIndent
;
3278 /* Draw text and icon */
3280 /* Initialise the icon display area */
3281 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3282 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3283 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3284 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3286 /* Initialise the text display area */
3287 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3288 rectText
.left
= rectIcon
.right
;
3290 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3291 rectText
.right
= pDIStruct
->rcItem
.right
;
3293 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3295 /* Draw the icon from the image list */
3296 ImageList_Draw(ilItemImage
,
3303 /* Draw the associated text */
3304 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3308 /***********************************************************************
3309 * FILEDLG95_LOOKIN_OnCommand
3311 * LookIn combo box WM_COMMAND message handler
3312 * If the function succeeds, the return value is nonzero.
3314 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3316 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3318 TRACE("%p\n", fodInfos
);
3324 LPSFOLDER tmpFolder
;
3327 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3329 if( iItem
== CB_ERR
) return FALSE
;
3331 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3336 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3337 tmpFolder
->pidlItem
,
3340 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3341 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3351 /***********************************************************************
3352 * FILEDLG95_LOOKIN_AddItem
3354 * Adds an absolute pidl item to the lookin combo box
3355 * returns the index of the inserted item
3357 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3359 LPITEMIDLIST pidlNext
;
3362 LookInInfos
*liInfos
;
3364 TRACE("%08x\n", iInsertId
);
3369 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3372 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3373 tmpFolder
->m_iIndent
= 0;
3375 /* Calculate the indentation of the item in the lookin*/
3377 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3379 tmpFolder
->m_iIndent
++;
3382 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3384 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3385 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3387 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3388 SHGetFileInfoW((LPCWSTR
)pidl
,
3392 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3393 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3395 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3397 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3401 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3403 /* Add the item at the end of the list */
3406 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3408 /* Insert the item at the iInsertId position*/
3411 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3414 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3418 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3419 MemFree( tmpFolder
);
3424 /***********************************************************************
3425 * FILEDLG95_LOOKIN_InsertItemAfterParent
3427 * Insert an item below its parent
3429 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3432 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3437 if (pidl
== pidlParent
)
3440 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3444 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3447 /* Free pidlParent memory */
3448 COMDLG32_SHFree(pidlParent
);
3450 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3453 /***********************************************************************
3454 * FILEDLG95_LOOKIN_SelectItem
3456 * Adds an absolute pidl item to the lookin combo box
3457 * returns the index of the inserted item
3459 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3462 LookInInfos
*liInfos
;
3466 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3468 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3472 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3473 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3478 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3479 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3483 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3485 if(iRemovedItem
< iItemPos
)
3490 CBSetCurSel(hwnd
,iItemPos
);
3491 liInfos
->uSelectedItem
= iItemPos
;
3497 /***********************************************************************
3498 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3500 * Remove the item with an expansion level over iExpansionLevel
3502 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3505 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3509 if(liInfos
->iMaxIndentation
<= 2)
3512 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3514 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3515 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3517 CBDeleteString(hwnd
,iItemPos
);
3518 liInfos
->iMaxIndentation
--;
3526 /***********************************************************************
3527 * FILEDLG95_LOOKIN_SearchItem
3529 * Search for pidl in the lookin combo box
3530 * returns the index of the found item
3532 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3535 int iCount
= CBGetCount(hwnd
);
3537 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3539 if (iCount
!= CB_ERR
)
3543 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3545 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3547 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3555 /***********************************************************************
3556 * FILEDLG95_LOOKIN_Clean
3558 * Clean the memory used by the lookin combo box
3560 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3562 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3563 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3565 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3569 /* Delete each string of the combo and their associated data */
3570 if (iCount
!= CB_ERR
)
3572 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3574 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3575 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3577 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3581 /* LookInInfos structure */
3583 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3586 /***********************************************************************
3589 * Fill the FORMATETC used in the shell id list
3591 static FORMATETC
get_def_format(void)
3593 static CLIPFORMAT cfFormat
;
3594 FORMATETC formatetc
;
3596 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3597 formatetc
.cfFormat
= cfFormat
;
3599 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3600 formatetc
.lindex
= -1;
3601 formatetc
.tymed
= TYMED_HGLOBAL
;
3605 /***********************************************************************
3606 * FILEDLG95_FILENAME_FillFromSelection
3608 * fills the edit box from the cached DataObject
3610 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3612 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3614 LPWSTR lpstrAllFiles
, lpstrTmp
;
3615 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3618 FORMATETC formatetc
= get_def_format();
3622 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3625 cida
= GlobalLock(medium
.u
.hGlobal
);
3626 nFileSelected
= cida
->cidl
;
3628 /* Allocate a buffer */
3629 nAllFilesMaxLength
= MAX_PATH
+ 3;
3630 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3634 /* Loop through the selection, handle only files (not folders) */
3635 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3637 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3640 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3642 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3644 nAllFilesMaxLength
*= 2;
3645 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3648 lpstrAllFiles
= lpstrTmp
;
3651 lpstrAllFiles
[nAllFilesLength
++] = '"';
3652 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3653 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3654 nAllFilesLength
+= nThisFileLength
;
3655 lpstrAllFiles
[nAllFilesLength
++] = '"';
3656 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3663 /* If there's only one file, use the name as-is without quotes */
3664 lpstrTmp
= lpstrAllFiles
;
3668 lpstrTmp
[nThisFileLength
] = 0;
3670 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3671 /* Select the file name like Windows does */
3672 if (filename_is_edit(fodInfos
))
3673 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3677 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3678 COMCTL32_ReleaseStgMedium(medium
);
3682 /* copied from shell32 to avoid linking to it
3683 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3684 * is dependent on whether emulated OS is unicode or not.
3686 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3691 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3692 COMDLG32_SHFree(src
->u
.pOleStr
);
3696 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3701 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3706 FIXME("unknown type %x!\n", src
->uType
);
3707 if (len
) *dest
= '\0';
3713 /***********************************************************************
3714 * FILEDLG95_FILENAME_GetFileNames
3716 * Copies the filenames to a delimited string list.
3718 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3720 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3721 UINT nFileCount
= 0; /* number of files */
3722 UINT nStrLen
= 0; /* length of string in edit control */
3723 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3727 /* get the filenames from the filename control */
3728 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3729 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3730 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3732 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3734 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3740 * DATAOBJECT Helper functions
3743 /***********************************************************************
3744 * COMCTL32_ReleaseStgMedium
3746 * like ReleaseStgMedium from ole32
3748 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3750 if(medium
.pUnkForRelease
)
3752 IUnknown_Release(medium
.pUnkForRelease
);
3756 GlobalUnlock(medium
.u
.hGlobal
);
3757 GlobalFree(medium
.u
.hGlobal
);
3761 /***********************************************************************
3762 * GetPidlFromDataObject
3764 * Return pidl(s) by number from the cached DataObject
3766 * nPidlIndex=0 gets the fully qualified root path
3768 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3772 FORMATETC formatetc
= get_def_format();
3773 LPITEMIDLIST pidl
= NULL
;
3775 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3780 /* Get the pidls from IDataObject */
3781 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3783 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3784 if(nPidlIndex
<= cida
->cidl
)
3786 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3788 COMCTL32_ReleaseStgMedium(medium
);
3793 /***********************************************************************
3796 * Return the number of selected items in the DataObject.
3799 static UINT
GetNumSelected( IDataObject
*doSelected
)
3803 FORMATETC formatetc
= get_def_format();
3805 TRACE("sv=%p\n", doSelected
);
3807 if (!doSelected
) return 0;
3809 /* Get the pidls from IDataObject */
3810 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3812 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3813 retVal
= cida
->cidl
;
3814 COMCTL32_ReleaseStgMedium(medium
);
3824 /***********************************************************************
3827 * Get the pidl's display name (relative to folder) and
3828 * put it in lpstrFileName.
3830 * Return NOERROR on success,
3834 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3839 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3843 SHGetDesktopFolder(&lpsf
);
3844 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3845 IShellFolder_Release(lpsf
);
3849 /* Get the display name of the pidl relative to the folder */
3850 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3852 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3857 /***********************************************************************
3858 * GetShellFolderFromPidl
3860 * pidlRel is the item pidl relative
3861 * Return the IShellFolder of the absolute pidl
3863 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3865 IShellFolder
*psf
= NULL
,*psfParent
;
3867 TRACE("%p\n", pidlAbs
);
3869 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3872 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3874 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3876 IShellFolder_Release(psfParent
);
3880 /* return the desktop */
3886 /***********************************************************************
3889 * Return the LPITEMIDLIST to the parent of the pidl in the list
3891 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3893 LPITEMIDLIST pidlParent
;
3895 TRACE("%p\n", pidl
);
3897 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3898 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3903 /***********************************************************************
3906 * returns the pidl of the file name relative to folder
3907 * NULL if an error occurred
3909 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3911 LPITEMIDLIST pidl
= NULL
;
3914 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3916 if(!lpcstrFileName
) return NULL
;
3917 if(!*lpcstrFileName
) return NULL
;
3921 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3922 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3923 IShellFolder_Release(lpsf
);
3928 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3935 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3937 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3940 TRACE("%p, %p\n", psf
, pidl
);
3942 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3944 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3945 /* see documentation shell 4.1*/
3946 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3949 /***********************************************************************
3950 * BrowseSelectedFolder
3952 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3954 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3955 BOOL bBrowseSelFolder
= FALSE
;
3959 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3961 LPITEMIDLIST pidlSelection
;
3963 /* get the file selected */
3964 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3965 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3967 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3968 pidlSelection
, SBSP_RELATIVE
) ) )
3971 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
3972 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3974 bBrowseSelFolder
= TRUE
;
3975 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3976 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3978 COMDLG32_SHFree( pidlSelection
);
3981 return bBrowseSelFolder
;
3985 * Memory allocation methods */
3986 static void *MemAlloc(UINT size
)
3988 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3991 static void MemFree(void *mem
)
3993 HeapFree(GetProcessHeap(),0,mem
);
3996 static inline BOOL
valid_struct_size( DWORD size
)
3998 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
3999 (size
== sizeof( OPENFILENAMEW
));
4002 static inline BOOL
is_win16_looks(DWORD flags
)
4004 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4005 !(flags
& OFN_EXPLORER
));
4008 /* ------------------ APIs ---------------------- */
4010 /***********************************************************************
4011 * GetOpenFileNameA (COMDLG32.@)
4013 * Creates a dialog box for the user to select a file to open.
4016 * TRUE on success: user enters a valid file
4017 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4020 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
4022 TRACE("flags %08x\n", ofn
->Flags
);
4024 if (!valid_struct_size( ofn
->lStructSize
))
4026 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4030 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4031 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4032 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4034 if (is_win16_looks(ofn
->Flags
))
4035 return GetFileName31A(ofn
, OPEN_DIALOG
);
4038 FileOpenDlgInfos info
;
4040 init_filedlg_infoA(ofn
, &info
);
4041 return GetFileDialog95(&info
, OPEN_DIALOG
);
4045 /***********************************************************************
4046 * GetOpenFileNameW (COMDLG32.@)
4048 * Creates a dialog box for the user to select a file to open.
4051 * TRUE on success: user enters a valid file
4052 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4055 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4057 TRACE("flags %08x\n", ofn
->Flags
);
4059 if (!valid_struct_size( ofn
->lStructSize
))
4061 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4065 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4066 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4067 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4069 if (is_win16_looks(ofn
->Flags
))
4070 return GetFileName31W(ofn
, OPEN_DIALOG
);
4073 FileOpenDlgInfos info
;
4075 init_filedlg_infoW(ofn
, &info
);
4076 return GetFileDialog95(&info
, OPEN_DIALOG
);
4081 /***********************************************************************
4082 * GetSaveFileNameA (COMDLG32.@)
4084 * Creates a dialog box for the user to select a file to save.
4087 * TRUE on success: user enters a valid file
4088 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4091 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4093 if (!valid_struct_size( ofn
->lStructSize
))
4095 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4099 if (is_win16_looks(ofn
->Flags
))
4100 return GetFileName31A(ofn
, SAVE_DIALOG
);
4103 FileOpenDlgInfos info
;
4105 init_filedlg_infoA(ofn
, &info
);
4106 return GetFileDialog95(&info
, SAVE_DIALOG
);
4110 /***********************************************************************
4111 * GetSaveFileNameW (COMDLG32.@)
4113 * Creates a dialog box for the user to select a file to save.
4116 * TRUE on success: user enters a valid file
4117 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4120 BOOL WINAPI
GetSaveFileNameW(
4121 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4123 if (!valid_struct_size( ofn
->lStructSize
))
4125 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4129 if (is_win16_looks(ofn
->Flags
))
4130 return GetFileName31W(ofn
, SAVE_DIALOG
);
4133 FileOpenDlgInfos info
;
4135 init_filedlg_infoW(ofn
, &info
);
4136 return GetFileDialog95(&info
, SAVE_DIALOG
);
4140 /***********************************************************************
4141 * GetFileTitleA (COMDLG32.@)
4143 * See GetFileTitleW.
4145 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4148 UNICODE_STRING strWFile
;
4151 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4152 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4153 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4154 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4155 RtlFreeUnicodeString( &strWFile
);
4156 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4161 /***********************************************************************
4162 * GetFileTitleW (COMDLG32.@)
4164 * Get the name of a file.
4167 * lpFile [I] name and location of file
4168 * lpTitle [O] returned file name
4169 * cbBuf [I] buffer size of lpTitle
4173 * Failure: negative number.
4175 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4178 static const WCHAR brkpoint
[] = {'*','[',']',0};
4179 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4181 if(lpFile
== NULL
|| lpTitle
== NULL
)
4184 len
= lstrlenW(lpFile
);
4189 if(strpbrkW(lpFile
, brkpoint
))
4194 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4197 for(i
= len
; i
>= 0; i
--)
4199 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4209 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4211 len
= lstrlenW(lpFile
+i
)+1;
4215 lstrcpyW(lpTitle
, &lpFile
[i
]);