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)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
137 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
139 static const WCHAR LastVisitedMRUW
[] =
140 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
141 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
142 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
143 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
144 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
146 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
148 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
150 return GetPropW(hwnd
, filedlg_info_propnameW
);
153 /***********************************************************************
157 /* Internal functions used by the dialog */
158 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
159 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
160 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
161 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
162 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
163 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
164 static void FILEDLG95_Clean(HWND hwnd
);
166 /* Functions used by the shell navigation */
167 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
168 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
169 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
170 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
171 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
173 /* Functions used by the EDIT box */
174 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
176 /* Functions used by the filetype combo box */
177 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
178 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
179 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
180 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
182 /* Functions used by the Look In combo box */
183 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
184 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
185 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
186 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
187 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
188 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
189 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
190 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
191 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
193 /* Functions for dealing with the most-recently-used registry keys */
194 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
195 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
196 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
198 /* Miscellaneous tool functions */
199 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
200 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
201 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
202 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
203 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
204 static UINT
GetNumSelected( IDataObject
*doSelected
);
205 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
207 /* Shell memory allocation */
208 static void *MemAlloc(UINT size
);
209 static void MemFree(void *mem
);
211 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
212 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
213 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
214 static BOOL
BrowseSelectedFolder(HWND hwnd
);
216 /***********************************************************************
219 * Creates an Open common dialog box that lets the user select
220 * the drive, directory, and the name of a file or set of files to open.
222 * IN : The FileOpenDlgInfos structure associated with the dialog
223 * OUT : TRUE on success
224 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
226 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
233 /* test for missing functionality */
234 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
236 FIXME("Flags 0x%08x not yet implemented\n",
237 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
240 /* Create the dialog from a template */
242 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
244 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
247 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
248 !(template = LockResource( hDlgTmpl
)))
250 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
254 /* msdn: explorer style dialogs permit sizing by default.
255 * The OFN_ENABLESIZING flag is only needed when a hook or
256 * custom template is provided */
257 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
258 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
259 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
261 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
263 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
264 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
267 /* old style hook messages */
268 if (IsHooked(fodInfos
))
270 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
271 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
272 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
273 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
276 if (fodInfos
->unicode
)
277 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
279 fodInfos
->ofnInfos
->hwndOwner
,
283 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
285 fodInfos
->ofnInfos
->hwndOwner
,
288 if (fodInfos
->ole_initialized
)
291 /* Unable to create the dialog */
298 static WCHAR
*heap_strdupAtoW(const char *str
)
306 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
307 ret
= MemAlloc(len
* sizeof(WCHAR
));
308 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
313 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
315 INITCOMMONCONTROLSEX icc
;
317 /* Initialize ComboBoxEx32 */
318 icc
.dwSize
= sizeof(icc
);
319 icc
.dwICC
= ICC_USEREX_CLASSES
;
320 InitCommonControlsEx(&icc
);
322 /* Initialize CommDlgExtendedError() */
323 COMDLG32_SetCommDlgExtendedError(0);
325 memset(info
, 0, sizeof(*info
));
327 /* Pass in the original ofn */
328 info
->ofnInfos
= ofn
;
330 info
->title
= ofn
->lpstrTitle
;
331 info
->defext
= ofn
->lpstrDefExt
;
332 info
->filter
= ofn
->lpstrFilter
;
333 info
->customfilter
= ofn
->lpstrCustomFilter
;
337 info
->filename
= MemAlloc(ofn
->nMaxFile
* sizeof(WCHAR
));
338 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
341 if (ofn
->lpstrInitialDir
)
343 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
346 info
->initdir
= MemAlloc(len
* sizeof(WCHAR
));
347 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
351 info
->unicode
= TRUE
;
354 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
359 ofnW
= *(OPENFILENAMEW
*)ofn
;
361 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
362 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
363 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
367 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
368 ofnW
.lpstrFile
= MemAlloc(len
* sizeof(WCHAR
));
369 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
373 if (ofn
->lpstrFilter
)
378 /* filter is a list... title\0ext\0......\0\0 */
379 s
= ofn
->lpstrFilter
;
380 while (*s
) s
= s
+strlen(s
)+1;
382 n
= s
- ofn
->lpstrFilter
;
383 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
384 ofnW
.lpstrFilter
= MemAlloc(len
* sizeof(WCHAR
));
385 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
388 /* convert lpstrCustomFilter */
389 if (ofn
->lpstrCustomFilter
)
394 /* customfilter contains a pair of strings... title\0ext\0 */
395 s
= ofn
->lpstrCustomFilter
;
396 if (*s
) s
= s
+strlen(s
)+1;
397 if (*s
) s
= s
+strlen(s
)+1;
398 n
= s
- ofn
->lpstrCustomFilter
;
399 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
400 ofnW
.lpstrCustomFilter
= MemAlloc(len
* sizeof(WCHAR
));
401 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
404 init_filedlg_infoW(&ofnW
, info
);
406 /* fixup A-specific fields */
407 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
408 info
->unicode
= FALSE
;
410 /* free what was duplicated */
411 MemFree((WCHAR
*)ofnW
.lpstrInitialDir
);
412 MemFree((WCHAR
*)ofnW
.lpstrFile
);
415 /***********************************************************************
418 * Call GetFileName95 with this structure and clean the memory.
420 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
422 WCHAR
*current_dir
= NULL
;
425 /* save current directory */
426 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
428 current_dir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
429 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
435 ret
= GetFileName95(info
);
438 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
439 ret
= GetFileName95(info
);
445 /* set the lpstrFileTitle */
446 if (ret
&& info
->ofnInfos
->lpstrFile
&& info
->ofnInfos
->lpstrFileTitle
)
450 LPOPENFILENAMEW ofn
= info
->ofnInfos
;
451 WCHAR
*file_title
= PathFindFileNameW(ofn
->lpstrFile
);
452 lstrcpynW(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
456 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)info
->ofnInfos
;
457 char *file_title
= PathFindFileNameA(ofn
->lpstrFile
);
458 lstrcpynA(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
464 SetCurrentDirectoryW(current_dir
);
465 MemFree(current_dir
);
470 MemFree((WCHAR
*)info
->defext
);
471 MemFree((WCHAR
*)info
->title
);
472 MemFree((WCHAR
*)info
->filter
);
473 MemFree((WCHAR
*)info
->customfilter
);
476 MemFree(info
->filename
);
477 MemFree(info
->initdir
);
481 /******************************************************************************
482 * COMDLG32_GetDisplayNameOf [internal]
484 * Helper function to get the display name for a pidl.
486 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
487 LPSHELLFOLDER psfDesktop
;
490 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
493 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
494 IShellFolder_Release(psfDesktop
);
498 IShellFolder_Release(psfDesktop
);
499 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
502 /******************************************************************************
503 * COMDLG32_GetCanonicalPath [internal]
505 * Helper function to get the canonical path.
507 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
508 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
510 WCHAR lpstrTemp
[MAX_PATH
];
512 /* Get the current directory name */
513 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
516 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
518 PathAddBackslashW(lpstrPathAndFile
);
520 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
522 /* if the user specified a fully qualified path use it */
523 if(PathIsRelativeW(lpstrFile
))
525 lstrcatW(lpstrPathAndFile
, lpstrFile
);
529 /* does the path have a drive letter? */
530 if (PathGetDriveNumberW(lpstrFile
) == -1)
531 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
533 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
536 /* resolve "." and ".." */
537 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
538 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
539 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
542 /***********************************************************************
543 * COMDLG32_SplitFileNames [internal]
545 * Creates a delimited list of filenames.
547 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
549 UINT nStrCharCount
= 0; /* index in src buffer */
550 UINT nFileIndex
= 0; /* index in dest buffer */
551 UINT nFileCount
= 0; /* number of files */
553 /* we might get single filename without any '"',
554 * so we need nStrLen + terminating \0 + end-of-list \0 */
555 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
558 /* build delimited file list from filenames */
559 while ( nStrCharCount
<= nStrLen
)
561 if ( lpstrEdit
[nStrCharCount
]=='"' )
564 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
566 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
569 (*lpstrFileList
)[nFileIndex
++] = 0;
575 /* single, unquoted string */
576 if ((nStrLen
> 0) && (nFileIndex
== 0) )
578 lstrcpyW(*lpstrFileList
, lpstrEdit
);
579 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
584 (*lpstrFileList
)[nFileIndex
++] = '\0';
586 *sizeUsed
= nFileIndex
;
590 /***********************************************************************
591 * ArrangeCtrlPositions [internal]
593 * NOTE: Make sure to add testcases for any changes made here.
595 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
597 HWND hwndChild
, hwndStc32
;
598 RECT rectParent
, rectChild
, rectStc32
;
602 /* Take into account if open as read only checkbox and help button
607 RECT rectHelp
, rectCancel
;
608 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
609 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
610 /* subtract the height of the help button plus the space between
611 * the help button and the cancel button to the height of the dialog
613 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
617 There are two possibilities to add components to the default file dialog box.
619 By default, all the new components are added below the standard dialog box (the else case).
621 However, if there is a static text component with the stc32 id, a special case happens.
622 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
623 in the window and the cx and cy indicate how to size the window.
624 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
625 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
629 GetClientRect(hwndParentDlg
, &rectParent
);
631 /* when arranging controls we have to use fixed parent size */
632 rectParent
.bottom
-= help_fixup
;
634 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
637 GetWindowRect(hwndStc32
, &rectStc32
);
638 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
640 /* set the size of the stc32 control according to the size of
641 * client area of the parent dialog
643 SetWindowPos(hwndStc32
, 0,
645 rectParent
.right
, rectParent
.bottom
,
646 SWP_NOMOVE
| SWP_NOZORDER
);
649 SetRectEmpty(&rectStc32
);
651 /* this part moves controls of the child dialog */
652 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
655 if (hwndChild
!= hwndStc32
)
657 GetWindowRect(hwndChild
, &rectChild
);
658 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
660 /* move only if stc32 exist */
661 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
663 /* move to the right of visible controls of the parent dialog */
664 rectChild
.left
+= rectParent
.right
;
665 rectChild
.left
-= rectStc32
.right
;
667 /* move even if stc32 doesn't exist */
668 if (rectChild
.top
>= rectStc32
.bottom
)
670 /* move below visible controls of the parent dialog */
671 rectChild
.top
+= rectParent
.bottom
;
672 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
675 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
676 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
678 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
681 /* this part moves controls of the parent dialog */
682 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
685 if (hwndChild
!= hwndChildDlg
)
687 GetWindowRect(hwndChild
, &rectChild
);
688 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
690 /* left,top of stc32 marks the position of controls
691 * from the parent dialog
693 rectChild
.left
+= rectStc32
.left
;
694 rectChild
.top
+= rectStc32
.top
;
696 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
697 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
699 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
702 /* calculate the size of the resulting dialog */
704 /* here we have to use original parent size */
705 GetClientRect(hwndParentDlg
, &rectParent
);
706 GetClientRect(hwndChildDlg
, &rectChild
);
707 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
708 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
713 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
714 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
716 chgx
= rectChild
.right
- rectParent
.right
;
718 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
719 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
721 /* Unconditionally set new dialog
722 * height to that of the child
724 chgy
= rectChild
.bottom
- rectParent
.bottom
;
729 chgy
= rectChild
.bottom
- help_fixup
;
731 /* set the size of the parent dialog */
732 GetWindowRect(hwndParentDlg
, &rectParent
);
733 SetWindowPos(hwndParentDlg
, 0,
735 rectParent
.right
- rectParent
.left
+ chgx
,
736 rectParent
.bottom
- rectParent
.top
+ chgy
,
737 SWP_NOMOVE
| SWP_NOZORDER
);
740 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
749 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
759 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
760 * structure's hInstance parameter is not a HINSTANCE, but
761 * instead a pointer to a template resource to use.
763 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
766 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
768 hinst
= COMDLG32_hInstance
;
769 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
771 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
777 hinst
= fodInfos
->ofnInfos
->hInstance
;
778 if(fodInfos
->unicode
)
780 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
781 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
785 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
786 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
790 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
793 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
794 !(template = LockResource( hDlgTmpl
)))
796 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
800 if (fodInfos
->unicode
)
801 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
802 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
803 (LPARAM
)fodInfos
->ofnInfos
);
805 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
806 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
807 (LPARAM
)fodInfos
->ofnInfos
);
810 else if( IsHooked(fodInfos
))
815 WORD menu
,class,title
;
817 GetClientRect(hwnd
,&rectHwnd
);
818 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
819 temp
.tmplate
.dwExtendedStyle
= 0;
820 temp
.tmplate
.cdit
= 0;
825 temp
.menu
= temp
.class = temp
.title
= 0;
827 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
828 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
835 /***********************************************************************
836 * SendCustomDlgNotificationMessage
838 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
841 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
843 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
844 LRESULT hook_result
= 0;
846 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
848 if(!fodInfos
) return 0;
850 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
852 TRACE("CALL NOTIFY for %x\n", uCode
);
853 if(fodInfos
->unicode
)
856 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
857 ofnNotify
.hdr
.idFrom
=0;
858 ofnNotify
.hdr
.code
= uCode
;
859 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
860 ofnNotify
.pszFile
= NULL
;
861 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
866 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
867 ofnNotify
.hdr
.idFrom
=0;
868 ofnNotify
.hdr
.code
= uCode
;
869 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
870 ofnNotify
.pszFile
= NULL
;
871 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
873 TRACE("RET NOTIFY\n");
875 TRACE("Retval: 0x%08lx\n", hook_result
);
879 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
883 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
885 TRACE("CDM_GETFILEPATH:\n");
887 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
890 /* get path and filenames */
891 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
892 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
893 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
896 p
= buffer
+ strlenW(buffer
);
898 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
900 if (fodInfos
->unicode
)
902 total
= strlenW( buffer
) + 1;
903 if (result
) lstrcpynW( result
, buffer
, size
);
904 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
908 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
909 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
910 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
912 HeapFree( GetProcessHeap(), 0, buffer
);
916 /***********************************************************************
917 * FILEDLG95_HandleCustomDialogMessages
919 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
921 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
923 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
924 WCHAR lpstrPath
[MAX_PATH
];
927 if(!fodInfos
) return FALSE
;
931 case CDM_GETFILEPATH
:
932 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
935 case CDM_GETFOLDERPATH
:
936 TRACE("CDM_GETFOLDERPATH:\n");
937 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
940 if (fodInfos
->unicode
)
941 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
943 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
944 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
946 retval
= lstrlenW(lpstrPath
) + 1;
949 case CDM_GETFOLDERIDLIST
:
950 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
951 if (retval
<= wParam
)
952 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
956 TRACE("CDM_GETSPEC:\n");
957 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
960 if (fodInfos
->unicode
)
961 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
963 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
967 case CDM_SETCONTROLTEXT
:
968 TRACE("CDM_SETCONTROLTEXT:\n");
971 if( fodInfos
->unicode
)
972 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
974 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
979 case CDM_HIDECONTROL
:
980 /* MSDN states that it should fail for not OFN_EXPLORER case */
981 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
983 HWND control
= GetDlgItem( hwnd
, wParam
);
984 if (control
) ShowWindow( control
, SW_HIDE
);
991 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
992 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
995 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
999 /***********************************************************************
1000 * FILEDLG95_OnWMGetMMI
1002 * WM_GETMINMAXINFO message handler for resizable dialogs
1004 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1006 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1007 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1008 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1010 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1015 /***********************************************************************
1016 * FILEDLG95_OnWMSize
1018 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1020 * FIXME: this could be made more elaborate. Now use a simple scheme
1021 * where the file view is enlarged and the controls are either moved
1022 * vertically or horizontally to get out of the way. Only the "grip"
1023 * is moved in both directions to stay in the corner.
1025 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1031 FileOpenDlgInfos
*fodInfos
;
1033 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1034 fodInfos
= get_filedlg_infoptr(hwnd
);
1035 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1036 /* get the new dialog rectangle */
1037 GetWindowRect( hwnd
, &rc
);
1038 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1039 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1040 /* not initialized yet */
1041 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1042 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1043 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1045 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1046 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1047 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1048 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1049 /* change the size of the view window */
1050 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1051 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1052 hdwp
= BeginDeferWindowPos( 10);
1053 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1054 rcview
.right
- rcview
.left
+ chgx
,
1055 rcview
.bottom
- rcview
.top
+ chgy
,
1056 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1057 /* change position and sizes of the controls */
1058 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1060 int ctrlid
= GetDlgCtrlID( ctrl
);
1061 GetWindowRect( ctrl
, &rc
);
1062 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1063 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1065 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1067 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1069 else if( rc
.top
> rcview
.bottom
)
1071 /* if it was below the shell view
1075 /* file name (edit or comboboxex) and file types combo change also width */
1079 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1080 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1081 SWP_NOACTIVATE
| SWP_NOZORDER
);
1083 /* then these buttons must move out of the way */
1087 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1089 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1092 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1094 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1097 else if( rc
.left
> rcview
.right
)
1099 /* if it was to the right of the shell view
1101 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1103 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1110 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1112 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1113 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1114 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1116 case IDC_TOOLBARSTATIC
:
1118 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1120 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1123 /* not resized in windows. Since wine uses this invisible control
1124 * to size the browser view it needs to be resized */
1125 case IDC_SHELLSTATIC
:
1126 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1127 rc
.right
- rc
.left
+ chgx
,
1128 rc
.bottom
- rc
.top
+ chgy
,
1129 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1134 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1135 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1137 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1138 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1140 GetWindowRect( ctrl
, &rc
);
1141 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1142 if( rc
.top
> rcview
.bottom
)
1144 /* if it was below the shell view
1146 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1147 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1148 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1150 else if( rc
.left
> rcview
.right
)
1152 /* if it was to the right of the shell view
1154 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1155 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1156 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1159 /* size the custom dialog at the end: some applications do some
1160 * control re-arranging at this point */
1161 GetClientRect(hwnd
, &rc
);
1162 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1163 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1165 EndDeferWindowPos( hdwp
);
1166 /* should not be needed */
1167 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1171 /***********************************************************************
1174 * File open dialog procedure
1176 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1179 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1186 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1188 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1189 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1191 /* Some shell namespace extensions depend on COM being initialized. */
1192 if (SUCCEEDED(OleInitialize(NULL
)))
1193 fodInfos
->ole_initialized
= TRUE
;
1195 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1197 FILEDLG95_InitControls(hwnd
);
1199 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1201 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1202 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1203 RECT client
, client_adjusted
;
1205 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1207 style
|= WS_SIZEBOX
;
1208 ex_style
|= WS_EX_WINDOWEDGE
;
1211 style
&= ~WS_SIZEBOX
;
1212 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1213 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1215 GetClientRect( hwnd
, &client
);
1216 GetClientRect( hwnd
, &client_adjusted
);
1217 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1219 GetWindowRect( hwnd
, &rc
);
1220 rc
.right
+= client_adjusted
.right
- client
.right
;
1221 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1222 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1223 SWP_NOZORDER
| SWP_NOMOVE
);
1225 GetWindowRect( hwnd
, &rc
);
1226 fodInfos
->DlgInfos
.hwndGrip
=
1227 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1228 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1229 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1230 rc
.right
- gripx
, rc
.bottom
- gripy
,
1231 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1234 fodInfos
->DlgInfos
.hwndCustomDlg
=
1235 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1237 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1238 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1240 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1241 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1243 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1244 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1245 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1248 /* if the app has changed the position of the invisible listbox,
1249 * change that of the listview (browser) as well */
1250 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1251 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1252 if( !EqualRect( &rc
, &rcstc
))
1254 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1255 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1256 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1257 SWP_NOACTIVATE
| SWP_NOZORDER
);
1260 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1262 GetWindowRect( hwnd
, &rc
);
1263 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1264 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1265 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1266 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1267 GetClientRect( hwnd
, &rc
);
1268 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1269 rc
.right
- gripx
, rc
.bottom
- gripy
,
1270 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1271 /* resize the dialog to the previous invocation */
1272 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1273 SetWindowPos( hwnd
, NULL
,
1274 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1275 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1278 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1279 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1284 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1285 case WM_GETMINMAXINFO
:
1286 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1288 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1291 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1294 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1300 case WM_GETISHELLBROWSER
:
1301 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1305 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1306 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1307 MemDialogSize
= fodInfos
->sizedlg
;
1308 RemovePropW(hwnd
, filedlg_info_propnameW
);
1313 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1316 /* set up the button tooltips strings */
1317 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1319 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1320 switch(lpnmh
->idFrom
)
1322 /* Up folder button */
1323 case FCIDM_TB_UPFOLDER
:
1324 stringId
= IDS_UPFOLDER
;
1326 /* New folder button */
1327 case FCIDM_TB_NEWFOLDER
:
1328 stringId
= IDS_NEWFOLDER
;
1330 /* List option button */
1331 case FCIDM_TB_SMALLICON
:
1332 stringId
= IDS_LISTVIEW
;
1334 /* Details option button */
1335 case FCIDM_TB_REPORTVIEW
:
1336 stringId
= IDS_REPORTVIEW
;
1338 /* Desktop button */
1339 case FCIDM_TB_DESKTOP
:
1340 stringId
= IDS_TODESKTOP
;
1345 lpdi
->hinst
= COMDLG32_hInstance
;
1346 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1351 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1352 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1357 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1359 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1360 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1363 /***********************************************************************
1364 * FILEDLG95_InitControls
1366 * WM_INITDIALOG message handler (before hook notification)
1368 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1370 BOOL win2000plus
= FALSE
;
1371 BOOL win98plus
= FALSE
;
1372 BOOL handledPath
= FALSE
;
1373 OSVERSIONINFOW osVi
;
1374 static const WCHAR szwSlash
[] = { '\\', 0 };
1375 static const WCHAR szwStar
[] = { '*',0 };
1377 static const TBBUTTON tbb
[] =
1379 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1380 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1381 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1382 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1383 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1384 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1385 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1386 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1387 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1389 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1394 HIMAGELIST toolbarImageList
;
1395 SHFILEINFOA shFileInfo
;
1396 ITEMIDLIST
*desktopPidl
;
1398 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1400 TRACE("%p\n", fodInfos
);
1402 /* Get windows version emulating */
1403 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1404 GetVersionExW(&osVi
);
1405 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1406 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1407 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1408 win2000plus
= (osVi
.dwMajorVersion
> 4);
1409 if (win2000plus
) win98plus
= TRUE
;
1411 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1414 /* Use either the edit or the comboboxex for the filename control */
1415 if (filename_is_edit( fodInfos
))
1417 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1418 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1422 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1423 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1426 /* Get the hwnd of the controls */
1427 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1428 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1430 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1431 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1433 /* construct the toolbar */
1434 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1435 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1437 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1438 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1439 rectTB
.left
= rectlook
.right
;
1440 rectTB
.top
= rectlook
.top
-1;
1442 if (fodInfos
->unicode
)
1443 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1444 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1445 rectTB
.left
, rectTB
.top
,
1446 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1447 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1449 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1450 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1451 rectTB
.left
, rectTB
.top
,
1452 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1453 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1455 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1457 /* FIXME: use TB_LOADIMAGES when implemented */
1458 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1459 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1460 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1462 /* Retrieve and add desktop icon to the toolbar */
1463 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1464 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1465 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1466 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1467 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1469 DestroyIcon(shFileInfo
.hIcon
);
1470 CoTaskMemFree(desktopPidl
);
1472 /* Finish Toolbar Construction */
1473 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1474 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1476 /* Set the window text with the text specified in the OPENFILENAME structure */
1479 SetWindowTextW(hwnd
,fodInfos
->title
);
1481 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1484 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1485 SetWindowTextW(hwnd
, buf
);
1488 /* Initialise the file name edit control */
1489 handledPath
= FALSE
;
1490 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1492 if(fodInfos
->filename
)
1494 /* 1. If win2000 or higher and filename contains a path, use it
1495 in preference over the lpstrInitialDir */
1496 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1497 WCHAR tmpBuf
[MAX_PATH
];
1501 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1504 /* nameBit is always shorter than the original filename. It may be NULL
1505 * when the filename contains only a drive name instead of file name */
1508 lstrcpyW(fodInfos
->filename
,nameBit
);
1512 *fodInfos
->filename
= '\0';
1514 MemFree(fodInfos
->initdir
);
1515 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1516 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1518 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1519 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1521 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1524 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1528 /* 2. (All platforms) If initdir is not null, then use it */
1529 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1531 /* Work out the proper path as supplied one might be relative */
1532 /* (Here because supplying '.' as dir browses to My Computer) */
1533 WCHAR tmpBuf
[MAX_PATH
];
1534 WCHAR tmpBuf2
[MAX_PATH
];
1538 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1539 if (PathFileExistsW(tmpBuf
)) {
1540 /* initdir does not have to be a directory. If a file is
1541 * specified, the dir part is taken */
1542 if (PathIsDirectoryW(tmpBuf
)) {
1543 PathAddBackslashW(tmpBuf
);
1544 lstrcatW(tmpBuf
, szwStar
);
1546 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1549 MemFree(fodInfos
->initdir
);
1550 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1551 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1553 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1556 else if (fodInfos
->initdir
)
1558 MemFree(fodInfos
->initdir
);
1559 fodInfos
->initdir
= NULL
;
1560 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1564 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1566 /* 3. All except w2k+: if filename contains a path use it */
1567 if (!win2000plus
&& fodInfos
->filename
&&
1568 *fodInfos
->filename
&&
1569 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1570 WCHAR tmpBuf
[MAX_PATH
];
1574 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1579 /* nameBit is always shorter than the original filename */
1580 lstrcpyW(fodInfos
->filename
, nameBit
);
1583 len
= lstrlenW(tmpBuf
);
1584 MemFree(fodInfos
->initdir
);
1585 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1586 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1589 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1590 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1592 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1595 /* 4. Win2000+: Recently used */
1596 if (!handledPath
&& win2000plus
) {
1597 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1598 fodInfos
->initdir
[0] = '\0';
1600 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1602 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1605 MemFree(fodInfos
->initdir
);
1606 fodInfos
->initdir
= NULL
;
1610 /* 5. win98+ and win2000+ if any files of specified filter types in
1611 current directory, use it */
1612 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1614 LPCWSTR lpstrPos
= fodInfos
->filter
;
1615 WIN32_FIND_DATAW FindFileData
;
1620 /* filter is a list... title\0ext\0......\0\0 */
1622 /* Skip the title */
1623 if(! *lpstrPos
) break; /* end */
1624 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1626 /* See if any files exist in the current dir with this extension */
1627 if(! *lpstrPos
) break; /* end */
1629 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1631 if (hFind
== INVALID_HANDLE_VALUE
) {
1632 /* None found - continue search */
1633 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1637 MemFree(fodInfos
->initdir
);
1638 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1639 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1642 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1643 debugstr_w(lpstrPos
));
1650 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1651 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1652 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1654 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1656 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1659 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1660 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1662 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1665 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1668 } else if (!handledPath
) {
1669 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1670 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1672 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1675 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1676 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1678 /* Must the open as read only check box be checked ?*/
1679 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1681 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1684 /* Must the open as read only check box be hidden? */
1685 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1687 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1688 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1691 /* Must the help button be hidden? */
1692 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1694 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1695 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1698 /* change Open to Save */
1699 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1702 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1703 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1704 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1705 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1708 /* Initialize the filter combo box */
1709 FILEDLG95_FILETYPE_Init(hwnd
);
1714 /***********************************************************************
1715 * FILEDLG95_ResizeControls
1717 * WM_INITDIALOG message handler (after hook notification)
1719 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1721 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1723 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1726 UINT flags
= SWP_NOACTIVATE
;
1728 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1729 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1731 /* resize the custom dialog to the parent size */
1732 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1733 GetClientRect(hwnd
, &rc
);
1736 /* our own fake template is zero sized and doesn't have children, so
1737 * there is no need to resize it. Picasa depends on it.
1739 flags
|= SWP_NOSIZE
;
1742 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1743 0, 0, rc
.right
, rc
.bottom
, flags
);
1747 /* Resize the height; if opened as read-only, checkbox and help button are
1748 * hidden and we are not using a custom template nor a customDialog
1750 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1751 (!(fodInfos
->ofnInfos
->Flags
&
1752 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1754 RECT rectDlg
, rectHelp
, rectCancel
;
1755 GetWindowRect(hwnd
, &rectDlg
);
1756 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1757 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1758 /* subtract the height of the help button plus the space between the help
1759 * button and the cancel button to the height of the dialog
1761 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1762 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1763 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1769 /***********************************************************************
1770 * FILEDLG95_FillControls
1772 * WM_INITDIALOG message handler (after hook notification)
1774 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1776 LPITEMIDLIST pidlItemId
= NULL
;
1778 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1780 TRACE("dir=%s file=%s\n",
1781 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1783 /* Get the initial directory pidl */
1785 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1787 WCHAR path
[MAX_PATH
];
1789 GetCurrentDirectoryW(MAX_PATH
,path
);
1790 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1793 /* Initialise shell objects */
1794 FILEDLG95_SHELL_Init(hwnd
);
1796 /* Initialize the Look In combo box */
1797 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1799 /* Browse to the initial directory */
1800 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1802 /* Free pidlItem memory */
1803 COMDLG32_SHFree(pidlItemId
);
1807 /***********************************************************************
1810 * Regroups all the cleaning functions of the filedlg
1812 void FILEDLG95_Clean(HWND hwnd
)
1814 FILEDLG95_FILETYPE_Clean(hwnd
);
1815 FILEDLG95_LOOKIN_Clean(hwnd
);
1816 FILEDLG95_SHELL_Clean(hwnd
);
1818 /***********************************************************************
1819 * FILEDLG95_OnWMCommand
1821 * WM_COMMAND message handler
1823 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1825 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1826 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1827 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1833 FILEDLG95_OnOpen(hwnd
);
1837 FILEDLG95_Clean(hwnd
);
1838 EndDialog(hwnd
, FALSE
);
1840 /* Filetype combo box */
1842 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1844 /* LookIn combo box */
1846 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1849 /* --- toolbar --- */
1850 /* Up folder button */
1851 case FCIDM_TB_UPFOLDER
:
1852 FILEDLG95_SHELL_UpFolder(hwnd
);
1854 /* New folder button */
1855 case FCIDM_TB_NEWFOLDER
:
1856 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1858 /* List option button */
1859 case FCIDM_TB_SMALLICON
:
1860 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1862 /* Details option button */
1863 case FCIDM_TB_REPORTVIEW
:
1864 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1866 /* Details option button */
1867 case FCIDM_TB_DESKTOP
:
1868 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1876 /* Do not use the listview selection anymore */
1877 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1881 /***********************************************************************
1882 * FILEDLG95_OnWMGetIShellBrowser
1884 * WM_GETISHELLBROWSER message handler
1886 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1888 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1892 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1898 /***********************************************************************
1899 * FILEDLG95_SendFileOK
1901 * Sends the CDN_FILEOK notification if required
1904 * TRUE if the dialog should close
1905 * FALSE if the dialog should not be closed
1907 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1909 /* ask the hook if we can close */
1910 if(IsHooked(fodInfos
))
1915 /* First send CDN_FILEOK as MSDN doc says */
1916 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1917 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1920 TRACE("canceled\n");
1924 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1925 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1926 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1929 TRACE("canceled\n");
1936 /***********************************************************************
1937 * FILEDLG95_OnOpenMultipleFiles
1939 * Handles the opening of multiple files.
1942 * check destination buffer size
1944 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1946 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1947 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1948 UINT nCount
, nSizePath
;
1952 if(fodInfos
->unicode
)
1954 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1955 ofn
->lpstrFile
[0] = '\0';
1959 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1960 ofn
->lpstrFile
[0] = '\0';
1963 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1965 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1966 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1967 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1969 LPWSTR lpstrTemp
= lpstrFileList
;
1971 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1975 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1978 WCHAR lpstrNotFound
[100];
1979 WCHAR lpstrMsg
[100];
1981 static const WCHAR nl
[] = {'\n',0};
1983 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1984 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1986 lstrcpyW(tmp
, lpstrTemp
);
1988 lstrcatW(tmp
, lpstrNotFound
);
1990 lstrcatW(tmp
, lpstrMsg
);
1992 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1996 /* move to the next file in the list of files */
1997 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1998 COMDLG32_SHFree(pidl
);
2002 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2003 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2005 /* For "oldstyle" dialog the components have to
2006 be separated by blanks (not '\0'!) and short
2007 filenames have to be used! */
2008 FIXME("Components have to be separated by blanks\n");
2010 if(fodInfos
->unicode
)
2012 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2013 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2014 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2018 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2020 if (ofn
->lpstrFile
!= NULL
)
2022 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2023 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2024 if (ofn
->nMaxFile
> nSizePath
)
2026 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2027 ofn
->lpstrFile
+ nSizePath
,
2028 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2033 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2034 fodInfos
->ofnInfos
->nFileExtension
= 0;
2036 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2039 /* clean and exit */
2040 FILEDLG95_Clean(hwnd
);
2041 return EndDialog(hwnd
,TRUE
);
2044 /* Returns the 'slot name' of the given module_name in the registry's
2045 * most-recently-used list. This will be an ASCII value in the
2046 * range ['a','z'). Returns zero on error.
2048 * The slot's value in the registry has the form:
2049 * module_name\0mru_path\0
2051 * If stored_path is given, then stored_path will contain the path name
2052 * stored in the registry's MRU list for the given module_name.
2054 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2055 * MRU list key for the given module_name.
2057 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2059 WCHAR mru_list
[32], *cur_mru_slot
;
2060 BOOL taken
[25] = {0};
2061 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2062 HKEY hkey_tmp
, *hkey
;
2071 *stored_path
= '\0';
2073 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2075 WARN("Unable to create MRU key: %d\n", ret
);
2079 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2080 (LPBYTE
)mru_list
, &mru_list_size
);
2081 if(ret
|| key_type
!= REG_SZ
){
2082 if(ret
== ERROR_FILE_NOT_FOUND
)
2085 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2090 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2091 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2092 DWORD value_data_size
= sizeof(value_data
);
2094 *value_name
= *cur_mru_slot
;
2096 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2097 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2098 if(ret
|| key_type
!= REG_BINARY
){
2099 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2103 if(!strcmpiW(module_name
, value_data
)){
2107 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2115 /* the module name isn't in the registry, so find the next open slot */
2116 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2117 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2118 for(i
= 0; i
< 25; ++i
){
2123 /* all slots are taken, so return the last one in MRUList */
2125 return *cur_mru_slot
;
2128 /* save the given filename as most-recently-used path for this module */
2129 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2131 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2135 /* get the current executable's name */
2136 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2137 WARN("GotModuleFileName failed: %d\n", GetLastError());
2140 module_name
= strrchrW(module_path
, '\\');
2142 module_name
= module_path
;
2146 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2151 { /* update the slot's info */
2152 WCHAR
*path_ends
, *final
;
2153 DWORD path_len
, final_len
;
2155 /* use only the path segment of `filename' */
2156 path_ends
= strrchrW(filename
, '\\');
2157 path_len
= path_ends
- filename
;
2159 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2161 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2164 lstrcpyW(final
, module_name
);
2165 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2166 final
[final_len
-1] = '\0';
2168 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2169 final_len
* sizeof(WCHAR
));
2171 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2180 { /* update MRUList value */
2181 WCHAR old_mru_list
[32], new_mru_list
[32];
2182 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2183 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2185 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2186 (LPBYTE
)old_mru_list
, &mru_list_size
);
2187 if(ret
|| key_type
!= REG_SZ
){
2188 if(ret
== ERROR_FILE_NOT_FOUND
){
2189 new_mru_list
[0] = slot
;
2190 new_mru_list
[1] = '\0';
2192 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2197 /* copy old list data over so that the new slot is at the start
2199 *new_mru_slot
++ = slot
;
2200 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2201 if(*old_mru_slot
!= slot
)
2202 *new_mru_slot
++ = *old_mru_slot
;
2204 *new_mru_slot
= '\0';
2207 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2208 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2210 WARN("Error saving MRUList data: %d\n", ret
);
2217 /* load the most-recently-used path for this module */
2218 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2220 WCHAR module_path
[MAX_PATH
], *module_name
;
2222 /* get the current executable's name */
2223 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2224 WARN("GotModuleFileName failed: %d\n", GetLastError());
2227 module_name
= strrchrW(module_path
, '\\');
2229 module_name
= module_path
;
2233 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2234 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2237 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2239 WCHAR strMsgTitle
[MAX_PATH
];
2240 WCHAR strMsgText
[MAX_PATH
];
2242 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2244 strMsgTitle
[0] = '\0';
2245 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2246 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2249 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2250 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2252 int nOpenAction
= defAction
;
2253 LPWSTR lpszTemp
, lpszTemp1
;
2254 LPITEMIDLIST pidl
= NULL
;
2255 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2257 /* check for invalid chars */
2258 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2260 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2264 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2266 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2269 LPSHELLFOLDER lpsfChild
;
2270 WCHAR lpwstrTemp
[MAX_PATH
];
2271 DWORD dwEaten
, dwAttributes
;
2274 lstrcpyW(lpwstrTemp
, lpszTemp
);
2275 p
= PathFindNextComponentW(lpwstrTemp
);
2277 if (!p
) break; /* end of path */
2280 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2282 /* There are no wildcards when OFN_NOVALIDATE is set */
2283 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2285 static const WCHAR wszWild
[] = { '*', '?', 0 };
2286 /* if the last element is a wildcard do a search */
2287 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2289 nOpenAction
= ONOPEN_SEARCH
;
2293 lpszTemp1
= lpszTemp
;
2295 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2297 /* append a backslash to drive letters */
2298 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2299 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2300 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2302 PathAddBackslashW(lpwstrTemp
);
2305 dwAttributes
= SFGAO_FOLDER
;
2306 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2308 /* the path component is valid, we have a pidl of the next path component */
2309 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2310 if(dwAttributes
& SFGAO_FOLDER
)
2312 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2314 ERR("bind to failed\n"); /* should not fail */
2317 IShellFolder_Release(*ppsf
);
2325 /* end dialog, return value */
2326 nOpenAction
= ONOPEN_OPEN
;
2329 COMDLG32_SHFree(pidl
);
2332 else if (!(flags
& OFN_NOVALIDATE
))
2334 if(*lpszTemp
|| /* points to trailing null for last path element */
2335 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2337 if(flags
& OFN_PATHMUSTEXIST
)
2339 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2345 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2347 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2351 /* change to the current folder */
2352 nOpenAction
= ONOPEN_OPEN
;
2357 nOpenAction
= ONOPEN_OPEN
;
2361 if(pidl
) COMDLG32_SHFree(pidl
);
2366 /***********************************************************************
2369 * Ok button WM_COMMAND message handler
2371 * If the function succeeds, the return value is nonzero.
2373 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2375 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2376 LPWSTR lpstrFileList
;
2377 UINT nFileCount
= 0;
2380 WCHAR lpstrPathAndFile
[MAX_PATH
];
2381 LPSHELLFOLDER lpsf
= NULL
;
2384 TRACE("hwnd=%p\n", hwnd
);
2386 /* try to browse the selected item */
2387 if(BrowseSelectedFolder(hwnd
))
2390 /* get the files from the edit control */
2391 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2398 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2402 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2405 Step 1: Build a complete path name from the current folder and
2406 the filename or path in the edit box.
2408 - the path in the edit box is a root path
2409 (with or without drive letter)
2410 - the edit box contains ".." (or a path with ".." in it)
2413 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2414 MemFree(lpstrFileList
);
2417 Step 2: here we have a cleaned up path
2419 We have to parse the path step by step to see if we have to browse
2420 to a folder if the path points to a directory or the last
2421 valid element is a directory.
2424 lpstrPathAndFile: cleaned up path
2428 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2429 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2430 nOpenAction
= ONOPEN_OPEN
;
2432 nOpenAction
= ONOPEN_BROWSE
;
2434 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2435 fodInfos
->ofnInfos
->Flags
,
2436 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2442 Step 3: here we have a cleaned up and validated path
2445 lpsf: ShellFolder bound to the rightmost valid path component
2446 lpstrPathAndFile: cleaned up path
2447 nOpenAction: action to do
2449 TRACE("end validate sf=%p\n", lpsf
);
2453 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2454 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2457 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2460 /* replace the current filter */
2461 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2462 len
= lstrlenW(lpszTemp
)+1;
2463 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2464 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2466 /* set the filter cb to the extension when possible */
2467 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2468 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2471 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2472 TRACE("ONOPEN_BROWSE\n");
2474 IPersistFolder2
* ppf2
;
2475 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2477 LPITEMIDLIST pidlCurrent
;
2478 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2479 IPersistFolder2_Release(ppf2
);
2480 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2482 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2483 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2485 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2486 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2489 else if( nOpenAction
== ONOPEN_SEARCH
)
2491 if (fodInfos
->Shell
.FOIShellView
)
2492 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2494 COMDLG32_SHFree(pidlCurrent
);
2495 if (filename_is_edit( fodInfos
))
2496 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2501 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2502 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2508 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2509 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2513 /* update READONLY check box flag */
2514 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2515 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2517 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2519 /* Attach the file extension with file name*/
2520 ext
= PathFindExtensionW(lpstrPathAndFile
);
2521 if (! *ext
&& fodInfos
->defext
)
2523 /* if no extension is specified with file name, then */
2524 /* attach the extension from file filter or default one */
2526 WCHAR
*filterExt
= NULL
;
2527 LPWSTR lpstrFilter
= NULL
;
2528 static const WCHAR szwDot
[] = {'.',0};
2529 int PathLength
= lstrlenW(lpstrPathAndFile
);
2531 /*Get the file extension from file type filter*/
2532 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2533 fodInfos
->ofnInfos
->nFilterIndex
-1);
2535 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2537 WCHAR
* filterSearchIndex
;
2538 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2539 strcpyW(filterExt
, lpstrFilter
);
2541 /* if a semicolon-separated list of file extensions was given, do not include the
2542 semicolon or anything after it in the extension.
2543 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2544 filterSearchIndex
= strchrW(filterExt
, ';');
2545 if (filterSearchIndex
)
2547 filterSearchIndex
[0] = '\0';
2550 /* find the file extension by searching for the first dot in filterExt */
2551 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2552 /* if the extension is invalid or contains a glob, ignore it */
2553 filterSearchIndex
= strchrW(filterExt
, '.');
2554 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2556 strcpyW(filterExt
, filterSearchIndex
);
2560 HeapFree(GetProcessHeap(), 0, filterExt
);
2567 /* use the default file extension */
2568 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2569 strcpyW(filterExt
, fodInfos
->defext
);
2572 if (*filterExt
) /* ignore filterExt="" */
2575 lstrcatW(lpstrPathAndFile
, szwDot
);
2576 /* Attach the extension */
2577 lstrcatW(lpstrPathAndFile
, filterExt
);
2580 HeapFree(GetProcessHeap(), 0, filterExt
);
2582 /* In Open dialog: if file does not exist try without extension */
2583 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2584 lpstrPathAndFile
[PathLength
] = '\0';
2586 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2589 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2590 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2592 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2595 /* In Save dialog: check if the file already exists */
2596 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2597 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2598 && PathFileExistsW(lpstrPathAndFile
))
2600 WCHAR lpstrOverwrite
[100];
2603 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2604 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2605 MB_YESNO
| MB_ICONEXCLAMATION
);
2606 if (answer
== IDNO
|| answer
== IDCANCEL
)
2613 /* In Open dialog: check if it should be created if it doesn't exist */
2614 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2615 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2616 && !PathFileExistsW(lpstrPathAndFile
))
2618 WCHAR lpstrCreate
[100];
2621 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2622 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2623 MB_YESNO
| MB_ICONEXCLAMATION
);
2624 if (answer
== IDNO
|| answer
== IDCANCEL
)
2631 /* Check that the size of the file does not exceed buffer size.
2632 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2633 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2634 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2637 /* fill destination buffer */
2638 if (fodInfos
->ofnInfos
->lpstrFile
)
2640 if(fodInfos
->unicode
)
2642 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2644 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2645 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2646 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2650 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2652 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2653 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2654 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2655 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2659 if(fodInfos
->unicode
)
2663 /* set filename offset */
2664 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2665 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2667 /* set extension offset */
2668 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2669 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2674 CHAR tempFileA
[MAX_PATH
];
2676 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2677 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2678 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2680 /* set filename offset */
2681 lpszTemp
= PathFindFileNameA(tempFileA
);
2682 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2684 /* set extension offset */
2685 lpszTemp
= PathFindExtensionA(tempFileA
);
2686 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2689 /* copy currently selected filter to lpstrCustomFilter */
2690 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2692 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2693 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2694 NULL
, 0, NULL
, NULL
);
2695 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2697 LPSTR s
= ofn
->lpstrCustomFilter
;
2698 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2699 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2700 s
, len
, NULL
, NULL
);
2705 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2708 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2711 FILEDLG95_Clean(hwnd
);
2712 ret
= EndDialog(hwnd
, TRUE
);
2718 size
= lstrlenW(lpstrPathAndFile
) + 1;
2719 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2721 /* return needed size in first two bytes of lpstrFile */
2722 if(fodInfos
->ofnInfos
->lpstrFile
)
2723 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2724 FILEDLG95_Clean(hwnd
);
2725 ret
= EndDialog(hwnd
, FALSE
);
2726 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2733 if(lpsf
) IShellFolder_Release(lpsf
);
2737 /***********************************************************************
2738 * FILEDLG95_SHELL_Init
2740 * Initialisation of the shell objects
2742 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2744 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2749 * Initialisation of the FileOpenDialogInfos structure
2755 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2757 /* Disable multi-select if flag not set */
2758 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2760 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2762 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2763 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2765 /* Construct the IShellBrowser interface */
2766 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2771 /***********************************************************************
2772 * FILEDLG95_SHELL_ExecuteCommand
2774 * Change the folder option and refresh the view
2775 * If the function succeeds, the return value is nonzero.
2777 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2779 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2782 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2784 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2789 CMINVOKECOMMANDINFO ci
;
2790 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2791 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2795 IContextMenu_InvokeCommand(pcm
, &ci
);
2796 IContextMenu_Release(pcm
);
2802 /***********************************************************************
2803 * FILEDLG95_SHELL_UpFolder
2805 * Browse to the specified object
2806 * If the function succeeds, the return value is nonzero.
2808 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2810 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2814 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2818 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2819 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2825 /***********************************************************************
2826 * FILEDLG95_SHELL_BrowseToDesktop
2828 * Browse to the Desktop
2829 * If the function succeeds, the return value is nonzero.
2831 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2833 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2839 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2840 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2841 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2842 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2843 COMDLG32_SHFree(pidl
);
2844 return SUCCEEDED(hres
);
2846 /***********************************************************************
2847 * FILEDLG95_SHELL_Clean
2849 * Cleans the memory used by shell objects
2851 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2853 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2857 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2859 /* clean Shell interfaces */
2860 if (fodInfos
->Shell
.FOIShellView
)
2862 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2863 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2865 if (fodInfos
->Shell
.FOIShellFolder
)
2866 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2867 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2868 if (fodInfos
->Shell
.FOIDataObject
)
2869 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2872 /***********************************************************************
2873 * FILEDLG95_FILETYPE_Init
2875 * Initialisation of the file type combo box
2877 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2879 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2880 int nFilters
= 0; /* number of filters */
2885 if(fodInfos
->customfilter
)
2887 /* customfilter has one entry... title\0ext\0
2888 * Set first entry of combo box item with customfilter
2891 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2894 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2896 /* Copy the extensions */
2897 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2898 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2899 lstrcpyW(lpstrExt
,lpstrPos
);
2901 /* Add the item at the end of the combo */
2902 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2903 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2906 if(fodInfos
->filter
)
2908 LPCWSTR lpstrPos
= fodInfos
->filter
;
2912 /* filter is a list... title\0ext\0......\0\0
2913 * Set the combo item text to the title and the item data
2916 LPCWSTR lpstrDisplay
;
2920 if(! *lpstrPos
) break; /* end */
2921 lpstrDisplay
= lpstrPos
;
2922 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2924 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2928 /* Copy the extensions */
2929 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2930 lstrcpyW(lpstrExt
,lpstrPos
);
2931 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2933 /* Add the item at the end of the combo */
2934 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2936 /* malformed filters are added anyway... */
2937 if (!*lpstrExt
) break;
2942 * Set the current filter to the one specified
2943 * in the initialisation structure
2945 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2949 /* Check to make sure our index isn't out of bounds. */
2950 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2951 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2952 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2954 /* set default filter index */
2955 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2956 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2958 /* calculate index of Combo Box item */
2959 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2960 if (fodInfos
->customfilter
== NULL
)
2963 /* Set the current index selection. */
2964 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2966 /* Get the corresponding text string from the combo box. */
2967 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2970 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2976 CharLowerW(lpstrFilter
); /* lowercase */
2977 len
= lstrlenW(lpstrFilter
)+1;
2978 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2979 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2982 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2986 /***********************************************************************
2987 * FILEDLG95_FILETYPE_OnCommand
2989 * WM_COMMAND of the file type combo box
2990 * If the function succeeds, the return value is nonzero.
2992 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2994 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3002 /* Get the current item of the filetype combo box */
3003 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3005 /* set the current filter index */
3006 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3007 (fodInfos
->customfilter
== NULL
? 1 : 0);
3009 /* Set the current filter with the current selection */
3010 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3012 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3014 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3017 CharLowerW(lpstrFilter
); /* lowercase */
3018 len
= lstrlenW(lpstrFilter
)+1;
3019 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3020 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3021 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3022 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3025 /* Refresh the actual view to display the included items*/
3026 if (fodInfos
->Shell
.FOIShellView
)
3027 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3032 /***********************************************************************
3033 * FILEDLG95_FILETYPE_SearchExt
3035 * searches for an extension in the filetype box
3037 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3039 int i
, iCount
= CBGetCount(hwnd
);
3041 TRACE("%s\n", debugstr_w(lpstrExt
));
3043 if(iCount
!= CB_ERR
)
3045 for(i
=0;i
<iCount
;i
++)
3047 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3054 /***********************************************************************
3055 * FILEDLG95_FILETYPE_Clean
3057 * Clean the memory used by the filetype combo box
3059 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3061 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3063 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3067 /* Delete each string of the combo and their associated data */
3068 if(iCount
!= CB_ERR
)
3070 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3072 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3073 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3076 /* Current filter */
3077 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3081 /***********************************************************************
3082 * FILEDLG95_LOOKIN_Init
3084 * Initialisation of the look in combo box
3087 /* Small helper function, to determine if the unixfs shell extension is rooted
3088 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3090 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3092 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3093 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3094 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3095 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3096 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3097 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3098 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3100 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3107 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3109 IShellFolder
*psfRoot
, *psfDrives
;
3110 IEnumIDList
*lpeRoot
, *lpeDrives
;
3111 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3114 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3118 liInfos
->iMaxIndentation
= 0;
3120 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3122 hdc
= GetDC( hwndCombo
);
3123 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3124 GetTextMetricsW( hdc
, &tm
);
3125 ReleaseDC( hwndCombo
, hdc
);
3127 /* set item height for both text field and listbox */
3128 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3129 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3131 /* Turn on the extended UI for the combo box like Windows does */
3132 CBSetExtendedUI(hwndCombo
, TRUE
);
3134 /* Initialise data of Desktop folder */
3135 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3136 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3137 COMDLG32_SHFree(pidlTmp
);
3139 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3141 SHGetDesktopFolder(&psfRoot
);
3145 /* enumerate the contents of the desktop */
3146 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3148 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3150 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3152 /* If the unixfs extension is rooted, we don't expand the drives by default */
3153 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3155 /* special handling for CSIDL_DRIVES */
3156 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3158 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3160 /* enumerate the drives */
3161 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3163 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3165 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3166 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3167 COMDLG32_SHFree(pidlAbsTmp
);
3168 COMDLG32_SHFree(pidlTmp1
);
3170 IEnumIDList_Release(lpeDrives
);
3172 IShellFolder_Release(psfDrives
);
3177 COMDLG32_SHFree(pidlTmp
);
3179 IEnumIDList_Release(lpeRoot
);
3181 IShellFolder_Release(psfRoot
);
3184 COMDLG32_SHFree(pidlDrives
);
3187 /***********************************************************************
3188 * FILEDLG95_LOOKIN_DrawItem
3190 * WM_DRAWITEM message handler
3192 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3194 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3195 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3196 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3200 HIMAGELIST ilItemImage
;
3203 LPSFOLDER tmpFolder
;
3204 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3205 UINT icon_width
, icon_height
;
3209 if(pDIStruct
->itemID
== -1)
3212 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3213 pDIStruct
->itemID
)))
3217 icon_width
= GetSystemMetrics(SM_CXICON
);
3218 icon_height
= GetSystemMetrics(SM_CYICON
);
3219 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3221 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3222 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3223 shgfi_flags
|= SHGFI_SMALLICON
;
3226 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3227 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3229 /* Is this item selected ? */
3230 if(pDIStruct
->itemState
& ODS_SELECTED
)
3232 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3233 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3234 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3238 SetTextColor(pDIStruct
->hDC
,crText
);
3239 SetBkColor(pDIStruct
->hDC
,crWin
);
3240 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3243 /* Do not indent item if drawing in the edit of the combo */
3244 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3247 iIndentation
= tmpFolder
->m_iIndent
;
3249 /* Draw text and icon */
3251 /* Initialise the icon display area */
3252 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3253 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3254 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3255 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3257 /* Initialise the text display area */
3258 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3259 rectText
.left
= rectIcon
.right
;
3261 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3262 rectText
.right
= pDIStruct
->rcItem
.right
;
3264 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3266 /* Draw the icon from the image list */
3267 ImageList_Draw(ilItemImage
,
3274 /* Draw the associated text */
3275 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3279 /***********************************************************************
3280 * FILEDLG95_LOOKIN_OnCommand
3282 * LookIn combo box WM_COMMAND message handler
3283 * If the function succeeds, the return value is nonzero.
3285 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3287 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3289 TRACE("%p\n", fodInfos
);
3295 LPSFOLDER tmpFolder
;
3298 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3300 if( iItem
== CB_ERR
) return FALSE
;
3302 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3307 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3308 tmpFolder
->pidlItem
,
3311 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3312 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3322 /***********************************************************************
3323 * FILEDLG95_LOOKIN_AddItem
3325 * Adds an absolute pidl item to the lookin combo box
3326 * returns the index of the inserted item
3328 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3330 LPITEMIDLIST pidlNext
;
3333 LookInInfos
*liInfos
;
3335 TRACE("%08x\n", iInsertId
);
3340 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3343 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3344 tmpFolder
->m_iIndent
= 0;
3346 /* Calculate the indentation of the item in the lookin*/
3348 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3350 tmpFolder
->m_iIndent
++;
3353 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3355 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3356 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3358 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3359 SHGetFileInfoW((LPCWSTR
)pidl
,
3363 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3365 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3367 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3371 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3373 /* Add the item at the end of the list */
3376 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3378 /* Insert the item at the iInsertId position*/
3381 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3384 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3388 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3389 MemFree( tmpFolder
);
3394 /***********************************************************************
3395 * FILEDLG95_LOOKIN_InsertItemAfterParent
3397 * Insert an item below its parent
3399 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3402 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3407 if (pidl
== pidlParent
)
3410 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3414 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3417 /* Free pidlParent memory */
3418 COMDLG32_SHFree(pidlParent
);
3420 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3423 /***********************************************************************
3424 * FILEDLG95_LOOKIN_SelectItem
3426 * Adds an absolute pidl item to the lookin combo box
3427 * returns the index of the inserted item
3429 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3432 LookInInfos
*liInfos
;
3436 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3438 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3442 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3443 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3448 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3449 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3453 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3455 if(iRemovedItem
< iItemPos
)
3460 CBSetCurSel(hwnd
,iItemPos
);
3461 liInfos
->uSelectedItem
= iItemPos
;
3467 /***********************************************************************
3468 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3470 * Remove the item with an expansion level over iExpansionLevel
3472 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3475 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3479 if(liInfos
->iMaxIndentation
<= 2)
3482 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3484 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3485 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3487 CBDeleteString(hwnd
,iItemPos
);
3488 liInfos
->iMaxIndentation
--;
3496 /***********************************************************************
3497 * FILEDLG95_LOOKIN_SearchItem
3499 * Search for pidl in the lookin combo box
3500 * returns the index of the found item
3502 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3505 int iCount
= CBGetCount(hwnd
);
3507 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3509 if (iCount
!= CB_ERR
)
3513 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3515 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3517 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3525 /***********************************************************************
3526 * FILEDLG95_LOOKIN_Clean
3528 * Clean the memory used by the lookin combo box
3530 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3532 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3533 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3535 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3539 /* Delete each string of the combo and their associated data */
3540 if (iCount
!= CB_ERR
)
3542 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3544 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3545 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3547 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3551 /* LookInInfos structure */
3553 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3556 /***********************************************************************
3559 * Fill the FORMATETC used in the shell id list
3561 static FORMATETC
get_def_format(void)
3563 static CLIPFORMAT cfFormat
;
3564 FORMATETC formatetc
;
3566 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3567 formatetc
.cfFormat
= cfFormat
;
3569 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3570 formatetc
.lindex
= -1;
3571 formatetc
.tymed
= TYMED_HGLOBAL
;
3575 /***********************************************************************
3576 * FILEDLG95_FILENAME_FillFromSelection
3578 * fills the edit box from the cached DataObject
3580 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3582 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3584 LPWSTR lpstrAllFiles
, lpstrTmp
;
3585 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3588 FORMATETC formatetc
= get_def_format();
3592 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3595 cida
= GlobalLock(medium
.u
.hGlobal
);
3596 nFileSelected
= cida
->cidl
;
3598 /* Allocate a buffer */
3599 nAllFilesMaxLength
= MAX_PATH
+ 3;
3600 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3604 /* Loop through the selection, handle only files (not folders) */
3605 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3607 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3610 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3612 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3614 nAllFilesMaxLength
*= 2;
3615 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3618 lpstrAllFiles
= lpstrTmp
;
3621 lpstrAllFiles
[nAllFilesLength
++] = '"';
3622 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3623 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3624 nAllFilesLength
+= nThisFileLength
;
3625 lpstrAllFiles
[nAllFilesLength
++] = '"';
3626 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3633 /* If there's only one file, use the name as-is without quotes */
3634 lpstrTmp
= lpstrAllFiles
;
3638 lpstrTmp
[nThisFileLength
] = 0;
3640 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3641 /* Select the file name like Windows does */
3642 if (filename_is_edit(fodInfos
))
3643 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3647 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3648 COMCTL32_ReleaseStgMedium(medium
);
3652 /* copied from shell32 to avoid linking to it
3653 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3654 * is dependent on whether emulated OS is unicode or not.
3656 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3661 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3662 COMDLG32_SHFree(src
->u
.pOleStr
);
3666 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3671 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3676 FIXME("unknown type %x!\n", src
->uType
);
3677 if (len
) *dest
= '\0';
3683 /***********************************************************************
3684 * FILEDLG95_FILENAME_GetFileNames
3686 * Copies the filenames to a delimited string list.
3688 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3690 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3691 UINT nFileCount
= 0; /* number of files */
3692 UINT nStrLen
= 0; /* length of string in edit control */
3693 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3697 /* get the filenames from the filename control */
3698 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3699 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3700 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3702 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3704 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3710 * DATAOBJECT Helper functions
3713 /***********************************************************************
3714 * COMCTL32_ReleaseStgMedium
3716 * like ReleaseStgMedium from ole32
3718 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3720 if(medium
.pUnkForRelease
)
3722 IUnknown_Release(medium
.pUnkForRelease
);
3726 GlobalUnlock(medium
.u
.hGlobal
);
3727 GlobalFree(medium
.u
.hGlobal
);
3731 /***********************************************************************
3732 * GetPidlFromDataObject
3734 * Return pidl(s) by number from the cached DataObject
3736 * nPidlIndex=0 gets the fully qualified root path
3738 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3742 FORMATETC formatetc
= get_def_format();
3743 LPITEMIDLIST pidl
= NULL
;
3745 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3750 /* Get the pidls from IDataObject */
3751 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3753 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3754 if(nPidlIndex
<= cida
->cidl
)
3756 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3758 COMCTL32_ReleaseStgMedium(medium
);
3763 /***********************************************************************
3766 * Return the number of selected items in the DataObject.
3769 static UINT
GetNumSelected( IDataObject
*doSelected
)
3773 FORMATETC formatetc
= get_def_format();
3775 TRACE("sv=%p\n", doSelected
);
3777 if (!doSelected
) return 0;
3779 /* Get the pidls from IDataObject */
3780 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3782 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3783 retVal
= cida
->cidl
;
3784 COMCTL32_ReleaseStgMedium(medium
);
3794 /***********************************************************************
3797 * Get the pidl's display name (relative to folder) and
3798 * put it in lpstrFileName.
3800 * Return NOERROR on success,
3804 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3809 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3813 SHGetDesktopFolder(&lpsf
);
3814 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3815 IShellFolder_Release(lpsf
);
3819 /* Get the display name of the pidl relative to the folder */
3820 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3822 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3827 /***********************************************************************
3828 * GetShellFolderFromPidl
3830 * pidlRel is the item pidl relative
3831 * Return the IShellFolder of the absolute pidl
3833 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3835 IShellFolder
*psf
= NULL
,*psfParent
;
3837 TRACE("%p\n", pidlAbs
);
3839 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3842 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3844 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3846 IShellFolder_Release(psfParent
);
3850 /* return the desktop */
3856 /***********************************************************************
3859 * Return the LPITEMIDLIST to the parent of the pidl in the list
3861 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3863 LPITEMIDLIST pidlParent
;
3865 TRACE("%p\n", pidl
);
3867 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3868 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3873 /***********************************************************************
3876 * returns the pidl of the file name relative to folder
3877 * NULL if an error occurred
3879 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3881 LPITEMIDLIST pidl
= NULL
;
3884 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3886 if(!lpcstrFileName
) return NULL
;
3887 if(!*lpcstrFileName
) return NULL
;
3891 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3892 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3893 IShellFolder_Release(lpsf
);
3898 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3905 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3907 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3910 TRACE("%p, %p\n", psf
, pidl
);
3912 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3914 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3915 /* see documentation shell 4.1*/
3916 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3919 /***********************************************************************
3920 * BrowseSelectedFolder
3922 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3924 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3925 BOOL bBrowseSelFolder
= FALSE
;
3929 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3931 LPITEMIDLIST pidlSelection
;
3933 /* get the file selected */
3934 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3935 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3937 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3938 pidlSelection
, SBSP_RELATIVE
) ) )
3941 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
3942 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3944 bBrowseSelFolder
= TRUE
;
3945 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3946 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3948 COMDLG32_SHFree( pidlSelection
);
3951 return bBrowseSelFolder
;
3955 * Memory allocation methods */
3956 static void *MemAlloc(UINT size
)
3958 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3961 static void MemFree(void *mem
)
3963 HeapFree(GetProcessHeap(),0,mem
);
3966 static inline BOOL
valid_struct_size( DWORD size
)
3968 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
3969 (size
== sizeof( OPENFILENAMEW
));
3972 static inline BOOL
is_win16_looks(DWORD flags
)
3974 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
3975 !(flags
& OFN_EXPLORER
));
3978 /* ------------------ APIs ---------------------- */
3980 /***********************************************************************
3981 * GetOpenFileNameA (COMDLG32.@)
3983 * Creates a dialog box for the user to select a file to open.
3986 * TRUE on success: user enters a valid file
3987 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3990 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
3992 TRACE("flags %08x\n", ofn
->Flags
);
3994 if (!valid_struct_size( ofn
->lStructSize
))
3996 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4000 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4001 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4002 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4004 if (is_win16_looks(ofn
->Flags
))
4005 return GetFileName31A(ofn
, OPEN_DIALOG
);
4008 FileOpenDlgInfos info
;
4010 init_filedlg_infoA(ofn
, &info
);
4011 return GetFileDialog95(&info
, OPEN_DIALOG
);
4015 /***********************************************************************
4016 * GetOpenFileNameW (COMDLG32.@)
4018 * Creates a dialog box for the user to select a file to open.
4021 * TRUE on success: user enters a valid file
4022 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4025 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4027 TRACE("flags %08x\n", ofn
->Flags
);
4029 if (!valid_struct_size( ofn
->lStructSize
))
4031 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4035 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4036 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4037 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4039 if (is_win16_looks(ofn
->Flags
))
4040 return GetFileName31W(ofn
, OPEN_DIALOG
);
4043 FileOpenDlgInfos info
;
4045 init_filedlg_infoW(ofn
, &info
);
4046 return GetFileDialog95(&info
, OPEN_DIALOG
);
4051 /***********************************************************************
4052 * GetSaveFileNameA (COMDLG32.@)
4054 * Creates a dialog box for the user to select a file to save.
4057 * TRUE on success: user enters a valid file
4058 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4061 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4063 if (!valid_struct_size( ofn
->lStructSize
))
4065 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4069 if (is_win16_looks(ofn
->Flags
))
4070 return GetFileName31A(ofn
, SAVE_DIALOG
);
4073 FileOpenDlgInfos info
;
4075 init_filedlg_infoA(ofn
, &info
);
4076 return GetFileDialog95(&info
, SAVE_DIALOG
);
4080 /***********************************************************************
4081 * GetSaveFileNameW (COMDLG32.@)
4083 * Creates a dialog box for the user to select a file to save.
4086 * TRUE on success: user enters a valid file
4087 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4090 BOOL WINAPI
GetSaveFileNameW(
4091 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4093 if (!valid_struct_size( ofn
->lStructSize
))
4095 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4099 if (is_win16_looks(ofn
->Flags
))
4100 return GetFileName31W(ofn
, SAVE_DIALOG
);
4103 FileOpenDlgInfos info
;
4105 init_filedlg_infoW(ofn
, &info
);
4106 return GetFileDialog95(&info
, SAVE_DIALOG
);
4110 /***********************************************************************
4111 * GetFileTitleA (COMDLG32.@)
4113 * See GetFileTitleW.
4115 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4118 UNICODE_STRING strWFile
;
4121 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4122 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4123 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4124 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4125 RtlFreeUnicodeString( &strWFile
);
4126 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4131 /***********************************************************************
4132 * GetFileTitleW (COMDLG32.@)
4134 * Get the name of a file.
4137 * lpFile [I] name and location of file
4138 * lpTitle [O] returned file name
4139 * cbBuf [I] buffer size of lpTitle
4143 * Failure: negative number.
4145 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4148 static const WCHAR brkpoint
[] = {'*','[',']',0};
4149 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4151 if(lpFile
== NULL
|| lpTitle
== NULL
)
4154 len
= lstrlenW(lpFile
);
4159 if(strpbrkW(lpFile
, brkpoint
))
4164 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4167 for(i
= len
; i
>= 0; i
--)
4169 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4179 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4181 len
= lstrlenW(lpFile
+i
)+1;
4185 lstrcpyW(lpTitle
, &lpFile
[i
]);