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 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
140 static const WCHAR LastVisitedMRUW
[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
147 /***********************************************************************
151 /* Internal functions used by the dialog */
152 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
153 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
154 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
155 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
156 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
157 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
158 static void FILEDLG95_Clean(HWND hwnd
);
160 /* Functions used by the shell navigation */
161 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
162 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
163 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
165 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
170 /* Functions used by the filetype combo box */
171 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
172 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
178 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
179 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
189 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
192 /* Miscellaneous tool functions */
193 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
194 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
195 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
196 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
197 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
198 static UINT
GetNumSelected( IDataObject
*doSelected
);
199 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium
);
201 /* Shell memory allocation */
202 static void *MemAlloc(UINT size
);
203 static void MemFree(void *mem
);
205 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
206 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
207 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
208 static BOOL
BrowseSelectedFolder(HWND hwnd
);
210 /***********************************************************************
213 * Creates an Open common dialog box that lets the user select
214 * the drive, directory, and the name of a file or set of files to open.
216 * IN : The FileOpenDlgInfos structure associated with the dialog
217 * OUT : TRUE on success
218 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
220 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
224 LPCVOID origTemplate
;
226 LPDLGTEMPLATEW
template;
231 /* test for missing functionality */
232 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
234 FIXME("Flags 0x%08x not yet implemented\n",
235 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
238 /* Create the dialog from a template */
240 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
242 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
245 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
246 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
247 !(origTemplate
= LockResource(hDlgTmpl
)))
249 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
252 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
254 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
257 memcpy(template, origTemplate
, dwSize
);
259 /* msdn: explorer style dialogs permit sizing by default.
260 * The OFN_ENABLESIZING flag is only needed when a hook or
261 * custom tmeplate is provided */
262 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
263 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
264 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
266 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
268 template->style
|= WS_SIZEBOX
;
269 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
270 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
273 template->style
&= ~WS_SIZEBOX
;
276 /* old style hook messages */
277 if (IsHooked(fodInfos
))
279 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
280 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
281 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
282 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr
= OleInitialize(NULL
);
288 if (fodInfos
->unicode
)
289 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
291 fodInfos
->ofnInfos
->hwndOwner
,
295 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
297 fodInfos
->ofnInfos
->hwndOwner
,
303 HeapFree(GetProcessHeap(), 0, template);
305 /* Unable to create the dialog */
312 /***********************************************************************
315 * Call GetFileName95 with this structure and clean the memory.
317 * IN : The OPENFILENAMEA initialisation structure passed to
318 * GetOpenFileNameA win api function (see filedlg.c)
320 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
323 FileOpenDlgInfos fodInfos
;
324 LPSTR lpstrSavDir
= NULL
;
326 LPWSTR defext
= NULL
;
327 LPWSTR filter
= NULL
;
328 LPWSTR customfilter
= NULL
;
329 INITCOMMONCONTROLSEX icc
;
331 /* Initialize ComboBoxEx32 */
332 icc
.dwSize
= sizeof(icc
);
333 icc
.dwICC
= ICC_USEREX_CLASSES
;
334 InitCommonControlsEx(&icc
);
336 /* Initialize CommDlgExtendedError() */
337 COMDLG32_SetCommDlgExtendedError(0);
339 /* Initialize FileOpenDlgInfos structure */
340 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
342 /* Pass in the original ofn */
343 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
345 /* save current directory */
346 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
348 lpstrSavDir
= MemAlloc(MAX_PATH
);
349 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
352 fodInfos
.unicode
= FALSE
;
354 /* convert all the input strings to unicode */
355 if(ofn
->lpstrInitialDir
)
357 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
358 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
359 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
362 fodInfos
.initdir
= NULL
;
366 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
367 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
370 fodInfos
.filename
= NULL
;
374 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
375 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
378 fodInfos
.defext
= defext
;
382 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
383 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
384 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
386 fodInfos
.title
= title
;
388 if (ofn
->lpstrFilter
)
393 /* filter is a list... title\0ext\0......\0\0 */
394 s
= ofn
->lpstrFilter
;
395 while (*s
) s
= s
+strlen(s
)+1;
397 n
= s
- ofn
->lpstrFilter
;
398 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
399 filter
= MemAlloc(len
*sizeof(WCHAR
));
400 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
402 fodInfos
.filter
= filter
;
404 /* convert lpstrCustomFilter */
405 if (ofn
->lpstrCustomFilter
)
410 /* customfilter contains a pair of strings... title\0ext\0 */
411 s
= ofn
->lpstrCustomFilter
;
412 if (*s
) s
= s
+strlen(s
)+1;
413 if (*s
) s
= s
+strlen(s
)+1;
414 n
= s
- ofn
->lpstrCustomFilter
;
415 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
416 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
417 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
419 fodInfos
.customfilter
= customfilter
;
421 /* Initialize the dialog property */
422 fodInfos
.DlgInfos
.dwDlgProp
= 0;
423 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
428 ret
= GetFileName95(&fodInfos
);
431 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
432 ret
= GetFileName95(&fodInfos
);
438 /* set the lpstrFileTitle */
439 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
441 LPSTR lpstrFileTitle
= PathFindFileNameA(ofn
->lpstrFile
);
442 lstrcpynA(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
447 SetCurrentDirectoryA(lpstrSavDir
);
448 MemFree(lpstrSavDir
);
454 MemFree(customfilter
);
455 MemFree(fodInfos
.initdir
);
456 MemFree(fodInfos
.filename
);
458 TRACE("selected file: %s\n",ofn
->lpstrFile
);
463 /***********************************************************************
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
470 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
473 FileOpenDlgInfos fodInfos
;
474 LPWSTR lpstrSavDir
= NULL
;
475 INITCOMMONCONTROLSEX icc
;
477 /* Initialize ComboBoxEx32 */
478 icc
.dwSize
= sizeof(icc
);
479 icc
.dwICC
= ICC_USEREX_CLASSES
;
480 InitCommonControlsEx(&icc
);
482 /* Initialize CommDlgExtendedError() */
483 COMDLG32_SetCommDlgExtendedError(0);
485 /* Initialize FileOpenDlgInfos structure */
486 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
488 /* Pass in the original ofn */
489 fodInfos
.ofnInfos
= ofn
;
491 fodInfos
.title
= ofn
->lpstrTitle
;
492 fodInfos
.defext
= ofn
->lpstrDefExt
;
493 fodInfos
.filter
= ofn
->lpstrFilter
;
494 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
496 /* convert string arguments, save others */
499 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
500 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
503 fodInfos
.filename
= NULL
;
505 if(ofn
->lpstrInitialDir
)
507 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
508 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
509 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
510 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
513 fodInfos
.initdir
= NULL
;
515 /* save current directory */
516 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
518 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
519 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
522 fodInfos
.unicode
= TRUE
;
527 ret
= GetFileName95(&fodInfos
);
530 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
531 ret
= GetFileName95(&fodInfos
);
537 /* set the lpstrFileTitle */
538 if (ret
&& ofn
->lpstrFile
&& ofn
->lpstrFileTitle
)
540 LPWSTR lpstrFileTitle
= PathFindFileNameW(ofn
->lpstrFile
);
541 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
546 SetCurrentDirectoryW(lpstrSavDir
);
547 MemFree(lpstrSavDir
);
550 /* restore saved IN arguments and convert OUT arguments back */
551 MemFree(fodInfos
.filename
);
552 MemFree(fodInfos
.initdir
);
556 /******************************************************************************
557 * COMDLG32_GetDisplayNameOf [internal]
559 * Helper function to get the display name for a pidl.
561 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
562 LPSHELLFOLDER psfDesktop
;
565 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
568 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
569 IShellFolder_Release(psfDesktop
);
573 IShellFolder_Release(psfDesktop
);
574 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
577 /******************************************************************************
578 * COMDLG32_GetCanonicalPath [internal]
580 * Helper function to get the canonical path.
582 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
583 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
585 WCHAR lpstrTemp
[MAX_PATH
];
587 /* Get the current directory name */
588 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
591 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
593 PathAddBackslashW(lpstrPathAndFile
);
595 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
597 /* if the user specified a fully qualified path use it */
598 if(PathIsRelativeW(lpstrFile
))
600 lstrcatW(lpstrPathAndFile
, lpstrFile
);
604 /* does the path have a drive letter? */
605 if (PathGetDriveNumberW(lpstrFile
) == -1)
606 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
608 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
611 /* resolve "." and ".." */
612 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
613 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
614 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
617 /***********************************************************************
618 * COMDLG32_SplitFileNames [internal]
620 * Creates a delimited list of filenames.
622 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
624 UINT nStrCharCount
= 0; /* index in src buffer */
625 UINT nFileIndex
= 0; /* index in dest buffer */
626 UINT nFileCount
= 0; /* number of files */
628 /* we might get single filename without any '"',
629 * so we need nStrLen + terminating \0 + end-of-list \0 */
630 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
633 /* build delimited file list from filenames */
634 while ( nStrCharCount
<= nStrLen
)
636 if ( lpstrEdit
[nStrCharCount
]=='"' )
639 while ((nStrCharCount
<= nStrLen
) && (lpstrEdit
[nStrCharCount
]!='"'))
641 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
644 (*lpstrFileList
)[nFileIndex
++] = 0;
650 /* single, unquoted string */
651 if ((nStrLen
> 0) && (nFileIndex
== 0) )
653 lstrcpyW(*lpstrFileList
, lpstrEdit
);
654 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
659 (*lpstrFileList
)[nFileIndex
++] = '\0';
661 *sizeUsed
= nFileIndex
;
665 /***********************************************************************
666 * ArrangeCtrlPositions [internal]
668 * NOTE: Make sure to add testcases for any changes made here.
670 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
672 HWND hwndChild
, hwndStc32
;
673 RECT rectParent
, rectChild
, rectStc32
;
677 /* Take into account if open as read only checkbox and help button
682 RECT rectHelp
, rectCancel
;
683 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
684 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
685 /* subtract the height of the help button plus the space between
686 * the help button and the cancel button to the height of the dialog
688 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
692 There are two possibilities to add components to the default file dialog box.
694 By default, all the new components are added below the standard dialog box (the else case).
696 However, if there is a static text component with the stc32 id, a special case happens.
697 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
698 in the window and the cx and cy indicate how to size the window.
699 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
700 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
704 GetClientRect(hwndParentDlg
, &rectParent
);
706 /* when arranging controls we have to use fixed parent size */
707 rectParent
.bottom
-= help_fixup
;
709 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
712 GetWindowRect(hwndStc32
, &rectStc32
);
713 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
715 /* set the size of the stc32 control according to the size of
716 * client area of the parent dialog
718 SetWindowPos(hwndStc32
, 0,
720 rectParent
.right
, rectParent
.bottom
,
721 SWP_NOMOVE
| SWP_NOZORDER
);
724 SetRectEmpty(&rectStc32
);
726 /* this part moves controls of the child dialog */
727 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
730 if (hwndChild
!= hwndStc32
)
732 GetWindowRect(hwndChild
, &rectChild
);
733 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
735 /* move only if stc32 exist */
736 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
738 /* move to the right of visible controls of the parent dialog */
739 rectChild
.left
+= rectParent
.right
;
740 rectChild
.left
-= rectStc32
.right
;
742 /* move even if stc32 doesn't exist */
743 if (rectChild
.top
>= rectStc32
.bottom
)
745 /* move below visible controls of the parent dialog */
746 rectChild
.top
+= rectParent
.bottom
;
747 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
750 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
751 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
753 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
756 /* this part moves controls of the parent dialog */
757 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
760 if (hwndChild
!= hwndChildDlg
)
762 GetWindowRect(hwndChild
, &rectChild
);
763 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
765 /* left,top of stc32 marks the position of controls
766 * from the parent dialog
768 rectChild
.left
+= rectStc32
.left
;
769 rectChild
.top
+= rectStc32
.top
;
771 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
772 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
774 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
777 /* calculate the size of the resulting dialog */
779 /* here we have to use original parent size */
780 GetClientRect(hwndParentDlg
, &rectParent
);
781 GetClientRect(hwndChildDlg
, &rectChild
);
782 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
783 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
788 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
789 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
791 chgx
= rectChild
.right
- rectParent
.right
;
793 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
794 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
796 /* Unconditionally set new dialog
797 * height to that of the child
799 chgy
= rectChild
.bottom
- rectParent
.bottom
;
804 chgy
= rectChild
.bottom
- help_fixup
;
806 /* set the size of the parent dialog */
807 GetWindowRect(hwndParentDlg
, &rectParent
);
808 SetWindowPos(hwndParentDlg
, 0,
810 rectParent
.right
- rectParent
.left
+ chgx
,
811 rectParent
.bottom
- rectParent
.top
+ chgy
,
812 SWP_NOMOVE
| SWP_NOZORDER
);
815 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
824 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
834 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
835 * structure's hInstance parameter is not a HINSTANCE, but
836 * instead a pointer to a template resource to use.
838 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
841 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
843 hinst
= COMDLG32_hInstance
;
844 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
846 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
852 hinst
= fodInfos
->ofnInfos
->hInstance
;
853 if(fodInfos
->unicode
)
855 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
856 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
860 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
861 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
865 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
868 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
869 !(template = LockResource( hDlgTmpl
)))
871 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
875 if (fodInfos
->unicode
)
876 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
877 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
878 (LPARAM
)fodInfos
->ofnInfos
);
880 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
881 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
882 (LPARAM
)fodInfos
->ofnInfos
);
885 else if( IsHooked(fodInfos
))
890 WORD menu
,class,title
;
892 GetClientRect(hwnd
,&rectHwnd
);
893 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
894 temp
.tmplate
.dwExtendedStyle
= 0;
895 temp
.tmplate
.cdit
= 0;
900 temp
.menu
= temp
.class = temp
.title
= 0;
902 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
903 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
910 /***********************************************************************
911 * SendCustomDlgNotificationMessage
913 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
916 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
918 LRESULT hook_result
= 0;
919 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
921 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
923 if(!fodInfos
) return 0;
925 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
927 TRACE("CALL NOTIFY for %x\n", uCode
);
928 if(fodInfos
->unicode
)
931 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
932 ofnNotify
.hdr
.idFrom
=0;
933 ofnNotify
.hdr
.code
= uCode
;
934 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
935 ofnNotify
.pszFile
= NULL
;
936 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
941 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
942 ofnNotify
.hdr
.idFrom
=0;
943 ofnNotify
.hdr
.code
= uCode
;
944 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
945 ofnNotify
.pszFile
= NULL
;
946 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
948 TRACE("RET NOTIFY\n");
950 TRACE("Retval: 0x%08lx\n", hook_result
);
954 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
958 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
960 TRACE("CDM_GETFILEPATH:\n");
962 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
965 /* get path and filenames */
966 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
967 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
968 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
971 p
= buffer
+ strlenW(buffer
);
973 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
975 if (fodInfos
->unicode
)
977 total
= strlenW( buffer
) + 1;
978 if (result
) lstrcpynW( result
, buffer
, size
);
979 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
983 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
984 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
985 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
987 HeapFree( GetProcessHeap(), 0, buffer
);
991 /***********************************************************************
992 * FILEDLG95_HandleCustomDialogMessages
994 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
996 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
998 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
999 WCHAR lpstrPath
[MAX_PATH
];
1002 if(!fodInfos
) return FALSE
;
1006 case CDM_GETFILEPATH
:
1007 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1010 case CDM_GETFOLDERPATH
:
1011 TRACE("CDM_GETFOLDERPATH:\n");
1012 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1015 if (fodInfos
->unicode
)
1016 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1018 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1019 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1021 retval
= lstrlenW(lpstrPath
) + 1;
1024 case CDM_GETFOLDERIDLIST
:
1025 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1026 if (retval
<= wParam
)
1027 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1031 TRACE("CDM_GETSPEC:\n");
1032 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1035 if (fodInfos
->unicode
)
1036 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1038 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1042 case CDM_SETCONTROLTEXT
:
1043 TRACE("CDM_SETCONTROLTEXT:\n");
1046 if( fodInfos
->unicode
)
1047 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1049 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1054 case CDM_HIDECONTROL
:
1055 /* MSDN states that it should fail for not OFN_EXPLORER case */
1056 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1058 HWND control
= GetDlgItem( hwnd
, wParam
);
1059 if (control
) ShowWindow( control
, SW_HIDE
);
1062 else retval
= FALSE
;
1066 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1067 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1070 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1074 /***********************************************************************
1075 * FILEDLG95_OnWMGetMMI
1077 * WM_GETMINMAXINFO message handler for resizable dialogs
1079 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1081 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1082 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1083 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1085 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1090 /***********************************************************************
1091 * FILEDLG95_OnWMSize
1093 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1095 * FIXME: this could be made more elaborate. Now use a simple scheme
1096 * where the file view is enlarged and the controls are either moved
1097 * vertically or horizontally to get out of the way. Only the "grip"
1098 * is moved in both directions to stay in the corner.
1100 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1106 FileOpenDlgInfos
*fodInfos
;
1108 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1109 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1110 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1111 /* get the new dialog rectangle */
1112 GetWindowRect( hwnd
, &rc
);
1113 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1114 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1115 /* not initialized yet */
1116 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1117 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1118 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1120 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1121 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1122 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1123 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1124 /* change the size of the view window */
1125 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1126 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1127 hdwp
= BeginDeferWindowPos( 10);
1128 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1129 rcview
.right
- rcview
.left
+ chgx
,
1130 rcview
.bottom
- rcview
.top
+ chgy
,
1131 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1132 /* change position and sizes of the controls */
1133 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1135 int ctrlid
= GetDlgCtrlID( ctrl
);
1136 GetWindowRect( ctrl
, &rc
);
1137 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1138 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1140 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1142 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1144 else if( rc
.top
> rcview
.bottom
)
1146 /* if it was below the shell view
1150 /* file name (edit or comboboxex) and file types combo change also width */
1154 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1155 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1156 SWP_NOACTIVATE
| SWP_NOZORDER
);
1158 /* then these buttons must move out of the way */
1162 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1164 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1167 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1169 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1172 else if( rc
.left
> rcview
.right
)
1174 /* if it was to the right of the shell view
1176 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1178 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1185 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1187 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1188 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1189 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1191 case IDC_TOOLBARSTATIC
:
1193 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1195 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1198 /* not resized in windows. Since wine uses this invisible control
1199 * to size the browser view it needs to be resized */
1200 case IDC_SHELLSTATIC
:
1201 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1202 rc
.right
- rc
.left
+ chgx
,
1203 rc
.bottom
- rc
.top
+ chgy
,
1204 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1209 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1210 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1212 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1213 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1215 GetWindowRect( ctrl
, &rc
);
1216 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1217 if( rc
.top
> rcview
.bottom
)
1219 /* if it was below the shell view
1221 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1222 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1223 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1225 else if( rc
.left
> rcview
.right
)
1227 /* if it was to the right of the shell view
1229 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1230 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1231 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1234 /* size the custom dialog at the end: some applications do some
1235 * control re-arranging at this point */
1236 GetClientRect(hwnd
, &rc
);
1237 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1238 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1240 EndDeferWindowPos( hdwp
);
1241 /* should not be needed */
1242 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1246 /***********************************************************************
1249 * File open dialog procedure
1251 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1254 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1261 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1263 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1264 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1266 /* Adds the FileOpenDlgInfos in the property list of the dialog
1267 so it will be easily accessible through a GetPropA(...) */
1268 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1270 FILEDLG95_InitControls(hwnd
);
1272 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1274 GetWindowRect( hwnd
, &rc
);
1275 fodInfos
->DlgInfos
.hwndGrip
=
1276 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1277 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1278 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1279 rc
.right
- gripx
, rc
.bottom
- gripy
,
1280 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1283 fodInfos
->DlgInfos
.hwndCustomDlg
=
1284 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1286 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1287 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1289 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1290 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1292 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1293 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1294 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1297 /* if the app has changed the position of the invisible listbox,
1298 * change that of the listview (browser) as well */
1299 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1300 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1301 if( !EqualRect( &rc
, &rcstc
))
1303 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1304 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1305 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1306 SWP_NOACTIVATE
| SWP_NOZORDER
);
1309 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1311 GetWindowRect( hwnd
, &rc
);
1312 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1313 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1314 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1315 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1316 GetClientRect( hwnd
, &rc
);
1317 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1318 rc
.right
- gripx
, rc
.bottom
- gripy
,
1319 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1320 /* resize the dialog to the previous invocation */
1321 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1322 SetWindowPos( hwnd
, NULL
,
1323 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1324 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1327 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1328 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1333 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1334 case WM_GETMINMAXINFO
:
1335 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1337 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1340 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1343 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1349 case WM_GETISHELLBROWSER
:
1350 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1354 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1355 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1356 MemDialogSize
= fodInfos
->sizedlg
;
1357 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1362 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1365 /* set up the button tooltips strings */
1366 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1368 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1369 switch(lpnmh
->idFrom
)
1371 /* Up folder button */
1372 case FCIDM_TB_UPFOLDER
:
1373 stringId
= IDS_UPFOLDER
;
1375 /* New folder button */
1376 case FCIDM_TB_NEWFOLDER
:
1377 stringId
= IDS_NEWFOLDER
;
1379 /* List option button */
1380 case FCIDM_TB_SMALLICON
:
1381 stringId
= IDS_LISTVIEW
;
1383 /* Details option button */
1384 case FCIDM_TB_REPORTVIEW
:
1385 stringId
= IDS_REPORTVIEW
;
1387 /* Desktop button */
1388 case FCIDM_TB_DESKTOP
:
1389 stringId
= IDS_TODESKTOP
;
1394 lpdi
->hinst
= COMDLG32_hInstance
;
1395 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1400 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1401 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1406 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1408 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1409 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1412 /***********************************************************************
1413 * FILEDLG95_InitControls
1415 * WM_INITDIALOG message handler (before hook notification)
1417 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1419 BOOL win2000plus
= FALSE
;
1420 BOOL win98plus
= FALSE
;
1421 BOOL handledPath
= FALSE
;
1422 OSVERSIONINFOW osVi
;
1423 static const WCHAR szwSlash
[] = { '\\', 0 };
1424 static const WCHAR szwStar
[] = { '*',0 };
1426 static const TBBUTTON tbb
[] =
1428 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1429 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1430 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1431 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1432 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1433 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1434 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1435 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1436 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1438 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1443 HIMAGELIST toolbarImageList
;
1444 SHFILEINFOA shFileInfo
;
1445 ITEMIDLIST
*desktopPidl
;
1447 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1449 TRACE("%p\n", fodInfos
);
1451 /* Get windows version emulating */
1452 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1453 GetVersionExW(&osVi
);
1454 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1455 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1456 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1457 win2000plus
= (osVi
.dwMajorVersion
> 4);
1458 if (win2000plus
) win98plus
= TRUE
;
1460 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1463 /* Use either the edit or the comboboxex for the filename control */
1464 if (filename_is_edit( fodInfos
))
1466 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1467 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1471 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1472 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1475 /* Get the hwnd of the controls */
1476 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1477 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1479 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1480 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1482 /* construct the toolbar */
1483 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1484 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1486 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1487 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1488 rectTB
.left
= rectlook
.right
;
1489 rectTB
.top
= rectlook
.top
-1;
1491 if (fodInfos
->unicode
)
1492 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1493 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1494 rectTB
.left
, rectTB
.top
,
1495 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1496 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1498 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1499 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1500 rectTB
.left
, rectTB
.top
,
1501 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1502 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1504 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1506 /* FIXME: use TB_LOADIMAGES when implemented */
1507 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1508 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1509 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1511 /* Retrieve and add desktop icon to the toolbar */
1512 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1513 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1514 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1515 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1516 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1518 DestroyIcon(shFileInfo
.hIcon
);
1519 CoTaskMemFree(desktopPidl
);
1521 /* Finish Toolbar Construction */
1522 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1523 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1525 /* Set the window text with the text specified in the OPENFILENAME structure */
1528 SetWindowTextW(hwnd
,fodInfos
->title
);
1530 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1533 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1534 SetWindowTextW(hwnd
, buf
);
1537 /* Initialise the file name edit control */
1538 handledPath
= FALSE
;
1539 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1541 if(fodInfos
->filename
)
1543 /* 1. If win2000 or higher and filename contains a path, use it
1544 in preference over the lpstrInitialDir */
1545 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1546 WCHAR tmpBuf
[MAX_PATH
];
1550 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1553 /* nameBit is always shorter than the original filename. It may be NULL
1554 * when the filename contains only a drive name instead of file name */
1557 lstrcpyW(fodInfos
->filename
,nameBit
);
1561 *fodInfos
->filename
= '\0';
1563 MemFree(fodInfos
->initdir
);
1564 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1565 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1567 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1568 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1570 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1573 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1577 /* 2. (All platforms) If initdir is not null, then use it */
1578 if (!handledPath
&& fodInfos
->initdir
&& *fodInfos
->initdir
)
1580 /* Work out the proper path as supplied one might be relative */
1581 /* (Here because supplying '.' as dir browses to My Computer) */
1582 WCHAR tmpBuf
[MAX_PATH
];
1583 WCHAR tmpBuf2
[MAX_PATH
];
1587 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1588 if (PathFileExistsW(tmpBuf
)) {
1589 /* initdir does not have to be a directory. If a file is
1590 * specified, the dir part is taken */
1591 if (PathIsDirectoryW(tmpBuf
)) {
1592 PathAddBackslashW(tmpBuf
);
1593 lstrcatW(tmpBuf
, szwStar
);
1595 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1598 MemFree(fodInfos
->initdir
);
1599 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1) * sizeof(WCHAR
));
1600 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1602 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1605 else if (fodInfos
->initdir
)
1607 MemFree(fodInfos
->initdir
);
1608 fodInfos
->initdir
= NULL
;
1609 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1613 if (!handledPath
&& (!fodInfos
->initdir
|| !*fodInfos
->initdir
))
1615 /* 3. All except w2k+: if filename contains a path use it */
1616 if (!win2000plus
&& fodInfos
->filename
&&
1617 *fodInfos
->filename
&&
1618 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1619 WCHAR tmpBuf
[MAX_PATH
];
1623 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1628 /* nameBit is always shorter than the original filename */
1629 lstrcpyW(fodInfos
->filename
, nameBit
);
1632 len
= lstrlenW(tmpBuf
);
1633 MemFree(fodInfos
->initdir
);
1634 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1635 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1638 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1639 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1641 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1644 /* 4. Win2000+: Recently used */
1645 if (!handledPath
&& win2000plus
) {
1646 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1647 fodInfos
->initdir
[0] = '\0';
1649 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1651 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1654 MemFree(fodInfos
->initdir
);
1655 fodInfos
->initdir
= NULL
;
1659 /* 5. win98+ and win2000+ if any files of specified filter types in
1660 current directory, use it */
1661 if (win98plus
&& !handledPath
&& fodInfos
->filter
&& *fodInfos
->filter
) {
1663 LPCWSTR lpstrPos
= fodInfos
->filter
;
1664 WIN32_FIND_DATAW FindFileData
;
1669 /* filter is a list... title\0ext\0......\0\0 */
1671 /* Skip the title */
1672 if(! *lpstrPos
) break; /* end */
1673 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1675 /* See if any files exist in the current dir with this extension */
1676 if(! *lpstrPos
) break; /* end */
1678 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1680 if (hFind
== INVALID_HANDLE_VALUE
) {
1681 /* None found - continue search */
1682 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1686 MemFree(fodInfos
->initdir
);
1687 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1688 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1691 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1692 debugstr_w(lpstrPos
));
1699 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1700 if (!handledPath
&& (win2000plus
|| win98plus
)) {
1701 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1703 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1705 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1708 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1709 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1711 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1714 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1717 } else if (!handledPath
) {
1718 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1719 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1721 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1724 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1725 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1727 /* Must the open as read only check box be checked ?*/
1728 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1730 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1733 /* Must the open as read only check box be hidden? */
1734 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1736 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1737 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1740 /* Must the help button be hidden? */
1741 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1743 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1744 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1747 /* change Open to Save */
1748 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1751 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1752 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1753 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1754 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1757 /* Initialize the filter combo box */
1758 FILEDLG95_FILETYPE_Init(hwnd
);
1763 /***********************************************************************
1764 * FILEDLG95_ResizeControls
1766 * WM_INITDIALOG message handler (after hook notification)
1768 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1770 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1772 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1775 UINT flags
= SWP_NOACTIVATE
;
1777 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1778 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1780 /* resize the custom dialog to the parent size */
1781 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1782 GetClientRect(hwnd
, &rc
);
1785 /* our own fake template is zero sized and doesn't have children, so
1786 * there is no need to resize it. Picasa depends on it.
1788 flags
|= SWP_NOSIZE
;
1791 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1792 0, 0, rc
.right
, rc
.bottom
, flags
);
1796 /* Resize the height; if opened as read-only, checkbox and help button are
1797 * hidden and we are not using a custom template nor a customDialog
1799 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1800 (!(fodInfos
->ofnInfos
->Flags
&
1801 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1803 RECT rectDlg
, rectHelp
, rectCancel
;
1804 GetWindowRect(hwnd
, &rectDlg
);
1805 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1806 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1807 /* subtract the height of the help button plus the space between the help
1808 * button and the cancel button to the height of the dialog
1810 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1811 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1812 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1818 /***********************************************************************
1819 * FILEDLG95_FillControls
1821 * WM_INITDIALOG message handler (after hook notification)
1823 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1825 LPITEMIDLIST pidlItemId
= NULL
;
1827 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1829 TRACE("dir=%s file=%s\n",
1830 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1832 /* Get the initial directory pidl */
1834 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1836 WCHAR path
[MAX_PATH
];
1838 GetCurrentDirectoryW(MAX_PATH
,path
);
1839 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1842 /* Initialise shell objects */
1843 FILEDLG95_SHELL_Init(hwnd
);
1845 /* Initialize the Look In combo box */
1846 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1848 /* Browse to the initial directory */
1849 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1851 /* Free pidlItem memory */
1852 COMDLG32_SHFree(pidlItemId
);
1856 /***********************************************************************
1859 * Regroups all the cleaning functions of the filedlg
1861 void FILEDLG95_Clean(HWND hwnd
)
1863 FILEDLG95_FILETYPE_Clean(hwnd
);
1864 FILEDLG95_LOOKIN_Clean(hwnd
);
1865 FILEDLG95_SHELL_Clean(hwnd
);
1867 /***********************************************************************
1868 * FILEDLG95_OnWMCommand
1870 * WM_COMMAND message handler
1872 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1874 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1875 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1876 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1882 FILEDLG95_OnOpen(hwnd
);
1886 FILEDLG95_Clean(hwnd
);
1887 EndDialog(hwnd
, FALSE
);
1889 /* Filetype combo box */
1891 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1893 /* LookIn combo box */
1895 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1898 /* --- toolbar --- */
1899 /* Up folder button */
1900 case FCIDM_TB_UPFOLDER
:
1901 FILEDLG95_SHELL_UpFolder(hwnd
);
1903 /* New folder button */
1904 case FCIDM_TB_NEWFOLDER
:
1905 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1907 /* List option button */
1908 case FCIDM_TB_SMALLICON
:
1909 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1911 /* Details option button */
1912 case FCIDM_TB_REPORTVIEW
:
1913 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1915 /* Details option button */
1916 case FCIDM_TB_DESKTOP
:
1917 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1925 /* Do not use the listview selection anymore */
1926 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1930 /***********************************************************************
1931 * FILEDLG95_OnWMGetIShellBrowser
1933 * WM_GETISHELLBROWSER message handler
1935 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1937 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1941 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1947 /***********************************************************************
1948 * FILEDLG95_SendFileOK
1950 * Sends the CDN_FILEOK notification if required
1953 * TRUE if the dialog should close
1954 * FALSE if the dialog should not be closed
1956 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1958 /* ask the hook if we can close */
1959 if(IsHooked(fodInfos
))
1964 /* First send CDN_FILEOK as MSDN doc says */
1965 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1966 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1969 TRACE("canceled\n");
1973 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1974 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1975 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1978 TRACE("canceled\n");
1985 /***********************************************************************
1986 * FILEDLG95_OnOpenMultipleFiles
1988 * Handles the opening of multiple files.
1991 * check destination buffer size
1993 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1995 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1996 UINT nCount
, nSizePath
;
1997 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2001 if(fodInfos
->unicode
)
2003 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2004 ofn
->lpstrFile
[0] = '\0';
2008 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2009 ofn
->lpstrFile
[0] = '\0';
2012 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2014 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2015 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2016 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2018 LPWSTR lpstrTemp
= lpstrFileList
;
2020 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2024 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2027 WCHAR lpstrNotFound
[100];
2028 WCHAR lpstrMsg
[100];
2030 static const WCHAR nl
[] = {'\n',0};
2032 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2033 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2035 lstrcpyW(tmp
, lpstrTemp
);
2037 lstrcatW(tmp
, lpstrNotFound
);
2039 lstrcatW(tmp
, lpstrMsg
);
2041 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2045 /* move to the next file in the list of files */
2046 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2047 COMDLG32_SHFree(pidl
);
2051 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2052 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2054 /* For "oldstyle" dialog the components have to
2055 be separated by blanks (not '\0'!) and short
2056 filenames have to be used! */
2057 FIXME("Components have to be separated by blanks\n");
2059 if(fodInfos
->unicode
)
2061 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2062 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2063 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2067 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2069 if (ofn
->lpstrFile
!= NULL
)
2071 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2072 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2073 if (ofn
->nMaxFile
> nSizePath
)
2075 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2076 ofn
->lpstrFile
+ nSizePath
,
2077 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2082 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2083 fodInfos
->ofnInfos
->nFileExtension
= 0;
2085 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2088 /* clean and exit */
2089 FILEDLG95_Clean(hwnd
);
2090 return EndDialog(hwnd
,TRUE
);
2093 /* Returns the 'slot name' of the given module_name in the registry's
2094 * most-recently-used list. This will be an ASCII value in the
2095 * range ['a','z'). Returns zero on error.
2097 * The slot's value in the registry has the form:
2098 * module_name\0mru_path\0
2100 * If stored_path is given, then stored_path will contain the path name
2101 * stored in the registry's MRU list for the given module_name.
2103 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2104 * MRU list key for the given module_name.
2106 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2108 WCHAR mru_list
[32], *cur_mru_slot
;
2109 BOOL taken
[25] = {0};
2110 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2111 HKEY hkey_tmp
, *hkey
;
2120 *stored_path
= '\0';
2122 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2124 WARN("Unable to create MRU key: %d\n", ret
);
2128 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2129 (LPBYTE
)mru_list
, &mru_list_size
);
2130 if(ret
|| key_type
!= REG_SZ
){
2131 if(ret
== ERROR_FILE_NOT_FOUND
)
2134 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2139 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2140 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2141 DWORD value_data_size
= sizeof(value_data
);
2143 *value_name
= *cur_mru_slot
;
2145 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2146 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2147 if(ret
|| key_type
!= REG_BINARY
){
2148 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2152 if(!strcmpiW(module_name
, value_data
)){
2156 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2164 /* the module name isn't in the registry, so find the next open slot */
2165 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2166 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2167 for(i
= 0; i
< 25; ++i
){
2172 /* all slots are taken, so return the last one in MRUList */
2174 return *cur_mru_slot
;
2177 /* save the given filename as most-recently-used path for this module */
2178 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2180 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2184 /* get the current executable's name */
2185 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2186 WARN("GotModuleFileName failed: %d\n", GetLastError());
2189 module_name
= strrchrW(module_path
, '\\');
2191 module_name
= module_path
;
2195 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2200 { /* update the slot's info */
2201 WCHAR
*path_ends
, *final
;
2202 DWORD path_len
, final_len
;
2204 /* use only the path segment of `filename' */
2205 path_ends
= strrchrW(filename
, '\\');
2206 path_len
= path_ends
- filename
;
2208 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2210 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2213 lstrcpyW(final
, module_name
);
2214 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2215 final
[final_len
-1] = '\0';
2217 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2218 final_len
* sizeof(WCHAR
));
2220 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2229 { /* update MRUList value */
2230 WCHAR old_mru_list
[32], new_mru_list
[32];
2231 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2232 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2234 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2235 (LPBYTE
)old_mru_list
, &mru_list_size
);
2236 if(ret
|| key_type
!= REG_SZ
){
2237 if(ret
== ERROR_FILE_NOT_FOUND
){
2238 new_mru_list
[0] = slot
;
2239 new_mru_list
[1] = '\0';
2241 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2246 /* copy old list data over so that the new slot is at the start
2248 *new_mru_slot
++ = slot
;
2249 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2250 if(*old_mru_slot
!= slot
)
2251 *new_mru_slot
++ = *old_mru_slot
;
2253 *new_mru_slot
= '\0';
2256 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2257 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2259 WARN("Error saving MRUList data: %d\n", ret
);
2266 /* load the most-recently-used path for this module */
2267 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2269 WCHAR module_path
[MAX_PATH
], *module_name
;
2271 /* get the current executable's name */
2272 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2273 WARN("GotModuleFileName failed: %d\n", GetLastError());
2276 module_name
= strrchrW(module_path
, '\\');
2278 module_name
= module_path
;
2282 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2283 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2286 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2288 WCHAR strMsgTitle
[MAX_PATH
];
2289 WCHAR strMsgText
[MAX_PATH
];
2291 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2293 strMsgTitle
[0] = '\0';
2294 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2295 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2298 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2299 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2301 int nOpenAction
= defAction
;
2302 LPWSTR lpszTemp
, lpszTemp1
;
2303 LPITEMIDLIST pidl
= NULL
;
2304 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2306 /* check for invalid chars */
2307 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2309 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2313 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2315 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2318 LPSHELLFOLDER lpsfChild
;
2319 WCHAR lpwstrTemp
[MAX_PATH
];
2320 DWORD dwEaten
, dwAttributes
;
2323 lstrcpyW(lpwstrTemp
, lpszTemp
);
2324 p
= PathFindNextComponentW(lpwstrTemp
);
2326 if (!p
) break; /* end of path */
2329 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2331 /* There are no wildcards when OFN_NOVALIDATE is set */
2332 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2334 static const WCHAR wszWild
[] = { '*', '?', 0 };
2335 /* if the last element is a wildcard do a search */
2336 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2338 nOpenAction
= ONOPEN_SEARCH
;
2342 lpszTemp1
= lpszTemp
;
2344 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2346 /* append a backslash to drive letters */
2347 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2348 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2349 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2351 PathAddBackslashW(lpwstrTemp
);
2354 dwAttributes
= SFGAO_FOLDER
;
2355 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2357 /* the path component is valid, we have a pidl of the next path component */
2358 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2359 if(dwAttributes
& SFGAO_FOLDER
)
2361 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2363 ERR("bind to failed\n"); /* should not fail */
2366 IShellFolder_Release(*ppsf
);
2374 /* end dialog, return value */
2375 nOpenAction
= ONOPEN_OPEN
;
2378 COMDLG32_SHFree(pidl
);
2381 else if (!(flags
& OFN_NOVALIDATE
))
2383 if(*lpszTemp
|| /* points to trailing null for last path element */
2384 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2386 if(flags
& OFN_PATHMUSTEXIST
)
2388 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2394 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2396 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2400 /* change to the current folder */
2401 nOpenAction
= ONOPEN_OPEN
;
2406 nOpenAction
= ONOPEN_OPEN
;
2410 if(pidl
) COMDLG32_SHFree(pidl
);
2415 /***********************************************************************
2418 * Ok button WM_COMMAND message handler
2420 * If the function succeeds, the return value is nonzero.
2422 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2424 LPWSTR lpstrFileList
;
2425 UINT nFileCount
= 0;
2428 WCHAR lpstrPathAndFile
[MAX_PATH
];
2429 LPSHELLFOLDER lpsf
= NULL
;
2431 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2433 TRACE("hwnd=%p\n", hwnd
);
2435 /* try to browse the selected item */
2436 if(BrowseSelectedFolder(hwnd
))
2439 /* get the files from the edit control */
2440 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2447 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2451 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2454 Step 1: Build a complete path name from the current folder and
2455 the filename or path in the edit box.
2457 - the path in the edit box is a root path
2458 (with or without drive letter)
2459 - the edit box contains ".." (or a path with ".." in it)
2462 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2463 MemFree(lpstrFileList
);
2466 Step 2: here we have a cleaned up path
2468 We have to parse the path step by step to see if we have to browse
2469 to a folder if the path points to a directory or the last
2470 valid element is a directory.
2473 lpstrPathAndFile: cleaned up path
2477 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2478 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2479 nOpenAction
= ONOPEN_OPEN
;
2481 nOpenAction
= ONOPEN_BROWSE
;
2483 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2484 fodInfos
->ofnInfos
->Flags
,
2485 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2491 Step 3: here we have a cleaned up and validated path
2494 lpsf: ShellFolder bound to the rightmost valid path component
2495 lpstrPathAndFile: cleaned up path
2496 nOpenAction: action to do
2498 TRACE("end validate sf=%p\n", lpsf
);
2502 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2503 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2506 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2509 /* replace the current filter */
2510 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2511 len
= lstrlenW(lpszTemp
)+1;
2512 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2513 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2515 /* set the filter cb to the extension when possible */
2516 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2517 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2520 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2521 TRACE("ONOPEN_BROWSE\n");
2523 IPersistFolder2
* ppf2
;
2524 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2526 LPITEMIDLIST pidlCurrent
;
2527 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2528 IPersistFolder2_Release(ppf2
);
2529 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2531 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2532 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2534 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2535 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_SETTEXT
, 0, (LPARAM
)"");
2538 else if( nOpenAction
== ONOPEN_SEARCH
)
2540 if (fodInfos
->Shell
.FOIShellView
)
2541 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2543 COMDLG32_SHFree(pidlCurrent
);
2544 if (filename_is_edit( fodInfos
))
2545 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2550 hwnd
= (HWND
)SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, CBEM_GETEDITCONTROL
, 0, 0);
2551 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2557 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2558 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2562 /* update READONLY check box flag */
2563 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2564 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2566 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2568 /* Attach the file extension with file name*/
2569 ext
= PathFindExtensionW(lpstrPathAndFile
);
2570 if (! *ext
&& fodInfos
->defext
)
2572 /* if no extension is specified with file name, then */
2573 /* attach the extension from file filter or default one */
2575 WCHAR
*filterExt
= NULL
;
2576 LPWSTR lpstrFilter
= NULL
;
2577 static const WCHAR szwDot
[] = {'.',0};
2578 int PathLength
= lstrlenW(lpstrPathAndFile
);
2580 /*Get the file extension from file type filter*/
2581 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2582 fodInfos
->ofnInfos
->nFilterIndex
-1);
2584 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2586 WCHAR
* filterSearchIndex
;
2587 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2588 strcpyW(filterExt
, lpstrFilter
);
2590 /* if a semicolon-separated list of file extensions was given, do not include the
2591 semicolon or anything after it in the extension.
2592 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2593 filterSearchIndex
= strchrW(filterExt
, ';');
2594 if (filterSearchIndex
)
2596 filterSearchIndex
[0] = '\0';
2599 /* find the file extension by searching for the first dot in filterExt */
2600 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2601 /* if the extension is invalid or contains a glob, ignore it */
2602 filterSearchIndex
= strchrW(filterExt
, '.');
2603 if (filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2605 strcpyW(filterExt
, filterSearchIndex
);
2609 HeapFree(GetProcessHeap(), 0, filterExt
);
2616 /* use the default file extension */
2617 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2618 strcpyW(filterExt
, fodInfos
->defext
);
2621 if (*filterExt
) /* ignore filterExt="" */
2624 lstrcatW(lpstrPathAndFile
, szwDot
);
2625 /* Attach the extension */
2626 lstrcatW(lpstrPathAndFile
, filterExt
);
2629 HeapFree(GetProcessHeap(), 0, filterExt
);
2631 /* In Open dialog: if file does not exist try without extension */
2632 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2633 lpstrPathAndFile
[PathLength
] = '\0';
2635 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2638 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2639 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2641 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2644 /* In Save dialog: check if the file already exists */
2645 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2646 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2647 && PathFileExistsW(lpstrPathAndFile
))
2649 WCHAR lpstrOverwrite
[100];
2652 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2653 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2654 MB_YESNO
| MB_ICONEXCLAMATION
);
2655 if (answer
== IDNO
|| answer
== IDCANCEL
)
2662 /* In Open dialog: check if it should be created if it doesn't exist */
2663 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2664 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2665 && !PathFileExistsW(lpstrPathAndFile
))
2667 WCHAR lpstrCreate
[100];
2670 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2671 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2672 MB_YESNO
| MB_ICONEXCLAMATION
);
2673 if (answer
== IDNO
|| answer
== IDCANCEL
)
2680 /* Check that the size of the file does not exceed buffer size.
2681 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2682 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2683 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2686 /* fill destination buffer */
2687 if (fodInfos
->ofnInfos
->lpstrFile
)
2689 if(fodInfos
->unicode
)
2691 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2693 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2694 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2695 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2699 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2701 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2702 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2703 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2704 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2708 if(fodInfos
->unicode
)
2712 /* set filename offset */
2713 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2714 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2716 /* set extension offset */
2717 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2718 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2723 CHAR tempFileA
[MAX_PATH
];
2725 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2726 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2727 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2729 /* set filename offset */
2730 lpszTemp
= PathFindFileNameA(tempFileA
);
2731 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2733 /* set extension offset */
2734 lpszTemp
= PathFindExtensionA(tempFileA
);
2735 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2738 /* copy currently selected filter to lpstrCustomFilter */
2739 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2741 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2742 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2743 NULL
, 0, NULL
, NULL
);
2744 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2746 LPSTR s
= ofn
->lpstrCustomFilter
;
2747 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2748 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2749 s
, len
, NULL
, NULL
);
2754 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2757 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2760 FILEDLG95_Clean(hwnd
);
2761 ret
= EndDialog(hwnd
, TRUE
);
2767 size
= lstrlenW(lpstrPathAndFile
) + 1;
2768 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2770 /* return needed size in first two bytes of lpstrFile */
2771 if(fodInfos
->ofnInfos
->lpstrFile
)
2772 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2773 FILEDLG95_Clean(hwnd
);
2774 ret
= EndDialog(hwnd
, FALSE
);
2775 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2782 if(lpsf
) IShellFolder_Release(lpsf
);
2786 /***********************************************************************
2787 * FILEDLG95_SHELL_Init
2789 * Initialisation of the shell objects
2791 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2793 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2798 * Initialisation of the FileOpenDialogInfos structure
2804 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2806 /* Disable multi-select if flag not set */
2807 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2809 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2811 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2812 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2814 /* Construct the IShellBrowser interface */
2815 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2820 /***********************************************************************
2821 * FILEDLG95_SHELL_ExecuteCommand
2823 * Change the folder option and refresh the view
2824 * If the function succeeds, the return value is nonzero.
2826 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2828 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2831 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2833 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2838 CMINVOKECOMMANDINFO ci
;
2839 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2840 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2844 IContextMenu_InvokeCommand(pcm
, &ci
);
2845 IContextMenu_Release(pcm
);
2851 /***********************************************************************
2852 * FILEDLG95_SHELL_UpFolder
2854 * Browse to the specified object
2855 * If the function succeeds, the return value is nonzero.
2857 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2859 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2863 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2867 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2868 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2874 /***********************************************************************
2875 * FILEDLG95_SHELL_BrowseToDesktop
2877 * Browse to the Desktop
2878 * If the function succeeds, the return value is nonzero.
2880 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2882 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2888 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2889 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2890 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2891 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2892 COMDLG32_SHFree(pidl
);
2893 return SUCCEEDED(hres
);
2895 /***********************************************************************
2896 * FILEDLG95_SHELL_Clean
2898 * Cleans the memory used by shell objects
2900 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2902 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2906 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2908 /* clean Shell interfaces */
2909 if (fodInfos
->Shell
.FOIShellView
)
2911 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2912 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2914 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2915 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2916 if (fodInfos
->Shell
.FOIDataObject
)
2917 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2920 /***********************************************************************
2921 * FILEDLG95_FILETYPE_Init
2923 * Initialisation of the file type combo box
2925 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2927 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2928 int nFilters
= 0; /* number of filters */
2933 if(fodInfos
->customfilter
)
2935 /* customfilter has one entry... title\0ext\0
2936 * Set first entry of combo box item with customfilter
2939 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2942 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2944 /* Copy the extensions */
2945 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2946 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2947 lstrcpyW(lpstrExt
,lpstrPos
);
2949 /* Add the item at the end of the combo */
2950 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2951 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2954 if(fodInfos
->filter
)
2956 LPCWSTR lpstrPos
= fodInfos
->filter
;
2960 /* filter is a list... title\0ext\0......\0\0
2961 * Set the combo item text to the title and the item data
2964 LPCWSTR lpstrDisplay
;
2968 if(! *lpstrPos
) break; /* end */
2969 lpstrDisplay
= lpstrPos
;
2970 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2972 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2976 /* Copy the extensions */
2977 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2978 lstrcpyW(lpstrExt
,lpstrPos
);
2979 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2981 /* Add the item at the end of the combo */
2982 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2984 /* malformed filters are added anyway... */
2985 if (!*lpstrExt
) break;
2990 * Set the current filter to the one specified
2991 * in the initialisation structure
2993 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2997 /* Check to make sure our index isn't out of bounds. */
2998 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2999 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3000 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3002 /* set default filter index */
3003 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3004 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3006 /* calculate index of Combo Box item */
3007 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3008 if (fodInfos
->customfilter
== NULL
)
3011 /* Set the current index selection. */
3012 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3014 /* Get the corresponding text string from the combo box. */
3015 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3018 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3024 CharLowerW(lpstrFilter
); /* lowercase */
3025 len
= lstrlenW(lpstrFilter
)+1;
3026 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3027 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3030 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3034 /***********************************************************************
3035 * FILEDLG95_FILETYPE_OnCommand
3037 * WM_COMMAND of the file type combo box
3038 * If the function succeeds, the return value is nonzero.
3040 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3042 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3050 /* Get the current item of the filetype combo box */
3051 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3053 /* set the current filter index */
3054 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3055 (fodInfos
->customfilter
== NULL
? 1 : 0);
3057 /* Set the current filter with the current selection */
3058 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3060 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3062 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3065 CharLowerW(lpstrFilter
); /* lowercase */
3066 len
= lstrlenW(lpstrFilter
)+1;
3067 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3068 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3069 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3070 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3073 /* Refresh the actual view to display the included items*/
3074 if (fodInfos
->Shell
.FOIShellView
)
3075 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3080 /***********************************************************************
3081 * FILEDLG95_FILETYPE_SearchExt
3083 * searches for an extension in the filetype box
3085 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3087 int i
, iCount
= CBGetCount(hwnd
);
3089 TRACE("%s\n", debugstr_w(lpstrExt
));
3091 if(iCount
!= CB_ERR
)
3093 for(i
=0;i
<iCount
;i
++)
3095 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3102 /***********************************************************************
3103 * FILEDLG95_FILETYPE_Clean
3105 * Clean the memory used by the filetype combo box
3107 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3109 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3111 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3115 /* Delete each string of the combo and their associated data */
3116 if(iCount
!= CB_ERR
)
3118 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3120 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3121 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3124 /* Current filter */
3125 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3129 /***********************************************************************
3130 * FILEDLG95_LOOKIN_Init
3132 * Initialisation of the look in combo box
3135 /* Small helper function, to determine if the unixfs shell extension is rooted
3136 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3138 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3140 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3141 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3142 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3143 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3144 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3145 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3146 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3148 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3155 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3157 IShellFolder
*psfRoot
, *psfDrives
;
3158 IEnumIDList
*lpeRoot
, *lpeDrives
;
3159 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3162 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3166 liInfos
->iMaxIndentation
= 0;
3168 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3170 hdc
= GetDC( hwndCombo
);
3171 SelectObject( hdc
, (HFONT
)SendMessageW( hwndCombo
, WM_GETFONT
, 0, 0 ));
3172 GetTextMetricsW( hdc
, &tm
);
3173 ReleaseDC( hwndCombo
, hdc
);
3175 /* set item height for both text field and listbox */
3176 CBSetItemHeight( hwndCombo
, -1, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3177 CBSetItemHeight( hwndCombo
, 0, max( tm
.tmHeight
, GetSystemMetrics(SM_CYSMICON
) ));
3179 /* Turn on the extended UI for the combo box like Windows does */
3180 CBSetExtendedUI(hwndCombo
, TRUE
);
3182 /* Initialise data of Desktop folder */
3183 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3184 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3185 COMDLG32_SHFree(pidlTmp
);
3187 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3189 SHGetDesktopFolder(&psfRoot
);
3193 /* enumerate the contents of the desktop */
3194 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3196 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3198 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3200 /* If the unixfs extension is rooted, we don't expand the drives by default */
3201 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3203 /* special handling for CSIDL_DRIVES */
3204 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3206 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3208 /* enumerate the drives */
3209 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3211 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3213 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3214 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3215 COMDLG32_SHFree(pidlAbsTmp
);
3216 COMDLG32_SHFree(pidlTmp1
);
3218 IEnumIDList_Release(lpeDrives
);
3220 IShellFolder_Release(psfDrives
);
3225 COMDLG32_SHFree(pidlTmp
);
3227 IEnumIDList_Release(lpeRoot
);
3229 IShellFolder_Release(psfRoot
);
3232 COMDLG32_SHFree(pidlDrives
);
3235 /***********************************************************************
3236 * FILEDLG95_LOOKIN_DrawItem
3238 * WM_DRAWITEM message handler
3240 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3242 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3243 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3244 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3248 HIMAGELIST ilItemImage
;
3251 LPSFOLDER tmpFolder
;
3252 UINT shgfi_flags
= SHGFI_PIDL
| SHGFI_OPENICON
| SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
;
3253 UINT icon_width
, icon_height
;
3257 if(pDIStruct
->itemID
== -1)
3260 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3261 pDIStruct
->itemID
)))
3265 icon_width
= GetSystemMetrics(SM_CXICON
);
3266 icon_height
= GetSystemMetrics(SM_CYICON
);
3267 if (pDIStruct
->rcItem
.bottom
- pDIStruct
->rcItem
.top
< icon_height
)
3269 icon_width
= GetSystemMetrics(SM_CXSMICON
);
3270 icon_height
= GetSystemMetrics(SM_CYSMICON
);
3271 shgfi_flags
|= SHGFI_SMALLICON
;
3274 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3275 0, &sfi
, sizeof (sfi
), shgfi_flags
);
3277 /* Is this item selected ? */
3278 if(pDIStruct
->itemState
& ODS_SELECTED
)
3280 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3281 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3282 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3286 SetTextColor(pDIStruct
->hDC
,crText
);
3287 SetBkColor(pDIStruct
->hDC
,crWin
);
3288 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3291 /* Do not indent item if drawing in the edit of the combo */
3292 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3295 iIndentation
= tmpFolder
->m_iIndent
;
3297 /* Draw text and icon */
3299 /* Initialise the icon display area */
3300 rectIcon
.left
= pDIStruct
->rcItem
.left
+ 1 + icon_width
/2 * iIndentation
;
3301 rectIcon
.top
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- icon_height
) / 2;
3302 rectIcon
.right
= rectIcon
.left
+ icon_width
+ XTEXTOFFSET
;
3303 rectIcon
.bottom
= (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ icon_height
) / 2;
3305 /* Initialise the text display area */
3306 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3307 rectText
.left
= rectIcon
.right
;
3309 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3310 rectText
.right
= pDIStruct
->rcItem
.right
;
3312 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3314 /* Draw the icon from the image list */
3315 ImageList_Draw(ilItemImage
,
3322 /* Draw the associated text */
3323 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3327 /***********************************************************************
3328 * FILEDLG95_LOOKIN_OnCommand
3330 * LookIn combo box WM_COMMAND message handler
3331 * If the function succeeds, the return value is nonzero.
3333 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3335 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3337 TRACE("%p\n", fodInfos
);
3343 LPSFOLDER tmpFolder
;
3346 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3348 if( iItem
== CB_ERR
) return FALSE
;
3350 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3355 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3356 tmpFolder
->pidlItem
,
3359 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3360 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3370 /***********************************************************************
3371 * FILEDLG95_LOOKIN_AddItem
3373 * Adds an absolute pidl item to the lookin combo box
3374 * returns the index of the inserted item
3376 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3378 LPITEMIDLIST pidlNext
;
3381 LookInInfos
*liInfos
;
3383 TRACE("%08x\n", iInsertId
);
3388 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3391 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3392 tmpFolder
->m_iIndent
= 0;
3394 /* Calculate the indentation of the item in the lookin*/
3396 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3398 tmpFolder
->m_iIndent
++;
3401 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3403 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3404 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3406 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3407 SHGetFileInfoW((LPCWSTR
)pidl
,
3411 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3412 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3414 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3416 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3420 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3422 /* Add the item at the end of the list */
3425 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3427 /* Insert the item at the iInsertId position*/
3430 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3433 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3437 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3438 MemFree( tmpFolder
);
3443 /***********************************************************************
3444 * FILEDLG95_LOOKIN_InsertItemAfterParent
3446 * Insert an item below its parent
3448 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3451 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3456 if (pidl
== pidlParent
)
3459 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3463 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3466 /* Free pidlParent memory */
3467 COMDLG32_SHFree(pidlParent
);
3469 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3472 /***********************************************************************
3473 * FILEDLG95_LOOKIN_SelectItem
3475 * Adds an absolute pidl item to the lookin combo box
3476 * returns the index of the inserted item
3478 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3481 LookInInfos
*liInfos
;
3485 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3487 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3491 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3492 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3497 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3498 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3502 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3504 if(iRemovedItem
< iItemPos
)
3509 CBSetCurSel(hwnd
,iItemPos
);
3510 liInfos
->uSelectedItem
= iItemPos
;
3516 /***********************************************************************
3517 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3519 * Remove the item with an expansion level over iExpansionLevel
3521 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3524 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3528 if(liInfos
->iMaxIndentation
<= 2)
3531 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3533 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3534 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3536 CBDeleteString(hwnd
,iItemPos
);
3537 liInfos
->iMaxIndentation
--;
3545 /***********************************************************************
3546 * FILEDLG95_LOOKIN_SearchItem
3548 * Search for pidl in the lookin combo box
3549 * returns the index of the found item
3551 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3554 int iCount
= CBGetCount(hwnd
);
3556 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3558 if (iCount
!= CB_ERR
)
3562 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3564 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3566 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3574 /***********************************************************************
3575 * FILEDLG95_LOOKIN_Clean
3577 * Clean the memory used by the lookin combo box
3579 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3581 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3582 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3584 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3588 /* Delete each string of the combo and their associated data */
3589 if (iCount
!= CB_ERR
)
3591 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3593 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3594 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3596 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3600 /* LookInInfos structure */
3602 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3605 /***********************************************************************
3608 * Fill the FORMATETC used in the shell id list
3610 static FORMATETC
get_def_format(void)
3612 static CLIPFORMAT cfFormat
;
3613 FORMATETC formatetc
;
3615 if (!cfFormat
) cfFormat
= RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
);
3616 formatetc
.cfFormat
= cfFormat
;
3618 formatetc
.dwAspect
= DVASPECT_CONTENT
;
3619 formatetc
.lindex
= -1;
3620 formatetc
.tymed
= TYMED_HGLOBAL
;
3624 /***********************************************************************
3625 * FILEDLG95_FILENAME_FillFromSelection
3627 * fills the edit box from the cached DataObject
3629 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3631 FileOpenDlgInfos
*fodInfos
;
3633 LPWSTR lpstrAllFiles
, lpstrTmp
;
3634 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nAllFilesLength
= 0, nThisFileLength
, nAllFilesMaxLength
;
3637 FORMATETC formatetc
= get_def_format();
3640 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3642 if (FAILED(IDataObject_GetData(fodInfos
->Shell
.FOIDataObject
, &formatetc
, &medium
)))
3645 cida
= GlobalLock(medium
.u
.hGlobal
);
3646 nFileSelected
= cida
->cidl
;
3648 /* Allocate a buffer */
3649 nAllFilesMaxLength
= MAX_PATH
+ 3;
3650 lpstrAllFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nAllFilesMaxLength
* sizeof(WCHAR
));
3654 /* Loop through the selection, handle only files (not folders) */
3655 for (nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++)
3657 pidl
= (LPITEMIDLIST
)((LPBYTE
)cida
+ cida
->aoffset
[nFileToOpen
+ 1]);
3660 if (!IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
))
3662 if (nAllFilesLength
+ MAX_PATH
+ 3 > nAllFilesMaxLength
)
3664 nAllFilesMaxLength
*= 2;
3665 lpstrTmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpstrAllFiles
, nAllFilesMaxLength
* sizeof(WCHAR
));
3668 lpstrAllFiles
= lpstrTmp
;
3671 lpstrAllFiles
[nAllFilesLength
++] = '"';
3672 GetName(fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
| SHGDN_FORPARSING
, lpstrAllFiles
+ nAllFilesLength
);
3673 nThisFileLength
= lstrlenW(lpstrAllFiles
+ nAllFilesLength
);
3674 nAllFilesLength
+= nThisFileLength
;
3675 lpstrAllFiles
[nAllFilesLength
++] = '"';
3676 lpstrAllFiles
[nAllFilesLength
++] = ' ';
3683 /* If there's only one file, use the name as-is without quotes */
3684 lpstrTmp
= lpstrAllFiles
;
3688 lpstrTmp
[nThisFileLength
] = 0;
3690 SetWindowTextW(fodInfos
->DlgInfos
.hwndFileName
, lpstrTmp
);
3691 /* Select the file name like Windows does */
3692 if (filename_is_edit(fodInfos
))
3693 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3697 HeapFree(GetProcessHeap(), 0, lpstrAllFiles
);
3698 COMCTL32_ReleaseStgMedium(medium
);
3702 /* copied from shell32 to avoid linking to it
3703 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3704 * is dependent on whether emulated OS is unicode or not.
3706 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3711 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3712 COMDLG32_SHFree(src
->u
.pOleStr
);
3716 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3721 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3726 FIXME("unknown type %x!\n", src
->uType
);
3727 if (len
) *dest
= '\0';
3733 /***********************************************************************
3734 * FILEDLG95_FILENAME_GetFileNames
3736 * Copies the filenames to a delimited string list.
3738 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3740 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3741 UINT nFileCount
= 0; /* number of files */
3742 UINT nStrLen
= 0; /* length of string in edit control */
3743 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3747 /* get the filenames from the filename control */
3748 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3749 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3750 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3752 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3754 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3760 * DATAOBJECT Helper functions
3763 /***********************************************************************
3764 * COMCTL32_ReleaseStgMedium
3766 * like ReleaseStgMedium from ole32
3768 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3770 if(medium
.pUnkForRelease
)
3772 IUnknown_Release(medium
.pUnkForRelease
);
3776 GlobalUnlock(medium
.u
.hGlobal
);
3777 GlobalFree(medium
.u
.hGlobal
);
3781 /***********************************************************************
3782 * GetPidlFromDataObject
3784 * Return pidl(s) by number from the cached DataObject
3786 * nPidlIndex=0 gets the fully qualified root path
3788 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3792 FORMATETC formatetc
= get_def_format();
3793 LPITEMIDLIST pidl
= NULL
;
3795 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3800 /* Get the pidls from IDataObject */
3801 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3803 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3804 if(nPidlIndex
<= cida
->cidl
)
3806 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3808 COMCTL32_ReleaseStgMedium(medium
);
3813 /***********************************************************************
3816 * Return the number of selected items in the DataObject.
3819 static UINT
GetNumSelected( IDataObject
*doSelected
)
3823 FORMATETC formatetc
= get_def_format();
3825 TRACE("sv=%p\n", doSelected
);
3827 if (!doSelected
) return 0;
3829 /* Get the pidls from IDataObject */
3830 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3832 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3833 retVal
= cida
->cidl
;
3834 COMCTL32_ReleaseStgMedium(medium
);
3844 /***********************************************************************
3847 * Get the pidl's display name (relative to folder) and
3848 * put it in lpstrFileName.
3850 * Return NOERROR on success,
3854 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3859 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3863 SHGetDesktopFolder(&lpsf
);
3864 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3865 IShellFolder_Release(lpsf
);
3869 /* Get the display name of the pidl relative to the folder */
3870 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3872 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3877 /***********************************************************************
3878 * GetShellFolderFromPidl
3880 * pidlRel is the item pidl relative
3881 * Return the IShellFolder of the absolute pidl
3883 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3885 IShellFolder
*psf
= NULL
,*psfParent
;
3887 TRACE("%p\n", pidlAbs
);
3889 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3892 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3894 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3896 IShellFolder_Release(psfParent
);
3900 /* return the desktop */
3906 /***********************************************************************
3909 * Return the LPITEMIDLIST to the parent of the pidl in the list
3911 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3913 LPITEMIDLIST pidlParent
;
3915 TRACE("%p\n", pidl
);
3917 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3918 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3923 /***********************************************************************
3926 * returns the pidl of the file name relative to folder
3927 * NULL if an error occurred
3929 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3931 LPITEMIDLIST pidl
= NULL
;
3934 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3936 if(!lpcstrFileName
) return NULL
;
3937 if(!*lpcstrFileName
) return NULL
;
3941 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3942 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3943 IShellFolder_Release(lpsf
);
3948 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3955 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3957 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3960 TRACE("%p, %p\n", psf
, pidl
);
3962 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3964 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3965 /* see documentation shell 4.1*/
3966 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3969 /***********************************************************************
3970 * BrowseSelectedFolder
3972 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3974 BOOL bBrowseSelFolder
= FALSE
;
3975 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3979 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3981 LPITEMIDLIST pidlSelection
;
3983 /* get the file selected */
3984 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3985 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3987 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3988 pidlSelection
, SBSP_RELATIVE
) ) )
3990 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3991 ' ','n','o','t',' ','e','x','i','s','t',0};
3992 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3994 bBrowseSelFolder
= TRUE
;
3995 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3996 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3998 COMDLG32_SHFree( pidlSelection
);
4001 return bBrowseSelFolder
;
4005 * Memory allocation methods */
4006 static void *MemAlloc(UINT size
)
4008 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4011 static void MemFree(void *mem
)
4013 HeapFree(GetProcessHeap(),0,mem
);
4016 static inline BOOL
valid_struct_size( DWORD size
)
4018 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4019 (size
== sizeof( OPENFILENAMEW
));
4022 static inline BOOL
is_win16_looks(DWORD flags
)
4024 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4025 !(flags
& OFN_EXPLORER
));
4028 /* ------------------ APIs ---------------------- */
4030 /***********************************************************************
4031 * GetOpenFileNameA (COMDLG32.@)
4033 * Creates a dialog box for the user to select a file to open.
4036 * TRUE on success: user enters a valid file
4037 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4040 BOOL WINAPI
GetOpenFileNameA(
4041 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4043 TRACE("flags %08x\n", ofn
->Flags
);
4045 if (!valid_struct_size( ofn
->lStructSize
))
4047 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4051 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4052 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4053 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4055 if (is_win16_looks(ofn
->Flags
))
4056 return GetFileName31A(ofn
, OPEN_DIALOG
);
4058 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4061 /***********************************************************************
4062 * GetOpenFileNameW (COMDLG32.@)
4064 * Creates a dialog box for the user to select a file to open.
4067 * TRUE on success: user enters a valid file
4068 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4071 BOOL WINAPI
GetOpenFileNameW(
4072 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4074 TRACE("flags %08x\n", ofn
->Flags
);
4076 if (!valid_struct_size( ofn
->lStructSize
))
4078 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4082 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4083 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4084 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4086 if (is_win16_looks(ofn
->Flags
))
4087 return GetFileName31W(ofn
, OPEN_DIALOG
);
4089 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4093 /***********************************************************************
4094 * GetSaveFileNameA (COMDLG32.@)
4096 * Creates a dialog box for the user to select a file to save.
4099 * TRUE on success: user enters a valid file
4100 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4103 BOOL WINAPI
GetSaveFileNameA(
4104 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4106 if (!valid_struct_size( ofn
->lStructSize
))
4108 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4112 if (is_win16_looks(ofn
->Flags
))
4113 return GetFileName31A(ofn
, SAVE_DIALOG
);
4115 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4118 /***********************************************************************
4119 * GetSaveFileNameW (COMDLG32.@)
4121 * Creates a dialog box for the user to select a file to save.
4124 * TRUE on success: user enters a valid file
4125 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4128 BOOL WINAPI
GetSaveFileNameW(
4129 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4131 if (!valid_struct_size( ofn
->lStructSize
))
4133 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4137 if (is_win16_looks(ofn
->Flags
))
4138 return GetFileName31W(ofn
, SAVE_DIALOG
);
4140 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4143 /***********************************************************************
4144 * GetFileTitleA (COMDLG32.@)
4146 * See GetFileTitleW.
4148 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4151 UNICODE_STRING strWFile
;
4154 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4155 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4156 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4157 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4158 RtlFreeUnicodeString( &strWFile
);
4159 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4164 /***********************************************************************
4165 * GetFileTitleW (COMDLG32.@)
4167 * Get the name of a file.
4170 * lpFile [I] name and location of file
4171 * lpTitle [O] returned file name
4172 * cbBuf [I] buffer size of lpTitle
4176 * Failure: negative number.
4178 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4181 static const WCHAR brkpoint
[] = {'*','[',']',0};
4182 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4184 if(lpFile
== NULL
|| lpTitle
== NULL
)
4187 len
= lstrlenW(lpFile
);
4192 if(strpbrkW(lpFile
, brkpoint
))
4197 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4200 for(i
= len
; i
>= 0; i
--)
4202 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4212 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4214 len
= lstrlenW(lpFile
+i
)+1;
4218 lstrcpyW(lpTitle
, &lpFile
[i
]);