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
);
447 SetCurrentDirectoryW(current_dir
);
448 MemFree(current_dir
);
453 MemFree((WCHAR
*)info
->defext
);
454 MemFree((WCHAR
*)info
->title
);
455 MemFree((WCHAR
*)info
->filter
);
456 MemFree((WCHAR
*)info
->customfilter
);
459 MemFree(info
->filename
);
460 MemFree(info
->initdir
);
464 /******************************************************************************
465 * COMDLG32_GetDisplayNameOf [internal]
467 * Helper function to get the display name for a pidl.
469 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
470 LPSHELLFOLDER psfDesktop
;
473 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
476 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
477 IShellFolder_Release(psfDesktop
);
481 IShellFolder_Release(psfDesktop
);
482 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
485 /******************************************************************************
486 * COMDLG32_GetCanonicalPath [internal]
488 * Helper function to get the canonical path.
490 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
491 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
493 WCHAR lpstrTemp
[MAX_PATH
];
495 /* Get the current directory name */
496 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
499 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
501 PathAddBackslashW(lpstrPathAndFile
);
503 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
505 /* if the user specified a fully qualified path use it */
506 if(PathIsRelativeW(lpstrFile
))
508 lstrcatW(lpstrPathAndFile
, lpstrFile
);
512 /* does the path have a drive letter? */
513 if (PathGetDriveNumberW(lpstrFile
) == -1)
514 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
516 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
519 /* resolve "." and ".." */
520 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
521 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
522 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
525 /***********************************************************************
526 * COMDLG32_SplitFileNames [internal]
528 * Creates a delimited list of filenames.
530 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
532 UINT nStrCharCount
= 0; /* index in src buffer */
533 UINT nFileIndex
= 0; /* index in dest buffer */
534 UINT nFileCount
= 0; /* number of files */
536 /* we might get single filename without any '"',
537 * so we need nStrLen + terminating \0 + end-of-list \0 */
538 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
541 /* build delimited file list from filenames */
542 while ( nStrCharCount
<= nStrLen
)
544 if ( lpstrEdit
[nStrCharCount
]=='"' )
547 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
549 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
552 (*lpstrFileList
)[nFileIndex
++] = 0;
558 /* single, unquoted string */
559 if ((nStrLen
> 0) && (nFileIndex
== 0) )
561 lstrcpyW(*lpstrFileList
, lpstrEdit
);
562 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
567 (*lpstrFileList
)[nFileIndex
++] = '\0';
569 *sizeUsed
= nFileIndex
;
573 /***********************************************************************
574 * ArrangeCtrlPositions [internal]
576 * NOTE: Make sure to add testcases for any changes made here.
578 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
580 HWND hwndChild
, hwndStc32
;
581 RECT rectParent
, rectChild
, rectStc32
;
585 /* Take into account if open as read only checkbox and help button
590 RECT rectHelp
, rectCancel
;
591 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
592 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
593 /* subtract the height of the help button plus the space between
594 * the help button and the cancel button to the height of the dialog
596 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
600 There are two possibilities to add components to the default file dialog box.
602 By default, all the new components are added below the standard dialog box (the else case).
604 However, if there is a static text component with the stc32 id, a special case happens.
605 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
606 in the window and the cx and cy indicate how to size the window.
607 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
608 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
612 GetClientRect(hwndParentDlg
, &rectParent
);
614 /* when arranging controls we have to use fixed parent size */
615 rectParent
.bottom
-= help_fixup
;
617 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
620 GetWindowRect(hwndStc32
, &rectStc32
);
621 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
623 /* set the size of the stc32 control according to the size of
624 * client area of the parent dialog
626 SetWindowPos(hwndStc32
, 0,
628 rectParent
.right
, rectParent
.bottom
,
629 SWP_NOMOVE
| SWP_NOZORDER
);
632 SetRectEmpty(&rectStc32
);
634 /* this part moves controls of the child dialog */
635 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
638 if (hwndChild
!= hwndStc32
)
640 GetWindowRect(hwndChild
, &rectChild
);
641 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
643 /* move only if stc32 exist */
644 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
646 /* move to the right of visible controls of the parent dialog */
647 rectChild
.left
+= rectParent
.right
;
648 rectChild
.left
-= rectStc32
.right
;
650 /* move even if stc32 doesn't exist */
651 if (rectChild
.top
>= rectStc32
.bottom
)
653 /* move below visible controls of the parent dialog */
654 rectChild
.top
+= rectParent
.bottom
;
655 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
658 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
659 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
661 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
664 /* this part moves controls of the parent dialog */
665 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
668 if (hwndChild
!= hwndChildDlg
)
670 GetWindowRect(hwndChild
, &rectChild
);
671 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
673 /* left,top of stc32 marks the position of controls
674 * from the parent dialog
676 rectChild
.left
+= rectStc32
.left
;
677 rectChild
.top
+= rectStc32
.top
;
679 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
680 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
682 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
685 /* calculate the size of the resulting dialog */
687 /* here we have to use original parent size */
688 GetClientRect(hwndParentDlg
, &rectParent
);
689 GetClientRect(hwndChildDlg
, &rectChild
);
690 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
691 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
696 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
697 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
699 chgx
= rectChild
.right
- rectParent
.right
;
701 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
702 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
704 /* Unconditionally set new dialog
705 * height to that of the child
707 chgy
= rectChild
.bottom
- rectParent
.bottom
;
712 chgy
= rectChild
.bottom
- help_fixup
;
714 /* set the size of the parent dialog */
715 GetWindowRect(hwndParentDlg
, &rectParent
);
716 SetWindowPos(hwndParentDlg
, 0,
718 rectParent
.right
- rectParent
.left
+ chgx
,
719 rectParent
.bottom
- rectParent
.top
+ chgy
,
720 SWP_NOMOVE
| SWP_NOZORDER
);
723 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
732 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
739 TRACE("%p, %p\n", fodInfos
, hwnd
);
742 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
743 * structure's hInstance parameter is not a HINSTANCE, but
744 * instead a pointer to a template resource to use.
746 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
749 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
751 hinst
= COMDLG32_hInstance
;
752 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
754 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
760 hinst
= fodInfos
->ofnInfos
->hInstance
;
761 if(fodInfos
->unicode
)
763 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
764 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
768 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
769 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
773 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
776 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
777 !(template = LockResource( hDlgTmpl
)))
779 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
783 if (fodInfos
->unicode
)
784 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
785 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
786 (LPARAM
)fodInfos
->ofnInfos
);
788 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
789 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
790 (LPARAM
)fodInfos
->ofnInfos
);
793 else if( IsHooked(fodInfos
))
798 WORD menu
,class,title
;
800 GetClientRect(hwnd
,&rectHwnd
);
801 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
802 temp
.tmplate
.dwExtendedStyle
= 0;
803 temp
.tmplate
.cdit
= 0;
808 temp
.menu
= temp
.class = temp
.title
= 0;
810 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
811 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
818 /***********************************************************************
819 * SendCustomDlgNotificationMessage
821 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
824 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
826 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
830 TRACE("%p %d\n", hwndParentDlg
, uCode
);
832 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
835 TRACE("CALL NOTIFY for %d\n", uCode
);
837 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
838 ofnNotify
.hdr
.idFrom
= 0;
839 ofnNotify
.hdr
.code
= uCode
;
840 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
841 ofnNotify
.pszFile
= NULL
;
843 if (fodInfos
->unicode
)
844 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
846 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
848 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
853 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
857 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
864 /* get path and filenames */
865 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
866 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
867 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
870 p
= buffer
+ strlenW(buffer
);
872 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
874 if (fodInfos
->unicode
)
876 total
= strlenW( buffer
) + 1;
877 if (result
) lstrcpynW( result
, buffer
, size
);
878 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
882 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
883 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
884 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
886 HeapFree( GetProcessHeap(), 0, buffer
);
890 /***********************************************************************
891 * FILEDLG95_HandleCustomDialogMessages
893 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
895 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
897 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
898 WCHAR lpstrPath
[MAX_PATH
];
901 if(!fodInfos
) return FALSE
;
905 case CDM_GETFILEPATH
:
906 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
909 case CDM_GETFOLDERPATH
:
910 TRACE("CDM_GETFOLDERPATH:\n");
911 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
914 if (fodInfos
->unicode
)
915 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
917 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
918 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
920 retval
= lstrlenW(lpstrPath
) + 1;
923 case CDM_GETFOLDERIDLIST
:
924 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
925 if (retval
<= wParam
)
926 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
930 TRACE("CDM_GETSPEC:\n");
931 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
934 if (fodInfos
->unicode
)
935 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
937 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
941 case CDM_SETCONTROLTEXT
:
942 TRACE("CDM_SETCONTROLTEXT:\n");
945 if( fodInfos
->unicode
)
946 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
948 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
953 case CDM_HIDECONTROL
:
954 /* MSDN states that it should fail for not OFN_EXPLORER case */
955 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
957 HWND control
= GetDlgItem( hwnd
, wParam
);
958 if (control
) ShowWindow( control
, SW_HIDE
);
965 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
966 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
969 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
973 /***********************************************************************
974 * FILEDLG95_OnWMGetMMI
976 * WM_GETMINMAXINFO message handler for resizable dialogs
978 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
980 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
981 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
982 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
984 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
989 /***********************************************************************
992 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
994 * FIXME: this could be made more elaborate. Now use a simple scheme
995 * where the file view is enlarged and the controls are either moved
996 * vertically or horizontally to get out of the way. Only the "grip"
997 * is moved in both directions to stay in the corner.
999 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1005 FileOpenDlgInfos
*fodInfos
;
1007 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1008 fodInfos
= get_filedlg_infoptr(hwnd
);
1009 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1010 /* get the new dialog rectangle */
1011 GetWindowRect( hwnd
, &rc
);
1012 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1013 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1014 /* not initialized yet */
1015 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1016 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1017 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1019 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1020 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1021 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1022 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1023 /* change the size of the view window */
1024 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1025 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1026 hdwp
= BeginDeferWindowPos( 10);
1027 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1028 rcview
.right
- rcview
.left
+ chgx
,
1029 rcview
.bottom
- rcview
.top
+ chgy
,
1030 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1031 /* change position and sizes of the controls */
1032 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1034 int ctrlid
= GetDlgCtrlID( ctrl
);
1035 GetWindowRect( ctrl
, &rc
);
1036 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1037 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1039 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1041 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1043 else if( rc
.top
> rcview
.bottom
)
1045 /* if it was below the shell view
1049 /* file name (edit or comboboxex) and file types combo change also width */
1053 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1054 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1055 SWP_NOACTIVATE
| SWP_NOZORDER
);
1057 /* then these buttons must move out of the way */
1061 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1063 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1066 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1068 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1071 else if( rc
.left
> rcview
.right
)
1073 /* if it was to the right of the shell view
1075 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1077 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1084 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1086 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1087 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1088 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1090 case IDC_TOOLBARSTATIC
:
1092 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1094 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1097 /* not resized in windows. Since wine uses this invisible control
1098 * to size the browser view it needs to be resized */
1099 case IDC_SHELLSTATIC
:
1100 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1101 rc
.right
- rc
.left
+ chgx
,
1102 rc
.bottom
- rc
.top
+ chgy
,
1103 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1108 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1109 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1111 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1112 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1114 GetWindowRect( ctrl
, &rc
);
1115 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1116 if( rc
.top
> rcview
.bottom
)
1118 /* if it was below the shell view
1120 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1121 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1122 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1124 else if( rc
.left
> rcview
.right
)
1126 /* if it was to the right of the shell view
1128 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1129 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1130 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1133 /* size the custom dialog at the end: some applications do some
1134 * control re-arranging at this point */
1135 GetClientRect(hwnd
, &rc
);
1136 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1137 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1139 EndDeferWindowPos( hdwp
);
1140 /* should not be needed */
1141 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1145 /***********************************************************************
1148 * File open dialog procedure
1150 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1153 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1160 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1162 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1163 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1165 /* Some shell namespace extensions depend on COM being initialized. */
1166 if (SUCCEEDED(OleInitialize(NULL
)))
1167 fodInfos
->ole_initialized
= TRUE
;
1169 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1171 FILEDLG95_InitControls(hwnd
);
1173 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1175 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1176 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1177 RECT client
, client_adjusted
;
1179 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1181 style
|= WS_SIZEBOX
;
1182 ex_style
|= WS_EX_WINDOWEDGE
;
1185 style
&= ~WS_SIZEBOX
;
1186 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1187 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1189 GetClientRect( hwnd
, &client
);
1190 GetClientRect( hwnd
, &client_adjusted
);
1191 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1193 GetWindowRect( hwnd
, &rc
);
1194 rc
.right
+= client_adjusted
.right
- client
.right
;
1195 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1196 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1197 SWP_NOZORDER
| SWP_NOMOVE
);
1199 GetWindowRect( hwnd
, &rc
);
1200 fodInfos
->DlgInfos
.hwndGrip
=
1201 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1202 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1203 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1204 rc
.right
- gripx
, rc
.bottom
- gripy
,
1205 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1208 fodInfos
->DlgInfos
.hwndCustomDlg
=
1209 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1211 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1212 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1214 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1215 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1217 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1218 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1219 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1222 /* if the app has changed the position of the invisible listbox,
1223 * change that of the listview (browser) as well */
1224 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1225 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1226 if( !EqualRect( &rc
, &rcstc
))
1228 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1229 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1230 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1231 SWP_NOACTIVATE
| SWP_NOZORDER
);
1234 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1236 GetWindowRect( hwnd
, &rc
);
1237 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1238 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1239 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1240 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1241 GetClientRect( hwnd
, &rc
);
1242 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1243 rc
.right
- gripx
, rc
.bottom
- gripy
,
1244 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1245 /* resize the dialog to the previous invocation */
1246 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1247 SetWindowPos( hwnd
, NULL
,
1248 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1249 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1252 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1253 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1258 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1259 case WM_GETMINMAXINFO
:
1260 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1262 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1265 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1268 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1274 case WM_GETISHELLBROWSER
:
1275 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1279 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1280 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1281 MemDialogSize
= fodInfos
->sizedlg
;
1282 RemovePropW(hwnd
, filedlg_info_propnameW
);
1287 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1290 /* set up the button tooltips strings */
1291 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1293 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1294 switch(lpnmh
->idFrom
)
1296 /* Up folder button */
1297 case FCIDM_TB_UPFOLDER
:
1298 stringId
= IDS_UPFOLDER
;
1300 /* New folder button */
1301 case FCIDM_TB_NEWFOLDER
:
1302 stringId
= IDS_NEWFOLDER
;
1304 /* List option button */
1305 case FCIDM_TB_SMALLICON
:
1306 stringId
= IDS_LISTVIEW
;
1308 /* Details option button */
1309 case FCIDM_TB_REPORTVIEW
:
1310 stringId
= IDS_REPORTVIEW
;
1312 /* Desktop button */
1313 case FCIDM_TB_DESKTOP
:
1314 stringId
= IDS_TODESKTOP
;
1319 lpdi
->hinst
= COMDLG32_hInstance
;
1320 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1325 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1326 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1331 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1333 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1334 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1337 /***********************************************************************
1338 * FILEDLG95_InitControls
1340 * WM_INITDIALOG message handler (before hook notification)
1342 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1344 BOOL win2000plus
= FALSE
;
1345 BOOL win98plus
= FALSE
;
1346 BOOL handledPath
= FALSE
;
1347 OSVERSIONINFOW osVi
;
1348 static const WCHAR szwSlash
[] = { '\\', 0 };
1349 static const WCHAR szwStar
[] = { '*',0 };
1351 static const TBBUTTON tbb
[] =
1353 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1354 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1355 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1356 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1357 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1358 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1359 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1360 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1361 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1363 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1368 HIMAGELIST toolbarImageList
;
1369 SHFILEINFOA shFileInfo
;
1370 ITEMIDLIST
*desktopPidl
;
1372 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1374 TRACE("%p\n", fodInfos
);
1376 /* Get windows version emulating */
1377 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1378 GetVersionExW(&osVi
);
1379 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1380 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1381 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1382 win2000plus
= (osVi
.dwMajorVersion
> 4);
1383 if (win2000plus
) win98plus
= TRUE
;
1385 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1388 /* Use either the edit or the comboboxex for the filename control */
1389 if (filename_is_edit( fodInfos
))
1391 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1392 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1396 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1397 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1400 /* Get the hwnd of the controls */
1401 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1402 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1404 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1405 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1407 /* construct the toolbar */
1408 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1409 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1411 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1412 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1413 rectTB
.left
= rectlook
.right
;
1414 rectTB
.top
= rectlook
.top
-1;
1416 if (fodInfos
->unicode
)
1417 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1418 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1419 rectTB
.left
, rectTB
.top
,
1420 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1421 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1423 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1424 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1425 rectTB
.left
, rectTB
.top
,
1426 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1427 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1429 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1431 /* FIXME: use TB_LOADIMAGES when implemented */
1432 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1433 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1434 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1436 /* Retrieve and add desktop icon to the toolbar */
1437 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1438 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1439 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1440 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1441 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1443 DestroyIcon(shFileInfo
.hIcon
);
1444 CoTaskMemFree(desktopPidl
);
1446 /* Finish Toolbar Construction */
1447 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1448 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1450 /* Set the window text with the text specified in the OPENFILENAME structure */
1453 SetWindowTextW(hwnd
,fodInfos
->title
);
1455 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1458 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1459 SetWindowTextW(hwnd
, buf
);
1462 /* Initialise the file name edit control */
1463 handledPath
= FALSE
;
1464 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1466 if(fodInfos
->filename
)
1468 /* 1. If win2000 or higher and filename contains a path, use it
1469 in preference over the lpstrInitialDir */
1470 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1471 WCHAR tmpBuf
[MAX_PATH
];
1475 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1478 /* nameBit is always shorter than the original filename. It may be NULL
1479 * when the filename contains only a drive name instead of file name */
1482 lstrcpyW(fodInfos
->filename
,nameBit
);
1486 *fodInfos
->filename
= '\0';
1488 MemFree(fodInfos
->initdir
);
1489 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1490 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1492 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1493 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1495 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1498 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1502 /* 2. (All platforms) If initdir is not null, then use it */
1503 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1505 /* Work out the proper path as supplied one might be relative */
1506 /* (Here because supplying '.' as dir browses to My Computer) */
1507 WCHAR tmpBuf
[MAX_PATH
];
1508 WCHAR tmpBuf2
[MAX_PATH
];
1512 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1513 if (PathFileExistsW(tmpBuf
)) {
1514 /* initdir does not have to be a directory. If a file is
1515 * specified, the dir part is taken */
1516 if (PathIsDirectoryW(tmpBuf
)) {
1517 PathAddBackslashW(tmpBuf
);
1518 lstrcatW(tmpBuf
, szwStar
);
1520 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1523 MemFree(fodInfos
->initdir
);
1524 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1525 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1527 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1530 else if (fodInfos
->initdir
)
1532 MemFree(fodInfos
->initdir
);
1533 fodInfos
->initdir
= NULL
;
1534 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1538 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1540 /* 3. All except w2k+: if filename contains a path use it */
1541 if (!win2000plus
&& fodInfos
->filename
&&
1542 *fodInfos
->filename
&&
1543 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1544 WCHAR tmpBuf
[MAX_PATH
];
1548 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1553 /* nameBit is always shorter than the original filename */
1554 lstrcpyW(fodInfos
->filename
, nameBit
);
1557 len
= lstrlenW(tmpBuf
);
1558 MemFree(fodInfos
->initdir
);
1559 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1560 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1563 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1564 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1566 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1569 /* 4. Win2000+: Recently used */
1570 if (!handledPath
&& win2000plus
) {
1571 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1572 fodInfos
->initdir
[0] = '\0';
1574 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1576 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1579 MemFree(fodInfos
->initdir
);
1580 fodInfos
->initdir
= NULL
;
1584 /* 5. win98+ and win2000+ if any files of specified filter types in
1585 current directory, use it */
1586 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1588 LPCWSTR lpstrPos
= fodInfos
->filter
;
1589 WIN32_FIND_DATAW FindFileData
;
1594 /* filter is a list... title\0ext\0......\0\0 */
1596 /* Skip the title */
1597 if(! *lpstrPos
) break; /* end */
1598 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1600 /* See if any files exist in the current dir with this extension */
1601 if(! *lpstrPos
) break; /* end */
1603 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1605 if (hFind
== INVALID_HANDLE_VALUE
) {
1606 /* None found - continue search */
1607 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1611 MemFree(fodInfos
->initdir
);
1612 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1613 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1616 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1617 debugstr_w(lpstrPos
));
1624 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1625 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1626 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1628 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1630 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1633 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1634 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1636 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1639 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1642 } else if (!handledPath
) {
1643 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1644 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1646 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1649 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1650 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1652 /* Must the open as read only check box be checked ?*/
1653 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1655 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1658 /* Must the open as read only check box be hidden? */
1659 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1661 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1662 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1665 /* Must the help button be hidden? */
1666 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1668 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1669 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1672 /* change Open to Save */
1673 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1676 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1677 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1678 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1679 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1682 /* Initialize the filter combo box */
1683 FILEDLG95_FILETYPE_Init(hwnd
);
1688 /***********************************************************************
1689 * FILEDLG95_ResizeControls
1691 * WM_INITDIALOG message handler (after hook notification)
1693 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1695 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1697 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1700 UINT flags
= SWP_NOACTIVATE
;
1702 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1703 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1705 /* resize the custom dialog to the parent size */
1706 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1707 GetClientRect(hwnd
, &rc
);
1710 /* our own fake template is zero sized and doesn't have children, so
1711 * there is no need to resize it. Picasa depends on it.
1713 flags
|= SWP_NOSIZE
;
1716 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1717 0, 0, rc
.right
, rc
.bottom
, flags
);
1721 /* Resize the height; if opened as read-only, checkbox and help button are
1722 * hidden and we are not using a custom template nor a customDialog
1724 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1725 (!(fodInfos
->ofnInfos
->Flags
&
1726 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1728 RECT rectDlg
, rectHelp
, rectCancel
;
1729 GetWindowRect(hwnd
, &rectDlg
);
1730 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1731 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1732 /* subtract the height of the help button plus the space between the help
1733 * button and the cancel button to the height of the dialog
1735 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1736 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1737 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1743 /***********************************************************************
1744 * FILEDLG95_FillControls
1746 * WM_INITDIALOG message handler (after hook notification)
1748 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1750 LPITEMIDLIST pidlItemId
= NULL
;
1752 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1754 TRACE("dir=%s file=%s\n",
1755 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1757 /* Get the initial directory pidl */
1759 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1761 WCHAR path
[MAX_PATH
];
1763 GetCurrentDirectoryW(MAX_PATH
,path
);
1764 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1767 /* Initialise shell objects */
1768 FILEDLG95_SHELL_Init(hwnd
);
1770 /* Initialize the Look In combo box */
1771 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1773 /* Browse to the initial directory */
1774 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1776 /* Free pidlItem memory */
1777 COMDLG32_SHFree(pidlItemId
);
1781 /***********************************************************************
1784 * Regroups all the cleaning functions of the filedlg
1786 void FILEDLG95_Clean(HWND hwnd
)
1788 FILEDLG95_FILETYPE_Clean(hwnd
);
1789 FILEDLG95_LOOKIN_Clean(hwnd
);
1790 FILEDLG95_SHELL_Clean(hwnd
);
1792 /***********************************************************************
1793 * FILEDLG95_OnWMCommand
1795 * WM_COMMAND message handler
1797 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1799 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1800 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1801 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1807 FILEDLG95_OnOpen(hwnd
);
1811 FILEDLG95_Clean(hwnd
);
1812 EndDialog(hwnd
, FALSE
);
1814 /* Filetype combo box */
1816 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1818 /* LookIn combo box */
1820 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1823 /* --- toolbar --- */
1824 /* Up folder button */
1825 case FCIDM_TB_UPFOLDER
:
1826 FILEDLG95_SHELL_UpFolder(hwnd
);
1828 /* New folder button */
1829 case FCIDM_TB_NEWFOLDER
:
1830 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1832 /* List option button */
1833 case FCIDM_TB_SMALLICON
:
1834 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1836 /* Details option button */
1837 case FCIDM_TB_REPORTVIEW
:
1838 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1840 /* Details option button */
1841 case FCIDM_TB_DESKTOP
:
1842 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1850 /* Do not use the listview selection anymore */
1851 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1855 /***********************************************************************
1856 * FILEDLG95_OnWMGetIShellBrowser
1858 * WM_GETISHELLBROWSER message handler
1860 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1862 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1866 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1872 /***********************************************************************
1873 * FILEDLG95_SendFileOK
1875 * Sends the CDN_FILEOK notification if required
1878 * TRUE if the dialog should close
1879 * FALSE if the dialog should not be closed
1881 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1883 /* ask the hook if we can close */
1884 if(IsHooked(fodInfos
))
1889 /* First send CDN_FILEOK as MSDN doc says */
1890 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1891 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1894 TRACE("canceled\n");
1898 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1899 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1900 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1903 TRACE("canceled\n");
1910 /***********************************************************************
1911 * FILEDLG95_OnOpenMultipleFiles
1913 * Handles the opening of multiple files.
1916 * check destination buffer size
1918 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1920 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1921 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1922 UINT nCount
, nSizePath
;
1926 if(fodInfos
->unicode
)
1928 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1929 ofn
->lpstrFile
[0] = '\0';
1933 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1934 ofn
->lpstrFile
[0] = '\0';
1937 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1939 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1940 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1941 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1943 LPWSTR lpstrTemp
= lpstrFileList
;
1945 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1949 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1952 WCHAR lpstrNotFound
[100];
1953 WCHAR lpstrMsg
[100];
1955 static const WCHAR nl
[] = {'\n',0};
1957 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1958 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1960 lstrcpyW(tmp
, lpstrTemp
);
1962 lstrcatW(tmp
, lpstrNotFound
);
1964 lstrcatW(tmp
, lpstrMsg
);
1966 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1970 /* move to the next file in the list of files */
1971 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1972 COMDLG32_SHFree(pidl
);
1976 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1977 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1979 /* For "oldstyle" dialog the components have to
1980 be separated by blanks (not '\0'!) and short
1981 filenames have to be used! */
1982 FIXME("Components have to be separated by blanks\n");
1984 if(fodInfos
->unicode
)
1986 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1987 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1988 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1992 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1994 if (ofn
->lpstrFile
!= NULL
)
1996 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1997 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1998 if (ofn
->nMaxFile
> nSizePath
)
2000 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2001 ofn
->lpstrFile
+ nSizePath
,
2002 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2007 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2008 fodInfos
->ofnInfos
->nFileExtension
= 0;
2010 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2013 /* clean and exit */
2014 FILEDLG95_Clean(hwnd
);
2015 return EndDialog(hwnd
,TRUE
);
2018 /* Returns the 'slot name' of the given module_name in the registry's
2019 * most-recently-used list. This will be an ASCII value in the
2020 * range ['a','z'). Returns zero on error.
2022 * The slot's value in the registry has the form:
2023 * module_name\0mru_path\0
2025 * If stored_path is given, then stored_path will contain the path name
2026 * stored in the registry's MRU list for the given module_name.
2028 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2029 * MRU list key for the given module_name.
2031 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2033 WCHAR mru_list
[32], *cur_mru_slot
;
2034 BOOL taken
[25] = {0};
2035 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2036 HKEY hkey_tmp
, *hkey
;
2045 *stored_path
= '\0';
2047 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2049 WARN("Unable to create MRU key: %d\n", ret
);
2053 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2054 (LPBYTE
)mru_list
, &mru_list_size
);
2055 if(ret
|| key_type
!= REG_SZ
){
2056 if(ret
== ERROR_FILE_NOT_FOUND
)
2059 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2064 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2065 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2066 DWORD value_data_size
= sizeof(value_data
);
2068 *value_name
= *cur_mru_slot
;
2070 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2071 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2072 if(ret
|| key_type
!= REG_BINARY
){
2073 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2077 if(!strcmpiW(module_name
, value_data
)){
2081 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2089 /* the module name isn't in the registry, so find the next open slot */
2090 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2091 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2092 for(i
= 0; i
< 25; ++i
){
2097 /* all slots are taken, so return the last one in MRUList */
2099 return *cur_mru_slot
;
2102 /* save the given filename as most-recently-used path for this module */
2103 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2105 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2109 /* get the current executable's name */
2110 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2111 WARN("GotModuleFileName failed: %d\n", GetLastError());
2114 module_name
= strrchrW(module_path
, '\\');
2116 module_name
= module_path
;
2120 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2125 { /* update the slot's info */
2126 WCHAR
*path_ends
, *final
;
2127 DWORD path_len
, final_len
;
2129 /* use only the path segment of `filename' */
2130 path_ends
= strrchrW(filename
, '\\');
2131 path_len
= path_ends
- filename
;
2133 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2135 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2138 lstrcpyW(final
, module_name
);
2139 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2140 final
[final_len
-1] = '\0';
2142 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2143 final_len
* sizeof(WCHAR
));
2145 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2154 { /* update MRUList value */
2155 WCHAR old_mru_list
[32], new_mru_list
[32];
2156 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2157 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2159 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2160 (LPBYTE
)old_mru_list
, &mru_list_size
);
2161 if(ret
|| key_type
!= REG_SZ
){
2162 if(ret
== ERROR_FILE_NOT_FOUND
){
2163 new_mru_list
[0] = slot
;
2164 new_mru_list
[1] = '\0';
2166 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2171 /* copy old list data over so that the new slot is at the start
2173 *new_mru_slot
++ = slot
;
2174 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2175 if(*old_mru_slot
!= slot
)
2176 *new_mru_slot
++ = *old_mru_slot
;
2178 *new_mru_slot
= '\0';
2181 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2182 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2184 WARN("Error saving MRUList data: %d\n", ret
);
2191 /* load the most-recently-used path for this module */
2192 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2194 WCHAR module_path
[MAX_PATH
], *module_name
;
2196 /* get the current executable's name */
2197 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2198 WARN("GotModuleFileName failed: %d\n", GetLastError());
2201 module_name
= strrchrW(module_path
, '\\');
2203 module_name
= module_path
;
2207 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2208 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2211 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2213 WCHAR strMsgTitle
[MAX_PATH
];
2214 WCHAR strMsgText
[MAX_PATH
];
2216 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2218 strMsgTitle
[0] = '\0';
2219 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2220 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2223 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2224 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2226 int nOpenAction
= defAction
;
2227 LPWSTR lpszTemp
, lpszTemp1
;
2228 LPITEMIDLIST pidl
= NULL
;
2229 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2231 /* check for invalid chars */
2232 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2234 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2238 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2240 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2243 LPSHELLFOLDER lpsfChild
;
2244 WCHAR lpwstrTemp
[MAX_PATH
];
2245 DWORD dwEaten
, dwAttributes
;
2248 lstrcpyW(lpwstrTemp
, lpszTemp
);
2249 p
= PathFindNextComponentW(lpwstrTemp
);
2251 if (!p
) break; /* end of path */
2254 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2256 /* There are no wildcards when OFN_NOVALIDATE is set */
2257 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2259 static const WCHAR wszWild
[] = { '*', '?', 0 };
2260 /* if the last element is a wildcard do a search */
2261 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2263 nOpenAction
= ONOPEN_SEARCH
;
2267 lpszTemp1
= lpszTemp
;
2269 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2271 /* append a backslash to drive letters */
2272 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2273 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2274 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2276 PathAddBackslashW(lpwstrTemp
);
2279 dwAttributes
= SFGAO_FOLDER
;
2280 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2282 /* the path component is valid, we have a pidl of the next path component */
2283 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2284 if(dwAttributes
& SFGAO_FOLDER
)
2286 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2288 ERR("bind to failed\n"); /* should not fail */
2291 IShellFolder_Release(*ppsf
);
2299 /* end dialog, return value */
2300 nOpenAction
= ONOPEN_OPEN
;
2303 COMDLG32_SHFree(pidl
);
2306 else if (!(flags
& OFN_NOVALIDATE
))
2308 if(*lpszTemp
|| /* points to trailing null for last path element */
2309 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2311 if(flags
& OFN_PATHMUSTEXIST
)
2313 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2319 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2321 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2325 /* change to the current folder */
2326 nOpenAction
= ONOPEN_OPEN
;
2331 nOpenAction
= ONOPEN_OPEN
;
2335 if(pidl
) COMDLG32_SHFree(pidl
);
2340 /***********************************************************************
2343 * Ok button WM_COMMAND message handler
2345 * If the function succeeds, the return value is nonzero.
2347 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2349 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2350 LPWSTR lpstrFileList
;
2351 UINT nFileCount
= 0;
2354 WCHAR lpstrPathAndFile
[MAX_PATH
];
2355 LPSHELLFOLDER lpsf
= NULL
;
2358 TRACE("hwnd=%p\n", hwnd
);
2360 /* try to browse the selected item */
2361 if(BrowseSelectedFolder(hwnd
))
2364 /* get the files from the edit control */
2365 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2372 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2376 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2379 Step 1: Build a complete path name from the current folder and
2380 the filename or path in the edit box.
2382 - the path in the edit box is a root path
2383 (with or without drive letter)
2384 - the edit box contains ".." (or a path with ".." in it)
2387 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2388 MemFree(lpstrFileList
);
2391 Step 2: here we have a cleaned up path
2393 We have to parse the path step by step to see if we have to browse
2394 to a folder if the path points to a directory or the last
2395 valid element is a directory.
2398 lpstrPathAndFile: cleaned up path
2402 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2403 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2404 nOpenAction
= ONOPEN_OPEN
;
2406 nOpenAction
= ONOPEN_BROWSE
;
2408 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2409 fodInfos
->ofnInfos
->Flags
,
2410 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2416 Step 3: here we have a cleaned up and validated path
2419 lpsf: ShellFolder bound to the rightmost valid path component
2420 lpstrPathAndFile: cleaned up path
2421 nOpenAction: action to do
2423 TRACE("end validate sf=%p\n", lpsf
);
2427 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2428 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2431 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2434 /* replace the current filter */
2435 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2436 len
= lstrlenW(lpszTemp
)+1;
2437 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2438 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2440 /* set the filter cb to the extension when possible */
2441 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2442 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2445 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2446 TRACE("ONOPEN_BROWSE\n");
2448 IPersistFolder2
* ppf2
;
2449 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2451 LPITEMIDLIST pidlCurrent
;
2452 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2453 IPersistFolder2_Release(ppf2
);
2454 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2456 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2457 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2459 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2460 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2463 else if( nOpenAction
== ONOPEN_SEARCH
)
2465 if (fodInfos
->Shell
.FOIShellView
)
2466 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2468 COMDLG32_SHFree(pidlCurrent
);
2469 if (filename_is_edit( fodInfos
))
2470 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2475 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2476 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2482 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2483 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2487 /* update READONLY check box flag */
2488 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2489 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2491 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2493 /* Attach the file extension with file name*/
2494 ext
= PathFindExtensionW(lpstrPathAndFile
);
2495 if (! *ext
&& fodInfos
->defext
)
2497 /* if no extension is specified with file name, then */
2498 /* attach the extension from file filter or default one */
2500 WCHAR
*filterExt
= NULL
;
2501 LPWSTR lpstrFilter
= NULL
;
2502 static const WCHAR szwDot
[] = {'.',0};
2503 int PathLength
= lstrlenW(lpstrPathAndFile
);
2505 /*Get the file extension from file type filter*/
2506 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2507 fodInfos
->ofnInfos
->nFilterIndex
-1);
2509 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2511 WCHAR
* filterSearchIndex
;
2512 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2513 strcpyW(filterExt
, lpstrFilter
);
2515 /* if a semicolon-separated list of file extensions was given, do not include the
2516 semicolon or anything after it in the extension.
2517 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2518 filterSearchIndex
= strchrW(filterExt
, ';');
2519 if (filterSearchIndex
)
2521 filterSearchIndex
[0] = '\0';
2524 /* find the file extension by searching for the first dot in filterExt */
2525 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2526 /* if the extension is invalid or contains a glob, ignore it */
2527 filterSearchIndex
= strchrW(filterExt
, '.');
2528 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2530 strcpyW(filterExt
, filterSearchIndex
);
2534 HeapFree(GetProcessHeap(), 0, filterExt
);
2541 /* use the default file extension */
2542 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2543 strcpyW(filterExt
, fodInfos
->defext
);
2546 if (*filterExt
) /* ignore filterExt="" */
2549 lstrcatW(lpstrPathAndFile
, szwDot
);
2550 /* Attach the extension */
2551 lstrcatW(lpstrPathAndFile
, filterExt
);
2554 HeapFree(GetProcessHeap(), 0, filterExt
);
2556 /* In Open dialog: if file does not exist try without extension */
2557 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2558 lpstrPathAndFile
[PathLength
] = '\0';
2560 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2563 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2564 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2566 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2569 /* In Save dialog: check if the file already exists */
2570 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2571 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2572 && PathFileExistsW(lpstrPathAndFile
))
2574 WCHAR lpstrOverwrite
[100];
2577 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2578 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2579 MB_YESNO
| MB_ICONEXCLAMATION
);
2580 if (answer
== IDNO
|| answer
== IDCANCEL
)
2587 /* In Open dialog: check if it should be created if it doesn't exist */
2588 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2589 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2590 && !PathFileExistsW(lpstrPathAndFile
))
2592 WCHAR lpstrCreate
[100];
2595 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2596 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2597 MB_YESNO
| MB_ICONEXCLAMATION
);
2598 if (answer
== IDNO
|| answer
== IDCANCEL
)
2605 /* Check that the size of the file does not exceed buffer size.
2606 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2607 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2608 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2611 /* fill destination buffer */
2612 if (fodInfos
->ofnInfos
->lpstrFile
)
2614 if(fodInfos
->unicode
)
2616 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2618 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2619 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2620 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2624 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2626 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2627 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2628 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2629 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2633 if(fodInfos
->unicode
)
2637 /* set filename offset */
2638 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2639 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2641 /* set extension offset */
2642 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2643 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2648 CHAR tempFileA
[MAX_PATH
];
2650 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2651 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2652 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2654 /* set filename offset */
2655 lpszTemp
= PathFindFileNameA(tempFileA
);
2656 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2658 /* set extension offset */
2659 lpszTemp
= PathFindExtensionA(tempFileA
);
2660 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2663 /* set the lpstrFileTitle */
2664 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2666 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2667 if(fodInfos
->unicode
)
2669 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2670 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2674 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2675 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2676 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2680 /* copy currently selected filter to lpstrCustomFilter */
2681 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2683 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2684 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2685 NULL
, 0, NULL
, NULL
);
2686 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2688 LPSTR s
= ofn
->lpstrCustomFilter
;
2689 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2690 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2691 s
, len
, NULL
, NULL
);
2696 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2699 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2702 FILEDLG95_Clean(hwnd
);
2703 ret
= EndDialog(hwnd
, TRUE
);
2709 size
= lstrlenW(lpstrPathAndFile
) + 1;
2710 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2712 /* return needed size in first two bytes of lpstrFile */
2713 if(fodInfos
->ofnInfos
->lpstrFile
)
2714 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2715 FILEDLG95_Clean(hwnd
);
2716 ret
= EndDialog(hwnd
, FALSE
);
2717 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2724 if(lpsf
) IShellFolder_Release(lpsf
);
2728 /***********************************************************************
2729 * FILEDLG95_SHELL_Init
2731 * Initialisation of the shell objects
2733 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2735 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2737 TRACE("%p\n", hwnd
);
2740 * Initialisation of the FileOpenDialogInfos structure
2746 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2748 /* Disable multi-select if flag not set */
2749 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2751 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2753 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2754 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2756 /* Construct the IShellBrowser interface */
2757 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2762 /***********************************************************************
2763 * FILEDLG95_SHELL_ExecuteCommand
2765 * Change the folder option and refresh the view
2766 * If the function succeeds, the return value is nonzero.
2768 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2770 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2773 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2775 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2780 CMINVOKECOMMANDINFO ci
;
2781 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2782 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2786 IContextMenu_InvokeCommand(pcm
, &ci
);
2787 IContextMenu_Release(pcm
);
2793 /***********************************************************************
2794 * FILEDLG95_SHELL_UpFolder
2796 * Browse to the specified object
2797 * If the function succeeds, the return value is nonzero.
2799 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2801 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2805 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2809 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2810 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2816 /***********************************************************************
2817 * FILEDLG95_SHELL_BrowseToDesktop
2819 * Browse to the Desktop
2820 * If the function succeeds, the return value is nonzero.
2822 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2824 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2830 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2831 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2832 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2833 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2834 COMDLG32_SHFree(pidl
);
2835 return SUCCEEDED(hres
);
2837 /***********************************************************************
2838 * FILEDLG95_SHELL_Clean
2840 * Cleans the memory used by shell objects
2842 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2844 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2848 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2850 /* clean Shell interfaces */
2851 if (fodInfos
->Shell
.FOIShellView
)
2853 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2854 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2856 if (fodInfos
->Shell
.FOIShellFolder
)
2857 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2858 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2859 if (fodInfos
->Shell
.FOIDataObject
)
2860 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2863 /***********************************************************************
2864 * FILEDLG95_FILETYPE_Init
2866 * Initialisation of the file type combo box
2868 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2870 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2871 int nFilters
= 0; /* number of filters */
2874 TRACE("%p\n", hwnd
);
2876 if(fodInfos
->customfilter
)
2878 /* customfilter has one entry... title\0ext\0
2879 * Set first entry of combo box item with customfilter
2882 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2885 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2887 /* Copy the extensions */
2888 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2889 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2890 lstrcpyW(lpstrExt
,lpstrPos
);
2892 /* Add the item at the end of the combo */
2893 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2894 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2897 if(fodInfos
->filter
)
2899 LPCWSTR lpstrPos
= fodInfos
->filter
;
2903 /* filter is a list... title\0ext\0......\0\0
2904 * Set the combo item text to the title and the item data
2907 LPCWSTR lpstrDisplay
;
2911 if(! *lpstrPos
) break; /* end */
2912 lpstrDisplay
= lpstrPos
;
2913 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2915 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2919 /* Copy the extensions */
2920 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2921 lstrcpyW(lpstrExt
,lpstrPos
);
2922 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2924 /* Add the item at the end of the combo */
2925 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2927 /* malformed filters are added anyway... */
2928 if (!*lpstrExt
) break;
2933 * Set the current filter to the one specified
2934 * in the initialisation structure
2936 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2940 /* Check to make sure our index isn't out of bounds. */
2941 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2942 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2943 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2945 /* set default filter index */
2946 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2947 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2949 /* calculate index of Combo Box item */
2950 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2951 if (fodInfos
->customfilter
== NULL
)
2954 /* Set the current index selection. */
2955 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2957 /* Get the corresponding text string from the combo box. */
2958 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2961 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2967 CharLowerW(lpstrFilter
); /* lowercase */
2968 len
= lstrlenW(lpstrFilter
)+1;
2969 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2970 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2973 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2977 /***********************************************************************
2978 * FILEDLG95_FILETYPE_OnCommand
2980 * WM_COMMAND of the file type combo box
2981 * If the function succeeds, the return value is nonzero.
2983 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2985 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2993 /* Get the current item of the filetype combo box */
2994 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2996 /* set the current filter index */
2997 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2998 (fodInfos
->customfilter
== NULL
? 1 : 0);
3000 /* Set the current filter with the current selection */
3001 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3003 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3005 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3008 CharLowerW(lpstrFilter
); /* lowercase */
3009 len
= lstrlenW(lpstrFilter
)+1;
3010 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3011 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3012 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3013 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3016 /* Refresh the actual view to display the included items*/
3017 if (fodInfos
->Shell
.FOIShellView
)
3018 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3023 /***********************************************************************
3024 * FILEDLG95_FILETYPE_SearchExt
3026 * searches for an extension in the filetype box
3028 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3030 int i
, iCount
= CBGetCount(hwnd
);
3032 TRACE("%s\n", debugstr_w(lpstrExt
));
3034 if(iCount
!= CB_ERR
)
3036 for(i
=0;i
<iCount
;i
++)
3038 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3045 /***********************************************************************
3046 * FILEDLG95_FILETYPE_Clean
3048 * Clean the memory used by the filetype combo box
3050 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3052 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3054 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3058 /* Delete each string of the combo and their associated data */
3059 if(iCount
!= CB_ERR
)
3061 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3063 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3064 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3067 /* Current filter */
3068 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3072 /***********************************************************************
3073 * FILEDLG95_LOOKIN_Init
3075 * Initialisation of the look in combo box
3078 /* Small helper function, to determine if the unixfs shell extension is rooted
3079 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3081 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3083 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3084 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3085 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3086 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3087 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3088 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3089 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3091 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3098 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3100 IShellFolder
*psfRoot
, *psfDrives
;
3101 IEnumIDList
*lpeRoot
, *lpeDrives
;
3102 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3105 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3107 TRACE("%p\n", hwndCombo
);
3109 liInfos
->iMaxIndentation
= 0;
3111 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3113 hdc
= GetDC( hwndCombo
);
3114 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3115 GetTextMetricsW( hdc
, &tm
);
3116 ReleaseDC( hwndCombo
, hdc
);
3118 /* set item height for both text field and listbox */
3119 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3120 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3122 /* Turn on the extended UI for the combo box like Windows does */
3123 CBSetExtendedUI(hwndCombo
, TRUE
);
3125 /* Initialise data of Desktop folder */
3126 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3127 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3128 COMDLG32_SHFree(pidlTmp
);
3130 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3132 SHGetDesktopFolder(&psfRoot
);
3136 /* enumerate the contents of the desktop */
3137 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3139 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3141 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3143 /* If the unixfs extension is rooted, we don't expand the drives by default */
3144 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3146 /* special handling for CSIDL_DRIVES */
3147 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3149 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3151 /* enumerate the drives */
3152 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3154 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3156 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3157 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3158 COMDLG32_SHFree(pidlAbsTmp
);
3159 COMDLG32_SHFree(pidlTmp1
);
3161 IEnumIDList_Release(lpeDrives
);
3163 IShellFolder_Release(psfDrives
);
3168 COMDLG32_SHFree(pidlTmp
);
3170 IEnumIDList_Release(lpeRoot
);
3172 IShellFolder_Release(psfRoot
);
3175 COMDLG32_SHFree(pidlDrives
);
3178 /***********************************************************************
3179 * FILEDLG95_LOOKIN_DrawItem
3181 * WM_DRAWITEM message handler
3183 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3185 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3186 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3187 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3191 HIMAGELIST ilItemImage
;
3194 LPSFOLDER tmpFolder
;
3195 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3196 UINT icon_width
, icon_height
;
3200 if(pDIStruct
->itemID
== -1)
3203 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3204 pDIStruct
->itemID
)))
3208 icon_width
= GetSystemMetrics(SM_CXICON
);
3209 icon_height
= GetSystemMetrics(SM_CYICON
);
3210 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3212 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3213 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3214 shgfi_flags
|= SHGFI_SMALLICON
;
3217 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3218 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3220 /* Is this item selected ? */
3221 if(pDIStruct
->itemState
& ODS_SELECTED
)
3223 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3224 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3225 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3229 SetTextColor(pDIStruct
->hDC
,crText
);
3230 SetBkColor(pDIStruct
->hDC
,crWin
);
3231 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3234 /* Do not indent item if drawing in the edit of the combo */
3235 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3238 iIndentation
= tmpFolder
->m_iIndent
;
3240 /* Draw text and icon */
3242 /* Initialise the icon display area */
3243 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3244 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3245 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3246 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3248 /* Initialise the text display area */
3249 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3250 rectText
.left
= rectIcon
.right
;
3252 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3253 rectText
.right
= pDIStruct
->rcItem
.right
;
3255 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3257 /* Draw the icon from the image list */
3258 ImageList_Draw(ilItemImage
,
3265 /* Draw the associated text */
3266 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3270 /***********************************************************************
3271 * FILEDLG95_LOOKIN_OnCommand
3273 * LookIn combo box WM_COMMAND message handler
3274 * If the function succeeds, the return value is nonzero.
3276 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3278 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3280 TRACE("%p\n", fodInfos
);
3286 LPSFOLDER tmpFolder
;
3289 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3291 if( iItem
== CB_ERR
) return FALSE
;
3293 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3298 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3299 tmpFolder
->pidlItem
,
3302 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3303 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3313 /***********************************************************************
3314 * FILEDLG95_LOOKIN_AddItem
3316 * Adds an absolute pidl item to the lookin combo box
3317 * returns the index of the inserted item
3319 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3321 LPITEMIDLIST pidlNext
;
3324 LookInInfos
*liInfos
;
3326 TRACE("%p, %p, %d\n", hwnd
, pidl
, iInsertId
);
3331 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3334 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3335 tmpFolder
->m_iIndent
= 0;
3337 /* Calculate the indentation of the item in the lookin*/
3339 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3341 tmpFolder
->m_iIndent
++;
3344 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3346 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3347 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3349 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3350 SHGetFileInfoW((LPCWSTR
)pidl
,
3354 SHGFI_DISPLAYNAME
| SHGFI_PIDL
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3356 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3358 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3362 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3364 /* Add the item at the end of the list */
3367 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3369 /* Insert the item at the iInsertId position*/
3372 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3375 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3379 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3380 MemFree( tmpFolder
);
3385 /***********************************************************************
3386 * FILEDLG95_LOOKIN_InsertItemAfterParent
3388 * Insert an item below its parent
3390 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3393 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3398 if (pidl
== pidlParent
)
3401 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3405 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3408 /* Free pidlParent memory */
3409 COMDLG32_SHFree(pidlParent
);
3411 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3414 /***********************************************************************
3415 * FILEDLG95_LOOKIN_SelectItem
3417 * Adds an absolute pidl item to the lookin combo box
3418 * returns the index of the inserted item
3420 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3423 LookInInfos
*liInfos
;
3425 TRACE("%p, %p\n", hwnd
, pidl
);
3427 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3429 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3433 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3434 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3439 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3440 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3444 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3446 if(iRemovedItem
< iItemPos
)
3451 CBSetCurSel(hwnd
,iItemPos
);
3452 liInfos
->uSelectedItem
= iItemPos
;
3458 /***********************************************************************
3459 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3461 * Remove the item with an expansion level over iExpansionLevel
3463 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3466 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3470 if(liInfos
->iMaxIndentation
<= 2)
3473 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3475 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3476 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3478 CBDeleteString(hwnd
,iItemPos
);
3479 liInfos
->iMaxIndentation
--;
3487 /***********************************************************************
3488 * FILEDLG95_LOOKIN_SearchItem
3490 * Search for pidl in the lookin combo box
3491 * returns the index of the found item
3493 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3496 int iCount
= CBGetCount(hwnd
);
3498 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3500 if (iCount
!= CB_ERR
)
3504 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3506 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3508 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3516 /***********************************************************************
3517 * FILEDLG95_LOOKIN_Clean
3519 * Clean the memory used by the lookin combo box
3521 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3523 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3524 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3526 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3530 /* Delete each string of the combo and their associated data */
3531 if (iCount
!= CB_ERR
)
3533 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3535 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3536 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3538 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3542 /* LookInInfos structure */
3544 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3547 /***********************************************************************
3550 * Fill the FORMATETC used in the shell id list
3552 static FORMATETC
get_def_format(void)
3554 static CLIPFORMAT cfFormat
;
3555 FORMATETC formatetc
;
3557 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3558 formatetc
.cfFormat
= cfFormat
;
3560 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3561 formatetc
.lindex
= -1;
3562 formatetc
.tymed
= TYMED_HGLOBAL
;
3566 /***********************************************************************
3567 * FILEDLG95_FILENAME_FillFromSelection
3569 * fills the edit box from the cached DataObject
3571 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3573 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3575 LPWSTR lpstrAllFiles
, lpstrTmp
;
3576 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3579 FORMATETC formatetc
= get_def_format();
3583 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3586 cida
= GlobalLock(medium
.u
.hGlobal
);
3587 nFileSelected
= cida
->cidl
;
3589 /* Allocate a buffer */
3590 nAllFilesMaxLength
= MAX_PATH
+ 3;
3591 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3595 /* Loop through the selection, handle only files (not folders) */
3596 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3598 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3601 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3603 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3605 nAllFilesMaxLength
*= 2;
3606 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3609 lpstrAllFiles
= lpstrTmp
;
3612 lpstrAllFiles
[nAllFilesLength
++] = '"';
3613 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3614 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3615 nAllFilesLength
+= nThisFileLength
;
3616 lpstrAllFiles
[nAllFilesLength
++] = '"';
3617 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3624 /* If there's only one file, use the name as-is without quotes */
3625 lpstrTmp
= lpstrAllFiles
;
3629 lpstrTmp
[nThisFileLength
] = 0;
3631 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3632 /* Select the file name like Windows does */
3633 if (filename_is_edit(fodInfos
))
3634 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3638 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3639 COMCTL32_ReleaseStgMedium(medium
);
3643 /* copied from shell32 to avoid linking to it
3644 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3645 * is dependent on whether emulated OS is unicode or not.
3647 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3652 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3653 COMDLG32_SHFree(src
->u
.pOleStr
);
3657 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3662 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3667 FIXME("unknown type %x!\n", src
->uType
);
3668 if (len
) *dest
= '\0';
3674 /***********************************************************************
3675 * FILEDLG95_FILENAME_GetFileNames
3677 * Copies the filenames to a delimited string list.
3679 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3681 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3682 UINT nFileCount
= 0; /* number of files */
3683 UINT nStrLen
= 0; /* length of string in edit control */
3684 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3688 /* get the filenames from the filename control */
3689 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3690 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3691 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3693 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3695 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3701 * DATAOBJECT Helper functions
3704 /***********************************************************************
3705 * COMCTL32_ReleaseStgMedium
3707 * like ReleaseStgMedium from ole32
3709 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3711 if(medium
.pUnkForRelease
)
3713 IUnknown_Release(medium
.pUnkForRelease
);
3717 GlobalUnlock(medium
.u
.hGlobal
);
3718 GlobalFree(medium
.u
.hGlobal
);
3722 /***********************************************************************
3723 * GetPidlFromDataObject
3725 * Return pidl(s) by number from the cached DataObject
3727 * nPidlIndex=0 gets the fully qualified root path
3729 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3733 FORMATETC formatetc
= get_def_format();
3734 LPITEMIDLIST pidl
= NULL
;
3736 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3741 /* Get the pidls from IDataObject */
3742 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3744 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3745 if(nPidlIndex
<= cida
->cidl
)
3747 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3749 COMCTL32_ReleaseStgMedium(medium
);
3754 /***********************************************************************
3757 * Return the number of selected items in the DataObject.
3760 static UINT
GetNumSelected( IDataObject
*doSelected
)
3764 FORMATETC formatetc
= get_def_format();
3766 TRACE("sv=%p\n", doSelected
);
3768 if (!doSelected
) return 0;
3770 /* Get the pidls from IDataObject */
3771 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3773 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3774 retVal
= cida
->cidl
;
3775 COMCTL32_ReleaseStgMedium(medium
);
3785 /***********************************************************************
3788 * Get the pidl's display name (relative to folder) and
3789 * put it in lpstrFileName.
3791 * Return NOERROR on success,
3795 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3800 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3804 SHGetDesktopFolder(&lpsf
);
3805 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3806 IShellFolder_Release(lpsf
);
3810 /* Get the display name of the pidl relative to the folder */
3811 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3813 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3818 /***********************************************************************
3819 * GetShellFolderFromPidl
3821 * pidlRel is the item pidl relative
3822 * Return the IShellFolder of the absolute pidl
3824 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3826 IShellFolder
*psf
= NULL
,*psfParent
;
3828 TRACE("%p\n", pidlAbs
);
3830 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3833 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3835 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3837 IShellFolder_Release(psfParent
);
3841 /* return the desktop */
3847 /***********************************************************************
3850 * Return the LPITEMIDLIST to the parent of the pidl in the list
3852 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3854 LPITEMIDLIST pidlParent
;
3856 TRACE("%p\n", pidl
);
3858 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3859 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3864 /***********************************************************************
3867 * returns the pidl of the file name relative to folder
3868 * NULL if an error occurred
3870 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3872 LPITEMIDLIST pidl
= NULL
;
3875 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3877 if(!lpcstrFileName
) return NULL
;
3878 if(!*lpcstrFileName
) return NULL
;
3882 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3883 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3884 IShellFolder_Release(lpsf
);
3889 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3896 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3898 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3901 TRACE("%p, %p\n", psf
, pidl
);
3903 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3905 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3906 /* see documentation shell 4.1*/
3907 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3910 /***********************************************************************
3911 * BrowseSelectedFolder
3913 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3915 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
3916 BOOL bBrowseSelFolder
= FALSE
;
3920 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3922 LPITEMIDLIST pidlSelection
;
3924 /* get the file selected */
3925 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3926 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3928 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3929 pidlSelection
, SBSP_RELATIVE
) ) )
3932 LoadStringW( COMDLG32_hInstance
, IDS_PATHNOTEXISTING
, buf
, sizeof(buf
)/sizeof(WCHAR
) );
3933 MessageBoxW( hwnd
, buf
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3935 bBrowseSelFolder
= TRUE
;
3936 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3937 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3939 COMDLG32_SHFree( pidlSelection
);
3942 return bBrowseSelFolder
;
3946 * Memory allocation methods */
3947 static void *MemAlloc(UINT size
)
3949 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3952 static void MemFree(void *mem
)
3954 HeapFree(GetProcessHeap(),0,mem
);
3957 static inline BOOL
valid_struct_size( DWORD size
)
3959 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
3960 (size
== sizeof( OPENFILENAMEW
));
3963 static inline BOOL
is_win16_looks(DWORD flags
)
3965 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
3966 !(flags
& OFN_EXPLORER
));
3969 /* ------------------ APIs ---------------------- */
3971 /***********************************************************************
3972 * GetOpenFileNameA (COMDLG32.@)
3974 * Creates a dialog box for the user to select a file to open.
3977 * TRUE on success: user enters a valid file
3978 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3981 BOOL WINAPI
GetOpenFileNameA(OPENFILENAMEA
*ofn
)
3983 TRACE("flags 0x%08x\n", ofn
->Flags
);
3985 if (!valid_struct_size( ofn
->lStructSize
))
3987 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
3991 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3992 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3993 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3995 if (is_win16_looks(ofn
->Flags
))
3996 return GetFileName31A(ofn
, OPEN_DIALOG
);
3999 FileOpenDlgInfos info
;
4001 init_filedlg_infoA(ofn
, &info
);
4002 return GetFileDialog95(&info
, OPEN_DIALOG
);
4006 /***********************************************************************
4007 * GetOpenFileNameW (COMDLG32.@)
4009 * Creates a dialog box for the user to select a file to open.
4012 * TRUE on success: user enters a valid file
4013 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4016 BOOL WINAPI
GetOpenFileNameW(OPENFILENAMEW
*ofn
)
4018 TRACE("flags 0x%08x\n", ofn
->Flags
);
4020 if (!valid_struct_size( ofn
->lStructSize
))
4022 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4026 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4027 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4028 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4030 if (is_win16_looks(ofn
->Flags
))
4031 return GetFileName31W(ofn
, OPEN_DIALOG
);
4034 FileOpenDlgInfos info
;
4036 init_filedlg_infoW(ofn
, &info
);
4037 return GetFileDialog95(&info
, OPEN_DIALOG
);
4042 /***********************************************************************
4043 * GetSaveFileNameA (COMDLG32.@)
4045 * Creates a dialog box for the user to select a file to save.
4048 * TRUE on success: user enters a valid file
4049 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4052 BOOL WINAPI
GetSaveFileNameA(OPENFILENAMEA
*ofn
)
4054 if (!valid_struct_size( ofn
->lStructSize
))
4056 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4060 if (is_win16_looks(ofn
->Flags
))
4061 return GetFileName31A(ofn
, SAVE_DIALOG
);
4064 FileOpenDlgInfos info
;
4066 init_filedlg_infoA(ofn
, &info
);
4067 return GetFileDialog95(&info
, SAVE_DIALOG
);
4071 /***********************************************************************
4072 * GetSaveFileNameW (COMDLG32.@)
4074 * Creates a dialog box for the user to select a file to save.
4077 * TRUE on success: user enters a valid file
4078 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4081 BOOL WINAPI
GetSaveFileNameW(
4082 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4084 if (!valid_struct_size( ofn
->lStructSize
))
4086 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4090 if (is_win16_looks(ofn
->Flags
))
4091 return GetFileName31W(ofn
, SAVE_DIALOG
);
4094 FileOpenDlgInfos info
;
4096 init_filedlg_infoW(ofn
, &info
);
4097 return GetFileDialog95(&info
, SAVE_DIALOG
);
4101 /***********************************************************************
4102 * GetFileTitleA (COMDLG32.@)
4104 * See GetFileTitleW.
4106 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4109 UNICODE_STRING strWFile
;
4112 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4113 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4114 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4115 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4116 RtlFreeUnicodeString( &strWFile
);
4117 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4122 /***********************************************************************
4123 * GetFileTitleW (COMDLG32.@)
4125 * Get the name of a file.
4128 * lpFile [I] name and location of file
4129 * lpTitle [O] returned file name
4130 * cbBuf [I] buffer size of lpTitle
4134 * Failure: negative number.
4136 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4139 static const WCHAR brkpoint
[] = {'*','[',']',0};
4140 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4142 if(lpFile
== NULL
|| lpTitle
== NULL
)
4145 len
= lstrlenW(lpFile
);
4150 if(strpbrkW(lpFile
, brkpoint
))
4155 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4158 for(i
= len
; i
>= 0; i
--)
4160 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4170 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4172 len
= lstrlenW(lpFile
+i
)+1;
4176 lstrcpyW(lpTitle
, &lpFile
[i
]);