2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
74 #include "filedlgbrowser.h"
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_DONTADDTORECENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex
; /* Index of picture in image list */
96 int m_iIndent
; /* Indentation index */
97 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
101 typedef struct tagLookInInfo
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
114 #define XTEXTOFFSET 3
119 /* SearchItem methods */
120 #define SEARCH_PIDL 1
122 #define ITEM_NOTFOUND -1
124 /* Undefined windows message sent by CreateViewObject*/
125 #define WM_GETISHELLBROWSER WM_USER+7
128 * Those macros exist in windowsx.h. However, you can't really use them since
129 * they rely on the UNICODE defines and can't be used inside Wine itself.
132 /* Combo box macros */
133 #define CBAddString(hwnd,str) \
134 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
136 #define CBInsertString(hwnd,str,pos) \
137 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
139 #define CBDeleteString(hwnd,pos) \
140 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
142 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
143 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
145 #define CBGetItemDataPtr(hwnd,iItemId) \
146 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
148 #define CBGetLBText(hwnd,iItemId,str) \
149 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
151 #define CBGetCurSel(hwnd) \
152 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
154 #define CBSetCurSel(hwnd,pos) \
155 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
157 #define CBGetCount(hwnd) \
158 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
159 #define CBShowDropDown(hwnd,show) \
160 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
161 #define CBSetItemHeight(hwnd,index,height) \
162 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
164 #define CBSetExtendedUI(hwnd,flag) \
165 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
167 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
168 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
169 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
171 static const WCHAR LastVisitedMRUW
[] =
172 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
174 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
175 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
176 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
178 /***********************************************************************
182 /* Internal functions used by the dialog */
183 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
184 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
185 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
186 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
187 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
188 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
189 static void FILEDLG95_Clean(HWND hwnd
);
191 /* Functions used by the shell navigation */
192 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
193 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
196 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
201 /* Functions used by the filetype combo box */
202 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
203 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
209 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
210 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
218 /* Functions for dealing with the most-recently-used registry keys */
219 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
220 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
221 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
223 /* Miscellaneous tool functions */
224 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
225 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
226 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
227 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
228 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
229 static UINT
GetNumSelected( IDataObject
*doSelected
);
231 /* Shell memory allocation */
232 static void *MemAlloc(UINT size
);
233 static void MemFree(void *mem
);
235 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
236 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
237 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
238 static BOOL
BrowseSelectedFolder(HWND hwnd
);
240 /***********************************************************************
243 * Creates an Open common dialog box that lets the user select
244 * the drive, directory, and the name of a file or set of files to open.
246 * IN : The FileOpenDlgInfos structure associated with the dialog
247 * OUT : TRUE on success
248 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
250 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
254 LPCVOID origTemplate
;
256 LPDLGTEMPLATEW
template;
261 /* test for missing functionality */
262 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
264 FIXME("Flags 0x%08x not yet implemented\n",
265 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
268 /* Create the dialog from a template */
270 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
272 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
275 if (!(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
276 !(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
277 !(origTemplate
= LockResource(hDlgTmpl
)))
279 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
282 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize
)))
284 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
287 memcpy(template, origTemplate
, dwSize
);
289 /* msdn: explorer style dialogs permit sizing by default.
290 * The OFN_ENABLESIZING flag is only needed when a hook or
291 * custom tmeplate is provided */
292 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
293 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
294 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
296 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
298 template->style
|= WS_SIZEBOX
;
299 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
300 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
303 template->style
&= ~WS_SIZEBOX
;
306 /* old style hook messages */
307 if (IsHooked(fodInfos
))
309 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
310 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
311 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
312 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
315 /* Some shell namespace extensions depend on COM being initialized. */
316 hr
= OleInitialize(NULL
);
318 if (fodInfos
->unicode
)
319 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
321 fodInfos
->ofnInfos
->hwndOwner
,
325 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
327 fodInfos
->ofnInfos
->hwndOwner
,
333 HeapFree(GetProcessHeap(), 0, template);
335 /* Unable to create the dialog */
342 /***********************************************************************
345 * Call GetFileName95 with this structure and clean the memory.
347 * IN : The OPENFILENAMEA initialisation structure passed to
348 * GetOpenFileNameA win api function (see filedlg.c)
350 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
353 FileOpenDlgInfos fodInfos
;
354 LPSTR lpstrSavDir
= NULL
;
356 LPWSTR defext
= NULL
;
357 LPWSTR filter
= NULL
;
358 LPWSTR customfilter
= NULL
;
360 /* Initialize CommDlgExtendedError() */
361 COMDLG32_SetCommDlgExtendedError(0);
363 /* Initialize FileOpenDlgInfos structure */
364 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
366 /* Pass in the original ofn */
367 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
369 /* save current directory */
370 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
372 lpstrSavDir
= MemAlloc(MAX_PATH
);
373 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
376 fodInfos
.unicode
= FALSE
;
378 /* convert all the input strings to unicode */
379 if(ofn
->lpstrInitialDir
)
381 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
382 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
383 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
386 fodInfos
.initdir
= NULL
;
390 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
391 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
394 fodInfos
.filename
= NULL
;
398 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
399 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
400 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
402 fodInfos
.defext
= defext
;
406 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
407 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
408 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
410 fodInfos
.title
= title
;
412 if (ofn
->lpstrFilter
)
417 /* filter is a list... title\0ext\0......\0\0 */
418 s
= ofn
->lpstrFilter
;
419 while (*s
) s
= s
+strlen(s
)+1;
421 n
= s
- ofn
->lpstrFilter
;
422 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
423 filter
= MemAlloc(len
*sizeof(WCHAR
));
424 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
426 fodInfos
.filter
= filter
;
428 /* convert lpstrCustomFilter */
429 if (ofn
->lpstrCustomFilter
)
434 /* customfilter contains a pair of strings... title\0ext\0 */
435 s
= ofn
->lpstrCustomFilter
;
436 if (*s
) s
= s
+strlen(s
)+1;
437 if (*s
) s
= s
+strlen(s
)+1;
438 n
= s
- ofn
->lpstrCustomFilter
;
439 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
440 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
441 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
443 fodInfos
.customfilter
= customfilter
;
445 /* Initialize the dialog property */
446 fodInfos
.DlgInfos
.dwDlgProp
= 0;
447 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
452 ret
= GetFileName95(&fodInfos
);
455 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
456 ret
= GetFileName95(&fodInfos
);
464 SetCurrentDirectoryA(lpstrSavDir
);
465 MemFree(lpstrSavDir
);
471 MemFree(customfilter
);
472 MemFree(fodInfos
.initdir
);
473 MemFree(fodInfos
.filename
);
475 TRACE("selected file: %s\n",ofn
->lpstrFile
);
480 /***********************************************************************
483 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
484 * Call GetFileName95 with this structure and clean the memory.
487 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
490 FileOpenDlgInfos fodInfos
;
491 LPWSTR lpstrSavDir
= NULL
;
493 /* Initialize CommDlgExtendedError() */
494 COMDLG32_SetCommDlgExtendedError(0);
496 /* Initialize FileOpenDlgInfos structure */
497 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
499 /* Pass in the original ofn */
500 fodInfos
.ofnInfos
= ofn
;
502 fodInfos
.title
= ofn
->lpstrTitle
;
503 fodInfos
.defext
= ofn
->lpstrDefExt
;
504 fodInfos
.filter
= ofn
->lpstrFilter
;
505 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
507 /* convert string arguments, save others */
510 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
511 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
514 fodInfos
.filename
= NULL
;
516 if(ofn
->lpstrInitialDir
)
518 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
519 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
520 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
521 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
524 fodInfos
.initdir
= NULL
;
526 /* save current directory */
527 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
529 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
530 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
533 fodInfos
.unicode
= TRUE
;
538 ret
= GetFileName95(&fodInfos
);
541 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
542 ret
= GetFileName95(&fodInfos
);
550 SetCurrentDirectoryW(lpstrSavDir
);
551 MemFree(lpstrSavDir
);
554 /* restore saved IN arguments and convert OUT arguments back */
555 MemFree(fodInfos
.filename
);
556 MemFree(fodInfos
.initdir
);
560 /******************************************************************************
561 * COMDLG32_GetDisplayNameOf [internal]
563 * Helper function to get the display name for a pidl.
565 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
566 LPSHELLFOLDER psfDesktop
;
569 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
572 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
573 IShellFolder_Release(psfDesktop
);
577 IShellFolder_Release(psfDesktop
);
578 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
581 /******************************************************************************
582 * COMDLG32_GetCanonicalPath [internal]
584 * Helper function to get the canonical path.
586 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
587 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
589 WCHAR lpstrTemp
[MAX_PATH
];
591 /* Get the current directory name */
592 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
595 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
597 PathAddBackslashW(lpstrPathAndFile
);
599 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
601 /* if the user specified a fully qualified path use it */
602 if(PathIsRelativeW(lpstrFile
))
604 lstrcatW(lpstrPathAndFile
, lpstrFile
);
608 /* does the path have a drive letter? */
609 if (PathGetDriveNumberW(lpstrFile
) == -1)
610 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
612 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
615 /* resolve "." and ".." */
616 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
617 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
618 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
621 /***********************************************************************
622 * COMDLG32_SplitFileNames [internal]
624 * Creates a delimited list of filenames.
626 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
628 UINT nStrCharCount
= 0; /* index in src buffer */
629 UINT nFileIndex
= 0; /* index in dest buffer */
630 UINT nFileCount
= 0; /* number of files */
632 /* we might get single filename without any '"',
633 * so we need nStrLen + terminating \0 + end-of-list \0 */
634 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
637 /* build delimited file list from filenames */
638 while ( nStrCharCount
<= nStrLen
)
640 if ( lpstrEdit
[nStrCharCount
]=='"' )
643 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
645 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
648 (*lpstrFileList
)[nFileIndex
++] = 0;
654 /* single, unquoted string */
655 if ((nStrLen
> 0) && (nFileIndex
== 0) )
657 lstrcpyW(*lpstrFileList
, lpstrEdit
);
658 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
663 (*lpstrFileList
)[nFileIndex
++] = '\0';
665 *sizeUsed
= nFileIndex
;
669 /***********************************************************************
670 * ArrangeCtrlPositions [internal]
672 * NOTE: Make sure to add testcases for any changes made here.
674 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
676 HWND hwndChild
, hwndStc32
;
677 RECT rectParent
, rectChild
, rectStc32
;
681 /* Take into account if open as read only checkbox and help button
686 RECT rectHelp
, rectCancel
;
687 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
688 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
689 /* subtract the height of the help button plus the space between
690 * the help button and the cancel button to the height of the dialog
692 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
696 There are two possibilities to add components to the default file dialog box.
698 By default, all the new components are added below the standard dialog box (the else case).
700 However, if there is a static text component with the stc32 id, a special case happens.
701 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
702 in the window and the cx and cy indicate how to size the window.
703 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
704 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
708 GetClientRect(hwndParentDlg
, &rectParent
);
710 /* when arranging controls we have to use fixed parent size */
711 rectParent
.bottom
-= help_fixup
;
713 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
716 GetWindowRect(hwndStc32
, &rectStc32
);
717 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
719 /* set the size of the stc32 control according to the size of
720 * client area of the parent dialog
722 SetWindowPos(hwndStc32
, 0,
724 rectParent
.right
, rectParent
.bottom
,
725 SWP_NOMOVE
| SWP_NOZORDER
);
728 SetRectEmpty(&rectStc32
);
730 /* this part moves controls of the child dialog */
731 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
734 if (hwndChild
!= hwndStc32
)
736 GetWindowRect(hwndChild
, &rectChild
);
737 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
739 /* move only if stc32 exist */
740 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
742 /* move to the right of visible controls of the parent dialog */
743 rectChild
.left
+= rectParent
.right
;
744 rectChild
.left
-= rectStc32
.right
;
746 /* move even if stc32 doesn't exist */
747 if (rectChild
.top
>= rectStc32
.bottom
)
749 /* move below visible controls of the parent dialog */
750 rectChild
.top
+= rectParent
.bottom
;
751 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
754 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
755 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
757 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
760 /* this part moves controls of the parent dialog */
761 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
764 if (hwndChild
!= hwndChildDlg
)
766 GetWindowRect(hwndChild
, &rectChild
);
767 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
769 /* left,top of stc32 marks the position of controls
770 * from the parent dialog
772 rectChild
.left
+= rectStc32
.left
;
773 rectChild
.top
+= rectStc32
.top
;
775 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
776 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
778 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
781 /* calculate the size of the resulting dialog */
783 /* here we have to use original parent size */
784 GetClientRect(hwndParentDlg
, &rectParent
);
785 GetClientRect(hwndChildDlg
, &rectChild
);
786 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
787 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
792 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
793 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
795 chgx
= rectChild
.right
- rectParent
.right
;
797 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
798 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
800 /* Unconditionally set new dialog
801 * height to that of the child
803 chgy
= rectChild
.bottom
- rectParent
.bottom
;
808 chgy
= rectChild
.bottom
- help_fixup
;
810 /* set the size of the parent dialog */
811 GetWindowRect(hwndParentDlg
, &rectParent
);
812 SetWindowPos(hwndParentDlg
, 0,
814 rectParent
.right
- rectParent
.left
+ chgx
,
815 rectParent
.bottom
- rectParent
.top
+ chgy
,
816 SWP_NOMOVE
| SWP_NOZORDER
);
819 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
828 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
838 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
839 * structure's hInstance parameter is not a HINSTANCE, but
840 * instead a pointer to a template resource to use.
842 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
845 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
847 hinst
= COMDLG32_hInstance
;
848 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
850 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
856 hinst
= fodInfos
->ofnInfos
->hInstance
;
857 if(fodInfos
->unicode
)
859 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
860 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
864 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
865 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
869 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
872 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
873 !(template = LockResource( hDlgTmpl
)))
875 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
879 if (fodInfos
->unicode
)
880 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
881 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
882 (LPARAM
)fodInfos
->ofnInfos
);
884 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
885 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
886 (LPARAM
)fodInfos
->ofnInfos
);
889 else if( IsHooked(fodInfos
))
894 WORD menu
,class,title
;
896 GetClientRect(hwnd
,&rectHwnd
);
897 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
898 temp
.tmplate
.dwExtendedStyle
= 0;
899 temp
.tmplate
.cdit
= 0;
904 temp
.menu
= temp
.class = temp
.title
= 0;
906 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
907 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
914 /***********************************************************************
915 * SendCustomDlgNotificationMessage
917 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
920 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
922 LRESULT hook_result
= 0;
923 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
925 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
927 if(!fodInfos
) return 0;
929 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
931 TRACE("CALL NOTIFY for %x\n", uCode
);
932 if(fodInfos
->unicode
)
935 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
936 ofnNotify
.hdr
.idFrom
=0;
937 ofnNotify
.hdr
.code
= uCode
;
938 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
939 ofnNotify
.pszFile
= NULL
;
940 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
945 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
946 ofnNotify
.hdr
.idFrom
=0;
947 ofnNotify
.hdr
.code
= uCode
;
948 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
949 ofnNotify
.pszFile
= NULL
;
950 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
952 TRACE("RET NOTIFY\n");
954 TRACE("Retval: 0x%08lx\n", hook_result
);
958 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
962 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
964 TRACE("CDM_GETFILEPATH:\n");
966 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
969 /* get path and filenames */
970 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
971 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
972 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
975 p
= buffer
+ strlenW(buffer
);
977 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
979 if (fodInfos
->unicode
)
981 total
= strlenW( buffer
) + 1;
982 if (result
) lstrcpynW( result
, buffer
, size
);
983 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
987 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
988 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
989 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
991 HeapFree( GetProcessHeap(), 0, buffer
);
995 /***********************************************************************
996 * FILEDLG95_HandleCustomDialogMessages
998 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1000 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1002 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1003 WCHAR lpstrPath
[MAX_PATH
];
1006 if(!fodInfos
) return FALSE
;
1010 case CDM_GETFILEPATH
:
1011 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1014 case CDM_GETFOLDERPATH
:
1015 TRACE("CDM_GETFOLDERPATH:\n");
1016 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1019 if (fodInfos
->unicode
)
1020 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1022 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1023 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1025 retval
= lstrlenW(lpstrPath
) + 1;
1028 case CDM_GETFOLDERIDLIST
:
1029 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1030 if (retval
<= wParam
)
1031 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1035 TRACE("CDM_GETSPEC:\n");
1036 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1039 if (fodInfos
->unicode
)
1040 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1042 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1046 case CDM_SETCONTROLTEXT
:
1047 TRACE("CDM_SETCONTROLTEXT:\n");
1050 if( fodInfos
->unicode
)
1051 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1053 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1058 case CDM_HIDECONTROL
:
1059 /* MSDN states that it should fail for not OFN_EXPLORER case */
1060 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1062 HWND control
= GetDlgItem( hwnd
, wParam
);
1063 if (control
) ShowWindow( control
, SW_HIDE
);
1066 else retval
= FALSE
;
1070 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1071 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1074 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1078 /***********************************************************************
1079 * FILEDLG95_OnWMGetMMI
1081 * WM_GETMINMAXINFO message handler for resizable dialogs
1083 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1085 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1086 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1087 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1089 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1094 /***********************************************************************
1095 * FILEDLG95_OnWMSize
1097 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1099 * FIXME: this could be made more elaborate. Now use a simple scheme
1100 * where the file view is enlarged and the controls are either moved
1101 * vertically or horizontally to get out of the way. Only the "grip"
1102 * is moved in both directions to stay in the corner.
1104 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1110 FileOpenDlgInfos
*fodInfos
;
1112 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1113 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1114 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1115 /* get the new dialog rectangle */
1116 GetWindowRect( hwnd
, &rc
);
1117 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1118 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1119 /* not initialized yet */
1120 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1121 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1122 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1124 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1125 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1126 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1127 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1128 /* change the size of the view window */
1129 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1130 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1131 hdwp
= BeginDeferWindowPos( 10);
1132 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1133 rcview
.right
- rcview
.left
+ chgx
,
1134 rcview
.bottom
- rcview
.top
+ chgy
,
1135 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1136 /* change position and sizes of the controls */
1137 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1139 int ctrlid
= GetDlgCtrlID( ctrl
);
1140 GetWindowRect( ctrl
, &rc
);
1141 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1142 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1144 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1146 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1148 else if( rc
.top
> rcview
.bottom
)
1150 /* if it was below the shell view
1154 /* file name (edit or comboboxex) and file types combo change also width */
1158 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1159 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1160 SWP_NOACTIVATE
| SWP_NOZORDER
);
1162 /* then these buttons must move out of the way */
1166 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1168 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1171 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1173 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1176 else if( rc
.left
> rcview
.right
)
1178 /* if it was to the right of the shell view
1180 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1182 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1189 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1191 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1192 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1193 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1195 case IDC_TOOLBARSTATIC
:
1197 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1199 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1202 /* not resized in windows. Since wine uses this invisible control
1203 * to size the browser view it needs to be resized */
1204 case IDC_SHELLSTATIC
:
1205 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1206 rc
.right
- rc
.left
+ chgx
,
1207 rc
.bottom
- rc
.top
+ chgy
,
1208 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1213 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1214 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1216 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1217 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1219 GetWindowRect( ctrl
, &rc
);
1220 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1221 if( rc
.top
> rcview
.bottom
)
1223 /* if it was below the shell view
1225 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1226 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1227 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1229 else if( rc
.left
> rcview
.right
)
1231 /* if it was to the right of the shell view
1233 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1234 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1235 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1238 /* size the custom dialog at the end: some applications do some
1239 * control re-arranging at this point */
1240 GetClientRect(hwnd
, &rc
);
1241 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1242 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1244 EndDeferWindowPos( hdwp
);
1245 /* should not be needed */
1246 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1250 /***********************************************************************
1253 * File open dialog procedure
1255 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1258 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1265 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1267 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1268 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1270 /* Adds the FileOpenDlgInfos in the property list of the dialog
1271 so it will be easily accessible through a GetPropA(...) */
1272 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1274 FILEDLG95_InitControls(hwnd
);
1276 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1278 GetWindowRect( hwnd
, &rc
);
1279 fodInfos
->DlgInfos
.hwndGrip
=
1280 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1281 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1282 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1283 rc
.right
- gripx
, rc
.bottom
- gripy
,
1284 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1287 fodInfos
->DlgInfos
.hwndCustomDlg
=
1288 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1290 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1291 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1293 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1294 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1296 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1297 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1298 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1301 /* if the app has changed the position of the invisible listbox,
1302 * change that of the listview (browser) as well */
1303 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1304 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1305 if( !EqualRect( &rc
, &rcstc
))
1307 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1308 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1309 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1310 SWP_NOACTIVATE
| SWP_NOZORDER
);
1313 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1315 GetWindowRect( hwnd
, &rc
);
1316 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1317 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1318 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1319 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1320 GetClientRect( hwnd
, &rc
);
1321 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1322 rc
.right
- gripx
, rc
.bottom
- gripy
,
1323 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1324 /* resize the dialog to the previous invocation */
1325 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1326 SetWindowPos( hwnd
, NULL
,
1327 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1328 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1331 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1332 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1337 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1338 case WM_GETMINMAXINFO
:
1339 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1341 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1344 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1347 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1353 case WM_GETISHELLBROWSER
:
1354 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1358 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1359 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1360 MemDialogSize
= fodInfos
->sizedlg
;
1361 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1366 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1369 /* set up the button tooltips strings */
1370 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1372 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1373 switch(lpnmh
->idFrom
)
1375 /* Up folder button */
1376 case FCIDM_TB_UPFOLDER
:
1377 stringId
= IDS_UPFOLDER
;
1379 /* New folder button */
1380 case FCIDM_TB_NEWFOLDER
:
1381 stringId
= IDS_NEWFOLDER
;
1383 /* List option button */
1384 case FCIDM_TB_SMALLICON
:
1385 stringId
= IDS_LISTVIEW
;
1387 /* Details option button */
1388 case FCIDM_TB_REPORTVIEW
:
1389 stringId
= IDS_REPORTVIEW
;
1391 /* Desktop button */
1392 case FCIDM_TB_DESKTOP
:
1393 stringId
= IDS_TODESKTOP
;
1398 lpdi
->hinst
= COMDLG32_hInstance
;
1399 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1404 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1405 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1410 static inline BOOL
filename_is_edit( const FileOpenDlgInfos
*info
)
1412 return (info
->ofnInfos
->lStructSize
== OPENFILENAME_SIZE_VERSION_400W
) &&
1413 (info
->ofnInfos
->Flags
& (OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
));
1416 /***********************************************************************
1417 * FILEDLG95_InitControls
1419 * WM_INITDIALOG message handler (before hook notification)
1421 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1423 int win2000plus
= 0;
1425 int handledPath
= FALSE
;
1426 OSVERSIONINFOW osVi
;
1427 static const WCHAR szwSlash
[] = { '\\', 0 };
1428 static const WCHAR szwStar
[] = { '*',0 };
1430 static const TBBUTTON tbb
[] =
1432 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1433 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1434 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1435 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1436 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1437 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1438 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1439 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1440 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1442 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1447 HIMAGELIST toolbarImageList
;
1448 SHFILEINFOA shFileInfo
;
1449 ITEMIDLIST
*desktopPidl
;
1451 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1453 TRACE("%p\n", fodInfos
);
1455 /* Get windows version emulating */
1456 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1457 GetVersionExW(&osVi
);
1458 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1459 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1460 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1461 win2000plus
= (osVi
.dwMajorVersion
> 4);
1462 if (win2000plus
) win98plus
= TRUE
;
1464 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1467 /* Use either the edit or the comboboxex for the filename control */
1468 if (filename_is_edit( fodInfos
))
1470 DestroyWindow( GetDlgItem( hwnd
, cmb13
) );
1471 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, edt1
);
1475 DestroyWindow( GetDlgItem( hwnd
, edt1
) );
1476 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem( hwnd
, cmb13
);
1479 /* Get the hwnd of the controls */
1480 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1481 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1483 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1484 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1486 /* construct the toolbar */
1487 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1488 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1490 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1491 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1492 rectTB
.left
= rectlook
.right
;
1493 rectTB
.top
= rectlook
.top
-1;
1495 if (fodInfos
->unicode
)
1496 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1497 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1498 rectTB
.left
, rectTB
.top
,
1499 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1500 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1502 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1503 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1504 rectTB
.left
, rectTB
.top
,
1505 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1506 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1508 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1510 /* FIXME: use TB_LOADIMAGES when implemented */
1511 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1512 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1513 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1515 /* Retrieve and add desktop icon to the toolbar */
1516 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1517 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1518 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1519 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1520 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1522 DestroyIcon(shFileInfo
.hIcon
);
1523 CoTaskMemFree(desktopPidl
);
1525 /* Finish Toolbar Construction */
1526 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1527 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1529 /* Set the window text with the text specified in the OPENFILENAME structure */
1532 SetWindowTextW(hwnd
,fodInfos
->title
);
1534 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1537 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1538 SetWindowTextW(hwnd
, buf
);
1541 /* Initialise the file name edit control */
1542 handledPath
= FALSE
;
1543 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1545 if(fodInfos
->filename
)
1547 /* 1. If win2000 or higher and filename contains a path, use it
1548 in preference over the lpstrInitialDir */
1549 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1550 WCHAR tmpBuf
[MAX_PATH
];
1554 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1557 /* nameBit is always shorter than the original filename */
1558 lstrcpyW(fodInfos
->filename
,nameBit
);
1561 MemFree(fodInfos
->initdir
);
1562 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1563 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1565 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1566 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1568 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1571 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1575 /* 2. (All platforms) If initdir is not null, then use it */
1576 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1577 (*fodInfos
->initdir
!=0x00))
1579 /* Work out the proper path as supplied one might be relative */
1580 /* (Here because supplying '.' as dir browses to My Computer) */
1581 if (handledPath
==FALSE
) {
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 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1593 lstrcatW(tmpBuf
, szwSlash
);
1595 lstrcatW(tmpBuf
, szwStar
);
1597 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1600 MemFree(fodInfos
->initdir
);
1601 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1602 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1604 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1607 else if (fodInfos
->initdir
)
1609 MemFree(fodInfos
->initdir
);
1610 fodInfos
->initdir
= NULL
;
1611 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1616 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1617 (*fodInfos
->initdir
==0x00)))
1619 /* 3. All except w2k+: if filename contains a path use it */
1620 if (!win2000plus
&& fodInfos
->filename
&&
1621 *fodInfos
->filename
&&
1622 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1623 WCHAR tmpBuf
[MAX_PATH
];
1627 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1632 /* nameBit is always shorter than the original filename */
1633 lstrcpyW(fodInfos
->filename
, nameBit
);
1636 len
= lstrlenW(tmpBuf
);
1637 MemFree(fodInfos
->initdir
);
1638 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1639 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1642 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1643 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1645 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, fodInfos
->filename
);
1648 /* 4. Win2000+: Recently used */
1649 if (handledPath
== FALSE
&& win2000plus
) {
1650 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1651 fodInfos
->initdir
[0] = '\0';
1653 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1655 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1658 MemFree(fodInfos
->initdir
);
1659 fodInfos
->initdir
= NULL
;
1663 /* 5. win98+ and win2000+ if any files of specified filter types in
1664 current directory, use it */
1665 if ( win98plus
&& handledPath
== FALSE
&&
1666 fodInfos
->filter
&& *fodInfos
->filter
) {
1668 LPCWSTR lpstrPos
= fodInfos
->filter
;
1669 WIN32_FIND_DATAW FindFileData
;
1674 /* filter is a list... title\0ext\0......\0\0 */
1676 /* Skip the title */
1677 if(! *lpstrPos
) break; /* end */
1678 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1680 /* See if any files exist in the current dir with this extension */
1681 if(! *lpstrPos
) break; /* end */
1683 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1685 if (hFind
== INVALID_HANDLE_VALUE
) {
1686 /* None found - continue search */
1687 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1691 MemFree(fodInfos
->initdir
);
1692 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1693 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1696 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1697 debugstr_w(lpstrPos
));
1704 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1705 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1706 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1708 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1710 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1713 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1714 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1716 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1719 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1722 } else if (handledPath
==FALSE
) {
1723 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1724 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1726 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1729 SetFocus( fodInfos
->DlgInfos
.hwndFileName
);
1730 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1732 /* Must the open as read only check box be checked ?*/
1733 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1735 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1738 /* Must the open as read only check box be hidden? */
1739 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1741 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1742 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1745 /* Must the help button be hidden? */
1746 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1748 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1749 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1752 /* change Open to Save */
1753 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1756 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1757 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1758 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1759 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1762 /* Initialize the filter combo box */
1763 FILEDLG95_FILETYPE_Init(hwnd
);
1768 /***********************************************************************
1769 * FILEDLG95_ResizeControls
1771 * WM_INITDIALOG message handler (after hook notification)
1773 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1775 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1777 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1780 UINT flags
= SWP_NOACTIVATE
;
1782 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1783 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1785 /* resize the custom dialog to the parent size */
1786 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1787 GetClientRect(hwnd
, &rc
);
1790 /* our own fake template is zero sized and doesn't have children, so
1791 * there is no need to resize it. Picasa depends on it.
1793 flags
|= SWP_NOSIZE
;
1796 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1797 0, 0, rc
.right
, rc
.bottom
, flags
);
1801 /* Resize the height, if open as read only checkbox ad help button are
1802 * hidden and we are not using a custom template nor a customDialog
1804 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1805 (!(fodInfos
->ofnInfos
->Flags
&
1806 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1808 RECT rectDlg
, rectHelp
, rectCancel
;
1809 GetWindowRect(hwnd
, &rectDlg
);
1810 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1811 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1812 /* subtract the height of the help button plus the space between the help
1813 * button and the cancel button to the height of the dialog
1815 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1816 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1817 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1823 /***********************************************************************
1824 * FILEDLG95_FillControls
1826 * WM_INITDIALOG message handler (after hook notification)
1828 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1830 LPITEMIDLIST pidlItemId
= NULL
;
1832 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1834 TRACE("dir=%s file=%s\n",
1835 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1837 /* Get the initial directory pidl */
1839 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1841 WCHAR path
[MAX_PATH
];
1843 GetCurrentDirectoryW(MAX_PATH
,path
);
1844 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1847 /* Initialise shell objects */
1848 FILEDLG95_SHELL_Init(hwnd
);
1850 /* Initialize the Look In combo box */
1851 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1853 /* Browse to the initial directory */
1854 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1856 /* Free pidlItem memory */
1857 COMDLG32_SHFree(pidlItemId
);
1861 /***********************************************************************
1864 * Regroups all the cleaning functions of the filedlg
1866 void FILEDLG95_Clean(HWND hwnd
)
1868 FILEDLG95_FILETYPE_Clean(hwnd
);
1869 FILEDLG95_LOOKIN_Clean(hwnd
);
1870 FILEDLG95_SHELL_Clean(hwnd
);
1872 /***********************************************************************
1873 * FILEDLG95_OnWMCommand
1875 * WM_COMMAND message handler
1877 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1879 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1880 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1881 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1887 FILEDLG95_OnOpen(hwnd
);
1891 FILEDLG95_Clean(hwnd
);
1892 EndDialog(hwnd
, FALSE
);
1894 /* Filetype combo box */
1896 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1898 /* LookIn combo box */
1900 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1903 /* --- toolbar --- */
1904 /* Up folder button */
1905 case FCIDM_TB_UPFOLDER
:
1906 FILEDLG95_SHELL_UpFolder(hwnd
);
1908 /* New folder button */
1909 case FCIDM_TB_NEWFOLDER
:
1910 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1912 /* List option button */
1913 case FCIDM_TB_SMALLICON
:
1914 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1916 /* Details option button */
1917 case FCIDM_TB_REPORTVIEW
:
1918 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1920 /* Details option button */
1921 case FCIDM_TB_DESKTOP
:
1922 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1930 /* Do not use the listview selection anymore */
1931 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1935 /***********************************************************************
1936 * FILEDLG95_OnWMGetIShellBrowser
1938 * WM_GETISHELLBROWSER message handler
1940 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1942 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1946 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1952 /***********************************************************************
1953 * FILEDLG95_SendFileOK
1955 * Sends the CDN_FILEOK notification if required
1958 * TRUE if the dialog should close
1959 * FALSE if the dialog should not be closed
1961 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1963 /* ask the hook if we can close */
1964 if(IsHooked(fodInfos
))
1969 /* First send CDN_FILEOK as MSDN doc says */
1970 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1971 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1974 TRACE("canceled\n");
1978 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1979 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1980 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1983 TRACE("canceled\n");
1990 /***********************************************************************
1991 * FILEDLG95_OnOpenMultipleFiles
1993 * Handles the opening of multiple files.
1996 * check destination buffer size
1998 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
2000 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
2001 UINT nCount
, nSizePath
;
2002 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2006 if(fodInfos
->unicode
)
2008 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2009 ofn
->lpstrFile
[0] = '\0';
2013 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2014 ofn
->lpstrFile
[0] = '\0';
2017 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2019 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2020 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2021 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2023 LPWSTR lpstrTemp
= lpstrFileList
;
2025 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2029 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2032 WCHAR lpstrNotFound
[100];
2033 WCHAR lpstrMsg
[100];
2035 static const WCHAR nl
[] = {'\n',0};
2037 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2038 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2040 lstrcpyW(tmp
, lpstrTemp
);
2042 lstrcatW(tmp
, lpstrNotFound
);
2044 lstrcatW(tmp
, lpstrMsg
);
2046 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2050 /* move to the next file in the list of files */
2051 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2052 COMDLG32_SHFree(pidl
);
2056 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2057 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2059 /* For "oldstyle" dialog the components have to
2060 be separated by blanks (not '\0'!) and short
2061 filenames have to be used! */
2062 FIXME("Components have to be separated by blanks\n");
2064 if(fodInfos
->unicode
)
2066 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2067 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2068 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2072 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2074 if (ofn
->lpstrFile
!= NULL
)
2076 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2077 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2078 if (ofn
->nMaxFile
> nSizePath
)
2080 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2081 ofn
->lpstrFile
+ nSizePath
,
2082 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2087 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2088 fodInfos
->ofnInfos
->nFileExtension
= 0;
2090 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2093 /* clean and exit */
2094 FILEDLG95_Clean(hwnd
);
2095 return EndDialog(hwnd
,TRUE
);
2098 /* Returns the 'slot name' of the given module_name in the registry's
2099 * most-recently-used list. This will be an ASCII value in the
2100 * range ['a','z'). Returns zero on error.
2102 * The slot's value in the registry has the form:
2103 * module_name\0mru_path\0
2105 * If stored_path is given, then stored_path will contain the path name
2106 * stored in the registry's MRU list for the given module_name.
2108 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2109 * MRU list key for the given module_name.
2111 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2113 WCHAR mru_list
[32], *cur_mru_slot
;
2114 BOOL taken
[25] = {0};
2115 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2116 HKEY hkey_tmp
, *hkey
;
2125 *stored_path
= '\0';
2127 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2129 WARN("Unable to create MRU key: %d\n", ret
);
2133 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2134 (LPBYTE
)mru_list
, &mru_list_size
);
2135 if(ret
|| key_type
!= REG_SZ
){
2136 if(ret
== ERROR_FILE_NOT_FOUND
)
2139 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2144 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2145 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2146 DWORD value_data_size
= sizeof(value_data
);
2148 *value_name
= *cur_mru_slot
;
2150 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2151 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2152 if(ret
|| key_type
!= REG_BINARY
){
2153 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2157 if(!strcmpiW(module_name
, value_data
)){
2161 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2169 /* the module name isn't in the registry, so find the next open slot */
2170 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2171 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2172 for(i
= 0; i
< 25; ++i
){
2177 /* all slots are taken, so return the last one in MRUList */
2179 return *cur_mru_slot
;
2182 /* save the given filename as most-recently-used path for this module */
2183 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2185 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2189 /* get the current executable's name */
2190 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2191 WARN("GotModuleFileName failed: %d\n", GetLastError());
2194 module_name
= strrchrW(module_path
, '\\');
2196 module_name
= module_path
;
2200 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2205 { /* update the slot's info */
2206 WCHAR
*path_ends
, *final
;
2207 DWORD path_len
, final_len
;
2209 /* use only the path segment of `filename' */
2210 path_ends
= strrchrW(filename
, '\\');
2211 path_len
= path_ends
- filename
;
2213 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2215 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2218 lstrcpyW(final
, module_name
);
2219 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2220 final
[final_len
-1] = '\0';
2222 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2223 final_len
* sizeof(WCHAR
));
2225 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2234 { /* update MRUList value */
2235 WCHAR old_mru_list
[32], new_mru_list
[32];
2236 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2237 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2239 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2240 (LPBYTE
)old_mru_list
, &mru_list_size
);
2241 if(ret
|| key_type
!= REG_SZ
){
2242 if(ret
== ERROR_FILE_NOT_FOUND
){
2243 new_mru_list
[0] = slot
;
2244 new_mru_list
[1] = '\0';
2246 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2251 /* copy old list data over so that the new slot is at the start
2253 *new_mru_slot
++ = slot
;
2254 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2255 if(*old_mru_slot
!= slot
)
2256 *new_mru_slot
++ = *old_mru_slot
;
2258 *new_mru_slot
= '\0';
2261 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2262 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2264 WARN("Error saving MRUList data: %d\n", ret
);
2271 /* load the most-recently-used path for this module */
2272 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2274 WCHAR module_path
[MAX_PATH
], *module_name
;
2276 /* get the current executable's name */
2277 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2278 WARN("GotModuleFileName failed: %d\n", GetLastError());
2281 module_name
= strrchrW(module_path
, '\\');
2283 module_name
= module_path
;
2287 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2288 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2291 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2293 WCHAR strMsgTitle
[MAX_PATH
];
2294 WCHAR strMsgText
[MAX_PATH
];
2296 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2298 strMsgTitle
[0] = '\0';
2299 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2300 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2303 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2304 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2306 int nOpenAction
= defAction
;
2307 LPWSTR lpszTemp
, lpszTemp1
;
2308 LPITEMIDLIST pidl
= NULL
;
2309 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2311 /* check for invalid chars */
2312 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2314 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2318 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2320 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2323 LPSHELLFOLDER lpsfChild
;
2324 WCHAR lpwstrTemp
[MAX_PATH
];
2325 DWORD dwEaten
, dwAttributes
;
2328 lstrcpyW(lpwstrTemp
, lpszTemp
);
2329 p
= PathFindNextComponentW(lpwstrTemp
);
2331 if (!p
) break; /* end of path */
2334 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2336 /* There are no wildcards when OFN_NOVALIDATE is set */
2337 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2339 static const WCHAR wszWild
[] = { '*', '?', 0 };
2340 /* if the last element is a wildcard do a search */
2341 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2343 nOpenAction
= ONOPEN_SEARCH
;
2347 lpszTemp1
= lpszTemp
;
2349 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2351 /* append a backslash to drive letters */
2352 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2353 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2354 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2356 PathAddBackslashW(lpwstrTemp
);
2359 dwAttributes
= SFGAO_FOLDER
;
2360 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2362 /* the path component is valid, we have a pidl of the next path component */
2363 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2364 if(dwAttributes
& SFGAO_FOLDER
)
2366 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2368 ERR("bind to failed\n"); /* should not fail */
2371 IShellFolder_Release(*ppsf
);
2379 /* end dialog, return value */
2380 nOpenAction
= ONOPEN_OPEN
;
2383 COMDLG32_SHFree(pidl
);
2386 else if (!(flags
& OFN_NOVALIDATE
))
2388 if(*lpszTemp
|| /* points to trailing null for last path element */
2389 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2391 if(flags
& OFN_PATHMUSTEXIST
)
2393 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2399 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2401 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2405 /* change to the current folder */
2406 nOpenAction
= ONOPEN_OPEN
;
2411 nOpenAction
= ONOPEN_OPEN
;
2415 if(pidl
) COMDLG32_SHFree(pidl
);
2420 /***********************************************************************
2423 * Ok button WM_COMMAND message handler
2425 * If the function succeeds, the return value is nonzero.
2427 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2429 LPWSTR lpstrFileList
;
2430 UINT nFileCount
= 0;
2433 WCHAR lpstrPathAndFile
[MAX_PATH
];
2434 LPSHELLFOLDER lpsf
= NULL
;
2436 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2438 TRACE("hwnd=%p\n", hwnd
);
2440 /* try to browse the selected item */
2441 if(BrowseSelectedFolder(hwnd
))
2444 /* get the files from the edit control */
2445 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2452 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2456 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2459 Step 1: Build a complete path name from the current folder and
2460 the filename or path in the edit box.
2462 - the path in the edit box is a root path
2463 (with or without drive letter)
2464 - the edit box contains ".." (or a path with ".." in it)
2467 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2468 MemFree(lpstrFileList
);
2471 Step 2: here we have a cleaned up path
2473 We have to parse the path step by step to see if we have to browse
2474 to a folder if the path points to a directory or the last
2475 valid element is a directory.
2478 lpstrPathAndFile: cleaned up path
2482 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2483 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2484 nOpenAction
= ONOPEN_OPEN
;
2486 nOpenAction
= ONOPEN_BROWSE
;
2488 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2489 fodInfos
->ofnInfos
->Flags
,
2490 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2496 Step 3: here we have a cleaned up and validated path
2499 lpsf: ShellFolder bound to the rightmost valid path component
2500 lpstrPathAndFile: cleaned up path
2501 nOpenAction: action to do
2503 TRACE("end validate sf=%p\n", lpsf
);
2507 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2508 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2511 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2514 /* replace the current filter */
2515 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2516 len
= lstrlenW(lpszTemp
)+1;
2517 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2518 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2520 /* set the filter cb to the extension when possible */
2521 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2522 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2525 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2526 TRACE("ONOPEN_BROWSE\n");
2528 IPersistFolder2
* ppf2
;
2529 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2531 LPITEMIDLIST pidlCurrent
;
2532 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2533 IPersistFolder2_Release(ppf2
);
2534 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2536 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2537 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2539 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2542 else if( nOpenAction
== ONOPEN_SEARCH
)
2544 if (fodInfos
->Shell
.FOIShellView
)
2545 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2547 COMDLG32_SHFree(pidlCurrent
);
2548 if (filename_is_edit( fodInfos
))
2549 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2554 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2555 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2559 /* update READONLY check box flag */
2560 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2561 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2563 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2565 /* Attach the file extension with file name*/
2566 ext
= PathFindExtensionW(lpstrPathAndFile
);
2567 if (! *ext
&& fodInfos
->defext
)
2569 /* if no extension is specified with file name, then */
2570 /* attach the extension from file filter or default one */
2572 WCHAR
*filterExt
= NULL
;
2573 LPWSTR lpstrFilter
= NULL
;
2574 static const WCHAR szwDot
[] = {'.',0};
2575 int PathLength
= lstrlenW(lpstrPathAndFile
);
2577 /*Get the file extension from file type filter*/
2578 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2579 fodInfos
->ofnInfos
->nFilterIndex
-1);
2581 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2583 WCHAR
* filterSearchIndex
;
2584 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter
) + 1) * sizeof(WCHAR
));
2585 strcpyW(filterExt
, lpstrFilter
);
2587 /* if a semicolon-separated list of file extensions was given, do not include the
2588 semicolon or anything after it in the extension.
2589 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2590 filterSearchIndex
= strchrW(filterExt
, ';');
2591 if (filterSearchIndex
)
2593 filterSearchIndex
[0] = '\0';
2596 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2597 /* if the extension is invalid or contains a glob, ignore it */
2598 filterSearchIndex
= PathFindExtensionW(filterExt
);
2599 if (*filterSearchIndex
++ && !strchrW(filterSearchIndex
, '*') && !strchrW(filterSearchIndex
, '?'))
2601 strcpyW(filterExt
, filterSearchIndex
);
2605 HeapFree(GetProcessHeap(), 0, filterExt
);
2612 /* use the default file extension */
2613 filterExt
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos
->defext
) + 1) * sizeof(WCHAR
));
2614 strcpyW(filterExt
, fodInfos
->defext
);
2617 if (*filterExt
) /* ignore filterExt="" */
2620 lstrcatW(lpstrPathAndFile
, szwDot
);
2621 /* Attach the extension */
2622 lstrcatW(lpstrPathAndFile
, filterExt
);
2625 HeapFree(GetProcessHeap(), 0, filterExt
);
2627 /* In Open dialog: if file does not exist try without extension */
2628 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2629 lpstrPathAndFile
[PathLength
] = '\0';
2631 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2634 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2635 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2637 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2640 /* In Save dialog: check if the file already exists */
2641 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2642 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2643 && PathFileExistsW(lpstrPathAndFile
))
2645 WCHAR lpstrOverwrite
[100];
2648 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2649 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2650 MB_YESNO
| MB_ICONEXCLAMATION
);
2651 if (answer
== IDNO
|| answer
== IDCANCEL
)
2658 /* In Open dialog: check if it should be created if it doesn't exist */
2659 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2660 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2661 && !PathFileExistsW(lpstrPathAndFile
))
2663 WCHAR lpstrCreate
[100];
2666 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2667 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2668 MB_YESNO
| MB_ICONEXCLAMATION
);
2669 if (answer
== IDNO
|| answer
== IDCANCEL
)
2676 /* Check that the size of the file does not exceed buffer size.
2677 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2678 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2679 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2682 /* fill destination buffer */
2683 if (fodInfos
->ofnInfos
->lpstrFile
)
2685 if(fodInfos
->unicode
)
2687 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2689 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2690 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2691 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2695 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2697 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2698 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2699 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2700 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2704 if(fodInfos
->unicode
)
2708 /* set filename offset */
2709 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2710 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2712 /* set extension offset */
2713 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2714 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2719 CHAR tempFileA
[MAX_PATH
];
2721 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2722 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2723 tempFileA
, sizeof(tempFileA
), NULL
, NULL
);
2725 /* set filename offset */
2726 lpszTemp
= PathFindFileNameA(tempFileA
);
2727 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- tempFileA
);
2729 /* set extension offset */
2730 lpszTemp
= PathFindExtensionA(tempFileA
);
2731 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- tempFileA
) + 1 : 0;
2734 /* set the lpstrFileTitle */
2735 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2737 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2738 if(fodInfos
->unicode
)
2740 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2741 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2745 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2746 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2747 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2751 /* copy currently selected filter to lpstrCustomFilter */
2752 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2754 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2755 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2756 NULL
, 0, NULL
, NULL
);
2757 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2759 LPSTR s
= ofn
->lpstrCustomFilter
;
2760 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2761 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2762 s
, len
, NULL
, NULL
);
2767 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2770 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2773 FILEDLG95_Clean(hwnd
);
2774 ret
= EndDialog(hwnd
, TRUE
);
2780 size
= lstrlenW(lpstrPathAndFile
) + 1;
2781 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2783 /* return needed size in first two bytes of lpstrFile */
2784 if(fodInfos
->ofnInfos
->lpstrFile
)
2785 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2786 FILEDLG95_Clean(hwnd
);
2787 ret
= EndDialog(hwnd
, FALSE
);
2788 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2795 if(lpsf
) IShellFolder_Release(lpsf
);
2799 /***********************************************************************
2800 * FILEDLG95_SHELL_Init
2802 * Initialisation of the shell objects
2804 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2806 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2811 * Initialisation of the FileOpenDialogInfos structure
2817 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2819 /* Disable multi-select if flag not set */
2820 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2822 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2824 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2825 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2827 /* Construct the IShellBrowser interface */
2828 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2833 /***********************************************************************
2834 * FILEDLG95_SHELL_ExecuteCommand
2836 * Change the folder option and refresh the view
2837 * If the function succeeds, the return value is nonzero.
2839 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2841 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2844 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2846 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2851 CMINVOKECOMMANDINFO ci
;
2852 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2853 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2857 IContextMenu_InvokeCommand(pcm
, &ci
);
2858 IContextMenu_Release(pcm
);
2864 /***********************************************************************
2865 * FILEDLG95_SHELL_UpFolder
2867 * Browse to the specified object
2868 * If the function succeeds, the return value is nonzero.
2870 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2872 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2876 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2880 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2881 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2887 /***********************************************************************
2888 * FILEDLG95_SHELL_BrowseToDesktop
2890 * Browse to the Desktop
2891 * If the function succeeds, the return value is nonzero.
2893 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2895 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2901 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2902 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2903 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2904 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2905 COMDLG32_SHFree(pidl
);
2906 return SUCCEEDED(hres
);
2908 /***********************************************************************
2909 * FILEDLG95_SHELL_Clean
2911 * Cleans the memory used by shell objects
2913 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2915 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2919 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2921 /* clean Shell interfaces */
2922 if (fodInfos
->Shell
.FOIShellView
)
2924 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2925 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2927 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2928 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2929 if (fodInfos
->Shell
.FOIDataObject
)
2930 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2933 /***********************************************************************
2934 * FILEDLG95_FILETYPE_Init
2936 * Initialisation of the file type combo box
2938 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2940 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2941 int nFilters
= 0; /* number of filters */
2946 if(fodInfos
->customfilter
)
2948 /* customfilter has one entry... title\0ext\0
2949 * Set first entry of combo box item with customfilter
2952 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2955 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2957 /* Copy the extensions */
2958 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2959 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2960 lstrcpyW(lpstrExt
,lpstrPos
);
2962 /* Add the item at the end of the combo */
2963 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2964 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2967 if(fodInfos
->filter
)
2969 LPCWSTR lpstrPos
= fodInfos
->filter
;
2973 /* filter is a list... title\0ext\0......\0\0
2974 * Set the combo item text to the title and the item data
2977 LPCWSTR lpstrDisplay
;
2981 if(! *lpstrPos
) break; /* end */
2982 lpstrDisplay
= lpstrPos
;
2983 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2985 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2989 /* Copy the extensions */
2990 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2991 lstrcpyW(lpstrExt
,lpstrPos
);
2992 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2994 /* Add the item at the end of the combo */
2995 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2997 /* malformed filters are added anyway... */
2998 if (!*lpstrExt
) break;
3003 * Set the current filter to the one specified
3004 * in the initialisation structure
3006 if (fodInfos
->filter
|| fodInfos
->customfilter
)
3010 /* Check to make sure our index isn't out of bounds. */
3011 if ( fodInfos
->ofnInfos
->nFilterIndex
>
3012 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
3013 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
3015 /* set default filter index */
3016 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
3017 fodInfos
->ofnInfos
->nFilterIndex
= 1;
3019 /* calculate index of Combo Box item */
3020 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
3021 if (fodInfos
->customfilter
== NULL
)
3024 /* Set the current index selection. */
3025 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
3027 /* Get the corresponding text string from the combo box. */
3028 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3031 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
3037 CharLowerW(lpstrFilter
); /* lowercase */
3038 len
= lstrlenW(lpstrFilter
)+1;
3039 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3040 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3043 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3047 /***********************************************************************
3048 * FILEDLG95_FILETYPE_OnCommand
3050 * WM_COMMAND of the file type combo box
3051 * If the function succeeds, the return value is nonzero.
3053 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3055 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3063 /* Get the current item of the filetype combo box */
3064 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3066 /* set the current filter index */
3067 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3068 (fodInfos
->customfilter
== NULL
? 1 : 0);
3070 /* Set the current filter with the current selection */
3071 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3073 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3075 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3078 CharLowerW(lpstrFilter
); /* lowercase */
3079 len
= lstrlenW(lpstrFilter
)+1;
3080 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3081 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3082 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3083 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3086 /* Refresh the actual view to display the included items*/
3087 if (fodInfos
->Shell
.FOIShellView
)
3088 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3093 /***********************************************************************
3094 * FILEDLG95_FILETYPE_SearchExt
3096 * searches for an extension in the filetype box
3098 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3100 int i
, iCount
= CBGetCount(hwnd
);
3102 TRACE("%s\n", debugstr_w(lpstrExt
));
3104 if(iCount
!= CB_ERR
)
3106 for(i
=0;i
<iCount
;i
++)
3108 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3115 /***********************************************************************
3116 * FILEDLG95_FILETYPE_Clean
3118 * Clean the memory used by the filetype combo box
3120 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3122 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3124 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3128 /* Delete each string of the combo and their associated data */
3129 if(iCount
!= CB_ERR
)
3131 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3133 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3134 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3137 /* Current filter */
3138 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3142 /***********************************************************************
3143 * FILEDLG95_LOOKIN_Init
3145 * Initialisation of the look in combo box
3148 /* Small helper function, to determine if the unixfs shell extension is rooted
3149 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3151 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3153 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3154 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3156 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3157 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3158 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3159 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3161 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3168 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3170 IShellFolder
*psfRoot
, *psfDrives
;
3171 IEnumIDList
*lpeRoot
, *lpeDrives
;
3172 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3174 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3178 liInfos
->iMaxIndentation
= 0;
3180 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3182 /* set item height for both text field and listbox */
3183 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
3184 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
3186 /* Turn on the extended UI for the combo box like Windows does */
3187 CBSetExtendedUI(hwndCombo
, TRUE
);
3189 /* Initialise data of Desktop folder */
3190 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3191 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3192 COMDLG32_SHFree(pidlTmp
);
3194 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3196 SHGetDesktopFolder(&psfRoot
);
3200 /* enumerate the contents of the desktop */
3201 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3203 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3205 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3207 /* If the unixfs extension is rooted, we don't expand the drives by default */
3208 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3210 /* special handling for CSIDL_DRIVES */
3211 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3213 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3215 /* enumerate the drives */
3216 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3218 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3220 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3221 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3222 COMDLG32_SHFree(pidlAbsTmp
);
3223 COMDLG32_SHFree(pidlTmp1
);
3225 IEnumIDList_Release(lpeDrives
);
3227 IShellFolder_Release(psfDrives
);
3232 COMDLG32_SHFree(pidlTmp
);
3234 IEnumIDList_Release(lpeRoot
);
3236 IShellFolder_Release(psfRoot
);
3239 COMDLG32_SHFree(pidlDrives
);
3242 /***********************************************************************
3243 * FILEDLG95_LOOKIN_DrawItem
3245 * WM_DRAWITEM message handler
3247 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3249 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3250 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3251 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3255 HIMAGELIST ilItemImage
;
3258 LPSFOLDER tmpFolder
;
3259 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
3263 if(pDIStruct
->itemID
== -1)
3266 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3267 pDIStruct
->itemID
)))
3271 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
3273 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3277 SHGFI_PIDL
| SHGFI_SMALLICON
|
3278 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
3279 SHGFI_DISPLAYNAME
);
3283 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3287 SHGFI_PIDL
| SHGFI_SMALLICON
|
3288 SHGFI_SYSICONINDEX
|
3292 /* Is this item selected ? */
3293 if(pDIStruct
->itemState
& ODS_SELECTED
)
3295 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3296 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3297 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3301 SetTextColor(pDIStruct
->hDC
,crText
);
3302 SetBkColor(pDIStruct
->hDC
,crWin
);
3303 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3306 /* Do not indent item if drawing in the edit of the combo */
3307 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3310 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3314 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
3315 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
3320 iIndentation
= tmpFolder
->m_iIndent
;
3322 /* Draw text and icon */
3324 /* Initialise the icon display area */
3325 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
3326 rectIcon
.top
= pDIStruct
->rcItem
.top
;
3327 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
3328 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
3330 /* Initialise the text display area */
3331 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3332 rectText
.left
= rectIcon
.right
;
3334 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3335 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
3337 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3339 /* Draw the icon from the image list */
3340 ImageList_Draw(ilItemImage
,
3347 /* Draw the associated text */
3348 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3352 /***********************************************************************
3353 * FILEDLG95_LOOKIN_OnCommand
3355 * LookIn combo box WM_COMMAND message handler
3356 * If the function succeeds, the return value is nonzero.
3358 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3360 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3362 TRACE("%p\n", fodInfos
);
3368 LPSFOLDER tmpFolder
;
3371 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3373 if( iItem
== CB_ERR
) return FALSE
;
3375 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3380 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3381 tmpFolder
->pidlItem
,
3384 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3385 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3395 /***********************************************************************
3396 * FILEDLG95_LOOKIN_AddItem
3398 * Adds an absolute pidl item to the lookin combo box
3399 * returns the index of the inserted item
3401 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3403 LPITEMIDLIST pidlNext
;
3406 LookInInfos
*liInfos
;
3408 TRACE("%08x\n", iInsertId
);
3413 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3416 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3417 tmpFolder
->m_iIndent
= 0;
3419 /* Calculate the indentation of the item in the lookin*/
3421 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3423 tmpFolder
->m_iIndent
++;
3426 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3428 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3429 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3431 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3432 SHGetFileInfoW((LPCWSTR
)pidl
,
3436 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3437 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3439 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3441 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3445 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3447 /* Add the item at the end of the list */
3450 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3452 /* Insert the item at the iInsertId position*/
3455 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3458 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3462 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3463 MemFree( tmpFolder
);
3468 /***********************************************************************
3469 * FILEDLG95_LOOKIN_InsertItemAfterParent
3471 * Insert an item below its parent
3473 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3476 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3481 if (pidl
== pidlParent
)
3484 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3488 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3491 /* Free pidlParent memory */
3492 COMDLG32_SHFree(pidlParent
);
3494 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3497 /***********************************************************************
3498 * FILEDLG95_LOOKIN_SelectItem
3500 * Adds an absolute pidl item to the lookin combo box
3501 * returns the index of the inserted item
3503 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3506 LookInInfos
*liInfos
;
3510 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3512 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3516 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3517 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3522 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3523 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3527 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3529 if(iRemovedItem
< iItemPos
)
3534 CBSetCurSel(hwnd
,iItemPos
);
3535 liInfos
->uSelectedItem
= iItemPos
;
3541 /***********************************************************************
3542 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3544 * Remove the item with an expansion level over iExpansionLevel
3546 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3549 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3553 if(liInfos
->iMaxIndentation
<= 2)
3556 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3558 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3559 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3561 CBDeleteString(hwnd
,iItemPos
);
3562 liInfos
->iMaxIndentation
--;
3570 /***********************************************************************
3571 * FILEDLG95_LOOKIN_SearchItem
3573 * Search for pidl in the lookin combo box
3574 * returns the index of the found item
3576 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3579 int iCount
= CBGetCount(hwnd
);
3581 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3583 if (iCount
!= CB_ERR
)
3587 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3589 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3591 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3599 /***********************************************************************
3600 * FILEDLG95_LOOKIN_Clean
3602 * Clean the memory used by the lookin combo box
3604 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3606 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3607 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3609 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3613 /* Delete each string of the combo and their associated data */
3614 if (iCount
!= CB_ERR
)
3616 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3618 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3619 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3621 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3625 /* LookInInfos structure */
3627 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3630 /***********************************************************************
3631 * FILEDLG95_FILENAME_FillFromSelection
3633 * fills the edit box from the cached DataObject
3635 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3637 FileOpenDlgInfos
*fodInfos
;
3639 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3640 WCHAR lpstrTemp
[MAX_PATH
];
3641 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3644 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3646 /* Count how many files we have */
3647 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3649 /* calculate the string length, count files */
3650 if (nFileSelected
>= 1)
3652 nLength
+= 3; /* first and last quotes, trailing \0 */
3653 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3655 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3659 /* get the total length of the selected file names */
3660 lpstrTemp
[0] = '\0';
3661 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3663 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3665 nLength
+= lstrlenW( lpstrTemp
) + 3;
3668 COMDLG32_SHFree( pidl
);
3673 /* allocate the buffer */
3674 if (nFiles
<= 1) nLength
= MAX_PATH
;
3675 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3677 /* Generate the string for the edit control */
3680 lpstrCurrFile
= lpstrAllFile
;
3681 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3683 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3687 /* get the file name */
3688 lpstrTemp
[0] = '\0';
3689 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3691 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3695 *lpstrCurrFile
++ = '\"';
3696 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3697 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3698 *lpstrCurrFile
++ = '\"';
3699 *lpstrCurrFile
++ = ' ';
3704 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3707 COMDLG32_SHFree( pidl
);
3710 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3712 /* Select the file name like Windows does */
3713 if (filename_is_edit( fodInfos
))
3714 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3716 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3720 /* copied from shell32 to avoid linking to it
3721 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3722 * is dependent on whether emulated OS is unicode or not.
3724 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3729 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3730 COMDLG32_SHFree(src
->u
.pOleStr
);
3734 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3739 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3744 FIXME("unknown type %x!\n", src
->uType
);
3745 if (len
) *dest
= '\0';
3751 /***********************************************************************
3752 * FILEDLG95_FILENAME_GetFileNames
3754 * Copies the filenames to a delimited string list.
3756 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3758 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3759 UINT nFileCount
= 0; /* number of files */
3760 UINT nStrLen
= 0; /* length of string in edit control */
3761 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3765 /* get the filenames from the filename control */
3766 nStrLen
= GetWindowTextLengthW( fodInfos
->DlgInfos
.hwndFileName
);
3767 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3768 GetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrEdit
, nStrLen
+1);
3770 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3772 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3777 #define SETDefFormatEtc(fe,cf,med) \
3779 (fe).cfFormat = cf;\
3780 (fe).dwAspect = DVASPECT_CONTENT; \
3787 * DATAOBJECT Helper functions
3790 /***********************************************************************
3791 * COMCTL32_ReleaseStgMedium
3793 * like ReleaseStgMedium from ole32
3795 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3797 if(medium
.pUnkForRelease
)
3799 IUnknown_Release(medium
.pUnkForRelease
);
3803 GlobalUnlock(medium
.u
.hGlobal
);
3804 GlobalFree(medium
.u
.hGlobal
);
3808 /***********************************************************************
3809 * GetPidlFromDataObject
3811 * Return pidl(s) by number from the cached DataObject
3813 * nPidlIndex=0 gets the fully qualified root path
3815 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3819 FORMATETC formatetc
;
3820 LPITEMIDLIST pidl
= NULL
;
3822 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3827 /* Set the FORMATETC structure*/
3828 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3830 /* Get the pidls from IDataObject */
3831 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3833 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3834 if(nPidlIndex
<= cida
->cidl
)
3836 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3838 COMCTL32_ReleaseStgMedium(medium
);
3843 /***********************************************************************
3846 * Return the number of selected items in the DataObject.
3849 static UINT
GetNumSelected( IDataObject
*doSelected
)
3853 FORMATETC formatetc
;
3855 TRACE("sv=%p\n", doSelected
);
3857 if (!doSelected
) return 0;
3859 /* Set the FORMATETC structure*/
3860 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3862 /* Get the pidls from IDataObject */
3863 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3865 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3866 retVal
= cida
->cidl
;
3867 COMCTL32_ReleaseStgMedium(medium
);
3877 /***********************************************************************
3880 * Get the pidl's display name (relative to folder) and
3881 * put it in lpstrFileName.
3883 * Return NOERROR on success,
3887 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3892 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3896 SHGetDesktopFolder(&lpsf
);
3897 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3898 IShellFolder_Release(lpsf
);
3902 /* Get the display name of the pidl relative to the folder */
3903 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3905 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3910 /***********************************************************************
3911 * GetShellFolderFromPidl
3913 * pidlRel is the item pidl relative
3914 * Return the IShellFolder of the absolute pidl
3916 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3918 IShellFolder
*psf
= NULL
,*psfParent
;
3920 TRACE("%p\n", pidlAbs
);
3922 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3925 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3927 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3929 IShellFolder_Release(psfParent
);
3933 /* return the desktop */
3939 /***********************************************************************
3942 * Return the LPITEMIDLIST to the parent of the pidl in the list
3944 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3946 LPITEMIDLIST pidlParent
;
3948 TRACE("%p\n", pidl
);
3950 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3951 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3956 /***********************************************************************
3959 * returns the pidl of the file name relative to folder
3960 * NULL if an error occurred
3962 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3964 LPITEMIDLIST pidl
= NULL
;
3967 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3969 if(!lpcstrFileName
) return NULL
;
3970 if(!*lpcstrFileName
) return NULL
;
3974 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3975 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3976 IShellFolder_Release(lpsf
);
3981 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3988 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3990 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3993 TRACE("%p, %p\n", psf
, pidl
);
3995 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3997 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3998 /* see documentation shell 4.1*/
3999 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
4002 /***********************************************************************
4003 * BrowseSelectedFolder
4005 static BOOL
BrowseSelectedFolder(HWND hwnd
)
4007 BOOL bBrowseSelFolder
= FALSE
;
4008 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
4012 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
4014 LPITEMIDLIST pidlSelection
;
4016 /* get the file selected */
4017 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
4018 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
4020 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
4021 pidlSelection
, SBSP_RELATIVE
) ) )
4023 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
4024 ' ','n','o','t',' ','e','x','i','s','t',0};
4025 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
4027 bBrowseSelFolder
= TRUE
;
4028 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
4029 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
4031 COMDLG32_SHFree( pidlSelection
);
4034 return bBrowseSelFolder
;
4038 * Memory allocation methods */
4039 static void *MemAlloc(UINT size
)
4041 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
4044 static void MemFree(void *mem
)
4046 HeapFree(GetProcessHeap(),0,mem
);
4049 static inline BOOL
valid_struct_size( DWORD size
)
4051 return (size
== OPENFILENAME_SIZE_VERSION_400W
) ||
4052 (size
== sizeof( OPENFILENAMEW
));
4055 static inline BOOL
is_win16_looks(DWORD flags
)
4057 return (flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
) &&
4058 !(flags
& OFN_EXPLORER
));
4061 /* ------------------ APIs ---------------------- */
4063 /***********************************************************************
4064 * GetOpenFileNameA (COMDLG32.@)
4066 * Creates a dialog box for the user to select a file to open.
4069 * TRUE on success: user enters a valid file
4070 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4073 BOOL WINAPI
GetOpenFileNameA(
4074 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4076 TRACE("flags %08x\n", ofn
->Flags
);
4078 if (!valid_struct_size( ofn
->lStructSize
))
4080 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4084 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4085 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4086 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4088 if (is_win16_looks(ofn
->Flags
))
4089 return GetFileName31A(ofn
, OPEN_DIALOG
);
4091 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4094 /***********************************************************************
4095 * GetOpenFileNameW (COMDLG32.@)
4097 * Creates a dialog box for the user to select a file to open.
4100 * TRUE on success: user enters a valid file
4101 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4104 BOOL WINAPI
GetOpenFileNameW(
4105 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4107 TRACE("flags %08x\n", ofn
->Flags
);
4109 if (!valid_struct_size( ofn
->lStructSize
))
4111 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4115 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4116 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4117 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4119 if (is_win16_looks(ofn
->Flags
))
4120 return GetFileName31W(ofn
, OPEN_DIALOG
);
4122 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4126 /***********************************************************************
4127 * GetSaveFileNameA (COMDLG32.@)
4129 * Creates a dialog box for the user to select a file to save.
4132 * TRUE on success: user enters a valid file
4133 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4136 BOOL WINAPI
GetSaveFileNameA(
4137 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4139 if (!valid_struct_size( ofn
->lStructSize
))
4141 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4145 if (is_win16_looks(ofn
->Flags
))
4146 return GetFileName31A(ofn
, SAVE_DIALOG
);
4148 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4151 /***********************************************************************
4152 * GetSaveFileNameW (COMDLG32.@)
4154 * Creates a dialog box for the user to select a file to save.
4157 * TRUE on success: user enters a valid file
4158 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4161 BOOL WINAPI
GetSaveFileNameW(
4162 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4164 if (!valid_struct_size( ofn
->lStructSize
))
4166 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE
);
4170 if (is_win16_looks(ofn
->Flags
))
4171 return GetFileName31W(ofn
, SAVE_DIALOG
);
4173 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4176 /***********************************************************************
4177 * GetFileTitleA (COMDLG32.@)
4179 * See GetFileTitleW.
4181 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4184 UNICODE_STRING strWFile
;
4187 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4188 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4189 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4190 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4191 RtlFreeUnicodeString( &strWFile
);
4192 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4197 /***********************************************************************
4198 * GetFileTitleW (COMDLG32.@)
4200 * Get the name of a file.
4203 * lpFile [I] name and location of file
4204 * lpTitle [O] returned file name
4205 * cbBuf [I] buffer size of lpTitle
4209 * Failure: negative number.
4211 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4214 static const WCHAR brkpoint
[] = {'*','[',']',0};
4215 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4217 if(lpFile
== NULL
|| lpTitle
== NULL
)
4220 len
= lstrlenW(lpFile
);
4225 if(strpbrkW(lpFile
, brkpoint
))
4230 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4233 for(i
= len
; i
>= 0; i
--)
4235 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4245 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4247 len
= lstrlenW(lpFile
+i
)+1;
4251 lstrcpyW(lpTitle
, &lpFile
[i
]);