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)
48 // RegGetValueW is supported by Win2k3 SP1 but headers need Win Vista
50 #define _WIN32_WINNT 0x0600
52 #define WIN32_NO_STATUS
54 #define COM_NO_WINDOWS_H
57 //#include "wine/port.h"
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
70 //#include "winbase.h"
79 #include "filedlg31.h"
81 //#include "shellapi.h"
83 #include "filedlgbrowser.h"
86 #include <wine/unicode.h>
87 #include <wine/debug.h>
89 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
91 #define UNIMPLEMENTED_FLAGS \
92 (OFN_DONTADDTORECENT |\
93 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
94 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
96 #define IsHooked(fodInfos) \
97 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
98 /***********************************************************************
99 * Data structure and global variables
101 typedef struct SFolder
103 int m_iImageIndex
; /* Index of picture in image list */
105 int m_iIndent
; /* Indentation index */
106 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
108 } SFOLDER
,*LPSFOLDER
;
110 typedef struct tagLookInInfo
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
145 #define CBInsertString(hwnd,str,pos) \
146 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
148 #define CBDeleteString(hwnd,pos) \
149 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
151 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
152 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
154 #define CBGetItemDataPtr(hwnd,iItemId) \
155 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
157 #define CBGetLBText(hwnd,iItemId,str) \
158 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
160 #define CBGetCurSel(hwnd) \
161 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
163 #define CBSetCurSel(hwnd,pos) \
164 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
166 #define CBGetCount(hwnd) \
167 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
168 #define CBShowDropDown(hwnd,show) \
169 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
170 #define CBSetItemHeight(hwnd,index,height) \
171 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
173 #define CBSetExtendedUI(hwnd,flag) \
174 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
176 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
177 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
178 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
180 static const WCHAR LastVisitedMRUW
[] =
181 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
182 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
184 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
185 static const WCHAR MRUListW
[] = {'M','R','U','L','i','s','t',0};
187 /***********************************************************************
191 /* Internal functions used by the dialog */
192 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
193 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
194 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
);
195 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
196 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
197 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
198 static void FILEDLG95_Clean(HWND hwnd
);
200 /* Functions used by the shell navigation */
201 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
202 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
203 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
204 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
205 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
207 /* Functions used by the EDIT box */
208 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
210 /* Functions used by the filetype combo box */
211 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
212 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
213 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
214 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
216 /* Functions used by the Look In combo box */
217 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
218 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
219 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
220 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
221 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
222 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
223 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
224 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
225 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
227 /* Functions for dealing with the most-recently-used registry keys */
228 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
);
229 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
);
230 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
);
232 /* Miscellaneous tool functions */
233 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
234 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
235 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
236 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
237 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
238 static UINT
GetNumSelected( IDataObject
*doSelected
);
240 /* Shell memory allocation */
241 static void *MemAlloc(UINT size
);
242 static void MemFree(void *mem
);
244 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
245 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
246 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
247 static BOOL
BrowseSelectedFolder(HWND hwnd
);
249 /***********************************************************************
252 * Creates an Open common dialog box that lets the user select
253 * the drive, directory, and the name of a file or set of files to open.
255 * IN : The FileOpenDlgInfos structure associated with the dialog
256 * OUT : TRUE on success
257 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
259 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
268 LPDLGTEMPLATE hDialogTemplate
;
270 /* test for missing functionality */
271 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
273 FIXME("Flags 0x%08x not yet implemented\n",
274 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
277 /* Create the dialog from a template */
279 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
281 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
284 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
285 !(dwSize
= SizeofResource(COMDLG32_hInstance
, hRes
)) ||
286 !(hDialogTemplate
= malloc(dwSize
)) ||
287 !(template = LockResource( hDlgTmpl
)))
289 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
293 /* Copy the read only resource */
294 memcpy(hDialogTemplate
, template, dwSize
);
296 /* msdn: explorer style dialogs permit sizing by default.
297 * The OFN_ENABLESIZING flag is only needed when a hook or
298 * custom tmeplate is provided */
299 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
300 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
301 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
303 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
305 hDialogTemplate
->style
|= WS_SIZEBOX
;
306 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
307 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
310 hDialogTemplate
->style
&= ~WS_SIZEBOX
;
313 /* old style hook messages */
314 if (IsHooked(fodInfos
))
316 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
317 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
318 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
319 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
322 /* Some shell namespace extensions depend on COM being initialized. */
323 hr
= OleInitialize(NULL
);
325 if (fodInfos
->unicode
)
326 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
328 fodInfos
->ofnInfos
->hwndOwner
,
332 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
334 fodInfos
->ofnInfos
->hwndOwner
,
340 free(hDialogTemplate
);
342 /* Unable to create the dialog */
349 /***********************************************************************
352 * Call GetFileName95 with this structure and clean the memory.
354 * IN : The OPENFILENAMEA initialisation structure passed to
355 * GetOpenFileNameA win api function (see filedlg.c)
357 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
360 FileOpenDlgInfos fodInfos
;
361 LPSTR lpstrSavDir
= NULL
;
363 LPWSTR defext
= NULL
;
364 LPWSTR filter
= NULL
;
365 LPWSTR customfilter
= NULL
;
367 /* Initialize CommDlgExtendedError() */
368 COMDLG32_SetCommDlgExtendedError(0);
370 /* Initialize FileOpenDlgInfos structure */
371 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
373 /* Pass in the original ofn */
374 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
376 /* save current directory */
377 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
379 lpstrSavDir
= MemAlloc(MAX_PATH
);
380 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
383 fodInfos
.unicode
= FALSE
;
385 /* convert all the input strings to unicode */
386 if(ofn
->lpstrInitialDir
)
388 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
389 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
390 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
393 fodInfos
.initdir
= NULL
;
397 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
398 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
401 fodInfos
.filename
= NULL
;
405 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
406 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
407 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
409 fodInfos
.defext
= defext
;
413 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
414 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
415 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
417 fodInfos
.title
= title
;
419 if (ofn
->lpstrFilter
)
424 /* filter is a list... title\0ext\0......\0\0 */
425 s
= ofn
->lpstrFilter
;
426 while (*s
) s
= s
+strlen(s
)+1;
428 n
= s
- ofn
->lpstrFilter
;
429 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
430 filter
= MemAlloc(len
*sizeof(WCHAR
));
431 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
433 fodInfos
.filter
= filter
;
435 /* convert lpstrCustomFilter */
436 if (ofn
->lpstrCustomFilter
)
441 /* customfilter contains a pair of strings... title\0ext\0 */
442 s
= ofn
->lpstrCustomFilter
;
443 if (*s
) s
= s
+strlen(s
)+1;
444 if (*s
) s
= s
+strlen(s
)+1;
445 n
= s
- ofn
->lpstrCustomFilter
;
446 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
447 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
448 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
450 fodInfos
.customfilter
= customfilter
;
452 /* Initialize the dialog property */
453 fodInfos
.DlgInfos
.dwDlgProp
= 0;
454 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
459 ret
= GetFileName95(&fodInfos
);
462 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
463 ret
= GetFileName95(&fodInfos
);
471 SetCurrentDirectoryA(lpstrSavDir
);
472 MemFree(lpstrSavDir
);
478 MemFree(customfilter
);
479 MemFree(fodInfos
.initdir
);
480 MemFree(fodInfos
.filename
);
482 TRACE("selected file: %s\n",ofn
->lpstrFile
);
487 /***********************************************************************
490 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
491 * Call GetFileName95 with this structure and clean the memory.
494 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
497 FileOpenDlgInfos fodInfos
;
498 LPWSTR lpstrSavDir
= NULL
;
500 /* Initialize CommDlgExtendedError() */
501 COMDLG32_SetCommDlgExtendedError(0);
503 /* Initialize FileOpenDlgInfos structure */
504 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
506 /* Pass in the original ofn */
507 fodInfos
.ofnInfos
= ofn
;
509 fodInfos
.title
= ofn
->lpstrTitle
;
510 fodInfos
.defext
= ofn
->lpstrDefExt
;
511 fodInfos
.filter
= ofn
->lpstrFilter
;
512 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
514 /* convert string arguments, save others */
517 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
518 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
521 fodInfos
.filename
= NULL
;
523 if(ofn
->lpstrInitialDir
)
525 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
526 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
527 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
528 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
531 fodInfos
.initdir
= NULL
;
533 /* save current directory */
534 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
536 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
537 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
540 fodInfos
.unicode
= TRUE
;
545 ret
= GetFileName95(&fodInfos
);
548 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
549 ret
= GetFileName95(&fodInfos
);
557 SetCurrentDirectoryW(lpstrSavDir
);
558 MemFree(lpstrSavDir
);
561 /* restore saved IN arguments and convert OUT arguments back */
562 MemFree(fodInfos
.filename
);
563 MemFree(fodInfos
.initdir
);
567 /******************************************************************************
568 * COMDLG32_GetDisplayNameOf [internal]
570 * Helper function to get the display name for a pidl.
572 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
573 LPSHELLFOLDER psfDesktop
;
576 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
579 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
580 IShellFolder_Release(psfDesktop
);
584 IShellFolder_Release(psfDesktop
);
585 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
588 /******************************************************************************
589 * COMDLG32_GetCanonicalPath [internal]
591 * Helper function to get the canonical path.
593 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent
,
594 LPWSTR lpstrFile
, LPWSTR lpstrPathAndFile
)
596 WCHAR lpstrTemp
[MAX_PATH
];
598 /* Get the current directory name */
599 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent
, lpstrPathAndFile
))
602 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
604 PathAddBackslashW(lpstrPathAndFile
);
606 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
608 /* if the user specified a fully qualified path use it */
609 if(PathIsRelativeW(lpstrFile
))
611 lstrcatW(lpstrPathAndFile
, lpstrFile
);
615 /* does the path have a drive letter? */
616 if (PathGetDriveNumberW(lpstrFile
) == -1)
617 lstrcpyW(lpstrPathAndFile
+2, lpstrFile
);
619 lstrcpyW(lpstrPathAndFile
, lpstrFile
);
622 /* resolve "." and ".." */
623 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
624 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
625 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
628 /***********************************************************************
629 * COMDLG32_SplitFileNames [internal]
631 * Creates a delimited list of filenames.
633 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit
, UINT nStrLen
, LPWSTR
*lpstrFileList
, UINT
*sizeUsed
)
635 UINT nStrCharCount
= 0; /* index in src buffer */
636 UINT nFileIndex
= 0; /* index in dest buffer */
637 UINT nFileCount
= 0; /* number of files */
639 /* we might get single filename without any '"',
640 * so we need nStrLen + terminating \0 + end-of-list \0 */
641 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
644 /* build delimited file list from filenames */
645 while ( nStrCharCount
<= nStrLen
)
647 if ( lpstrEdit
[nStrCharCount
]=='"' )
650 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
652 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
655 (*lpstrFileList
)[nFileIndex
++] = 0;
661 /* single, unquoted string */
662 if ((nStrLen
> 0) && (nFileIndex
== 0) )
664 lstrcpyW(*lpstrFileList
, lpstrEdit
);
665 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
670 (*lpstrFileList
)[nFileIndex
++] = '\0';
672 *sizeUsed
= nFileIndex
;
676 /***********************************************************************
677 * ArrangeCtrlPositions [internal]
679 * NOTE: Make sure to add testcases for any changes made here.
681 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
683 HWND hwndChild
, hwndStc32
;
684 RECT rectParent
, rectChild
, rectStc32
;
688 /* Take into account if open as read only checkbox and help button
693 RECT rectHelp
, rectCancel
;
694 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
695 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
696 /* subtract the height of the help button plus the space between
697 * the help button and the cancel button to the height of the dialog
699 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
703 There are two possibilities to add components to the default file dialog box.
705 By default, all the new components are added below the standard dialog box (the else case).
707 However, if there is a static text component with the stc32 id, a special case happens.
708 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
709 in the window and the cx and cy indicate how to size the window.
710 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
711 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
715 GetClientRect(hwndParentDlg
, &rectParent
);
717 /* when arranging controls we have to use fixed parent size */
718 rectParent
.bottom
-= help_fixup
;
720 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
723 GetWindowRect(hwndStc32
, &rectStc32
);
724 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
726 /* set the size of the stc32 control according to the size of
727 * client area of the parent dialog
729 SetWindowPos(hwndStc32
, 0,
731 rectParent
.right
, rectParent
.bottom
,
732 SWP_NOMOVE
| SWP_NOZORDER
);
735 SetRectEmpty(&rectStc32
);
737 /* this part moves controls of the child dialog */
738 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
741 if (hwndChild
!= hwndStc32
)
743 GetWindowRect(hwndChild
, &rectChild
);
744 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
746 /* move only if stc32 exist */
747 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
749 /* move to the right of visible controls of the parent dialog */
750 rectChild
.left
+= rectParent
.right
;
751 rectChild
.left
-= rectStc32
.right
;
753 /* move even if stc32 doesn't exist */
754 if (rectChild
.top
>= rectStc32
.bottom
)
756 /* move below visible controls of the parent dialog */
757 rectChild
.top
+= rectParent
.bottom
;
758 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
761 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
762 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
764 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
767 /* this part moves controls of the parent dialog */
768 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
771 if (hwndChild
!= hwndChildDlg
)
773 GetWindowRect(hwndChild
, &rectChild
);
774 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
776 /* left,top of stc32 marks the position of controls
777 * from the parent dialog
779 rectChild
.left
+= rectStc32
.left
;
780 rectChild
.top
+= rectStc32
.top
;
782 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
783 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
785 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
788 /* calculate the size of the resulting dialog */
790 /* here we have to use original parent size */
791 GetClientRect(hwndParentDlg
, &rectParent
);
792 GetClientRect(hwndChildDlg
, &rectChild
);
793 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
794 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
799 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
800 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
802 chgx
= rectChild
.right
- rectParent
.right
;
804 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
805 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
807 /* Unconditionally set new dialog
808 * height to that of the child
810 chgy
= rectChild
.bottom
- rectParent
.bottom
;
815 chgy
= rectChild
.bottom
- help_fixup
;
817 /* set the size of the parent dialog */
818 GetWindowRect(hwndParentDlg
, &rectParent
);
819 SetWindowPos(hwndParentDlg
, 0,
821 rectParent
.right
- rectParent
.left
+ chgx
,
822 rectParent
.bottom
- rectParent
.top
+ chgy
,
823 SWP_NOMOVE
| SWP_NOZORDER
);
826 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
835 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
845 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
846 * structure's hInstance parameter is not a HINSTANCE, but
847 * instead a pointer to a template resource to use.
849 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
852 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
854 hinst
= COMDLG32_hInstance
;
855 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
857 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
863 hinst
= fodInfos
->ofnInfos
->hInstance
;
864 if(fodInfos
->unicode
)
866 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
867 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
871 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
872 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
876 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
879 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
880 !(template = LockResource( hDlgTmpl
)))
882 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
886 if (fodInfos
->unicode
)
887 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
888 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
889 (LPARAM
)fodInfos
->ofnInfos
);
891 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
892 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
893 (LPARAM
)fodInfos
->ofnInfos
);
896 else if( IsHooked(fodInfos
))
901 WORD menu
,class,title
;
903 GetClientRect(hwnd
,&rectHwnd
);
904 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
905 temp
.tmplate
.dwExtendedStyle
= 0;
906 temp
.tmplate
.cdit
= 0;
911 temp
.menu
= temp
.class = temp
.title
= 0;
913 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
914 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
921 /***********************************************************************
922 * SendCustomDlgNotificationMessage
924 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
927 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
929 LRESULT hook_result
= 0;
930 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
932 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
934 if(!fodInfos
) return 0;
936 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
938 TRACE("CALL NOTIFY for %x\n", uCode
);
939 if(fodInfos
->unicode
)
942 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
943 ofnNotify
.hdr
.idFrom
=0;
944 ofnNotify
.hdr
.code
= uCode
;
945 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
946 ofnNotify
.pszFile
= NULL
;
947 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
952 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
953 ofnNotify
.hdr
.idFrom
=0;
954 ofnNotify
.hdr
.code
= uCode
;
955 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
956 ofnNotify
.pszFile
= NULL
;
957 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
959 TRACE("RET NOTIFY\n");
961 TRACE("Retval: 0x%08lx\n", hook_result
);
965 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
969 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
971 TRACE("CDM_GETFILEPATH:\n");
973 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
976 /* get path and filenames */
977 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
978 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
979 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
982 p
= buffer
+ strlenW(buffer
);
984 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
986 if (fodInfos
->unicode
)
988 total
= strlenW( buffer
) + 1;
989 if (result
) lstrcpynW( result
, buffer
, size
);
990 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
994 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
995 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
996 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
998 HeapFree( GetProcessHeap(), 0, buffer
);
1002 /***********************************************************************
1003 * FILEDLG95_HandleCustomDialogMessages
1005 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1007 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1009 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1010 WCHAR lpstrPath
[MAX_PATH
];
1013 if(!fodInfos
) return FALSE
;
1017 case CDM_GETFILEPATH
:
1018 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
1021 case CDM_GETFOLDERPATH
:
1022 TRACE("CDM_GETFOLDERPATH:\n");
1023 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
1026 if (fodInfos
->unicode
)
1027 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
1029 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
1030 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
1032 retval
= lstrlenW(lpstrPath
) + 1;
1035 case CDM_GETFOLDERIDLIST
:
1036 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
1037 if (retval
<= wParam
)
1038 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
1042 TRACE("CDM_GETSPEC:\n");
1043 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
1046 if (fodInfos
->unicode
)
1047 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1049 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
1053 case CDM_SETCONTROLTEXT
:
1054 TRACE("CDM_SETCONTROLTEXT:\n");
1057 if( fodInfos
->unicode
)
1058 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
1060 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1065 case CDM_HIDECONTROL
:
1066 /* MSDN states that it should fail for not OFN_EXPLORER case */
1067 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1069 HWND control
= GetDlgItem( hwnd
, wParam
);
1070 if (control
) ShowWindow( control
, SW_HIDE
);
1073 else retval
= FALSE
;
1077 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1078 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1081 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1085 /***********************************************************************
1086 * FILEDLG95_OnWMGetMMI
1088 * WM_GETMINMAXINFO message handler for resizable dialogs
1090 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
1092 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1093 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1094 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
1096 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1101 /***********************************************************************
1102 * FILEDLG95_OnWMSize
1104 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1106 * FIXME: this could be made more elaborate. Now use a simple scheme
1107 * where the file view is enlarged and the controls are either moved
1108 * vertically or horizontally to get out of the way. Only the "grip"
1109 * is moved in both directions to stay in the corner.
1111 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
)
1117 FileOpenDlgInfos
*fodInfos
;
1119 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1120 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1121 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1122 /* get the new dialog rectangle */
1123 GetWindowRect( hwnd
, &rc
);
1124 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1125 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1126 /* not initialized yet */
1127 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1128 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1129 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1131 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1132 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1133 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1134 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1135 /* change the size of the view window */
1136 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1137 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1138 hdwp
= BeginDeferWindowPos( 10);
1139 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1140 rcview
.right
- rcview
.left
+ chgx
,
1141 rcview
.bottom
- rcview
.top
+ chgy
,
1142 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1143 /* change position and sizes of the controls */
1144 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1146 int ctrlid
= GetDlgCtrlID( ctrl
);
1147 GetWindowRect( ctrl
, &rc
);
1148 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1149 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1151 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1153 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1155 else if( rc
.top
> rcview
.bottom
)
1157 /* if it was below the shell view
1161 /* file name box and file types combo change also width */
1164 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1165 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1166 SWP_NOACTIVATE
| SWP_NOZORDER
);
1168 /* then these buttons must move out of the way */
1172 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1174 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1177 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1179 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1182 else if( rc
.left
> rcview
.right
)
1184 /* if it was to the right of the shell view
1186 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1188 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1195 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1197 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1198 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1199 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1201 case IDC_TOOLBARSTATIC
:
1203 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1205 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1208 /* not resized in windows. Since wine uses this invisible control
1209 * to size the browser view it needs to be resized */
1210 case IDC_SHELLSTATIC
:
1211 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1212 rc
.right
- rc
.left
+ chgx
,
1213 rc
.bottom
- rc
.top
+ chgy
,
1214 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1219 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1220 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1222 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1223 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1225 GetWindowRect( ctrl
, &rc
);
1226 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1227 if( rc
.top
> rcview
.bottom
)
1229 /* if it was below the shell view
1231 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1232 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1233 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1235 else if( rc
.left
> rcview
.right
)
1237 /* if it was to the right of the shell view
1239 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1240 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1241 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1244 /* size the custom dialog at the end: some applications do some
1245 * control re-arranging at this point */
1246 GetClientRect(hwnd
, &rc
);
1247 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1248 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1250 EndDeferWindowPos( hdwp
);
1251 /* should not be needed */
1252 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1256 /***********************************************************************
1259 * File open dialog procedure
1261 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1264 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1271 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1273 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1274 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1276 /* Adds the FileOpenDlgInfos in the property list of the dialog
1277 so it will be easily accessible through a GetPropA(...) */
1278 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1280 FILEDLG95_InitControls(hwnd
);
1282 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1284 GetWindowRect( hwnd
, &rc
);
1285 fodInfos
->DlgInfos
.hwndGrip
=
1286 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1287 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1288 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1289 rc
.right
- gripx
, rc
.bottom
- gripy
,
1290 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1293 fodInfos
->DlgInfos
.hwndCustomDlg
=
1294 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1296 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1297 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1299 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1300 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1302 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1303 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1304 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1307 /* if the app has changed the position of the invisible listbox,
1308 * change that of the listview (browser) as well */
1309 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1310 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1311 if( !EqualRect( &rc
, &rcstc
))
1313 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1314 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1315 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1316 SWP_NOACTIVATE
| SWP_NOZORDER
);
1319 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1321 GetWindowRect( hwnd
, &rc
);
1322 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1323 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1324 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1325 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1326 GetClientRect( hwnd
, &rc
);
1327 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1328 rc
.right
- gripx
, rc
.bottom
- gripy
,
1329 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1330 /* resize the dialog to the previous invocation */
1331 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1332 SetWindowPos( hwnd
, NULL
,
1333 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1334 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1337 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1338 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1343 return FILEDLG95_OnWMSize(hwnd
, wParam
);
1344 case WM_GETMINMAXINFO
:
1345 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1347 return FILEDLG95_OnWMCommand(hwnd
, wParam
);
1350 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1353 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1359 case WM_GETISHELLBROWSER
:
1360 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1364 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1365 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1366 MemDialogSize
= fodInfos
->sizedlg
;
1367 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1372 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1375 /* set up the button tooltips strings */
1376 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1378 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1379 switch(lpnmh
->idFrom
)
1381 /* Up folder button */
1382 case FCIDM_TB_UPFOLDER
:
1383 stringId
= IDS_UPFOLDER
;
1385 /* New folder button */
1386 case FCIDM_TB_NEWFOLDER
:
1387 stringId
= IDS_NEWFOLDER
;
1389 /* List option button */
1390 case FCIDM_TB_SMALLICON
:
1391 stringId
= IDS_LISTVIEW
;
1393 /* Details option button */
1394 case FCIDM_TB_REPORTVIEW
:
1395 stringId
= IDS_REPORTVIEW
;
1397 /* Desktop button */
1398 case FCIDM_TB_DESKTOP
:
1399 stringId
= IDS_TODESKTOP
;
1404 lpdi
->hinst
= COMDLG32_hInstance
;
1405 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1410 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1411 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
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
);
1466 /* Get the hwnd of the controls */
1467 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1468 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1469 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1471 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1472 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1474 /* construct the toolbar */
1475 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1476 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1478 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1479 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1480 rectTB
.left
= rectlook
.right
;
1481 rectTB
.top
= rectlook
.top
-1;
1483 if (fodInfos
->unicode
)
1484 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1485 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1486 rectTB
.left
, rectTB
.top
,
1487 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1488 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1490 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1491 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1492 rectTB
.left
, rectTB
.top
,
1493 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1494 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1496 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1498 /* FIXME: use TB_LOADIMAGES when implemented */
1499 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1500 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1501 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1503 /* Retrieve and add desktop icon to the toolbar */
1504 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1505 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1506 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1507 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1508 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1510 DestroyIcon(shFileInfo
.hIcon
);
1511 CoTaskMemFree(desktopPidl
);
1513 /* Finish Toolbar Construction */
1514 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1515 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1517 /* Set the window text with the text specified in the OPENFILENAME structure */
1520 SetWindowTextW(hwnd
,fodInfos
->title
);
1522 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1525 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_AS
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1526 SetWindowTextW(hwnd
, buf
);
1529 /* Initialise the file name edit control */
1530 handledPath
= FALSE
;
1531 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1533 if(fodInfos
->filename
)
1535 /* 1. If win2000 or higher and filename contains a path, use it
1536 in preference over the lpstrInitialDir */
1537 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1538 WCHAR tmpBuf
[MAX_PATH
];
1542 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1545 /* nameBit is always shorter than the original filename */
1546 lstrcpyW(fodInfos
->filename
,nameBit
);
1549 MemFree(fodInfos
->initdir
);
1550 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1551 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1553 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1554 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1556 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1559 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1563 /* 2. (All platforms) If initdir is not null, then use it */
1564 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1565 (*fodInfos
->initdir
!=0x00))
1567 /* Work out the proper path as supplied one might be relative */
1568 /* (Here because supplying '.' as dir browses to My Computer) */
1569 if (handledPath
==FALSE
) {
1570 WCHAR tmpBuf
[MAX_PATH
];
1571 WCHAR tmpBuf2
[MAX_PATH
];
1575 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1576 if( PathFileExistsW(tmpBuf
) ) {
1577 /* initdir does not have to be a directory. If a file is
1578 * specified, the dir part is taken */
1579 if( PathIsDirectoryW(tmpBuf
)) {
1580 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1581 lstrcatW(tmpBuf
, szwSlash
);
1583 lstrcatW(tmpBuf
, szwStar
);
1585 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1588 MemFree(fodInfos
->initdir
);
1589 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1590 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1592 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1595 else if (fodInfos
->initdir
)
1597 MemFree(fodInfos
->initdir
);
1598 fodInfos
->initdir
= NULL
;
1599 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1604 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1605 (*fodInfos
->initdir
==0x00)))
1607 /* 3. All except w2k+: if filename contains a path use it */
1608 if (!win2000plus
&& fodInfos
->filename
&&
1609 *fodInfos
->filename
&&
1610 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1611 WCHAR tmpBuf
[MAX_PATH
];
1615 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1620 /* nameBit is always shorter than the original filename */
1621 lstrcpyW(fodInfos
->filename
, nameBit
);
1624 len
= lstrlenW(tmpBuf
);
1625 MemFree(fodInfos
->initdir
);
1626 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1627 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1630 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1631 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1633 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1636 /* 4. Win2000+: Recently used */
1637 if (handledPath
== FALSE
&& win2000plus
) {
1638 fodInfos
->initdir
= MemAlloc(MAX_PATH
* sizeof(WCHAR
));
1639 fodInfos
->initdir
[0] = '\0';
1641 FILEDLG95_MRU_load_filename(fodInfos
->initdir
);
1643 if (fodInfos
->initdir
[0] && PathFileExistsW(fodInfos
->initdir
)){
1646 MemFree(fodInfos
->initdir
);
1647 fodInfos
->initdir
= NULL
;
1651 /* 5. win98+ and win2000+ if any files of specified filter types in
1652 current directory, use it */
1653 if ( win98plus
&& handledPath
== FALSE
&&
1654 fodInfos
->filter
&& *fodInfos
->filter
) {
1656 LPCWSTR lpstrPos
= fodInfos
->filter
;
1657 WIN32_FIND_DATAW FindFileData
;
1662 /* filter is a list... title\0ext\0......\0\0 */
1664 /* Skip the title */
1665 if(! *lpstrPos
) break; /* end */
1666 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1668 /* See if any files exist in the current dir with this extension */
1669 if(! *lpstrPos
) break; /* end */
1671 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1673 if (hFind
== INVALID_HANDLE_VALUE
) {
1674 /* None found - continue search */
1675 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1679 MemFree(fodInfos
->initdir
);
1680 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1681 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1684 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1685 debugstr_w(lpstrPos
));
1692 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1693 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1694 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1696 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1698 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1701 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1702 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1704 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1707 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1710 } else if (handledPath
==FALSE
) {
1711 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1712 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1714 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1717 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1718 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1720 /* Must the open as read only check box be checked ?*/
1721 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1723 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1726 /* Must the open as read only check box be hidden? */
1727 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1729 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1730 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1733 /* Must the help button be hidden? */
1734 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1736 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1737 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1740 /* change Open to Save */
1741 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1744 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1745 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1746 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1747 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1750 /* Initialize the filter combo box */
1751 FILEDLG95_FILETYPE_Init(hwnd
);
1756 /***********************************************************************
1757 * FILEDLG95_ResizeControls
1759 * WM_INITDIALOG message handler (after hook notification)
1761 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1763 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1765 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1768 UINT flags
= SWP_NOACTIVATE
;
1770 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1771 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1773 /* resize the custom dialog to the parent size */
1774 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1775 GetClientRect(hwnd
, &rc
);
1778 /* our own fake template is zero sized and doesn't have children, so
1779 * there is no need to resize it. Picasa depends on it.
1781 flags
|= SWP_NOSIZE
;
1784 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1785 0, 0, rc
.right
, rc
.bottom
, flags
);
1789 /* Resize the height, if open as read only checkbox ad help button are
1790 * hidden and we are not using a custom template nor a customDialog
1792 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1793 (!(fodInfos
->ofnInfos
->Flags
&
1794 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1796 RECT rectDlg
, rectHelp
, rectCancel
;
1797 GetWindowRect(hwnd
, &rectDlg
);
1798 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1799 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1800 /* subtract the height of the help button plus the space between the help
1801 * button and the cancel button to the height of the dialog
1803 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1804 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1805 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1811 /***********************************************************************
1812 * FILEDLG95_FillControls
1814 * WM_INITDIALOG message handler (after hook notification)
1816 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1818 LPITEMIDLIST pidlItemId
= NULL
;
1820 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1822 TRACE("dir=%s file=%s\n",
1823 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1825 /* Get the initial directory pidl */
1827 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1829 WCHAR path
[MAX_PATH
];
1831 GetCurrentDirectoryW(MAX_PATH
,path
);
1832 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1835 /* Initialise shell objects */
1836 FILEDLG95_SHELL_Init(hwnd
);
1838 /* Initialize the Look In combo box */
1839 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1841 /* Browse to the initial directory */
1842 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1844 /* Free pidlItem memory */
1845 COMDLG32_SHFree(pidlItemId
);
1849 /***********************************************************************
1852 * Regroups all the cleaning functions of the filedlg
1854 void FILEDLG95_Clean(HWND hwnd
)
1856 FILEDLG95_FILETYPE_Clean(hwnd
);
1857 FILEDLG95_LOOKIN_Clean(hwnd
);
1858 FILEDLG95_SHELL_Clean(hwnd
);
1860 /***********************************************************************
1861 * FILEDLG95_OnWMCommand
1863 * WM_COMMAND message handler
1865 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
)
1867 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1868 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1869 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1875 FILEDLG95_OnOpen(hwnd
);
1879 FILEDLG95_Clean(hwnd
);
1880 EndDialog(hwnd
, FALSE
);
1882 /* Filetype combo box */
1884 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1886 /* LookIn combo box */
1888 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1891 /* --- toolbar --- */
1892 /* Up folder button */
1893 case FCIDM_TB_UPFOLDER
:
1894 FILEDLG95_SHELL_UpFolder(hwnd
);
1896 /* New folder button */
1897 case FCIDM_TB_NEWFOLDER
:
1898 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1900 /* List option button */
1901 case FCIDM_TB_SMALLICON
:
1902 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1904 /* Details option button */
1905 case FCIDM_TB_REPORTVIEW
:
1906 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1908 /* Details option button */
1909 case FCIDM_TB_DESKTOP
:
1910 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1917 /* Do not use the listview selection anymore */
1918 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1922 /***********************************************************************
1923 * FILEDLG95_OnWMGetIShellBrowser
1925 * WM_GETISHELLBROWSER message handler
1927 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1929 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1933 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1939 /***********************************************************************
1940 * FILEDLG95_SendFileOK
1942 * Sends the CDN_FILEOK notification if required
1945 * TRUE if the dialog should close
1946 * FALSE if the dialog should not be closed
1948 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1950 /* ask the hook if we can close */
1951 if(IsHooked(fodInfos
))
1956 /* First send CDN_FILEOK as MSDN doc says */
1957 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1958 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1961 TRACE("canceled\n");
1965 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1966 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1967 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1970 TRACE("canceled\n");
1977 /***********************************************************************
1978 * FILEDLG95_OnOpenMultipleFiles
1980 * Handles the opening of multiple files.
1983 * check destination buffer size
1985 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1987 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1988 UINT nCount
, nSizePath
;
1989 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1993 if(fodInfos
->unicode
)
1995 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1996 ofn
->lpstrFile
[0] = '\0';
2000 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
2001 ofn
->lpstrFile
[0] = '\0';
2004 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
2006 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2007 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2008 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2010 LPWSTR lpstrTemp
= lpstrFileList
;
2012 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
2016 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
2019 WCHAR lpstrNotFound
[100];
2020 WCHAR lpstrMsg
[100];
2022 static const WCHAR nl
[] = {'\n',0};
2024 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
2025 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
2027 lstrcpyW(tmp
, lpstrTemp
);
2029 lstrcatW(tmp
, lpstrNotFound
);
2031 lstrcatW(tmp
, lpstrMsg
);
2033 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
2037 /* move to the next file in the list of files */
2038 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
2039 COMDLG32_SHFree(pidl
);
2043 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
2044 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
2046 /* For "oldstyle" dialog the components have to
2047 be separated by blanks (not '\0'!) and short
2048 filenames have to be used! */
2049 FIXME("Components have to be separated by blanks\n");
2051 if(fodInfos
->unicode
)
2053 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2054 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
2055 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
2059 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2061 if (ofn
->lpstrFile
!= NULL
)
2063 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
2064 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2065 if (ofn
->nMaxFile
> nSizePath
)
2067 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
2068 ofn
->lpstrFile
+ nSizePath
,
2069 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
2074 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
2075 fodInfos
->ofnInfos
->nFileExtension
= 0;
2077 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2080 /* clean and exit */
2081 FILEDLG95_Clean(hwnd
);
2082 return EndDialog(hwnd
,TRUE
);
2085 /* Returns the 'slot name' of the given module_name in the registry's
2086 * most-recently-used list. This will be an ASCII value in the
2087 * range ['a','z'). Returns zero on error.
2089 * The slot's value in the registry has the form:
2090 * module_name\0mru_path\0
2092 * If stored_path is given, then stored_path will contain the path name
2093 * stored in the registry's MRU list for the given module_name.
2095 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2096 * MRU list key for the given module_name.
2098 static WCHAR
FILEDLG95_MRU_get_slot(LPCWSTR module_name
, LPWSTR stored_path
, PHKEY hkey_ret
)
2100 WCHAR mru_list
[32], *cur_mru_slot
;
2101 BOOL taken
[25] = {0};
2102 DWORD mru_list_size
= sizeof(mru_list
), key_type
= -1, i
;
2103 HKEY hkey_tmp
, *hkey
;
2112 *stored_path
= '\0';
2114 ret
= RegCreateKeyW(HKEY_CURRENT_USER
, LastVisitedMRUW
, hkey
);
2116 WARN("Unable to create MRU key: %d\n", ret
);
2120 ret
= RegGetValueW(*hkey
, NULL
, MRUListW
, RRF_RT_REG_SZ
, &key_type
,
2121 (LPBYTE
)mru_list
, &mru_list_size
);
2122 if(ret
|| key_type
!= REG_SZ
){
2123 if(ret
== ERROR_FILE_NOT_FOUND
)
2126 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2131 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
){
2132 WCHAR value_data
[MAX_PATH
], value_name
[2] = {0};
2133 DWORD value_data_size
= sizeof(value_data
);
2135 *value_name
= *cur_mru_slot
;
2137 ret
= RegGetValueW(*hkey
, NULL
, value_name
, RRF_RT_REG_BINARY
,
2138 &key_type
, (LPBYTE
)value_data
, &value_data_size
);
2139 if(ret
|| key_type
!= REG_BINARY
){
2140 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type
, ret
);
2144 if(!strcmpiW(module_name
, value_data
)){
2148 lstrcpyW(stored_path
, value_data
+ lstrlenW(value_data
) + 1);
2156 /* the module name isn't in the registry, so find the next open slot */
2157 for(cur_mru_slot
= mru_list
; *cur_mru_slot
; ++cur_mru_slot
)
2158 taken
[*cur_mru_slot
- 'a'] = TRUE
;
2159 for(i
= 0; i
< 25; ++i
){
2164 /* all slots are taken, so return the last one in MRUList */
2166 return *cur_mru_slot
;
2169 /* save the given filename as most-recently-used path for this module */
2170 static void FILEDLG95_MRU_save_filename(LPCWSTR filename
)
2172 WCHAR module_path
[MAX_PATH
], *module_name
, slot
, slot_name
[2] = {0};
2176 /* get the current executable's name */
2177 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2178 WARN("GotModuleFileName failed: %d\n", GetLastError());
2181 module_name
= strrchrW(module_path
, '\\');
2183 module_name
= module_path
;
2187 slot
= FILEDLG95_MRU_get_slot(module_name
, NULL
, &hkey
);
2192 { /* update the slot's info */
2193 WCHAR
*path_ends
, *final
;
2194 DWORD path_len
, final_len
;
2196 /* use only the path segment of `filename' */
2197 path_ends
= strrchrW(filename
, '\\');
2198 path_len
= path_ends
- filename
;
2200 final_len
= path_len
+ lstrlenW(module_name
) + 2;
2202 final
= MemAlloc(final_len
* sizeof(WCHAR
));
2205 lstrcpyW(final
, module_name
);
2206 memcpy(final
+ lstrlenW(final
) + 1, filename
, path_len
* sizeof(WCHAR
));
2207 final
[final_len
-1] = '\0';
2209 ret
= RegSetValueExW(hkey
, slot_name
, 0, REG_BINARY
, (LPBYTE
)final
,
2210 final_len
* sizeof(WCHAR
));
2212 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name
), ret
);
2221 { /* update MRUList value */
2222 WCHAR old_mru_list
[32], new_mru_list
[32];
2223 WCHAR
*old_mru_slot
, *new_mru_slot
= new_mru_list
;
2224 DWORD mru_list_size
= sizeof(old_mru_list
), key_type
;
2226 ret
= RegGetValueW(hkey
, NULL
, MRUListW
, RRF_RT_ANY
, &key_type
,
2227 (LPBYTE
)old_mru_list
, &mru_list_size
);
2228 if(ret
|| key_type
!= REG_SZ
){
2229 if(ret
== ERROR_FILE_NOT_FOUND
){
2230 new_mru_list
[0] = slot
;
2231 new_mru_list
[1] = '\0';
2233 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type
, ret
);
2238 /* copy old list data over so that the new slot is at the start
2240 *new_mru_slot
++ = slot
;
2241 for(old_mru_slot
= old_mru_list
; *old_mru_slot
; ++old_mru_slot
){
2242 if(*old_mru_slot
!= slot
)
2243 *new_mru_slot
++ = *old_mru_slot
;
2245 *new_mru_slot
= '\0';
2248 ret
= RegSetValueExW(hkey
, MRUListW
, 0, REG_SZ
, (LPBYTE
)new_mru_list
,
2249 (lstrlenW(new_mru_list
) + 1) * sizeof(WCHAR
));
2251 WARN("Error saving MRUList data: %d\n", ret
);
2258 /* load the most-recently-used path for this module */
2259 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path
)
2261 WCHAR module_path
[MAX_PATH
], *module_name
;
2263 /* get the current executable's name */
2264 if(!GetModuleFileNameW(GetModuleHandleW(NULL
), module_path
, sizeof(module_path
)/sizeof(module_path
[0]))) {
2265 WARN("GotModuleFileName failed: %d\n", GetLastError());
2268 module_name
= strrchrW(module_path
, '\\');
2270 module_name
= module_path
;
2274 FILEDLG95_MRU_get_slot(module_name
, stored_path
, NULL
);
2275 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path
));
2278 void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
2280 WCHAR strMsgTitle
[MAX_PATH
];
2281 WCHAR strMsgText
[MAX_PATH
];
2283 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
2285 strMsgTitle
[0] = '\0';
2286 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
2287 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
2290 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile
, IShellFolder
**ppsf
,
2291 HWND hwnd
, DWORD flags
, BOOL isSaveDlg
, int defAction
)
2293 int nOpenAction
= defAction
;
2294 LPWSTR lpszTemp
, lpszTemp1
;
2295 LPITEMIDLIST pidl
= NULL
;
2296 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2298 /* check for invalid chars */
2299 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(flags
& OFN_NOVALIDATE
))
2301 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2305 if (FAILED (SHGetDesktopFolder(ppsf
))) return FALSE
;
2307 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2310 LPSHELLFOLDER lpsfChild
;
2311 WCHAR lpwstrTemp
[MAX_PATH
];
2312 DWORD dwEaten
, dwAttributes
;
2315 lstrcpyW(lpwstrTemp
, lpszTemp
);
2316 p
= PathFindNextComponentW(lpwstrTemp
);
2318 if (!p
) break; /* end of path */
2321 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2323 /* There are no wildcards when OFN_NOVALIDATE is set */
2324 if(*lpszTemp
==0 && !(flags
& OFN_NOVALIDATE
))
2326 static const WCHAR wszWild
[] = { '*', '?', 0 };
2327 /* if the last element is a wildcard do a search */
2328 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2330 nOpenAction
= ONOPEN_SEARCH
;
2334 lpszTemp1
= lpszTemp
;
2336 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), *ppsf
);
2338 /* append a backslash to drive letters */
2339 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2340 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2341 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2343 PathAddBackslashW(lpwstrTemp
);
2346 dwAttributes
= SFGAO_FOLDER
;
2347 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2349 /* the path component is valid, we have a pidl of the next path component */
2350 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2351 if(dwAttributes
& SFGAO_FOLDER
)
2353 if(FAILED(IShellFolder_BindToObject(*ppsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2355 ERR("bind to failed\n"); /* should not fail */
2358 IShellFolder_Release(*ppsf
);
2366 /* end dialog, return value */
2367 nOpenAction
= ONOPEN_OPEN
;
2370 COMDLG32_SHFree(pidl
);
2373 else if (!(flags
& OFN_NOVALIDATE
))
2375 if(*lpszTemp
|| /* points to trailing null for last path element */
2376 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2378 if(flags
& OFN_PATHMUSTEXIST
)
2380 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2386 if( (flags
& OFN_FILEMUSTEXIST
) && !isSaveDlg
)
2388 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2392 /* change to the current folder */
2393 nOpenAction
= ONOPEN_OPEN
;
2398 nOpenAction
= ONOPEN_OPEN
;
2402 if(pidl
) COMDLG32_SHFree(pidl
);
2407 /***********************************************************************
2410 * Ok button WM_COMMAND message handler
2412 * If the function succeeds, the return value is nonzero.
2414 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
2416 LPWSTR lpstrFileList
;
2417 UINT nFileCount
= 0;
2420 WCHAR lpstrPathAndFile
[MAX_PATH
];
2421 LPSHELLFOLDER lpsf
= NULL
;
2423 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2425 TRACE("hwnd=%p\n", hwnd
);
2427 /* try to browse the selected item */
2428 if(BrowseSelectedFolder(hwnd
))
2431 /* get the files from the edit control */
2432 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2439 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2443 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2446 Step 1: Build a complete path name from the current folder and
2447 the filename or path in the edit box.
2449 - the path in the edit box is a root path
2450 (with or without drive letter)
2451 - the edit box contains ".." (or a path with ".." in it)
2454 COMDLG32_GetCanonicalPath(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrFileList
, lpstrPathAndFile
);
2455 MemFree(lpstrFileList
);
2458 Step 2: here we have a cleaned up path
2460 We have to parse the path step by step to see if we have to browse
2461 to a folder if the path points to a directory or the last
2462 valid element is a directory.
2465 lpstrPathAndFile: cleaned up path
2469 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2470 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2471 nOpenAction
= ONOPEN_OPEN
;
2473 nOpenAction
= ONOPEN_BROWSE
;
2475 nOpenAction
= FILEDLG95_ValidatePathAction(lpstrPathAndFile
, &lpsf
, hwnd
,
2476 fodInfos
->ofnInfos
->Flags
,
2477 fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
,
2483 Step 3: here we have a cleaned up and validated path
2486 lpsf: ShellFolder bound to the rightmost valid path component
2487 lpstrPathAndFile: cleaned up path
2488 nOpenAction: action to do
2490 TRACE("end validate sf=%p\n", lpsf
);
2494 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2495 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2498 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2501 /* replace the current filter */
2502 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2503 len
= lstrlenW(lpszTemp
)+1;
2504 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2505 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2507 /* set the filter cb to the extension when possible */
2508 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2509 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2512 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2513 TRACE("ONOPEN_BROWSE\n");
2515 IPersistFolder2
* ppf2
;
2516 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2518 LPITEMIDLIST pidlCurrent
;
2519 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2520 IPersistFolder2_Release(ppf2
);
2521 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2523 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2524 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2526 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2529 else if( nOpenAction
== ONOPEN_SEARCH
)
2531 if (fodInfos
->Shell
.FOIShellView
)
2532 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2534 COMDLG32_SHFree(pidlCurrent
);
2535 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2540 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2541 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2545 /* update READONLY check box flag */
2546 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2547 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2549 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2551 /* Attach the file extension with file name*/
2552 ext
= PathFindExtensionW(lpstrPathAndFile
);
2555 /* if no extension is specified with file name, then */
2556 /* attach the extension from file filter or default one */
2558 const WCHAR
*filterExt
= NULL
;
2559 LPWSTR lpstrFilter
= NULL
;
2560 static const WCHAR szwDot
[] = {'.',0};
2561 int PathLength
= lstrlenW(lpstrPathAndFile
);
2563 /*Get the file extension from file type filter*/
2564 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2565 fodInfos
->ofnInfos
->nFilterIndex
-1);
2567 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2568 filterExt
= PathFindExtensionW(lpstrFilter
);
2570 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2571 filterExt
= filterExt
+ 1;
2572 else if ( fodInfos
->defext
) /* attach the default file extension*/
2573 filterExt
= fodInfos
->defext
;
2575 /* If extension contains a glob, ignore it */
2576 if ( filterExt
&& !strchrW(filterExt
, '*') && !strchrW(filterExt
, '?') )
2579 lstrcatW(lpstrPathAndFile
, szwDot
);
2580 /* Attach the extension */
2581 lstrcatW(lpstrPathAndFile
, filterExt
);
2584 /* In Open dialog: if file does not exist try without extension */
2585 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2586 lpstrPathAndFile
[PathLength
] = '\0';
2589 if (fodInfos
->defext
) /* add default extension */
2591 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2594 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2595 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2597 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2600 /* In Save dialog: check if the file already exists */
2601 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2602 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2603 && PathFileExistsW(lpstrPathAndFile
))
2605 WCHAR lpstrOverwrite
[100];
2608 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2609 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2610 MB_YESNO
| MB_ICONEXCLAMATION
);
2611 if (answer
== IDNO
|| answer
== IDCANCEL
)
2618 /* In Open dialog: check if it should be created if it doesn't exist */
2619 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2620 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2621 && !PathFileExistsW(lpstrPathAndFile
))
2623 WCHAR lpstrCreate
[100];
2626 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2627 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2628 MB_YESNO
| MB_ICONEXCLAMATION
);
2629 if (answer
== IDNO
|| answer
== IDCANCEL
)
2636 /* Check that the size of the file does not exceed buffer size.
2637 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2638 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2639 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2642 /* fill destination buffer */
2643 if (fodInfos
->ofnInfos
->lpstrFile
)
2645 if(fodInfos
->unicode
)
2647 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2649 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2650 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2651 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2655 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2657 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2658 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2659 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2660 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2664 if(fodInfos
->unicode
)
2668 /* set filename offset */
2669 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2670 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2672 /* set extension offset */
2673 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2674 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2679 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2681 /* set filename offset */
2682 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2683 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2685 /* set extension offset */
2686 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2687 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2690 /* set the lpstrFileTitle */
2691 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2693 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2694 if(fodInfos
->unicode
)
2696 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2697 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2701 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2702 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2703 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2707 /* copy currently selected filter to lpstrCustomFilter */
2708 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2710 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2711 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2712 NULL
, 0, NULL
, NULL
);
2713 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2715 LPSTR s
= ofn
->lpstrCustomFilter
;
2716 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2717 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2718 s
, len
, NULL
, NULL
);
2723 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2726 FILEDLG95_MRU_save_filename(lpstrPathAndFile
);
2729 FILEDLG95_Clean(hwnd
);
2730 ret
= EndDialog(hwnd
, TRUE
);
2736 size
= lstrlenW(lpstrPathAndFile
) + 1;
2737 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2739 /* return needed size in first two bytes of lpstrFile */
2740 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2741 FILEDLG95_Clean(hwnd
);
2742 ret
= EndDialog(hwnd
, FALSE
);
2743 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2750 if(lpsf
) IShellFolder_Release(lpsf
);
2754 /***********************************************************************
2755 * FILEDLG95_SHELL_Init
2757 * Initialisation of the shell objects
2759 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2761 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2766 * Initialisation of the FileOpenDialogInfos structure
2772 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2774 /* Disable multi-select if flag not set */
2775 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2777 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2779 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2780 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2782 /* Construct the IShellBrowser interface */
2783 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2788 /***********************************************************************
2789 * FILEDLG95_SHELL_ExecuteCommand
2791 * Change the folder option and refresh the view
2792 * If the function succeeds, the return value is nonzero.
2794 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2796 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2799 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2801 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2806 CMINVOKECOMMANDINFO ci
;
2807 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2808 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2812 IContextMenu_InvokeCommand(pcm
, &ci
);
2813 IContextMenu_Release(pcm
);
2819 /***********************************************************************
2820 * FILEDLG95_SHELL_UpFolder
2822 * Browse to the specified object
2823 * If the function succeeds, the return value is nonzero.
2825 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2827 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2831 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2835 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2836 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2842 /***********************************************************************
2843 * FILEDLG95_SHELL_BrowseToDesktop
2845 * Browse to the Desktop
2846 * If the function succeeds, the return value is nonzero.
2848 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2850 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2856 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2857 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2858 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2859 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2860 COMDLG32_SHFree(pidl
);
2861 return SUCCEEDED(hres
);
2863 /***********************************************************************
2864 * FILEDLG95_SHELL_Clean
2866 * Cleans the memory used by shell objects
2868 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2870 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2874 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2876 /* clean Shell interfaces */
2877 if (fodInfos
->Shell
.FOIShellView
)
2879 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2880 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2882 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2883 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2884 if (fodInfos
->Shell
.FOIDataObject
)
2885 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2888 /***********************************************************************
2889 * FILEDLG95_FILETYPE_Init
2891 * Initialisation of the file type combo box
2893 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2895 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2896 int nFilters
= 0; /* number of filters */
2901 if(fodInfos
->customfilter
)
2903 /* customfilter has one entry... title\0ext\0
2904 * Set first entry of combo box item with customfilter
2907 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2910 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2912 /* Copy the extensions */
2913 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2914 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2915 lstrcpyW(lpstrExt
,lpstrPos
);
2917 /* Add the item at the end of the combo */
2918 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2919 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2922 if(fodInfos
->filter
)
2924 LPCWSTR lpstrPos
= fodInfos
->filter
;
2928 /* filter is a list... title\0ext\0......\0\0
2929 * Set the combo item text to the title and the item data
2932 LPCWSTR lpstrDisplay
;
2936 if(! *lpstrPos
) break; /* end */
2937 lpstrDisplay
= lpstrPos
;
2938 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2940 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2944 /* Copy the extensions */
2945 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2946 lstrcpyW(lpstrExt
,lpstrPos
);
2947 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2949 /* Add the item at the end of the combo */
2950 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2952 /* malformed filters are added anyway... */
2953 if (!*lpstrExt
) break;
2958 * Set the current filter to the one specified
2959 * in the initialisation structure
2961 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2965 /* Check to make sure our index isn't out of bounds. */
2966 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2967 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2968 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2970 /* set default filter index */
2971 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2972 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2974 /* calculate index of Combo Box item */
2975 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2976 if (fodInfos
->customfilter
== NULL
)
2979 /* Set the current index selection. */
2980 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2982 /* Get the corresponding text string from the combo box. */
2983 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2986 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2992 CharLowerW(lpstrFilter
); /* lowercase */
2993 len
= lstrlenW(lpstrFilter
)+1;
2994 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2995 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2998 fodInfos
->ofnInfos
->nFilterIndex
= 0;
3002 /***********************************************************************
3003 * FILEDLG95_FILETYPE_OnCommand
3005 * WM_COMMAND of the file type combo box
3006 * If the function succeeds, the return value is nonzero.
3008 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3010 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3018 /* Get the current item of the filetype combo box */
3019 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3021 /* set the current filter index */
3022 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
3023 (fodInfos
->customfilter
== NULL
? 1 : 0);
3025 /* Set the current filter with the current selection */
3026 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3028 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
3030 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
3033 CharLowerW(lpstrFilter
); /* lowercase */
3034 len
= lstrlenW(lpstrFilter
)+1;
3035 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
3036 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
3037 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3038 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
3041 /* Refresh the actual view to display the included items*/
3042 if (fodInfos
->Shell
.FOIShellView
)
3043 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
3048 /***********************************************************************
3049 * FILEDLG95_FILETYPE_SearchExt
3051 * searches for an extension in the filetype box
3053 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
3055 int i
, iCount
= CBGetCount(hwnd
);
3057 TRACE("%s\n", debugstr_w(lpstrExt
));
3059 if(iCount
!= CB_ERR
)
3061 for(i
=0;i
<iCount
;i
++)
3063 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
3070 /***********************************************************************
3071 * FILEDLG95_FILETYPE_Clean
3073 * Clean the memory used by the filetype combo box
3075 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
3077 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3079 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
3083 /* Delete each string of the combo and their associated data */
3084 if(iCount
!= CB_ERR
)
3086 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3088 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
3089 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
3092 /* Current filter */
3093 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
3097 /***********************************************************************
3098 * FILEDLG95_LOOKIN_Init
3100 * Initialisation of the look in combo box
3103 /* Small helper function, to determine if the unixfs shell extension is rooted
3104 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3106 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3108 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
3109 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3110 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3111 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3112 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3113 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3114 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3116 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
3123 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
3125 IShellFolder
*psfRoot
, *psfDrives
;
3126 IEnumIDList
*lpeRoot
, *lpeDrives
;
3127 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
3129 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
3133 liInfos
->iMaxIndentation
= 0;
3135 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
3137 /* set item height for both text field and listbox */
3138 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
3139 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
3141 /* Turn on the extended UI for the combo box like Windows does */
3142 CBSetExtendedUI(hwndCombo
, TRUE
);
3144 /* Initialise data of Desktop folder */
3145 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
3146 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3147 COMDLG32_SHFree(pidlTmp
);
3149 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
3151 SHGetDesktopFolder(&psfRoot
);
3155 /* enumerate the contents of the desktop */
3156 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
3158 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
3160 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
3162 /* If the unixfs extension is rooted, we don't expand the drives by default */
3163 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3165 /* special handling for CSIDL_DRIVES */
3166 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
3168 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
3170 /* enumerate the drives */
3171 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
3173 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
3175 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
3176 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
3177 COMDLG32_SHFree(pidlAbsTmp
);
3178 COMDLG32_SHFree(pidlTmp1
);
3180 IEnumIDList_Release(lpeDrives
);
3182 IShellFolder_Release(psfDrives
);
3187 COMDLG32_SHFree(pidlTmp
);
3189 IEnumIDList_Release(lpeRoot
);
3191 IShellFolder_Release(psfRoot
);
3194 COMDLG32_SHFree(pidlDrives
);
3197 /***********************************************************************
3198 * FILEDLG95_LOOKIN_DrawItem
3200 * WM_DRAWITEM message handler
3202 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
3204 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
3205 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
3206 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
3210 HIMAGELIST ilItemImage
;
3213 LPSFOLDER tmpFolder
;
3214 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
3218 if(pDIStruct
->itemID
== -1)
3221 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
3222 pDIStruct
->itemID
)))
3226 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
3228 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3232 SHGFI_PIDL
| SHGFI_SMALLICON
|
3233 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
3234 SHGFI_DISPLAYNAME
);
3238 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3242 SHGFI_PIDL
| SHGFI_SMALLICON
|
3243 SHGFI_SYSICONINDEX
|
3247 /* Is this item selected ? */
3248 if(pDIStruct
->itemState
& ODS_SELECTED
)
3250 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
3251 SetBkColor(pDIStruct
->hDC
,crHighLight
);
3252 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
3256 SetTextColor(pDIStruct
->hDC
,crText
);
3257 SetBkColor(pDIStruct
->hDC
,crWin
);
3258 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
3261 /* Do not indent item if drawing in the edit of the combo */
3262 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
3265 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
3269 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
3270 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
3275 iIndentation
= tmpFolder
->m_iIndent
;
3277 /* Draw text and icon */
3279 /* Initialise the icon display area */
3280 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
3281 rectIcon
.top
= pDIStruct
->rcItem
.top
;
3282 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
3283 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
3285 /* Initialise the text display area */
3286 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
3287 rectText
.left
= rectIcon
.right
;
3289 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
3290 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
3292 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
3294 /* Draw the icon from the image list */
3295 ImageList_Draw(ilItemImage
,
3302 /* Draw the associated text */
3303 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3307 /***********************************************************************
3308 * FILEDLG95_LOOKIN_OnCommand
3310 * LookIn combo box WM_COMMAND message handler
3311 * If the function succeeds, the return value is nonzero.
3313 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3315 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3317 TRACE("%p\n", fodInfos
);
3323 LPSFOLDER tmpFolder
;
3326 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3328 if( iItem
== CB_ERR
) return FALSE
;
3330 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3335 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3336 tmpFolder
->pidlItem
,
3339 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3340 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3350 /***********************************************************************
3351 * FILEDLG95_LOOKIN_AddItem
3353 * Adds an absolute pidl item to the lookin combo box
3354 * returns the index of the inserted item
3356 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3358 LPITEMIDLIST pidlNext
;
3361 LookInInfos
*liInfos
;
3363 TRACE("%08x\n", iInsertId
);
3368 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3371 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3372 tmpFolder
->m_iIndent
= 0;
3374 /* Calculate the indentation of the item in the lookin*/
3376 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3378 tmpFolder
->m_iIndent
++;
3381 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3383 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3384 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3386 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3387 SHGetFileInfoW((LPCWSTR
)pidl
,
3391 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3392 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3394 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3396 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3400 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3402 /* Add the item at the end of the list */
3405 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3407 /* Insert the item at the iInsertId position*/
3410 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3413 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3417 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3418 MemFree( tmpFolder
);
3423 /***********************************************************************
3424 * FILEDLG95_LOOKIN_InsertItemAfterParent
3426 * Insert an item below its parent
3428 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3431 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3436 if (pidl
== pidlParent
)
3439 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3443 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3446 /* Free pidlParent memory */
3447 COMDLG32_SHFree(pidlParent
);
3449 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3452 /***********************************************************************
3453 * FILEDLG95_LOOKIN_SelectItem
3455 * Adds an absolute pidl item to the lookin combo box
3456 * returns the index of the inserted item
3458 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3461 LookInInfos
*liInfos
;
3465 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3467 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3471 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3472 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3477 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3478 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3482 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3484 if(iRemovedItem
< iItemPos
)
3489 CBSetCurSel(hwnd
,iItemPos
);
3490 liInfos
->uSelectedItem
= iItemPos
;
3496 /***********************************************************************
3497 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3499 * Remove the item with an expansion level over iExpansionLevel
3501 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3504 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3508 if(liInfos
->iMaxIndentation
<= 2)
3511 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3513 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3514 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3516 CBDeleteString(hwnd
,iItemPos
);
3517 liInfos
->iMaxIndentation
--;
3525 /***********************************************************************
3526 * FILEDLG95_LOOKIN_SearchItem
3528 * Search for pidl in the lookin combo box
3529 * returns the index of the found item
3531 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3534 int iCount
= CBGetCount(hwnd
);
3536 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3538 if (iCount
!= CB_ERR
)
3542 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3544 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3546 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3554 /***********************************************************************
3555 * FILEDLG95_LOOKIN_Clean
3557 * Clean the memory used by the lookin combo box
3559 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3561 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3562 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3564 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3568 /* Delete each string of the combo and their associated data */
3569 if (iCount
!= CB_ERR
)
3571 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3573 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3574 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3576 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3580 /* LookInInfos structure */
3582 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3585 /***********************************************************************
3586 * FILEDLG95_FILENAME_FillFromSelection
3588 * fills the edit box from the cached DataObject
3590 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3592 FileOpenDlgInfos
*fodInfos
;
3594 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3595 WCHAR lpstrTemp
[MAX_PATH
];
3596 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3599 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3601 /* Count how many files we have */
3602 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3604 /* calculate the string length, count files */
3605 if (nFileSelected
>= 1)
3607 nLength
+= 3; /* first and last quotes, trailing \0 */
3608 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3610 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3614 /* get the total length of the selected file names */
3615 lpstrTemp
[0] = '\0';
3616 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3618 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3620 nLength
+= lstrlenW( lpstrTemp
) + 3;
3623 COMDLG32_SHFree( pidl
);
3628 /* allocate the buffer */
3629 if (nFiles
<= 1) nLength
= MAX_PATH
;
3630 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3632 /* Generate the string for the edit control */
3635 lpstrCurrFile
= lpstrAllFile
;
3636 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3638 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3642 /* get the file name */
3643 lpstrTemp
[0] = '\0';
3644 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3646 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3650 *lpstrCurrFile
++ = '\"';
3651 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3652 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3653 *lpstrCurrFile
++ = '\"';
3654 *lpstrCurrFile
++ = ' ';
3659 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3662 COMDLG32_SHFree( pidl
);
3665 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3667 /* Select the file name like Windows does */
3668 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
3670 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3674 /* copied from shell32 to avoid linking to it
3675 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3676 * is dependent on whether emulated OS is unicode or not.
3678 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3683 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3684 COMDLG32_SHFree(src
->u
.pOleStr
);
3688 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3693 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3698 FIXME("unknown type %x!\n", src
->uType
);
3699 if (len
) *dest
= '\0';
3705 /***********************************************************************
3706 * FILEDLG95_FILENAME_GetFileNames
3708 * Copies the filenames to a delimited string list.
3710 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3712 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3713 UINT nFileCount
= 0; /* number of files */
3714 UINT nStrLen
= 0; /* length of string in edit control */
3715 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3719 /* get the filenames from the edit control */
3720 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3721 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3722 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3724 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3726 nFileCount
= COMDLG32_SplitFileNames(lpstrEdit
, nStrLen
, lpstrFileList
, sizeUsed
);
3731 #define SETDefFormatEtc(fe,cf,med) \
3733 (fe).cfFormat = cf;\
3734 (fe).dwAspect = DVASPECT_CONTENT; \
3741 * DATAOBJECT Helper functions
3744 /***********************************************************************
3745 * COMCTL32_ReleaseStgMedium
3747 * like ReleaseStgMedium from ole32
3749 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3751 if(medium
.pUnkForRelease
)
3753 IUnknown_Release(medium
.pUnkForRelease
);
3757 GlobalUnlock(medium
.u
.hGlobal
);
3758 GlobalFree(medium
.u
.hGlobal
);
3762 /***********************************************************************
3763 * GetPidlFromDataObject
3765 * Return pidl(s) by number from the cached DataObject
3767 * nPidlIndex=0 gets the fully qualified root path
3769 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3773 FORMATETC formatetc
;
3774 LPITEMIDLIST pidl
= NULL
;
3776 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3781 /* Set the FORMATETC structure*/
3782 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3784 /* Get the pidls from IDataObject */
3785 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3787 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3788 if(nPidlIndex
<= cida
->cidl
)
3790 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3792 COMCTL32_ReleaseStgMedium(medium
);
3797 /***********************************************************************
3800 * Return the number of selected items in the DataObject.
3803 static UINT
GetNumSelected( IDataObject
*doSelected
)
3807 FORMATETC formatetc
;
3809 TRACE("sv=%p\n", doSelected
);
3811 if (!doSelected
) return 0;
3813 /* Set the FORMATETC structure*/
3814 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3816 /* Get the pidls from IDataObject */
3817 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3819 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3820 retVal
= cida
->cidl
;
3821 COMCTL32_ReleaseStgMedium(medium
);
3831 /***********************************************************************
3834 * Get the pidl's display name (relative to folder) and
3835 * put it in lpstrFileName.
3837 * Return NOERROR on success,
3841 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3846 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3850 SHGetDesktopFolder(&lpsf
);
3851 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3852 IShellFolder_Release(lpsf
);
3856 /* Get the display name of the pidl relative to the folder */
3857 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3859 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3864 /***********************************************************************
3865 * GetShellFolderFromPidl
3867 * pidlRel is the item pidl relative
3868 * Return the IShellFolder of the absolute pidl
3870 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3872 IShellFolder
*psf
= NULL
,*psfParent
;
3874 TRACE("%p\n", pidlAbs
);
3876 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3879 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3881 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3883 IShellFolder_Release(psfParent
);
3887 /* return the desktop */
3893 /***********************************************************************
3896 * Return the LPITEMIDLIST to the parent of the pidl in the list
3898 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3900 LPITEMIDLIST pidlParent
;
3902 TRACE("%p\n", pidl
);
3904 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3905 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3910 /***********************************************************************
3913 * returns the pidl of the file name relative to folder
3914 * NULL if an error occurred
3916 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3918 LPITEMIDLIST pidl
= NULL
;
3921 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3923 if(!lpcstrFileName
) return NULL
;
3924 if(!*lpcstrFileName
) return NULL
;
3928 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3929 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3930 IShellFolder_Release(lpsf
);
3935 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3942 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3944 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3947 TRACE("%p, %p\n", psf
, pidl
);
3949 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3951 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3952 /* see documentation shell 4.1*/
3953 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3956 /***********************************************************************
3957 * BrowseSelectedFolder
3959 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3961 BOOL bBrowseSelFolder
= FALSE
;
3962 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3966 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3968 LPITEMIDLIST pidlSelection
;
3970 /* get the file selected */
3971 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3972 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3974 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3975 pidlSelection
, SBSP_RELATIVE
) ) )
3977 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3978 ' ','n','o','t',' ','e','x','i','s','t',0};
3979 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3981 bBrowseSelFolder
= TRUE
;
3982 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3983 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3985 COMDLG32_SHFree( pidlSelection
);
3988 return bBrowseSelFolder
;
3992 * Memory allocation methods */
3993 static void *MemAlloc(UINT size
)
3995 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3998 static void MemFree(void *mem
)
4000 HeapFree(GetProcessHeap(),0,mem
);
4004 * Old-style (win3.1) dialogs */
4006 /***********************************************************************
4007 * FD32_GetTemplate [internal]
4009 * Get a template (or FALSE if failure) when 16 bits dialogs are used
4010 * by a 32 bits application
4013 BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
4015 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
4016 LPOPENFILENAMEA ofnA
= lfs
->ofnA
;
4019 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
4021 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
4023 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
4027 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
4031 hResInfo
= FindResourceA(ofnA
->hInstance
,
4032 ofnA
->lpTemplateName
,
4035 hResInfo
= FindResourceW(ofnW
->hInstance
,
4036 ofnW
->lpTemplateName
,
4040 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
4043 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
4045 !(lfs
->template = LockResource(hDlgTmpl
)))
4047 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
4050 } else { /* get it from internal Wine resource */
4052 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
4053 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
4055 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
4058 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
4059 !(lfs
->template = LockResource( hDlgTmpl
)))
4061 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
4069 /***********************************************************************
4070 * FD32_WMMeasureItem [internal]
4072 static LONG
FD32_WMMeasureItem(LPARAM lParam
)
4074 LPMEASUREITEMSTRUCT lpmeasure
;
4076 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
4077 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
4082 /***********************************************************************
4083 * FileOpenDlgProc [internal]
4084 * Used for open and save, in fact.
4086 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
4087 WPARAM wParam
, LPARAM lParam
)
4089 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
4091 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
4092 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
4095 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
4097 return lRet
; /* else continue message processing */
4102 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
4104 case WM_MEASUREITEM
:
4105 return FD32_WMMeasureItem(lParam
);
4108 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
4111 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
4114 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
4115 switch (HIWORD(lParam
))
4118 SetTextColor((HDC16
)wParam
, 0x00000000);
4120 case CTLCOLOR_STATIC
:
4121 SetTextColor((HDC16
)wParam
, 0x00000000);
4131 /***********************************************************************
4132 * GetFileName31A [internal]
4134 * Creates a win31 style dialog box for the user to select a file to open/save.
4136 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
4137 UINT dlgType
/* type dialogue : open/save */
4143 if (!lpofn
|| !FD31_Init()) return FALSE
;
4145 TRACE("ofn flags %08x\n", lpofn
->Flags
);
4146 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, FALSE
);
4149 bRet
= DialogBoxIndirectParamA( COMDLG32_hInstance
, lfs
->template, lpofn
->hwndOwner
,
4150 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4151 FD31_DestroyPrivate(lfs
);
4154 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
4158 /***********************************************************************
4159 * GetFileName31W [internal]
4161 * Creates a win31 style dialog box for the user to select a file to open/save
4163 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
4164 UINT dlgType
/* type dialogue : open/save */
4170 if (!lpofn
|| !FD31_Init()) return FALSE
;
4172 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, TRUE
);
4175 bRet
= DialogBoxIndirectParamW( COMDLG32_hInstance
, lfs
->template, lpofn
->hwndOwner
,
4176 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4177 FD31_DestroyPrivate(lfs
);
4180 TRACE("file %s, file offset %d, ext offset %d\n",
4181 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
4185 /* ------------------ APIs ---------------------- */
4187 /***********************************************************************
4188 * GetOpenFileNameA (COMDLG32.@)
4190 * Creates a dialog box for the user to select a file to open.
4193 * TRUE on success: user enters a valid file
4194 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4197 BOOL WINAPI
GetOpenFileNameA(
4198 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4200 BOOL win16look
= FALSE
;
4202 TRACE("flags %08x\n", ofn
->Flags
);
4204 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4205 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4206 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4208 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4209 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4212 return GetFileName31A(ofn
, OPEN_DIALOG
);
4214 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4217 /***********************************************************************
4218 * GetOpenFileNameW (COMDLG32.@)
4220 * Creates a dialog box for the user to select a file to open.
4223 * TRUE on success: user enters a valid file
4224 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4227 BOOL WINAPI
GetOpenFileNameW(
4228 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4230 BOOL win16look
= FALSE
;
4232 TRACE("flags %08x\n", ofn
->Flags
);
4234 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4235 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4236 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4238 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4239 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4242 return GetFileName31W(ofn
, OPEN_DIALOG
);
4244 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4248 /***********************************************************************
4249 * GetSaveFileNameA (COMDLG32.@)
4251 * Creates a dialog box for the user to select a file to save.
4254 * TRUE on success: user enters a valid file
4255 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4258 BOOL WINAPI
GetSaveFileNameA(
4259 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4261 BOOL win16look
= FALSE
;
4263 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4264 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4267 return GetFileName31A(ofn
, SAVE_DIALOG
);
4269 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4272 /***********************************************************************
4273 * GetSaveFileNameW (COMDLG32.@)
4275 * Creates a dialog box for the user to select a file to save.
4278 * TRUE on success: user enters a valid file
4279 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4282 BOOL WINAPI
GetSaveFileNameW(
4283 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4285 BOOL win16look
= FALSE
;
4287 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4288 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4291 return GetFileName31W(ofn
, SAVE_DIALOG
);
4293 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4296 /***********************************************************************
4297 * GetFileTitleA (COMDLG32.@)
4299 * See GetFileTitleW.
4301 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4304 UNICODE_STRING strWFile
;
4307 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4308 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4309 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4310 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4311 RtlFreeUnicodeString( &strWFile
);
4312 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4317 /***********************************************************************
4318 * GetFileTitleW (COMDLG32.@)
4320 * Get the name of a file.
4323 * lpFile [I] name and location of file
4324 * lpTitle [O] returned file name
4325 * cbBuf [I] buffer size of lpTitle
4329 * Failure: negative number.
4331 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4334 static const WCHAR brkpoint
[] = {'*','[',']',0};
4335 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4337 if(lpFile
== NULL
|| lpTitle
== NULL
)
4340 len
= lstrlenW(lpFile
);
4345 if(strpbrkW(lpFile
, brkpoint
))
4350 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4353 for(i
= len
; i
>= 0; i
--)
4355 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4365 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4367 len
= lstrlenW(lpFile
+i
)+1;
4371 lstrcpyW(lpTitle
, &lpFile
[i
]);