2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
62 typedef struct SFolder
64 int m_iImageIndex
; /* Index of picture in image list */
66 int m_iIndent
; /* Indentation index */
67 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
71 typedef struct tagLookInInfo
78 /***********************************************************************
79 * Defines and global variables
82 /* Draw item constant */
88 /* SearchItem methods */
91 #define ITEM_NOTFOUND -1
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
136 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
137 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
139 static const WCHAR LastVisitedMRUW
[] =
140 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
141 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
142 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
143 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
144 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
146 static const WCHAR filedlg_info_propnameW
[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
148 FileOpenDlgInfos
*get_filedlg_infoptr(HWND hwnd
)
150 return GetPropW(hwnd
, filedlg_info_propnameW
);
153 /***********************************************************************
157 /* Internal functions used by the dialog */
158 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
159 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
160 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
161 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
162 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
163 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
164 static void FILEDLG95_Clean(HWND hwnd
);
166 /* Functions used by the shell navigation */
167 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
168 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
169 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
170 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
171 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
173 /* Functions used by the EDIT box */
174 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
176 /* Functions used by the filetype combo box */
177 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
178 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
179 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
180 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
182 /* Functions used by the Look In combo box */
183 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
184 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
185 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
186 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
187 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
188 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
189 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
190 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
191 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
193 /* Functions for dealing with the most-recently-used registry keys */
194 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
195 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
196 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
198 /* Miscellaneous tool functions */
199 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
200 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
201 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
202 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
203 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
204 static UINT
GetNumSelected( IDataObject
*doSelected
);
205 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
207 /* Shell memory allocation */
208 static void *MemAlloc(UINT size
);
209 static void MemFree(void *mem
);
211 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
212 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
213 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
214 static BOOL
BrowseSelectedFolder(HWND hwnd
);
216 /***********************************************************************
219 * Creates an Open common dialog box that lets the user select
220 * the drive, directory, and the name of a file or set of files to open.
222 * IN : The FileOpenDlgInfos structure associated with the dialog
223 * OUT : TRUE on success
224 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
226 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
233 /* test for missing functionality */
234 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
236 FIXME("Flags 0x%08x not yet implemented\n",
237 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
240 /* Create the dialog from a template */
242 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
244 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
247 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
248 !(template = LockResource( hDlgTmpl
)))
250 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
254 /* msdn: explorer style dialogs permit sizing by default.
255 * The OFN_ENABLESIZING flag is only needed when a hook or
256 * custom template is provided */
257 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
258 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
259 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
261 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
263 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
264 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
267 /* old style hook messages */
268 if (IsHooked(fodInfos
))
270 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
271 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
272 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
273 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
276 if (fodInfos
->unicode
)
277 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
279 fodInfos
->ofnInfos
->hwndOwner
,
283 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
285 fodInfos
->ofnInfos
->hwndOwner
,
288 if (fodInfos
->ole_initialized
)
291 /* Unable to create the dialog */
298 static WCHAR
*heap_strdupAtoW(const char *str
)
306 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
307 ret
= MemAlloc(len
* sizeof(WCHAR
));
308 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
313 static void init_filedlg_infoW(OPENFILENAMEW
*ofn
, FileOpenDlgInfos
*info
)
315 INITCOMMONCONTROLSEX icc
;
317 /* Initialize ComboBoxEx32 */
318 icc
.dwSize
= sizeof(icc
);
319 icc
.dwICC
= ICC_USEREX_CLASSES
;
320 InitCommonControlsEx(&icc
);
322 /* Initialize CommDlgExtendedError() */
323 COMDLG32_SetCommDlgExtendedError(0);
325 memset(info
, 0, sizeof(*info
));
327 /* Pass in the original ofn */
328 info
->ofnInfos
= ofn
;
330 info
->title
= ofn
->lpstrTitle
;
331 info
->defext
= ofn
->lpstrDefExt
;
332 info
->filter
= ofn
->lpstrFilter
;
333 info
->customfilter
= ofn
->lpstrCustomFilter
;
337 info
->filename
= MemAlloc(ofn
->nMaxFile
* sizeof(WCHAR
));
338 lstrcpynW(info
->filename
, ofn
->lpstrFile
, ofn
->nMaxFile
);
341 if (ofn
->lpstrInitialDir
)
343 DWORD len
= ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, NULL
, 0);
346 info
->initdir
= MemAlloc(len
* sizeof(WCHAR
));
347 ExpandEnvironmentStringsW(ofn
->lpstrInitialDir
, info
->initdir
, len
);
351 info
->unicode
= TRUE
;
354 static void init_filedlg_infoA(OPENFILENAMEA
*ofn
, FileOpenDlgInfos
*info
)
359 ofnW
= *(OPENFILENAMEW
*)ofn
;
361 ofnW
.lpstrInitialDir
= heap_strdupAtoW(ofn
->lpstrInitialDir
);
362 ofnW
.lpstrDefExt
= heap_strdupAtoW(ofn
->lpstrDefExt
);
363 ofnW
.lpstrTitle
= heap_strdupAtoW(ofn
->lpstrTitle
);
367 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, 0);
368 ofnW
.lpstrFile
= MemAlloc(len
* sizeof(WCHAR
));
369 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFile
, ofn
->nMaxFile
, ofnW
.lpstrFile
, len
);
373 if (ofn
->lpstrFilter
)
378 /* filter is a list... title\0ext\0......\0\0 */
379 s
= ofn
->lpstrFilter
;
380 while (*s
) s
= s
+strlen(s
)+1;
382 n
= s
- ofn
->lpstrFilter
;
383 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0);
384 ofnW
.lpstrFilter
= MemAlloc(len
* sizeof(WCHAR
));
385 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrFilter
, n
, (WCHAR
*)ofnW
.lpstrFilter
, len
);
388 /* convert lpstrCustomFilter */
389 if (ofn
->lpstrCustomFilter
)
394 /* customfilter contains a pair of strings... title\0ext\0 */
395 s
= ofn
->lpstrCustomFilter
;
396 if (*s
) s
= s
+strlen(s
)+1;
397 if (*s
) s
= s
+strlen(s
)+1;
398 n
= s
- ofn
->lpstrCustomFilter
;
399 len
= MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0);
400 ofnW
.lpstrCustomFilter
= MemAlloc(len
* sizeof(WCHAR
));
401 MultiByteToWideChar(CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, ofnW
.lpstrCustomFilter
, len
);
404 init_filedlg_infoW(&ofnW
, info
);
406 /* fixup A-specific fields */
407 info
->ofnInfos
= (OPENFILENAMEW
*)ofn
;
408 info
->unicode
= FALSE
;
410 /* free what was duplicated */
411 MemFree((WCHAR
*)ofnW
.lpstrInitialDir
);
412 MemFree((WCHAR
*)ofnW
.lpstrFile
);
415 /***********************************************************************
418 * Call GetFileName95 with this structure and clean the memory.
420 static BOOL
GetFileDialog95(FileOpenDlgInfos
*info
, UINT dlg_type
)
422 WCHAR
*current_dir
= NULL
;
425 /* save current directory */
426 if (info
->ofnInfos
->Flags
& OFN_NOCHANGEDIR
)
428 current_dir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
429 GetCurrentDirectoryW(MAX_PATH
, current_dir
);
435 ret
= GetFileName95(info
);
438 info
->DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
439 ret
= GetFileName95(info
);
445 /* set the lpstrFileTitle */
446 if (ret
&& info
->ofnInfos
->lpstrFile
&& info
->ofnInfos
->lpstrFileTitle
)
450 LPOPENFILENAMEW ofn
= info
->ofnInfos
;
451 WCHAR
*file_title
= PathFindFileNameW(ofn
->lpstrFile
);
452 lstrcpynW(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
456 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)info
->ofnInfos
;
457 char *file_title
= PathFindFileNameA(ofn
->lpstrFile
);
458 lstrcpynA(ofn
->lpstrFileTitle
, file_title
, ofn
->nMaxFileTitle
);
464 SetCurrentDirectoryW(current_dir
);
465 MemFree(current_dir
);
470 MemFree((WCHAR
*)info
->defext
);
471 MemFree((WCHAR
*)info
->title
);
472 MemFree((WCHAR
*)info
->filter
);
473 MemFree((WCHAR
*)info
->customfilter
);
476 MemFree(info
->filename
);
477 MemFree(info
->initdir
);
481 /******************************************************************************
482 * COMDLG32_GetDisplayNameOf [internal]
484 * Helper function to get the display name for a pidl.
486 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
487 LPSHELLFOLDER psfDesktop
;
490 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
493 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
494 IShellFolder_Release(psfDesktop
);
498 IShellFolder_Release(psfDesktop
);
499 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
502 /******************************************************************************
503 * COMDLG32_GetCanonicalPath [internal]
505 * Helper function to get the canonical path.
507 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
508 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
510 WCHAR lpstrTemp
[MAX_PATH
];
512 /* Get the current directory name */
513 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
516 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
518 PathAddBackslashW(lpstrPathAndFile
);
520 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
522 /* if the user specified a fully qualified path use it */
523 if(PathIsRelativeW(lpstrFile
))
525 lstrcatW(lpstrPathAndFile
, lpstrFile
);
529 /* does the path have a drive letter? */
530 if (PathGetDriveNumberW(lpstrFile
) == -1)
531 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
533 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
536 /* resolve "." and ".." */
537 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
538 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
539 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
542 /***********************************************************************
543 * COMDLG32_SplitFileNames [internal]
545 * Creates a delimited list of filenames.
547 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
549 UINT nStrCharCount
= 0; /* index in src buffer */
550 UINT nFileIndex
= 0; /* index in dest buffer */
551 UINT nFileCount
= 0; /* number of files */
553 /* we might get single filename without any '"',
554 * so we need nStrLen + terminating \0 + end-of-list \0 */
555 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
558 /* build delimited file list from filenames */
559 while ( nStrCharCount
<= nStrLen
)
561 if ( lpstrEdit
[nStrCharCount
]=='"' )
564 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
566 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
569 (*lpstrFileList
)[nFileIndex
++] = 0;
575 /* single, unquoted string */
576 if ((nStrLen
> 0) && (nFileIndex
== 0) )
578 lstrcpyW(*lpstrFileList
, lpstrEdit
);
579 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
584 (*lpstrFileList
)[nFileIndex
++] = '\0';
586 *sizeUsed
= nFileIndex
;
590 /***********************************************************************
591 * ArrangeCtrlPositions [internal]
593 * NOTE: Make sure to add testcases for any changes made here.
595 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
597 HWND hwndChild
, hwndStc32
;
598 RECT rectParent
, rectChild
, rectStc32
;
602 /* Take into account if open as read only checkbox and help button
607 RECT rectHelp
, rectCancel
;
608 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
609 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
610 /* subtract the height of the help button plus the space between
611 * the help button and the cancel button to the height of the dialog
613 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
617 There are two possibilities to add components to the default file dialog box.
619 By default, all the new components are added below the standard dialog box (the else case).
621 However, if there is a static text component with the stc32 id, a special case happens.
622 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
623 in the window and the cx and cy indicate how to size the window.
624 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
625 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
629 GetClientRect(hwndParentDlg
, &rectParent
);
631 /* when arranging controls we have to use fixed parent size */
632 rectParent
.bottom
-= help_fixup
;
634 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
637 GetWindowRect(hwndStc32
, &rectStc32
);
638 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
640 /* set the size of the stc32 control according to the size of
641 * client area of the parent dialog
643 SetWindowPos(hwndStc32
, 0,
645 rectParent
.right
, rectParent
.bottom
,
646 SWP_NOMOVE
| SWP_NOZORDER
);
649 SetRectEmpty(&rectStc32
);
651 /* this part moves controls of the child dialog */
652 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
655 if (hwndChild
!= hwndStc32
)
657 GetWindowRect(hwndChild
, &rectChild
);
658 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
660 /* move only if stc32 exist */
661 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
663 /* move to the right of visible controls of the parent dialog */
664 rectChild
.left
+= rectParent
.right
;
665 rectChild
.left
-= rectStc32
.right
;
667 /* move even if stc32 doesn't exist */
668 if (rectChild
.top
>= rectStc32
.bottom
)
670 /* move below visible controls of the parent dialog */
671 rectChild
.top
+= rectParent
.bottom
;
672 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
675 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
676 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
678 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
681 /* this part moves controls of the parent dialog */
682 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
685 if (hwndChild
!= hwndChildDlg
)
687 GetWindowRect(hwndChild
, &rectChild
);
688 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
690 /* left,top of stc32 marks the position of controls
691 * from the parent dialog
693 rectChild
.left
+= rectStc32
.left
;
694 rectChild
.top
+= rectStc32
.top
;
696 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
697 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
699 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
702 /* calculate the size of the resulting dialog */
704 /* here we have to use original parent size */
705 GetClientRect(hwndParentDlg
, &rectParent
);
706 GetClientRect(hwndChildDlg
, &rectChild
);
707 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
708 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
713 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
714 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
716 chgx
= rectChild
.right
- rectParent
.right
;
718 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
719 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
721 /* Unconditionally set new dialog
722 * height to that of the child
724 chgy
= rectChild
.bottom
- rectParent
.bottom
;
729 chgy
= rectChild
.bottom
- help_fixup
;
731 /* set the size of the parent dialog */
732 GetWindowRect(hwndParentDlg
, &rectParent
);
733 SetWindowPos(hwndParentDlg
, 0,
735 rectParent
.right
- rectParent
.left
+ chgx
,
736 rectParent
.bottom
- rectParent
.top
+ chgy
,
737 SWP_NOMOVE
| SWP_NOZORDER
);
740 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
749 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
756 TRACE("%p, %p\n", fodInfos
, hwnd
);
759 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
760 * structure's hInstance parameter is not a HINSTANCE, but
761 * instead a pointer to a template resource to use.
763 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
766 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
768 hinst
= COMDLG32_hInstance
;
769 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
771 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
777 hinst
= fodInfos
->ofnInfos
->hInstance
;
778 if(fodInfos
->unicode
)
780 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
781 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
785 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
786 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
790 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
793 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
794 !(template = LockResource( hDlgTmpl
)))
796 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
800 if (fodInfos
->unicode
)
801 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
802 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
803 (LPARAM
)fodInfos
->ofnInfos
);
805 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
806 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
807 (LPARAM
)fodInfos
->ofnInfos
);
810 else if( IsHooked(fodInfos
))
815 WORD menu
,class,title
;
817 GetClientRect(hwnd
,&rectHwnd
);
818 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
819 temp
.tmplate
.dwExtendedStyle
= 0;
820 temp
.tmplate
.cdit
= 0;
825 temp
.menu
= temp
.class = temp
.title
= 0;
827 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
828 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
835 /***********************************************************************
836 * SendCustomDlgNotificationMessage
838 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
841 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
843 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwndParentDlg
);
847 TRACE("%p %d\n", hwndParentDlg
, uCode
);
849 if (!fodInfos
|| !fodInfos
->DlgInfos
.hwndCustomDlg
)
852 TRACE("CALL NOTIFY for %d\n", uCode
);
854 ofnNotify
.hdr
.hwndFrom
= hwndParentDlg
;
855 ofnNotify
.hdr
.idFrom
= 0;
856 ofnNotify
.hdr
.code
= uCode
;
857 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
858 ofnNotify
.pszFile
= NULL
;
860 if (fodInfos
->unicode
)
861 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
863 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
, WM_NOTIFY
, 0, (LPARAM
)&ofnNotify
);
865 TRACE("RET NOTIFY retval %#lx\n", hook_result
);
870 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
874 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
876 TRACE("CDM_GETFILEPATH:\n");
878 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
881 /* get path and filenames */
882 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
883 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
884 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
887 p
= buffer
+ strlenW(buffer
);
889 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
891 if (fodInfos
->unicode
)
893 total
= strlenW( buffer
) + 1;
894 if (result
) lstrcpynW( result
, buffer
, size
);
895 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
899 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
900 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
901 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
903 HeapFree( GetProcessHeap(), 0, buffer
);
907 /***********************************************************************
908 * FILEDLG95_HandleCustomDialogMessages
910 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
912 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
914 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
915 WCHAR lpstrPath
[MAX_PATH
];
918 if(!fodInfos
) return FALSE
;
922 case CDM_GETFILEPATH
:
923 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
926 case CDM_GETFOLDERPATH
:
927 TRACE("CDM_GETFOLDERPATH:\n");
928 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
931 if (fodInfos
->unicode
)
932 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
934 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
935 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
937 retval
= lstrlenW(lpstrPath
) + 1;
940 case CDM_GETFOLDERIDLIST
:
941 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
942 if (retval
<= wParam
)
943 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
947 TRACE("CDM_GETSPEC:\n");
948 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
951 if (fodInfos
->unicode
)
952 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
954 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
958 case CDM_SETCONTROLTEXT
:
959 TRACE("CDM_SETCONTROLTEXT:\n");
962 if( fodInfos
->unicode
)
963 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
965 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
970 case CDM_HIDECONTROL
:
971 /* MSDN states that it should fail for not OFN_EXPLORER case */
972 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
974 HWND control
= GetDlgItem( hwnd
, wParam
);
975 if (control
) ShowWindow( control
, SW_HIDE
);
982 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
983 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
986 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
990 /***********************************************************************
991 * FILEDLG95_OnWMGetMMI
993 * WM_GETMINMAXINFO message handler for resizable dialogs
995 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
997 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
998 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
999 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1001 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1006 /***********************************************************************
1007 * FILEDLG95_OnWMSize
1009 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1011 * FIXME: this could be made more elaborate. Now use a simple scheme
1012 * where the file view is enlarged and the controls are either moved
1013 * vertically or horizontally to get out of the way. Only the "grip"
1014 * is moved in both directions to stay in the corner.
1016 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1022 FileOpenDlgInfos
*fodInfos
;
1024 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1025 fodInfos
= get_filedlg_infoptr(hwnd
);
1026 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1027 /* get the new dialog rectangle */
1028 GetWindowRect( hwnd
, &rc
);
1029 TRACE("%p, size from %d,%d to %d,%d\n", hwnd
, fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1030 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1031 /* not initialized yet */
1032 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1033 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1034 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1036 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1037 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1038 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1039 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1040 /* change the size of the view window */
1041 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1042 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1043 hdwp
= BeginDeferWindowPos( 10);
1044 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1045 rcview
.right
- rcview
.left
+ chgx
,
1046 rcview
.bottom
- rcview
.top
+ chgy
,
1047 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1048 /* change position and sizes of the controls */
1049 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1051 int ctrlid
= GetDlgCtrlID( ctrl
);
1052 GetWindowRect( ctrl
, &rc
);
1053 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1054 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1056 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1058 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1060 else if( rc
.top
> rcview
.bottom
)
1062 /* if it was below the shell view
1066 /* file name (edit or comboboxex) and file types combo change also width */
1070 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1071 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1072 SWP_NOACTIVATE
| SWP_NOZORDER
);
1074 /* then these buttons must move out of the way */
1078 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1080 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1083 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1085 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1088 else if( rc
.left
> rcview
.right
)
1090 /* if it was to the right of the shell view
1092 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1094 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1101 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1103 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1104 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1105 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1107 case IDC_TOOLBARSTATIC
:
1109 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1111 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1114 /* not resized in windows. Since wine uses this invisible control
1115 * to size the browser view it needs to be resized */
1116 case IDC_SHELLSTATIC
:
1117 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1118 rc
.right
- rc
.left
+ chgx
,
1119 rc
.bottom
- rc
.top
+ chgy
,
1120 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1125 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1126 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1128 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1129 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1131 GetWindowRect( ctrl
, &rc
);
1132 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1133 if( rc
.top
> rcview
.bottom
)
1135 /* if it was below the shell view
1137 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1138 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1139 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1141 else if( rc
.left
> rcview
.right
)
1143 /* if it was to the right of the shell view
1145 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1146 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1147 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1150 /* size the custom dialog at the end: some applications do some
1151 * control re-arranging at this point */
1152 GetClientRect(hwnd
, &rc
);
1153 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1154 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1156 EndDeferWindowPos( hdwp
);
1157 /* should not be needed */
1158 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1162 /***********************************************************************
1165 * File open dialog procedure
1167 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1170 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1177 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1179 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1180 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1182 /* Some shell namespace extensions depend on COM being initialized. */
1183 if (SUCCEEDED(OleInitialize(NULL
)))
1184 fodInfos
->ole_initialized
= TRUE
;
1186 SetPropW(hwnd
, filedlg_info_propnameW
, fodInfos
);
1188 FILEDLG95_InitControls(hwnd
);
1190 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1192 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1193 DWORD ex_style
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1194 RECT client
, client_adjusted
;
1196 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1198 style
|= WS_SIZEBOX
;
1199 ex_style
|= WS_EX_WINDOWEDGE
;
1202 style
&= ~WS_SIZEBOX
;
1203 SetWindowLongW(hwnd
, GWL_STYLE
, style
);
1204 SetWindowLongW(hwnd
, GWL_EXSTYLE
, ex_style
);
1206 GetClientRect( hwnd
, &client
);
1207 GetClientRect( hwnd
, &client_adjusted
);
1208 AdjustWindowRectEx( &client_adjusted
, style
, FALSE
, ex_style
);
1210 GetWindowRect( hwnd
, &rc
);
1211 rc
.right
+= client_adjusted
.right
- client
.right
;
1212 rc
.bottom
+= client_adjusted
.bottom
- client
.bottom
;
1213 SetWindowPos(hwnd
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
1214 SWP_NOZORDER
| SWP_NOMOVE
);
1216 GetWindowRect( hwnd
, &rc
);
1217 fodInfos
->DlgInfos
.hwndGrip
=
1218 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1219 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1220 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1221 rc
.right
- gripx
, rc
.bottom
- gripy
,
1222 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1225 fodInfos
->DlgInfos
.hwndCustomDlg
=
1226 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1228 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1229 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1231 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1232 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1234 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1235 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1236 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1239 /* if the app has changed the position of the invisible listbox,
1240 * change that of the listview (browser) as well */
1241 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1242 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1243 if( !EqualRect( &rc
, &rcstc
))
1245 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1246 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1247 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1248 SWP_NOACTIVATE
| SWP_NOZORDER
);
1251 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1253 GetWindowRect( hwnd
, &rc
);
1254 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1255 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1256 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1257 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1258 GetClientRect( hwnd
, &rc
);
1259 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1260 rc
.right
- gripx
, rc
.bottom
- gripy
,
1261 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1262 /* resize the dialog to the previous invocation */
1263 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1264 SetWindowPos( hwnd
, NULL
,
1265 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1266 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1269 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1270 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1275 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1276 case WM_GETMINMAXINFO
:
1277 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1279 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1282 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1285 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1291 case WM_GETISHELLBROWSER
:
1292 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1296 FileOpenDlgInfos
* fodInfos
= get_filedlg_infoptr(hwnd
);
1297 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1298 MemDialogSize
= fodInfos
->sizedlg
;
1299 RemovePropW(hwnd
, filedlg_info_propnameW
);
1304 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1307 /* set up the button tooltips strings */
1308 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1310 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1311 switch(lpnmh
->idFrom
)
1313 /* Up folder button */
1314 case FCIDM_TB_UPFOLDER
:
1315 stringId
= IDS_UPFOLDER
;
1317 /* New folder button */
1318 case FCIDM_TB_NEWFOLDER
:
1319 stringId
= IDS_NEWFOLDER
;
1321 /* List option button */
1322 case FCIDM_TB_SMALLICON
:
1323 stringId
= IDS_LISTVIEW
;
1325 /* Details option button */
1326 case FCIDM_TB_REPORTVIEW
:
1327 stringId
= IDS_REPORTVIEW
;
1329 /* Desktop button */
1330 case FCIDM_TB_DESKTOP
:
1331 stringId
= IDS_TODESKTOP
;
1336 lpdi
->hinst
= COMDLG32_hInstance
;
1337 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1342 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1343 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1348 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1350 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1351 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1354 /***********************************************************************
1355 * FILEDLG95_InitControls
1357 * WM_INITDIALOG message handler (before hook notification)
1359 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1361 BOOL win2000plus
= FALSE
;
1362 BOOL win98plus
= FALSE
;
1363 BOOL handledPath
= FALSE
;
1364 OSVERSIONINFOW osVi
;
1365 static const WCHAR szwSlash
[] = { '\\', 0 };
1366 static const WCHAR szwStar
[] = { '*',0 };
1368 static const TBBUTTON tbb
[] =
1370 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1371 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1372 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1373 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1374 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1375 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1376 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1377 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1378 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1380 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1385 HIMAGELIST toolbarImageList
;
1386 SHFILEINFOA shFileInfo
;
1387 ITEMIDLIST
*desktopPidl
;
1389 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1391 TRACE("%p\n", fodInfos
);
1393 /* Get windows version emulating */
1394 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1395 GetVersionExW(&osVi
);
1396 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1397 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1398 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1399 win2000plus
= (osVi
.dwMajorVersion
> 4);
1400 if (win2000plus
) win98plus
= TRUE
;
1402 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1405 /* Use either the edit or the comboboxex for the filename control */
1406 if (filename_is_edit( fodInfos
))
1408 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1409 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1413 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1414 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1417 /* Get the hwnd of the controls */
1418 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1419 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1421 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1422 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1424 /* construct the toolbar */
1425 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1426 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1428 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1429 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1430 rectTB
.left
= rectlook
.right
;
1431 rectTB
.top
= rectlook
.top
-1;
1433 if (fodInfos
->unicode
)
1434 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1435 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1436 rectTB
.left
, rectTB
.top
,
1437 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1438 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1440 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1441 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1442 rectTB
.left
, rectTB
.top
,
1443 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1444 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1446 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1448 /* FIXME: use TB_LOADIMAGES when implemented */
1449 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1450 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1451 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1453 /* Retrieve and add desktop icon to the toolbar */
1454 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1455 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1456 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1457 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1458 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1460 DestroyIcon(shFileInfo
.hIcon
);
1461 CoTaskMemFree(desktopPidl
);
1463 /* Finish Toolbar Construction */
1464 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1465 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1467 /* Set the window text with the text specified in the OPENFILENAME structure */
1470 SetWindowTextW(hwnd
,fodInfos
->title
);
1472 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1475 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1476 SetWindowTextW(hwnd
, buf
);
1479 /* Initialise the file name edit control */
1480 handledPath
= FALSE
;
1481 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1483 if(fodInfos
->filename
)
1485 /* 1. If win2000 or higher and filename contains a path, use it
1486 in preference over the lpstrInitialDir */
1487 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1488 WCHAR tmpBuf
[MAX_PATH
];
1492 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1495 /* nameBit is always shorter than the original filename. It may be NULL
1496 * when the filename contains only a drive name instead of file name */
1499 lstrcpyW(fodInfos
->filename
,nameBit
);
1503 *fodInfos
->filename
= '\0';
1505 MemFree(fodInfos
->initdir
);
1506 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1507 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1509 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1510 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1512 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1515 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1519 /* 2. (All platforms) If initdir is not null, then use it */
1520 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1522 /* Work out the proper path as supplied one might be relative */
1523 /* (Here because supplying '.' as dir browses to My Computer) */
1524 WCHAR tmpBuf
[MAX_PATH
];
1525 WCHAR tmpBuf2
[MAX_PATH
];
1529 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1530 if (PathFileExistsW(tmpBuf
)) {
1531 /* initdir does not have to be a directory. If a file is
1532 * specified, the dir part is taken */
1533 if (PathIsDirectoryW(tmpBuf
)) {
1534 PathAddBackslashW(tmpBuf
);
1535 lstrcatW(tmpBuf
, szwStar
);
1537 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1540 MemFree(fodInfos
->initdir
);
1541 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1542 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1544 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1547 else if (fodInfos
->initdir
)
1549 MemFree(fodInfos
->initdir
);
1550 fodInfos
->initdir
= NULL
;
1551 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1555 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1557 /* 3. All except w2k+: if filename contains a path use it */
1558 if (!win2000plus
&& fodInfos
->filename
&&
1559 *fodInfos
->filename
&&
1560 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1561 WCHAR tmpBuf
[MAX_PATH
];
1565 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1570 /* nameBit is always shorter than the original filename */
1571 lstrcpyW(fodInfos
->filename
, nameBit
);
1574 len
= lstrlenW(tmpBuf
);
1575 MemFree(fodInfos
->initdir
);
1576 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1577 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1580 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1581 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1583 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1586 /* 4. Win2000+: Recently used */
1587 if (!handledPath
&& win2000plus
) {
1588 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1589 fodInfos
->initdir
[0] = '\0';
1591 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1593 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1596 MemFree(fodInfos
->initdir
);
1597 fodInfos
->initdir
= NULL
;
1601 /* 5. win98+ and win2000+ if any files of specified filter types in
1602 current directory, use it */
1603 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1605 LPCWSTR lpstrPos
= fodInfos
->filter
;
1606 WIN32_FIND_DATAW FindFileData
;
1611 /* filter is a list... title\0ext\0......\0\0 */
1613 /* Skip the title */
1614 if(! *lpstrPos
) break; /* end */
1615 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1617 /* See if any files exist in the current dir with this extension */
1618 if(! *lpstrPos
) break; /* end */
1620 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1622 if (hFind
== INVALID_HANDLE_VALUE
) {
1623 /* None found - continue search */
1624 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1628 MemFree(fodInfos
->initdir
);
1629 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1630 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1633 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1634 debugstr_w(lpstrPos
));
1641 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1642 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1643 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1645 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1647 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1650 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1651 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1653 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1656 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1659 } else if (!handledPath
) {
1660 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1661 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1663 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1666 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1667 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1669 /* Must the open as read only check box be checked ?*/
1670 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1672 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1675 /* Must the open as read only check box be hidden? */
1676 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1678 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1679 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1682 /* Must the help button be hidden? */
1683 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1685 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1686 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1689 /* change Open to Save */
1690 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1693 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1694 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1695 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1696 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1699 /* Initialize the filter combo box */
1700 FILEDLG95_FILETYPE_Init(hwnd
);
1705 /***********************************************************************
1706 * FILEDLG95_ResizeControls
1708 * WM_INITDIALOG message handler (after hook notification)
1710 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1712 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1714 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1717 UINT flags
= SWP_NOACTIVATE
;
1719 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1720 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1722 /* resize the custom dialog to the parent size */
1723 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1724 GetClientRect(hwnd
, &rc
);
1727 /* our own fake template is zero sized and doesn't have children, so
1728 * there is no need to resize it. Picasa depends on it.
1730 flags
|= SWP_NOSIZE
;
1733 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1734 0, 0, rc
.right
, rc
.bottom
, flags
);
1738 /* Resize the height; if opened as read-only, checkbox and help button are
1739 * hidden and we are not using a custom template nor a customDialog
1741 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1742 (!(fodInfos
->ofnInfos
->Flags
&
1743 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1745 RECT rectDlg
, rectHelp
, rectCancel
;
1746 GetWindowRect(hwnd
, &rectDlg
);
1747 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1748 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1749 /* subtract the height of the help button plus the space between the help
1750 * button and the cancel button to the height of the dialog
1752 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1753 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1754 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1760 /***********************************************************************
1761 * FILEDLG95_FillControls
1763 * WM_INITDIALOG message handler (after hook notification)
1765 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1767 LPITEMIDLIST pidlItemId
= NULL
;
1769 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1771 TRACE("dir=%s file=%s\n",
1772 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1774 /* Get the initial directory pidl */
1776 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1778 WCHAR path
[MAX_PATH
];
1780 GetCurrentDirectoryW(MAX_PATH
,path
);
1781 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1784 /* Initialise shell objects */
1785 FILEDLG95_SHELL_Init(hwnd
);
1787 /* Initialize the Look In combo box */
1788 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1790 /* Browse to the initial directory */
1791 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1793 /* Free pidlItem memory */
1794 COMDLG32_SHFree(pidlItemId
);
1798 /***********************************************************************
1801 * Regroups all the cleaning functions of the filedlg
1803 void FILEDLG95_Clean(HWND hwnd
)
1805 FILEDLG95_FILETYPE_Clean(hwnd
);
1806 FILEDLG95_LOOKIN_Clean(hwnd
);
1807 FILEDLG95_SHELL_Clean(hwnd
);
1809 /***********************************************************************
1810 * FILEDLG95_OnWMCommand
1812 * WM_COMMAND message handler
1814 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1816 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1817 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1818 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1824 FILEDLG95_OnOpen(hwnd
);
1828 FILEDLG95_Clean(hwnd
);
1829 EndDialog(hwnd
, FALSE
);
1831 /* Filetype combo box */
1833 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1835 /* LookIn combo box */
1837 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1840 /* --- toolbar --- */
1841 /* Up folder button */
1842 case FCIDM_TB_UPFOLDER
:
1843 FILEDLG95_SHELL_UpFolder(hwnd
);
1845 /* New folder button */
1846 case FCIDM_TB_NEWFOLDER
:
1847 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1849 /* List option button */
1850 case FCIDM_TB_SMALLICON
:
1851 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1853 /* Details option button */
1854 case FCIDM_TB_REPORTVIEW
:
1855 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1857 /* Details option button */
1858 case FCIDM_TB_DESKTOP
:
1859 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1867 /* Do not use the listview selection anymore */
1868 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1872 /***********************************************************************
1873 * FILEDLG95_OnWMGetIShellBrowser
1875 * WM_GETISHELLBROWSER message handler
1877 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1879 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1883 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1889 /***********************************************************************
1890 * FILEDLG95_SendFileOK
1892 * Sends the CDN_FILEOK notification if required
1895 * TRUE if the dialog should close
1896 * FALSE if the dialog should not be closed
1898 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1900 /* ask the hook if we can close */
1901 if(IsHooked(fodInfos
))
1906 /* First send CDN_FILEOK as MSDN doc says */
1907 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1908 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1911 TRACE("canceled\n");
1915 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1916 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1917 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1920 TRACE("canceled\n");
1927 /***********************************************************************
1928 * FILEDLG95_OnOpenMultipleFiles
1930 * Handles the opening of multiple files.
1933 * check destination buffer size
1935 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1937 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
1938 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1939 UINT nCount
, nSizePath
;
1943 if(fodInfos
->unicode
)
1945 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1946 ofn
->lpstrFile
[0] = '\0';
1950 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1951 ofn
->lpstrFile
[0] = '\0';
1954 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1956 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1957 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1958 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1960 LPWSTR lpstrTemp
= lpstrFileList
;
1962 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1966 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1969 WCHAR lpstrNotFound
[100];
1970 WCHAR lpstrMsg
[100];
1972 static const WCHAR nl
[] = {'\n',0};
1974 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1975 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1977 lstrcpyW(tmp
, lpstrTemp
);
1979 lstrcatW(tmp
, lpstrNotFound
);
1981 lstrcatW(tmp
, lpstrMsg
);
1983 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1987 /* move to the next file in the list of files */
1988 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1989 COMDLG32_SHFree(pidl
);
1993 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1994 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1996 /* For "oldstyle" dialog the components have to
1997 be separated by blanks (not '\0'!) and short
1998 filenames have to be used! */
1999 FIXME("Components have to be separated by blanks\n");
2001 if(fodInfos
->unicode
)
2003 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2004 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2005 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2009 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2011 if (ofn
->lpstrFile
!= NULL
)
2013 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2014 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2015 if (ofn
->nMaxFile
> nSizePath
)
2017 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2018 ofn
->lpstrFile
+ nSizePath
,
2019 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2024 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2025 fodInfos
->ofnInfos
->nFileExtension
= 0;
2027 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2030 /* clean and exit */
2031 FILEDLG95_Clean(hwnd
);
2032 return EndDialog(hwnd
,TRUE
);
2035 /* Returns the 'slot name' of the given module_name in the registry's
2036 * most-recently-used list. This will be an ASCII value in the
2037 * range ['a','z'). Returns zero on error.
2039 * The slot's value in the registry has the form:
2040 * module_name\0mru_path\0
2042 * If stored_path is given, then stored_path will contain the path name
2043 * stored in the registry's MRU list for the given module_name.
2045 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2046 * MRU list key for the given module_name.
2048 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2050 WCHAR mru_list
[32], *cur_mru_slot
;
2051 BOOL taken
[25] = {0};
2052 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2053 HKEY hkey_tmp
, *hkey
;
2062 *stored_path
= '\0';
2064 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2066 WARN("Unable to create MRU key: %d\n", ret
);
2070 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2071 (LPBYTE
)mru_list
, &mru_list_size
);
2072 if(ret
|| key_type
!= REG_SZ
){
2073 if(ret
== ERROR_FILE_NOT_FOUND
)
2076 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2081 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2082 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2083 DWORD value_data_size
= sizeof(value_data
);
2085 *value_name
= *cur_mru_slot
;
2087 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2088 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2089 if(ret
|| key_type
!= REG_BINARY
){
2090 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2094 if(!strcmpiW(module_name
, value_data
)){
2098 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2106 /* the module name isn't in the registry, so find the next open slot */
2107 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2108 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2109 for(i
= 0; i
< 25; ++i
){
2114 /* all slots are taken, so return the last one in MRUList */
2116 return *cur_mru_slot
;
2119 /* save the given filename as most-recently-used path for this module */
2120 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2122 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2126 /* get the current executable's name */
2127 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2128 WARN("GotModuleFileName failed: %d\n", GetLastError());
2131 module_name
= strrchrW(module_path
, '\\');
2133 module_name
= module_path
;
2137 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2142 { /* update the slot's info */
2143 WCHAR
*path_ends
, *final
;
2144 DWORD path_len
, final_len
;
2146 /* use only the path segment of `filename' */
2147 path_ends
= strrchrW(filename
, '\\');
2148 path_len
= path_ends
- filename
;
2150 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2152 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2155 lstrcpyW(final
, module_name
);
2156 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2157 final
[final_len
-1] = '\0';
2159 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2160 final_len
* sizeof(WCHAR
));
2162 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2171 { /* update MRUList value */
2172 WCHAR old_mru_list
[32], new_mru_list
[32];
2173 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2174 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2176 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2177 (LPBYTE
)old_mru_list
, &mru_list_size
);
2178 if(ret
|| key_type
!= REG_SZ
){
2179 if(ret
== ERROR_FILE_NOT_FOUND
){
2180 new_mru_list
[0] = slot
;
2181 new_mru_list
[1] = '\0';
2183 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2188 /* copy old list data over so that the new slot is at the start
2190 *new_mru_slot
++ = slot
;
2191 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2192 if(*old_mru_slot
!= slot
)
2193 *new_mru_slot
++ = *old_mru_slot
;
2195 *new_mru_slot
= '\0';
2198 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2199 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2201 WARN("Error saving MRUList data: %d\n", ret
);
2208 /* load the most-recently-used path for this module */
2209 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2211 WCHAR module_path
[MAX_PATH
], *module_name
;
2213 /* get the current executable's name */
2214 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2215 WARN("GotModuleFileName failed: %d\n", GetLastError());
2218 module_name
= strrchrW(module_path
, '\\');
2220 module_name
= module_path
;
2224 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2225 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2228 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2230 WCHAR strMsgTitle
[MAX_PATH
];
2231 WCHAR strMsgText
[MAX_PATH
];
2233 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2235 strMsgTitle
[0] = '\0';
2236 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2237 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2240 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2241 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2243 int nOpenAction
= defAction
;
2244 LPWSTR lpszTemp
, lpszTemp1
;
2245 LPITEMIDLIST pidl
= NULL
;
2246 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2248 /* check for invalid chars */
2249 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2251 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2255 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2257 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2260 LPSHELLFOLDER lpsfChild
;
2261 WCHAR lpwstrTemp
[MAX_PATH
];
2262 DWORD dwEaten
, dwAttributes
;
2265 lstrcpyW(lpwstrTemp
, lpszTemp
);
2266 p
= PathFindNextComponentW(lpwstrTemp
);
2268 if (!p
) break; /* end of path */
2271 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2273 /* There are no wildcards when OFN_NOVALIDATE is set */
2274 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2276 static const WCHAR wszWild
[] = { '*', '?', 0 };
2277 /* if the last element is a wildcard do a search */
2278 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2280 nOpenAction
= ONOPEN_SEARCH
;
2284 lpszTemp1
= lpszTemp
;
2286 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2288 /* append a backslash to drive letters */
2289 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2290 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2291 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2293 PathAddBackslashW(lpwstrTemp
);
2296 dwAttributes
= SFGAO_FOLDER
;
2297 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2299 /* the path component is valid, we have a pidl of the next path component */
2300 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2301 if(dwAttributes
& SFGAO_FOLDER
)
2303 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2305 ERR("bind to failed\n"); /* should not fail */
2308 IShellFolder_Release(*ppsf
);
2316 /* end dialog, return value */
2317 nOpenAction
= ONOPEN_OPEN
;
2320 COMDLG32_SHFree(pidl
);
2323 else if (!(flags
& OFN_NOVALIDATE
))
2325 if(*lpszTemp
|| /* points to trailing null for last path element */
2326 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2328 if(flags
& OFN_PATHMUSTEXIST
)
2330 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2336 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2338 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2342 /* change to the current folder */
2343 nOpenAction
= ONOPEN_OPEN
;
2348 nOpenAction
= ONOPEN_OPEN
;
2352 if(pidl
) COMDLG32_SHFree(pidl
);
2357 /***********************************************************************
2360 * Ok button WM_COMMAND message handler
2362 * If the function succeeds, the return value is nonzero.
2364 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2366 FileOpenDlgInfos
*fodInfos
= get_filedlg_infoptr(hwnd
);
2367 LPWSTR lpstrFileList
;
2368 UINT nFileCount
= 0;
2371 WCHAR lpstrPathAndFile
[MAX_PATH
];
2372 LPSHELLFOLDER lpsf
= NULL
;
2375 TRACE("hwnd=%p\n", hwnd
);
2377 /* try to browse the selected item */
2378 if(BrowseSelectedFolder(hwnd
))
2381 /* get the files from the edit control */
2382 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2389 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2393 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2396 Step 1: Build a complete path name from the current folder and
2397 the filename or path in the edit box.
2399 - the path in the edit box is a root path
2400 (with or without drive letter)
2401 - the edit box contains ".." (or a path with ".." in it)
2404 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2405 MemFree(lpstrFileList
);
2408 Step 2: here we have a cleaned up path
2410 We have to parse the path step by step to see if we have to browse
2411 to a folder if the path points to a directory or the last
2412 valid element is a directory.
2415 lpstrPathAndFile: cleaned up path
2419 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2420 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2421 nOpenAction
= ONOPEN_OPEN
;
2423 nOpenAction
= ONOPEN_BROWSE
;
2425 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2426 fodInfos
->ofnInfos
->Flags
,
2427 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2433 Step 3: here we have a cleaned up and validated path
2436 lpsf: ShellFolder bound to the rightmost valid path component
2437 lpstrPathAndFile: cleaned up path
2438 nOpenAction: action to do
2440 TRACE("end validate sf=%p\n", lpsf
);
2444 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2445 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2448 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2451 /* replace the current filter */
2452 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2453 len
= lstrlenW(lpszTemp
)+1;
2454 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2455 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2457 /* set the filter cb to the extension when possible */
2458 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2459 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2462 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2463 TRACE("ONOPEN_BROWSE\n");
2465 IPersistFolder2
* ppf2
;
2466 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2468 LPITEMIDLIST pidlCurrent
;
2469 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2470 IPersistFolder2_Release(ppf2
);
2471 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2473 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2474 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2476 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2477 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2480 else if( nOpenAction
== ONOPEN_SEARCH
)
2482 if (fodInfos
->Shell
.FOIShellView
)
2483 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2485 COMDLG32_SHFree(pidlCurrent
);
2486 if (filename_is_edit( fodInfos
))
2487 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2492 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2493 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2499 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2500 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2504 /* update READONLY check box flag */
2505 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2506 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2508 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2510 /* Attach the file extension with file name*/
2511 ext
= PathFindExtensionW(lpstrPathAndFile
);
2512 if (! *ext
&& fodInfos
->defext
)
2514 /* if no extension is specified with file name, then */
2515 /* attach the extension from file filter or default one */
2517 WCHAR
*filterExt
= NULL
;
2518 LPWSTR lpstrFilter
= NULL
;
2519 static const WCHAR szwDot
[] = {'.',0};
2520 int PathLength
= lstrlenW(lpstrPathAndFile
);
2522 /*Get the file extension from file type filter*/
2523 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2524 fodInfos
->ofnInfos
->nFilterIndex
-1);
2526 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2528 WCHAR
* filterSearchIndex
;
2529 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2530 strcpyW(filterExt
, lpstrFilter
);
2532 /* if a semicolon-separated list of file extensions was given, do not include the
2533 semicolon or anything after it in the extension.
2534 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2535 filterSearchIndex
= strchrW(filterExt
, ';');
2536 if (filterSearchIndex
)
2538 filterSearchIndex
[0] = '\0';
2541 /* find the file extension by searching for the first dot in filterExt */
2542 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2543 /* if the extension is invalid or contains a glob, ignore it */
2544 filterSearchIndex
= strchrW(filterExt
, '.');
2545 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2547 strcpyW(filterExt
, filterSearchIndex
);
2551 HeapFree(GetProcessHeap(), 0, filterExt
);
2558 /* use the default file extension */
2559 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2560 strcpyW(filterExt
, fodInfos
->defext
);
2563 if (*filterExt
) /* ignore filterExt="" */
2566 lstrcatW(lpstrPathAndFile
, szwDot
);
2567 /* Attach the extension */
2568 lstrcatW(lpstrPathAndFile
, filterExt
);
2571 HeapFree(GetProcessHeap(), 0, filterExt
);
2573 /* In Open dialog: if file does not exist try without extension */
2574 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2575 lpstrPathAndFile
[PathLength
] = '\0';
2577 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2580 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2581 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2583 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2586 /* In Save dialog: check if the file already exists */
2587 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2588 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2589 && PathFileExistsW(lpstrPathAndFile
))
2591 WCHAR lpstrOverwrite
[100];
2594 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2595 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2596 MB_YESNO
| MB_ICONEXCLAMATION
);
2597 if (answer
== IDNO
|| answer
== IDCANCEL
)
2604 /* In Open dialog: check if it should be created if it doesn't exist */
2605 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2606 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2607 && !PathFileExistsW(lpstrPathAndFile
))
2609 WCHAR lpstrCreate
[100];
2612 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2613 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2614 MB_YESNO
| MB_ICONEXCLAMATION
);
2615 if (answer
== IDNO
|| answer
== IDCANCEL
)
2622 /* Check that the size of the file does not exceed buffer size.
2623 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2624 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2625 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2628 /* fill destination buffer */
2629 if (fodInfos
->ofnInfos
->lpstrFile
)
2631 if(fodInfos
->unicode
)
2633 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2635 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2636 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2637 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2641 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2643 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2644 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2645 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2646 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2650 if(fodInfos
->unicode
)
2654 /* set filename offset */
2655 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2656 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2658 /* set extension offset */
2659 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2660 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2665 CHAR tempFileA
[MAX_PATH
];
2667 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2668 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2669 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2671 /* set filename offset */
2672 lpszTemp
= PathFindFileNameA(tempFileA
);
2673 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2675 /* set extension offset */
2676 lpszTemp
= PathFindExtensionA(tempFileA
);
2677 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
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
]);