2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
71 #include "filedlg31.h"
75 #include "filedlgbrowser.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
109 /***********************************************************************
110 * Defines and global variables
113 /* Draw item constant */
115 #define XTEXTOFFSET 3
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
123 #define ITEM_NOTFOUND -1
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
172 static const WCHAR LastVisitedMRUW[] =
173 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
176 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
177 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
179 /***********************************************************************
183 /* Internal functions used by the dialog */
184 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 static BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Functions for dealing with the most-recently-used registry keys */
220 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
221 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
222 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
224 /* Miscellaneous tool functions */
225 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
226 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
227 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
228 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
229 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
230 static UINT GetNumSelected( IDataObject *doSelected );
232 /* Shell memory allocation */
233 static void *MemAlloc(UINT size);
234 static void MemFree(void *mem);
236 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
237 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
238 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
239 static BOOL BrowseSelectedFolder(HWND hwnd);
241 /***********************************************************************
244 * Creates an Open common dialog box that lets the user select
245 * the drive, directory, and the name of a file or set of files to open.
247 * IN : The FileOpenDlgInfos structure associated with the dialog
248 * OUT : TRUE on success
249 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
251 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
255 LPCVOID origTemplate;
257 LPDLGTEMPLATEW template;
262 /* test for missing functionality */
263 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
265 FIXME("Flags 0x%08x not yet implemented\n",
266 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
269 /* Create the dialog from a template */
271 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
273 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
276 if (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
277 !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
278 !(origTemplate = LockResource(hDlgTmpl)))
280 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
283 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
285 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
288 memcpy(template, origTemplate, dwSize);
290 /* msdn: explorer style dialogs permit sizing by default.
291 * The OFN_ENABLESIZING flag is only needed when a hook or
292 * custom tmeplate is provided */
293 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
294 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
295 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
297 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
299 template->style |= WS_SIZEBOX;
300 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
301 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
304 template->style &= ~WS_SIZEBOX;
307 /* old style hook messages */
308 if (IsHooked(fodInfos))
310 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
311 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
312 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
313 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
316 /* Some shell namespace extensions depend on COM being initialized. */
317 hr = OleInitialize(NULL);
319 if (fodInfos->unicode)
320 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
322 fodInfos->ofnInfos->hwndOwner,
326 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
328 fodInfos->ofnInfos->hwndOwner,
334 HeapFree(GetProcessHeap(), 0, template);
336 /* Unable to create the dialog */
343 /***********************************************************************
346 * Call GetFileName95 with this structure and clean the memory.
348 * IN : The OPENFILENAMEA initialisation structure passed to
349 * GetOpenFileNameA win api function (see filedlg.c)
351 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
354 FileOpenDlgInfos fodInfos;
355 LPSTR lpstrSavDir = NULL;
357 LPWSTR defext = NULL;
358 LPWSTR filter = NULL;
359 LPWSTR customfilter = NULL;
361 /* Initialize CommDlgExtendedError() */
362 COMDLG32_SetCommDlgExtendedError(0);
364 /* Initialize FileOpenDlgInfos structure */
365 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
367 /* Pass in the original ofn */
368 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
370 /* save current directory */
371 if (ofn->Flags & OFN_NOCHANGEDIR)
373 lpstrSavDir = MemAlloc(MAX_PATH);
374 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
377 fodInfos.unicode = FALSE;
379 /* convert all the input strings to unicode */
380 if(ofn->lpstrInitialDir)
382 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
383 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
384 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
387 fodInfos.initdir = NULL;
391 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
392 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
395 fodInfos.filename = NULL;
399 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
400 defext = MemAlloc((len+1)*sizeof(WCHAR));
401 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
403 fodInfos.defext = defext;
407 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
408 title = MemAlloc((len+1)*sizeof(WCHAR));
409 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
411 fodInfos.title = title;
413 if (ofn->lpstrFilter)
418 /* filter is a list... title\0ext\0......\0\0 */
419 s = ofn->lpstrFilter;
420 while (*s) s = s+strlen(s)+1;
422 n = s - ofn->lpstrFilter;
423 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
424 filter = MemAlloc(len*sizeof(WCHAR));
425 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
427 fodInfos.filter = filter;
429 /* convert lpstrCustomFilter */
430 if (ofn->lpstrCustomFilter)
435 /* customfilter contains a pair of strings... title\0ext\0 */
436 s = ofn->lpstrCustomFilter;
437 if (*s) s = s+strlen(s)+1;
438 if (*s) s = s+strlen(s)+1;
439 n = s - ofn->lpstrCustomFilter;
440 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
441 customfilter = MemAlloc(len*sizeof(WCHAR));
442 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
444 fodInfos.customfilter = customfilter;
446 /* Initialize the dialog property */
447 fodInfos.DlgInfos.dwDlgProp = 0;
448 fodInfos.DlgInfos.hwndCustomDlg = NULL;
453 ret = GetFileName95(&fodInfos);
456 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
457 ret = GetFileName95(&fodInfos);
465 SetCurrentDirectoryA(lpstrSavDir);
466 MemFree(lpstrSavDir);
472 MemFree(customfilter);
473 MemFree(fodInfos.initdir);
474 MemFree(fodInfos.filename);
476 TRACE("selected file: %s\n",ofn->lpstrFile);
481 /***********************************************************************
484 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
485 * Call GetFileName95 with this structure and clean the memory.
488 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
491 FileOpenDlgInfos fodInfos;
492 LPWSTR lpstrSavDir = NULL;
494 /* Initialize CommDlgExtendedError() */
495 COMDLG32_SetCommDlgExtendedError(0);
497 /* Initialize FileOpenDlgInfos structure */
498 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
500 /* Pass in the original ofn */
501 fodInfos.ofnInfos = ofn;
503 fodInfos.title = ofn->lpstrTitle;
504 fodInfos.defext = ofn->lpstrDefExt;
505 fodInfos.filter = ofn->lpstrFilter;
506 fodInfos.customfilter = ofn->lpstrCustomFilter;
508 /* convert string arguments, save others */
511 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
512 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
515 fodInfos.filename = NULL;
517 if(ofn->lpstrInitialDir)
519 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
520 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
521 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
522 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
525 fodInfos.initdir = NULL;
527 /* save current directory */
528 if (ofn->Flags & OFN_NOCHANGEDIR)
530 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
531 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
534 fodInfos.unicode = TRUE;
539 ret = GetFileName95(&fodInfos);
542 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
543 ret = GetFileName95(&fodInfos);
551 SetCurrentDirectoryW(lpstrSavDir);
552 MemFree(lpstrSavDir);
555 /* restore saved IN arguments and convert OUT arguments back */
556 MemFree(fodInfos.filename);
557 MemFree(fodInfos.initdir);
561 /******************************************************************************
562 * COMDLG32_GetDisplayNameOf [internal]
564 * Helper function to get the display name for a pidl.
566 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
567 LPSHELLFOLDER psfDesktop;
570 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
573 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
574 IShellFolder_Release(psfDesktop);
578 IShellFolder_Release(psfDesktop);
579 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
582 /******************************************************************************
583 * COMDLG32_GetCanonicalPath [internal]
585 * Helper function to get the canonical path.
587 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
588 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
590 WCHAR lpstrTemp[MAX_PATH];
592 /* Get the current directory name */
593 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
596 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
598 PathAddBackslashW(lpstrPathAndFile);
600 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
602 /* if the user specified a fully qualified path use it */
603 if(PathIsRelativeW(lpstrFile))
605 lstrcatW(lpstrPathAndFile, lpstrFile);
609 /* does the path have a drive letter? */
610 if (PathGetDriveNumberW(lpstrFile) == -1)
611 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
613 lstrcpyW(lpstrPathAndFile, lpstrFile);
616 /* resolve "." and ".." */
617 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
618 lstrcpyW(lpstrPathAndFile, lpstrTemp);
619 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
622 /***********************************************************************
623 * COMDLG32_SplitFileNames [internal]
625 * Creates a delimited list of filenames.
627 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
629 UINT nStrCharCount = 0; /* index in src buffer */
630 UINT nFileIndex = 0; /* index in dest buffer */
631 UINT nFileCount = 0; /* number of files */
633 /* we might get single filename without any '"',
634 * so we need nStrLen + terminating \0 + end-of-list \0 */
635 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
638 /* build delimited file list from filenames */
639 while ( nStrCharCount <= nStrLen )
641 if ( lpstrEdit[nStrCharCount]=='"' )
644 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
646 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
649 (*lpstrFileList)[nFileIndex++] = 0;
655 /* single, unquoted string */
656 if ((nStrLen > 0) && (nFileIndex == 0) )
658 lstrcpyW(*lpstrFileList, lpstrEdit);
659 nFileIndex = lstrlenW(lpstrEdit) + 1;
664 (*lpstrFileList)[nFileIndex++] = '\0';
666 *sizeUsed = nFileIndex;
670 /***********************************************************************
671 * ArrangeCtrlPositions [internal]
673 * NOTE: Make sure to add testcases for any changes made here.
675 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
677 HWND hwndChild, hwndStc32;
678 RECT rectParent, rectChild, rectStc32;
682 /* Take into account if open as read only checkbox and help button
687 RECT rectHelp, rectCancel;
688 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
689 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
690 /* subtract the height of the help button plus the space between
691 * the help button and the cancel button to the height of the dialog
693 help_fixup = rectHelp.bottom - rectCancel.bottom;
697 There are two possibilities to add components to the default file dialog box.
699 By default, all the new components are added below the standard dialog box (the else case).
701 However, if there is a static text component with the stc32 id, a special case happens.
702 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
703 in the window and the cx and cy indicate how to size the window.
704 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
705 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
709 GetClientRect(hwndParentDlg, &rectParent);
711 /* when arranging controls we have to use fixed parent size */
712 rectParent.bottom -= help_fixup;
714 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
717 GetWindowRect(hwndStc32, &rectStc32);
718 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
720 /* set the size of the stc32 control according to the size of
721 * client area of the parent dialog
723 SetWindowPos(hwndStc32, 0,
725 rectParent.right, rectParent.bottom,
726 SWP_NOMOVE | SWP_NOZORDER);
729 SetRectEmpty(&rectStc32);
731 /* this part moves controls of the child dialog */
732 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
735 if (hwndChild != hwndStc32)
737 GetWindowRect(hwndChild, &rectChild);
738 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
740 /* move only if stc32 exist */
741 if (hwndStc32 && rectChild.left > rectStc32.right)
743 /* move to the right of visible controls of the parent dialog */
744 rectChild.left += rectParent.right;
745 rectChild.left -= rectStc32.right;
747 /* move even if stc32 doesn't exist */
748 if (rectChild.top >= rectStc32.bottom)
750 /* move below visible controls of the parent dialog */
751 rectChild.top += rectParent.bottom;
752 rectChild.top -= rectStc32.bottom - rectStc32.top;
755 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
756 0, 0, SWP_NOSIZE | SWP_NOZORDER);
758 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
761 /* this part moves controls of the parent dialog */
762 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
765 if (hwndChild != hwndChildDlg)
767 GetWindowRect(hwndChild, &rectChild);
768 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
770 /* left,top of stc32 marks the position of controls
771 * from the parent dialog
773 rectChild.left += rectStc32.left;
774 rectChild.top += rectStc32.top;
776 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
777 0, 0, SWP_NOSIZE | SWP_NOZORDER);
779 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
782 /* calculate the size of the resulting dialog */
784 /* here we have to use original parent size */
785 GetClientRect(hwndParentDlg, &rectParent);
786 GetClientRect(hwndChildDlg, &rectChild);
787 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
788 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
793 if (rectParent.right > rectStc32.right - rectStc32.left)
794 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
796 chgx = rectChild.right - rectParent.right;
798 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
799 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
801 /* Unconditionally set new dialog
802 * height to that of the child
804 chgy = rectChild.bottom - rectParent.bottom;
809 chgy = rectChild.bottom - help_fixup;
811 /* set the size of the parent dialog */
812 GetWindowRect(hwndParentDlg, &rectParent);
813 SetWindowPos(hwndParentDlg, 0,
815 rectParent.right - rectParent.left + chgx,
816 rectParent.bottom - rectParent.top + chgy,
817 SWP_NOMOVE | SWP_NOZORDER);
820 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
829 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
839 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
840 * structure's hInstance parameter is not a HINSTANCE, but
841 * instead a pointer to a template resource to use.
843 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
846 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
848 hinst = COMDLG32_hInstance;
849 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
851 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
857 hinst = fodInfos->ofnInfos->hInstance;
858 if(fodInfos->unicode)
860 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
861 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
865 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
866 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
870 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
873 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
874 !(template = LockResource( hDlgTmpl )))
876 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
880 if (fodInfos->unicode)
881 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
882 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
883 (LPARAM)fodInfos->ofnInfos);
885 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
886 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
887 (LPARAM)fodInfos->ofnInfos);
890 else if( IsHooked(fodInfos))
895 WORD menu,class,title;
897 GetClientRect(hwnd,&rectHwnd);
898 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
899 temp.tmplate.dwExtendedStyle = 0;
900 temp.tmplate.cdit = 0;
905 temp.menu = temp.class = temp.title = 0;
907 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
908 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
915 /***********************************************************************
916 * SendCustomDlgNotificationMessage
918 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
921 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
923 LRESULT hook_result = 0;
924 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
926 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
928 if(!fodInfos) return 0;
930 if(fodInfos->DlgInfos.hwndCustomDlg)
932 TRACE("CALL NOTIFY for %x\n", uCode);
933 if(fodInfos->unicode)
936 ofnNotify.hdr.hwndFrom=hwndParentDlg;
937 ofnNotify.hdr.idFrom=0;
938 ofnNotify.hdr.code = uCode;
939 ofnNotify.lpOFN = fodInfos->ofnInfos;
940 ofnNotify.pszFile = NULL;
941 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
946 ofnNotify.hdr.hwndFrom=hwndParentDlg;
947 ofnNotify.hdr.idFrom=0;
948 ofnNotify.hdr.code = uCode;
949 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
950 ofnNotify.pszFile = NULL;
951 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
953 TRACE("RET NOTIFY\n");
955 TRACE("Retval: 0x%08lx\n", hook_result);
959 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
963 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
965 TRACE("CDM_GETFILEPATH:\n");
967 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
970 /* get path and filenames */
971 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
972 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
973 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
976 p = buffer + strlenW(buffer);
978 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
980 if (fodInfos->unicode)
982 total = strlenW( buffer) + 1;
983 if (result) lstrcpynW( result, buffer, size );
984 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
988 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
989 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
990 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
992 HeapFree( GetProcessHeap(), 0, buffer );
996 /***********************************************************************
997 * FILEDLG95_HandleCustomDialogMessages
999 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1001 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1003 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1004 WCHAR lpstrPath[MAX_PATH];
1007 if(!fodInfos) return FALSE;
1011 case CDM_GETFILEPATH:
1012 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1015 case CDM_GETFOLDERPATH:
1016 TRACE("CDM_GETFOLDERPATH:\n");
1017 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1020 if (fodInfos->unicode)
1021 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1023 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1024 (LPSTR)lParam, (int)wParam, NULL, NULL);
1026 retval = lstrlenW(lpstrPath) + 1;
1029 case CDM_GETFOLDERIDLIST:
1030 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1031 if (retval <= wParam)
1032 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1036 TRACE("CDM_GETSPEC:\n");
1037 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1040 if (fodInfos->unicode)
1041 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1043 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1047 case CDM_SETCONTROLTEXT:
1048 TRACE("CDM_SETCONTROLTEXT:\n");
1051 if( fodInfos->unicode )
1052 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1054 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1059 case CDM_HIDECONTROL:
1060 /* MSDN states that it should fail for not OFN_EXPLORER case */
1061 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1063 HWND control = GetDlgItem( hwnd, wParam );
1064 if (control) ShowWindow( control, SW_HIDE );
1067 else retval = FALSE;
1071 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1072 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1075 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1079 /***********************************************************************
1080 * FILEDLG95_OnWMGetMMI
1082 * WM_GETMINMAXINFO message handler for resizable dialogs
1084 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1086 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1087 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1088 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1090 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1095 /***********************************************************************
1096 * FILEDLG95_OnWMSize
1098 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1100 * FIXME: this could be made more elaborate. Now use a simple scheme
1101 * where the file view is enlarged and the controls are either moved
1102 * vertically or horizontally to get out of the way. Only the "grip"
1103 * is moved in both directions to stay in the corner.
1105 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1111 FileOpenDlgInfos *fodInfos;
1113 if( wParam != SIZE_RESTORED) return FALSE;
1114 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1115 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1116 /* get the new dialog rectangle */
1117 GetWindowRect( hwnd, &rc);
1118 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1119 rc.right -rc.left, rc.bottom -rc.top);
1120 /* not initialized yet */
1121 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1122 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1123 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1125 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1126 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1127 fodInfos->sizedlg.cx = rc.right - rc.left;
1128 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1129 /* change the size of the view window */
1130 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1131 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1132 hdwp = BeginDeferWindowPos( 10);
1133 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1134 rcview.right - rcview.left + chgx,
1135 rcview.bottom - rcview.top + chgy,
1136 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1137 /* change position and sizes of the controls */
1138 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1140 int ctrlid = GetDlgCtrlID( ctrl);
1141 GetWindowRect( ctrl, &rc);
1142 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1143 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1145 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1147 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1149 else if( rc.top > rcview.bottom)
1151 /* if it was below the shell view
1155 /* file name box and file types combo change also width */
1158 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1159 rc.right - rc.left + chgx, rc.bottom - rc.top,
1160 SWP_NOACTIVATE | SWP_NOZORDER);
1162 /* then these buttons must move out of the way */
1166 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1168 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1171 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1173 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1176 else if( rc.left > rcview.right)
1178 /* if it was to the right of the shell view
1180 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1182 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1189 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1191 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1192 rc.right - rc.left + chgx, rc.bottom - rc.top,
1193 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1195 case IDC_TOOLBARSTATIC:
1197 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1199 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1202 /* not resized in windows. Since wine uses this invisible control
1203 * to size the browser view it needs to be resized */
1204 case IDC_SHELLSTATIC:
1205 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1206 rc.right - rc.left + chgx,
1207 rc.bottom - rc.top + chgy,
1208 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1213 if(fodInfos->DlgInfos.hwndCustomDlg &&
1214 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1216 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1217 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1219 GetWindowRect( ctrl, &rc);
1220 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1221 if( rc.top > rcview.bottom)
1223 /* if it was below the shell view
1225 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1226 rc.right - rc.left, rc.bottom - rc.top,
1227 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1229 else if( rc.left > rcview.right)
1231 /* if it was to the right of the shell view
1233 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1234 rc.right - rc.left, rc.bottom - rc.top,
1235 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1238 /* size the custom dialog at the end: some applications do some
1239 * control re-arranging at this point */
1240 GetClientRect(hwnd, &rc);
1241 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1242 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1244 EndDeferWindowPos( hdwp);
1245 /* should not be needed */
1246 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1250 /***********************************************************************
1253 * File open dialog procedure
1255 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1258 TRACE("%p 0x%04x\n", hwnd, uMsg);
1265 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1267 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1268 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1270 /* Adds the FileOpenDlgInfos in the property list of the dialog
1271 so it will be easily accessible through a GetPropA(...) */
1272 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1274 FILEDLG95_InitControls(hwnd);
1276 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1278 GetWindowRect( hwnd, &rc);
1279 fodInfos->DlgInfos.hwndGrip =
1280 CreateWindowExA( 0, "SCROLLBAR", NULL,
1281 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1282 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1283 rc.right - gripx, rc.bottom - gripy,
1284 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1287 fodInfos->DlgInfos.hwndCustomDlg =
1288 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1290 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1291 FILEDLG95_FillControls(hwnd, wParam, lParam);
1293 if( fodInfos->DlgInfos.hwndCustomDlg)
1294 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1296 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1297 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1298 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1301 /* if the app has changed the position of the invisible listbox,
1302 * change that of the listview (browser) as well */
1303 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1304 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1305 if( !EqualRect( &rc, &rcstc))
1307 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1308 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1309 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1310 SWP_NOACTIVATE | SWP_NOZORDER);
1313 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1315 GetWindowRect( hwnd, &rc);
1316 fodInfos->sizedlg.cx = rc.right - rc.left;
1317 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1318 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1319 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1320 GetClientRect( hwnd, &rc);
1321 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1322 rc.right - gripx, rc.bottom - gripy,
1323 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1324 /* resize the dialog to the previous invocation */
1325 if( MemDialogSize.cx && MemDialogSize.cy)
1326 SetWindowPos( hwnd, NULL,
1327 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1328 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1331 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1332 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1337 return FILEDLG95_OnWMSize(hwnd, wParam);
1338 case WM_GETMINMAXINFO:
1339 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1341 return FILEDLG95_OnWMCommand(hwnd, wParam);
1344 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1347 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1353 case WM_GETISHELLBROWSER:
1354 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1358 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1359 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1360 MemDialogSize = fodInfos->sizedlg;
1361 RemovePropA(hwnd, FileOpenDlgInfosStr);
1366 LPNMHDR lpnmh = (LPNMHDR)lParam;
1369 /* set up the button tooltips strings */
1370 if(TTN_GETDISPINFOA == lpnmh->code )
1372 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1373 switch(lpnmh->idFrom )
1375 /* Up folder button */
1376 case FCIDM_TB_UPFOLDER:
1377 stringId = IDS_UPFOLDER;
1379 /* New folder button */
1380 case FCIDM_TB_NEWFOLDER:
1381 stringId = IDS_NEWFOLDER;
1383 /* List option button */
1384 case FCIDM_TB_SMALLICON:
1385 stringId = IDS_LISTVIEW;
1387 /* Details option button */
1388 case FCIDM_TB_REPORTVIEW:
1389 stringId = IDS_REPORTVIEW;
1391 /* Desktop button */
1392 case FCIDM_TB_DESKTOP:
1393 stringId = IDS_TODESKTOP;
1398 lpdi->hinst = COMDLG32_hInstance;
1399 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1404 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1405 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1410 /***********************************************************************
1411 * FILEDLG95_InitControls
1413 * WM_INITDIALOG message handler (before hook notification)
1415 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1417 int win2000plus = 0;
1419 int handledPath = FALSE;
1420 OSVERSIONINFOW osVi;
1421 static const WCHAR szwSlash[] = { '\\', 0 };
1422 static const WCHAR szwStar[] = { '*',0 };
1424 static const TBBUTTON tbb[] =
1426 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1427 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1428 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1429 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1430 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1431 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1432 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1433 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1434 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1436 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1441 HIMAGELIST toolbarImageList;
1442 SHFILEINFOA shFileInfo;
1443 ITEMIDLIST *desktopPidl;
1445 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1447 TRACE("%p\n", fodInfos);
1449 /* Get windows version emulating */
1450 osVi.dwOSVersionInfoSize = sizeof(osVi);
1451 GetVersionExW(&osVi);
1452 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1453 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1454 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1455 win2000plus = (osVi.dwMajorVersion > 4);
1456 if (win2000plus) win98plus = TRUE;
1458 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1460 /* Get the hwnd of the controls */
1461 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1462 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1463 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1465 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1466 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1468 /* construct the toolbar */
1469 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1470 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1472 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1473 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1474 rectTB.left = rectlook.right;
1475 rectTB.top = rectlook.top-1;
1477 if (fodInfos->unicode)
1478 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1479 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1480 rectTB.left, rectTB.top,
1481 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1482 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1484 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, 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 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1492 /* FIXME: use TB_LOADIMAGES when implemented */
1493 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1494 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1495 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1497 /* Retrieve and add desktop icon to the toolbar */
1498 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1499 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1500 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1501 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1502 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1504 DestroyIcon(shFileInfo.hIcon);
1505 CoTaskMemFree(desktopPidl);
1507 /* Finish Toolbar Construction */
1508 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1509 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1511 /* Set the window text with the text specified in the OPENFILENAME structure */
1514 SetWindowTextW(hwnd,fodInfos->title);
1516 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1519 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1520 SetWindowTextW(hwnd, buf);
1523 /* Initialise the file name edit control */
1524 handledPath = FALSE;
1525 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1527 if(fodInfos->filename)
1529 /* 1. If win2000 or higher and filename contains a path, use it
1530 in preference over the lpstrInitialDir */
1531 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1532 WCHAR tmpBuf[MAX_PATH];
1536 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1539 /* nameBit is always shorter than the original filename */
1540 lstrcpyW(fodInfos->filename,nameBit);
1543 MemFree(fodInfos->initdir);
1544 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1545 lstrcpyW(fodInfos->initdir, tmpBuf);
1547 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1548 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1550 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1553 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1557 /* 2. (All platforms) If initdir is not null, then use it */
1558 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1559 (*fodInfos->initdir!=0x00))
1561 /* Work out the proper path as supplied one might be relative */
1562 /* (Here because supplying '.' as dir browses to My Computer) */
1563 if (handledPath==FALSE) {
1564 WCHAR tmpBuf[MAX_PATH];
1565 WCHAR tmpBuf2[MAX_PATH];
1569 lstrcpyW(tmpBuf, fodInfos->initdir);
1570 if( PathFileExistsW(tmpBuf) ) {
1571 /* initdir does not have to be a directory. If a file is
1572 * specified, the dir part is taken */
1573 if( PathIsDirectoryW(tmpBuf)) {
1574 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1575 lstrcatW(tmpBuf, szwSlash);
1577 lstrcatW(tmpBuf, szwStar);
1579 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1582 MemFree(fodInfos->initdir);
1583 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1584 lstrcpyW(fodInfos->initdir, tmpBuf2);
1586 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1589 else if (fodInfos->initdir)
1591 MemFree(fodInfos->initdir);
1592 fodInfos->initdir = NULL;
1593 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1598 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1599 (*fodInfos->initdir==0x00)))
1601 /* 3. All except w2k+: if filename contains a path use it */
1602 if (!win2000plus && fodInfos->filename &&
1603 *fodInfos->filename &&
1604 strpbrkW(fodInfos->filename, szwSlash)) {
1605 WCHAR tmpBuf[MAX_PATH];
1609 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1614 /* nameBit is always shorter than the original filename */
1615 lstrcpyW(fodInfos->filename, nameBit);
1618 len = lstrlenW(tmpBuf);
1619 MemFree(fodInfos->initdir);
1620 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1621 lstrcpyW(fodInfos->initdir, tmpBuf);
1624 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1625 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1627 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1630 /* 4. Win2000+: Recently used */
1631 if (handledPath == FALSE && win2000plus) {
1632 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1633 fodInfos->initdir[0] = '\0';
1635 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1637 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1640 MemFree(fodInfos->initdir);
1641 fodInfos->initdir = NULL;
1645 /* 5. win98+ and win2000+ if any files of specified filter types in
1646 current directory, use it */
1647 if ( win98plus && handledPath == FALSE &&
1648 fodInfos->filter && *fodInfos->filter) {
1650 LPCWSTR lpstrPos = fodInfos->filter;
1651 WIN32_FIND_DATAW FindFileData;
1656 /* filter is a list... title\0ext\0......\0\0 */
1658 /* Skip the title */
1659 if(! *lpstrPos) break; /* end */
1660 lpstrPos += lstrlenW(lpstrPos) + 1;
1662 /* See if any files exist in the current dir with this extension */
1663 if(! *lpstrPos) break; /* end */
1665 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1667 if (hFind == INVALID_HANDLE_VALUE) {
1668 /* None found - continue search */
1669 lpstrPos += lstrlenW(lpstrPos) + 1;
1673 MemFree(fodInfos->initdir);
1674 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1675 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1678 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1679 debugstr_w(lpstrPos));
1686 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1687 if (handledPath == FALSE && (win2000plus || win98plus)) {
1688 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1690 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1692 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1695 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1696 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1698 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1701 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1704 } else if (handledPath==FALSE) {
1705 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1706 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1708 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1711 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1712 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1714 /* Must the open as read only check box be checked ?*/
1715 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1717 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1720 /* Must the open as read only check box be hidden? */
1721 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1723 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1724 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1727 /* Must the help button be hidden? */
1728 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1730 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1731 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1734 /* change Open to Save */
1735 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1738 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1739 SetDlgItemTextW(hwnd, IDOK, buf);
1740 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1741 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1744 /* Initialize the filter combo box */
1745 FILEDLG95_FILETYPE_Init(hwnd);
1750 /***********************************************************************
1751 * FILEDLG95_ResizeControls
1753 * WM_INITDIALOG message handler (after hook notification)
1755 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1757 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1759 if (fodInfos->DlgInfos.hwndCustomDlg)
1762 UINT flags = SWP_NOACTIVATE;
1764 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1765 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1767 /* resize the custom dialog to the parent size */
1768 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1769 GetClientRect(hwnd, &rc);
1772 /* our own fake template is zero sized and doesn't have children, so
1773 * there is no need to resize it. Picasa depends on it.
1775 flags |= SWP_NOSIZE;
1778 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1779 0, 0, rc.right, rc.bottom, flags);
1783 /* Resize the height, if open as read only checkbox ad help button are
1784 * hidden and we are not using a custom template nor a customDialog
1786 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1787 (!(fodInfos->ofnInfos->Flags &
1788 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1790 RECT rectDlg, rectHelp, rectCancel;
1791 GetWindowRect(hwnd, &rectDlg);
1792 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1793 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1794 /* subtract the height of the help button plus the space between the help
1795 * button and the cancel button to the height of the dialog
1797 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1798 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1799 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1805 /***********************************************************************
1806 * FILEDLG95_FillControls
1808 * WM_INITDIALOG message handler (after hook notification)
1810 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1812 LPITEMIDLIST pidlItemId = NULL;
1814 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1816 TRACE("dir=%s file=%s\n",
1817 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1819 /* Get the initial directory pidl */
1821 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1823 WCHAR path[MAX_PATH];
1825 GetCurrentDirectoryW(MAX_PATH,path);
1826 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1829 /* Initialise shell objects */
1830 FILEDLG95_SHELL_Init(hwnd);
1832 /* Initialize the Look In combo box */
1833 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1835 /* Browse to the initial directory */
1836 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1838 /* Free pidlItem memory */
1839 COMDLG32_SHFree(pidlItemId);
1843 /***********************************************************************
1846 * Regroups all the cleaning functions of the filedlg
1848 void FILEDLG95_Clean(HWND hwnd)
1850 FILEDLG95_FILETYPE_Clean(hwnd);
1851 FILEDLG95_LOOKIN_Clean(hwnd);
1852 FILEDLG95_SHELL_Clean(hwnd);
1854 /***********************************************************************
1855 * FILEDLG95_OnWMCommand
1857 * WM_COMMAND message handler
1859 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1861 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1862 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1863 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1869 FILEDLG95_OnOpen(hwnd);
1873 FILEDLG95_Clean(hwnd);
1874 EndDialog(hwnd, FALSE);
1876 /* Filetype combo box */
1878 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1880 /* LookIn combo box */
1882 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1885 /* --- toolbar --- */
1886 /* Up folder button */
1887 case FCIDM_TB_UPFOLDER:
1888 FILEDLG95_SHELL_UpFolder(hwnd);
1890 /* New folder button */
1891 case FCIDM_TB_NEWFOLDER:
1892 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1894 /* List option button */
1895 case FCIDM_TB_SMALLICON:
1896 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1898 /* Details option button */
1899 case FCIDM_TB_REPORTVIEW:
1900 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1902 /* Details option button */
1903 case FCIDM_TB_DESKTOP:
1904 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1911 /* Do not use the listview selection anymore */
1912 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1916 /***********************************************************************
1917 * FILEDLG95_OnWMGetIShellBrowser
1919 * WM_GETISHELLBROWSER message handler
1921 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1923 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1927 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1933 /***********************************************************************
1934 * FILEDLG95_SendFileOK
1936 * Sends the CDN_FILEOK notification if required
1939 * TRUE if the dialog should close
1940 * FALSE if the dialog should not be closed
1942 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1944 /* ask the hook if we can close */
1945 if(IsHooked(fodInfos))
1950 /* First send CDN_FILEOK as MSDN doc says */
1951 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1952 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1955 TRACE("canceled\n");
1959 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1960 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1961 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1964 TRACE("canceled\n");
1971 /***********************************************************************
1972 * FILEDLG95_OnOpenMultipleFiles
1974 * Handles the opening of multiple files.
1977 * check destination buffer size
1979 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1981 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1982 UINT nCount, nSizePath;
1983 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1987 if(fodInfos->unicode)
1989 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1990 ofn->lpstrFile[0] = '\0';
1994 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1995 ofn->lpstrFile[0] = '\0';
1998 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2000 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2001 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2002 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2004 LPWSTR lpstrTemp = lpstrFileList;
2006 for ( nCount = 0; nCount < nFileCount; nCount++ )
2010 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2013 WCHAR lpstrNotFound[100];
2014 WCHAR lpstrMsg[100];
2016 static const WCHAR nl[] = {'\n',0};
2018 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2019 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2021 lstrcpyW(tmp, lpstrTemp);
2023 lstrcatW(tmp, lpstrNotFound);
2025 lstrcatW(tmp, lpstrMsg);
2027 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2031 /* move to the next file in the list of files */
2032 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2033 COMDLG32_SHFree(pidl);
2037 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2038 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2040 /* For "oldstyle" dialog the components have to
2041 be separated by blanks (not '\0'!) and short
2042 filenames have to be used! */
2043 FIXME("Components have to be separated by blanks\n");
2045 if(fodInfos->unicode)
2047 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2048 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2049 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2053 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2055 if (ofn->lpstrFile != NULL)
2057 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2058 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2059 if (ofn->nMaxFile > nSizePath)
2061 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2062 ofn->lpstrFile + nSizePath,
2063 ofn->nMaxFile - nSizePath, NULL, NULL);
2068 fodInfos->ofnInfos->nFileOffset = nSizePath;
2069 fodInfos->ofnInfos->nFileExtension = 0;
2071 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2074 /* clean and exit */
2075 FILEDLG95_Clean(hwnd);
2076 return EndDialog(hwnd,TRUE);
2079 /* Returns the 'slot name' of the given module_name in the registry's
2080 * most-recently-used list. This will be an ASCII value in the
2081 * range ['a','z'). Returns zero on error.
2083 * The slot's value in the registry has the form:
2084 * module_name\0mru_path\0
2086 * If stored_path is given, then stored_path will contain the path name
2087 * stored in the registry's MRU list for the given module_name.
2089 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2090 * MRU list key for the given module_name.
2092 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2094 WCHAR mru_list[32], *cur_mru_slot;
2095 BOOL taken[25] = {0};
2096 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2097 HKEY hkey_tmp, *hkey;
2106 *stored_path = '\0';
2108 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2110 WARN("Unable to create MRU key: %d\n", ret);
2114 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2115 (LPBYTE)mru_list, &mru_list_size);
2116 if(ret || key_type != REG_SZ){
2117 if(ret == ERROR_FILE_NOT_FOUND)
2120 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2125 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2126 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2127 DWORD value_data_size = sizeof(value_data);
2129 *value_name = *cur_mru_slot;
2131 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2132 &key_type, (LPBYTE)value_data, &value_data_size);
2133 if(ret || key_type != REG_BINARY){
2134 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2138 if(!strcmpiW(module_name, value_data)){
2142 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2150 /* the module name isn't in the registry, so find the next open slot */
2151 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2152 taken[*cur_mru_slot - 'a'] = TRUE;
2153 for(i = 0; i < 25; ++i){
2158 /* all slots are taken, so return the last one in MRUList */
2160 return *cur_mru_slot;
2163 /* save the given filename as most-recently-used path for this module */
2164 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2166 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2170 /* get the current executable's name */
2171 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2172 WARN("GotModuleFileName failed: %d\n", GetLastError());
2175 module_name = strrchrW(module_path, '\\');
2177 module_name = module_path;
2181 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2186 { /* update the slot's info */
2187 WCHAR *path_ends, *final;
2188 DWORD path_len, final_len;
2190 /* use only the path segment of `filename' */
2191 path_ends = strrchrW(filename, '\\');
2192 path_len = path_ends - filename;
2194 final_len = path_len + lstrlenW(module_name) + 2;
2196 final = MemAlloc(final_len * sizeof(WCHAR));
2199 lstrcpyW(final, module_name);
2200 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2201 final[final_len-1] = '\0';
2203 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2204 final_len * sizeof(WCHAR));
2206 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2215 { /* update MRUList value */
2216 WCHAR old_mru_list[32], new_mru_list[32];
2217 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2218 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2220 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2221 (LPBYTE)old_mru_list, &mru_list_size);
2222 if(ret || key_type != REG_SZ){
2223 if(ret == ERROR_FILE_NOT_FOUND){
2224 new_mru_list[0] = slot;
2225 new_mru_list[1] = '\0';
2227 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2232 /* copy old list data over so that the new slot is at the start
2234 *new_mru_slot++ = slot;
2235 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2236 if(*old_mru_slot != slot)
2237 *new_mru_slot++ = *old_mru_slot;
2239 *new_mru_slot = '\0';
2242 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2243 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2245 WARN("Error saving MRUList data: %d\n", ret);
2252 /* load the most-recently-used path for this module */
2253 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2255 WCHAR module_path[MAX_PATH], *module_name;
2257 /* get the current executable's name */
2258 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2259 WARN("GotModuleFileName failed: %d\n", GetLastError());
2262 module_name = strrchrW(module_path, '\\');
2264 module_name = module_path;
2268 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2269 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2272 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2274 WCHAR strMsgTitle[MAX_PATH];
2275 WCHAR strMsgText [MAX_PATH];
2277 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2279 strMsgTitle[0] = '\0';
2280 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2281 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2284 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2285 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2287 int nOpenAction = defAction;
2288 LPWSTR lpszTemp, lpszTemp1;
2289 LPITEMIDLIST pidl = NULL;
2290 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2292 /* check for invalid chars */
2293 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2295 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2299 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2301 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2304 LPSHELLFOLDER lpsfChild;
2305 WCHAR lpwstrTemp[MAX_PATH];
2306 DWORD dwEaten, dwAttributes;
2309 lstrcpyW(lpwstrTemp, lpszTemp);
2310 p = PathFindNextComponentW(lpwstrTemp);
2312 if (!p) break; /* end of path */
2315 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2317 /* There are no wildcards when OFN_NOVALIDATE is set */
2318 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2320 static const WCHAR wszWild[] = { '*', '?', 0 };
2321 /* if the last element is a wildcard do a search */
2322 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2324 nOpenAction = ONOPEN_SEARCH;
2328 lpszTemp1 = lpszTemp;
2330 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2332 /* append a backslash to drive letters */
2333 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2334 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2335 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2337 PathAddBackslashW(lpwstrTemp);
2340 dwAttributes = SFGAO_FOLDER;
2341 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2343 /* the path component is valid, we have a pidl of the next path component */
2344 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2345 if(dwAttributes & SFGAO_FOLDER)
2347 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2349 ERR("bind to failed\n"); /* should not fail */
2352 IShellFolder_Release(*ppsf);
2360 /* end dialog, return value */
2361 nOpenAction = ONOPEN_OPEN;
2364 COMDLG32_SHFree(pidl);
2367 else if (!(flags & OFN_NOVALIDATE))
2369 if(*lpszTemp || /* points to trailing null for last path element */
2370 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2372 if(flags & OFN_PATHMUSTEXIST)
2374 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2380 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2382 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2386 /* change to the current folder */
2387 nOpenAction = ONOPEN_OPEN;
2392 nOpenAction = ONOPEN_OPEN;
2396 if(pidl) COMDLG32_SHFree(pidl);
2401 /***********************************************************************
2404 * Ok button WM_COMMAND message handler
2406 * If the function succeeds, the return value is nonzero.
2408 BOOL FILEDLG95_OnOpen(HWND hwnd)
2410 LPWSTR lpstrFileList;
2411 UINT nFileCount = 0;
2414 WCHAR lpstrPathAndFile[MAX_PATH];
2415 LPSHELLFOLDER lpsf = NULL;
2417 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2419 TRACE("hwnd=%p\n", hwnd);
2421 /* try to browse the selected item */
2422 if(BrowseSelectedFolder(hwnd))
2425 /* get the files from the edit control */
2426 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2433 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2437 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2440 Step 1: Build a complete path name from the current folder and
2441 the filename or path in the edit box.
2443 - the path in the edit box is a root path
2444 (with or without drive letter)
2445 - the edit box contains ".." (or a path with ".." in it)
2448 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2449 MemFree(lpstrFileList);
2452 Step 2: here we have a cleaned up path
2454 We have to parse the path step by step to see if we have to browse
2455 to a folder if the path points to a directory or the last
2456 valid element is a directory.
2459 lpstrPathAndFile: cleaned up path
2463 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2464 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2465 nOpenAction = ONOPEN_OPEN;
2467 nOpenAction = ONOPEN_BROWSE;
2469 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2470 fodInfos->ofnInfos->Flags,
2471 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2477 Step 3: here we have a cleaned up and validated path
2480 lpsf: ShellFolder bound to the rightmost valid path component
2481 lpstrPathAndFile: cleaned up path
2482 nOpenAction: action to do
2484 TRACE("end validate sf=%p\n", lpsf);
2488 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2489 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2492 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2495 /* replace the current filter */
2496 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2497 len = lstrlenW(lpszTemp)+1;
2498 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2499 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2501 /* set the filter cb to the extension when possible */
2502 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2503 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2506 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2507 TRACE("ONOPEN_BROWSE\n");
2509 IPersistFolder2 * ppf2;
2510 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2512 LPITEMIDLIST pidlCurrent;
2513 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2514 IPersistFolder2_Release(ppf2);
2515 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2517 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2518 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2520 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2523 else if( nOpenAction == ONOPEN_SEARCH )
2525 if (fodInfos->Shell.FOIShellView)
2526 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2528 COMDLG32_SHFree(pidlCurrent);
2529 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2534 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2535 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2539 /* update READONLY check box flag */
2540 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2541 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2543 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2545 /* Attach the file extension with file name*/
2546 ext = PathFindExtensionW(lpstrPathAndFile);
2547 if (! *ext && fodInfos->defext)
2549 /* if no extension is specified with file name, then */
2550 /* attach the extension from file filter or default one */
2552 WCHAR *filterExt = NULL;
2553 LPWSTR lpstrFilter = NULL;
2554 static const WCHAR szwDot[] = {'.',0};
2555 int PathLength = lstrlenW(lpstrPathAndFile);
2557 /*Get the file extension from file type filter*/
2558 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2559 fodInfos->ofnInfos->nFilterIndex-1);
2561 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2563 WCHAR* filterSearchIndex;
2564 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2565 strcpyW(filterExt, lpstrFilter);
2567 /* if a semicolon-separated list of file extensions was given, do not include the
2568 semicolon or anything after it in the extension.
2569 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2570 filterSearchIndex = strchrW(filterExt, ';');
2571 if (filterSearchIndex)
2573 filterSearchIndex[0] = '\0';
2576 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2577 /* if the extension is invalid or contains a glob, ignore it */
2578 filterSearchIndex = PathFindExtensionW(filterExt);
2579 if (*filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2581 strcpyW(filterExt, filterSearchIndex);
2585 HeapFree(GetProcessHeap(), 0, filterExt);
2592 /* use the default file extension */
2593 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2594 strcpyW(filterExt, fodInfos->defext);
2597 if (*filterExt) /* ignore filterExt="" */
2600 lstrcatW(lpstrPathAndFile, szwDot);
2601 /* Attach the extension */
2602 lstrcatW(lpstrPathAndFile, filterExt);
2605 HeapFree(GetProcessHeap(), 0, filterExt);
2607 /* In Open dialog: if file does not exist try without extension */
2608 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2609 lpstrPathAndFile[PathLength] = '\0';
2611 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2614 if (!lstrcmpiW(fodInfos->defext, ext))
2615 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2617 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2620 /* In Save dialog: check if the file already exists */
2621 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2622 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2623 && PathFileExistsW(lpstrPathAndFile))
2625 WCHAR lpstrOverwrite[100];
2628 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2629 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2630 MB_YESNO | MB_ICONEXCLAMATION);
2631 if (answer == IDNO || answer == IDCANCEL)
2638 /* In Open dialog: check if it should be created if it doesn't exist */
2639 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2640 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2641 && !PathFileExistsW(lpstrPathAndFile))
2643 WCHAR lpstrCreate[100];
2646 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2647 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2648 MB_YESNO | MB_ICONEXCLAMATION);
2649 if (answer == IDNO || answer == IDCANCEL)
2656 /* Check that the size of the file does not exceed buffer size.
2657 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2658 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2659 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2662 /* fill destination buffer */
2663 if (fodInfos->ofnInfos->lpstrFile)
2665 if(fodInfos->unicode)
2667 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2669 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2670 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2671 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2675 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2677 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2678 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2679 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2680 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2684 if(fodInfos->unicode)
2688 /* set filename offset */
2689 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2690 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2692 /* set extension offset */
2693 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2694 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2699 CHAR tempFileA[MAX_PATH];
2701 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2702 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2703 tempFileA, sizeof(tempFileA), NULL, NULL);
2705 /* set filename offset */
2706 lpszTemp = PathFindFileNameA(tempFileA);
2707 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2709 /* set extension offset */
2710 lpszTemp = PathFindExtensionA(tempFileA);
2711 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2714 /* set the lpstrFileTitle */
2715 if(fodInfos->ofnInfos->lpstrFileTitle)
2717 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2718 if(fodInfos->unicode)
2720 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2721 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2725 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2726 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2727 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2731 /* copy currently selected filter to lpstrCustomFilter */
2732 if (fodInfos->ofnInfos->lpstrCustomFilter)
2734 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2735 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2736 NULL, 0, NULL, NULL);
2737 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2739 LPSTR s = ofn->lpstrCustomFilter;
2740 s += strlen(ofn->lpstrCustomFilter)+1;
2741 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2742 s, len, NULL, NULL);
2747 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2750 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2753 FILEDLG95_Clean(hwnd);
2754 ret = EndDialog(hwnd, TRUE);
2760 size = lstrlenW(lpstrPathAndFile) + 1;
2761 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2763 /* return needed size in first two bytes of lpstrFile */
2764 if(fodInfos->ofnInfos->lpstrFile)
2765 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2766 FILEDLG95_Clean(hwnd);
2767 ret = EndDialog(hwnd, FALSE);
2768 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2775 if(lpsf) IShellFolder_Release(lpsf);
2779 /***********************************************************************
2780 * FILEDLG95_SHELL_Init
2782 * Initialisation of the shell objects
2784 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2786 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2791 * Initialisation of the FileOpenDialogInfos structure
2797 fodInfos->ShellInfos.hwndOwner = hwnd;
2799 /* Disable multi-select if flag not set */
2800 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2802 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2804 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2805 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2807 /* Construct the IShellBrowser interface */
2808 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2813 /***********************************************************************
2814 * FILEDLG95_SHELL_ExecuteCommand
2816 * Change the folder option and refresh the view
2817 * If the function succeeds, the return value is nonzero.
2819 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2821 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2824 TRACE("(%p,%p)\n", hwnd, lpVerb);
2826 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2831 CMINVOKECOMMANDINFO ci;
2832 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2833 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2837 IContextMenu_InvokeCommand(pcm, &ci);
2838 IContextMenu_Release(pcm);
2844 /***********************************************************************
2845 * FILEDLG95_SHELL_UpFolder
2847 * Browse to the specified object
2848 * If the function succeeds, the return value is nonzero.
2850 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2852 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2856 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2860 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2861 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2867 /***********************************************************************
2868 * FILEDLG95_SHELL_BrowseToDesktop
2870 * Browse to the Desktop
2871 * If the function succeeds, the return value is nonzero.
2873 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2875 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2881 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2882 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2883 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2884 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2885 COMDLG32_SHFree(pidl);
2886 return SUCCEEDED(hres);
2888 /***********************************************************************
2889 * FILEDLG95_SHELL_Clean
2891 * Cleans the memory used by shell objects
2893 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2895 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2899 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2901 /* clean Shell interfaces */
2902 if (fodInfos->Shell.FOIShellView)
2904 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2905 IShellView_Release(fodInfos->Shell.FOIShellView);
2907 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2908 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2909 if (fodInfos->Shell.FOIDataObject)
2910 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2913 /***********************************************************************
2914 * FILEDLG95_FILETYPE_Init
2916 * Initialisation of the file type combo box
2918 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2920 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2921 int nFilters = 0; /* number of filters */
2926 if(fodInfos->customfilter)
2928 /* customfilter has one entry... title\0ext\0
2929 * Set first entry of combo box item with customfilter
2932 LPCWSTR lpstrPos = fodInfos->customfilter;
2935 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2937 /* Copy the extensions */
2938 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2939 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2940 lstrcpyW(lpstrExt,lpstrPos);
2942 /* Add the item at the end of the combo */
2943 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2944 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2947 if(fodInfos->filter)
2949 LPCWSTR lpstrPos = fodInfos->filter;
2953 /* filter is a list... title\0ext\0......\0\0
2954 * Set the combo item text to the title and the item data
2957 LPCWSTR lpstrDisplay;
2961 if(! *lpstrPos) break; /* end */
2962 lpstrDisplay = lpstrPos;
2963 lpstrPos += lstrlenW(lpstrPos) + 1;
2965 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2969 /* Copy the extensions */
2970 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2971 lstrcpyW(lpstrExt,lpstrPos);
2972 lpstrPos += lstrlenW(lpstrPos) + 1;
2974 /* Add the item at the end of the combo */
2975 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2977 /* malformed filters are added anyway... */
2978 if (!*lpstrExt) break;
2983 * Set the current filter to the one specified
2984 * in the initialisation structure
2986 if (fodInfos->filter || fodInfos->customfilter)
2990 /* Check to make sure our index isn't out of bounds. */
2991 if ( fodInfos->ofnInfos->nFilterIndex >
2992 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2993 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2995 /* set default filter index */
2996 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2997 fodInfos->ofnInfos->nFilterIndex = 1;
2999 /* calculate index of Combo Box item */
3000 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3001 if (fodInfos->customfilter == NULL)
3004 /* Set the current index selection. */
3005 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3007 /* Get the corresponding text string from the combo box. */
3008 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3011 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3017 CharLowerW(lpstrFilter); /* lowercase */
3018 len = lstrlenW(lpstrFilter)+1;
3019 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3020 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3023 fodInfos->ofnInfos->nFilterIndex = 0;
3027 /***********************************************************************
3028 * FILEDLG95_FILETYPE_OnCommand
3030 * WM_COMMAND of the file type combo box
3031 * If the function succeeds, the return value is nonzero.
3033 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3035 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3043 /* Get the current item of the filetype combo box */
3044 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3046 /* set the current filter index */
3047 fodInfos->ofnInfos->nFilterIndex = iItem +
3048 (fodInfos->customfilter == NULL ? 1 : 0);
3050 /* Set the current filter with the current selection */
3051 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3053 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3055 if((INT_PTR)lpstrFilter != CB_ERR)
3058 CharLowerW(lpstrFilter); /* lowercase */
3059 len = lstrlenW(lpstrFilter)+1;
3060 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3061 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3062 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3063 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3066 /* Refresh the actual view to display the included items*/
3067 if (fodInfos->Shell.FOIShellView)
3068 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3073 /***********************************************************************
3074 * FILEDLG95_FILETYPE_SearchExt
3076 * searches for an extension in the filetype box
3078 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3080 int i, iCount = CBGetCount(hwnd);
3082 TRACE("%s\n", debugstr_w(lpstrExt));
3084 if(iCount != CB_ERR)
3086 for(i=0;i<iCount;i++)
3088 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3095 /***********************************************************************
3096 * FILEDLG95_FILETYPE_Clean
3098 * Clean the memory used by the filetype combo box
3100 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3102 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3104 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3108 /* Delete each string of the combo and their associated data */
3109 if(iCount != CB_ERR)
3111 for(iPos = iCount-1;iPos>=0;iPos--)
3113 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3114 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3117 /* Current filter */
3118 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3122 /***********************************************************************
3123 * FILEDLG95_LOOKIN_Init
3125 * Initialisation of the look in combo box
3128 /* Small helper function, to determine if the unixfs shell extension is rooted
3129 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3131 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3133 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3134 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3135 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3136 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3137 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3138 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3139 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3141 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3148 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3150 IShellFolder *psfRoot, *psfDrives;
3151 IEnumIDList *lpeRoot, *lpeDrives;
3152 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3154 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3158 liInfos->iMaxIndentation = 0;
3160 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3162 /* set item height for both text field and listbox */
3163 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3164 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3166 /* Turn on the extended UI for the combo box like Windows does */
3167 CBSetExtendedUI(hwndCombo, TRUE);
3169 /* Initialise data of Desktop folder */
3170 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3171 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3172 COMDLG32_SHFree(pidlTmp);
3174 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3176 SHGetDesktopFolder(&psfRoot);
3180 /* enumerate the contents of the desktop */
3181 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3183 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3185 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3187 /* If the unixfs extension is rooted, we don't expand the drives by default */
3188 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3190 /* special handling for CSIDL_DRIVES */
3191 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3193 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3195 /* enumerate the drives */
3196 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3198 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3200 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3201 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3202 COMDLG32_SHFree(pidlAbsTmp);
3203 COMDLG32_SHFree(pidlTmp1);
3205 IEnumIDList_Release(lpeDrives);
3207 IShellFolder_Release(psfDrives);
3212 COMDLG32_SHFree(pidlTmp);
3214 IEnumIDList_Release(lpeRoot);
3216 IShellFolder_Release(psfRoot);
3219 COMDLG32_SHFree(pidlDrives);
3222 /***********************************************************************
3223 * FILEDLG95_LOOKIN_DrawItem
3225 * WM_DRAWITEM message handler
3227 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3229 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3230 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3231 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3235 HIMAGELIST ilItemImage;
3238 LPSFOLDER tmpFolder;
3239 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3243 if(pDIStruct->itemID == -1)
3246 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3247 pDIStruct->itemID)))
3251 if(pDIStruct->itemID == liInfos->uSelectedItem)
3253 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3257 SHGFI_PIDL | SHGFI_SMALLICON |
3258 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3259 SHGFI_DISPLAYNAME );
3263 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3267 SHGFI_PIDL | SHGFI_SMALLICON |
3268 SHGFI_SYSICONINDEX |
3272 /* Is this item selected ? */
3273 if(pDIStruct->itemState & ODS_SELECTED)
3275 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3276 SetBkColor(pDIStruct->hDC,crHighLight);
3277 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3281 SetTextColor(pDIStruct->hDC,crText);
3282 SetBkColor(pDIStruct->hDC,crWin);
3283 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3286 /* Do not indent item if drawing in the edit of the combo */
3287 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3290 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3294 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3295 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3300 iIndentation = tmpFolder->m_iIndent;
3302 /* Draw text and icon */
3304 /* Initialise the icon display area */
3305 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3306 rectIcon.top = pDIStruct->rcItem.top;
3307 rectIcon.right = rectIcon.left + ICONWIDTH;
3308 rectIcon.bottom = pDIStruct->rcItem.bottom;
3310 /* Initialise the text display area */
3311 GetTextMetricsW(pDIStruct->hDC, &tm);
3312 rectText.left = rectIcon.right;
3314 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3315 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3317 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3319 /* Draw the icon from the image list */
3320 ImageList_Draw(ilItemImage,
3327 /* Draw the associated text */
3328 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3332 /***********************************************************************
3333 * FILEDLG95_LOOKIN_OnCommand
3335 * LookIn combo box WM_COMMAND message handler
3336 * If the function succeeds, the return value is nonzero.
3338 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3340 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3342 TRACE("%p\n", fodInfos);
3348 LPSFOLDER tmpFolder;
3351 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3353 if( iItem == CB_ERR) return FALSE;
3355 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3360 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3361 tmpFolder->pidlItem,
3364 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3365 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3375 /***********************************************************************
3376 * FILEDLG95_LOOKIN_AddItem
3378 * Adds an absolute pidl item to the lookin combo box
3379 * returns the index of the inserted item
3381 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3383 LPITEMIDLIST pidlNext;
3386 LookInInfos *liInfos;
3388 TRACE("%08x\n", iInsertId);
3393 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3396 tmpFolder = MemAlloc(sizeof(SFOLDER));
3397 tmpFolder->m_iIndent = 0;
3399 /* Calculate the indentation of the item in the lookin*/
3401 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3403 tmpFolder->m_iIndent++;
3406 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3408 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3409 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3411 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3412 SHGetFileInfoW((LPCWSTR)pidl,
3416 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3417 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3419 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3421 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3425 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3427 /* Add the item at the end of the list */
3430 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3432 /* Insert the item at the iInsertId position*/
3435 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3438 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3442 COMDLG32_SHFree( tmpFolder->pidlItem );
3443 MemFree( tmpFolder );
3448 /***********************************************************************
3449 * FILEDLG95_LOOKIN_InsertItemAfterParent
3451 * Insert an item below its parent
3453 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3456 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3461 if (pidl == pidlParent)
3464 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3468 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3471 /* Free pidlParent memory */
3472 COMDLG32_SHFree(pidlParent);
3474 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3477 /***********************************************************************
3478 * FILEDLG95_LOOKIN_SelectItem
3480 * Adds an absolute pidl item to the lookin combo box
3481 * returns the index of the inserted item
3483 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3486 LookInInfos *liInfos;
3490 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3492 liInfos = GetPropA(hwnd,LookInInfosStr);
3496 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3497 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3502 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3503 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3507 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3509 if(iRemovedItem < iItemPos)
3514 CBSetCurSel(hwnd,iItemPos);
3515 liInfos->uSelectedItem = iItemPos;
3521 /***********************************************************************
3522 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3524 * Remove the item with an expansion level over iExpansionLevel
3526 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3529 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3533 if(liInfos->iMaxIndentation <= 2)
3536 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3538 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3539 COMDLG32_SHFree(tmpFolder->pidlItem);
3541 CBDeleteString(hwnd,iItemPos);
3542 liInfos->iMaxIndentation--;
3550 /***********************************************************************
3551 * FILEDLG95_LOOKIN_SearchItem
3553 * Search for pidl in the lookin combo box
3554 * returns the index of the found item
3556 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3559 int iCount = CBGetCount(hwnd);
3561 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3563 if (iCount != CB_ERR)
3567 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3569 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3571 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3579 /***********************************************************************
3580 * FILEDLG95_LOOKIN_Clean
3582 * Clean the memory used by the lookin combo box
3584 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3586 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3587 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3589 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3593 /* Delete each string of the combo and their associated data */
3594 if (iCount != CB_ERR)
3596 for(iPos = iCount-1;iPos>=0;iPos--)
3598 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3599 COMDLG32_SHFree(tmpFolder->pidlItem);
3601 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3605 /* LookInInfos structure */
3607 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3610 /***********************************************************************
3611 * FILEDLG95_FILENAME_FillFromSelection
3613 * fills the edit box from the cached DataObject
3615 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3617 FileOpenDlgInfos *fodInfos;
3619 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3620 WCHAR lpstrTemp[MAX_PATH];
3621 LPWSTR lpstrAllFile, lpstrCurrFile;
3624 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3626 /* Count how many files we have */
3627 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3629 /* calculate the string length, count files */
3630 if (nFileSelected >= 1)
3632 nLength += 3; /* first and last quotes, trailing \0 */
3633 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3635 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3639 /* get the total length of the selected file names */
3640 lpstrTemp[0] = '\0';
3641 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3643 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3645 nLength += lstrlenW( lpstrTemp ) + 3;
3648 COMDLG32_SHFree( pidl );
3653 /* allocate the buffer */
3654 if (nFiles <= 1) nLength = MAX_PATH;
3655 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3657 /* Generate the string for the edit control */
3660 lpstrCurrFile = lpstrAllFile;
3661 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3663 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3667 /* get the file name */
3668 lpstrTemp[0] = '\0';
3669 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3671 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3675 *lpstrCurrFile++ = '\"';
3676 lstrcpyW( lpstrCurrFile, lpstrTemp );
3677 lpstrCurrFile += lstrlenW( lpstrTemp );
3678 *lpstrCurrFile++ = '\"';
3679 *lpstrCurrFile++ = ' ';
3684 lstrcpyW( lpstrAllFile, lpstrTemp );
3687 COMDLG32_SHFree( pidl );
3690 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3692 /* Select the file name like Windows does */
3693 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3695 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3699 /* copied from shell32 to avoid linking to it
3700 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3701 * is dependent on whether emulated OS is unicode or not.
3703 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3708 lstrcpynW(dest, src->u.pOleStr, len);
3709 COMDLG32_SHFree(src->u.pOleStr);
3713 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3718 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3723 FIXME("unknown type %x!\n", src->uType);
3724 if (len) *dest = '\0';
3730 /***********************************************************************
3731 * FILEDLG95_FILENAME_GetFileNames
3733 * Copies the filenames to a delimited string list.
3735 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3737 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3738 UINT nFileCount = 0; /* number of files */
3739 UINT nStrLen = 0; /* length of string in edit control */
3740 LPWSTR lpstrEdit; /* buffer for string from edit control */
3744 /* get the filenames from the edit control */
3745 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3746 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3747 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3749 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3751 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3756 #define SETDefFormatEtc(fe,cf,med) \
3758 (fe).cfFormat = cf;\
3759 (fe).dwAspect = DVASPECT_CONTENT; \
3766 * DATAOBJECT Helper functions
3769 /***********************************************************************
3770 * COMCTL32_ReleaseStgMedium
3772 * like ReleaseStgMedium from ole32
3774 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3776 if(medium.pUnkForRelease)
3778 IUnknown_Release(medium.pUnkForRelease);
3782 GlobalUnlock(medium.u.hGlobal);
3783 GlobalFree(medium.u.hGlobal);
3787 /***********************************************************************
3788 * GetPidlFromDataObject
3790 * Return pidl(s) by number from the cached DataObject
3792 * nPidlIndex=0 gets the fully qualified root path
3794 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3798 FORMATETC formatetc;
3799 LPITEMIDLIST pidl = NULL;
3801 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3806 /* Set the FORMATETC structure*/
3807 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3809 /* Get the pidls from IDataObject */
3810 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3812 LPIDA cida = GlobalLock(medium.u.hGlobal);
3813 if(nPidlIndex <= cida->cidl)
3815 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3817 COMCTL32_ReleaseStgMedium(medium);
3822 /***********************************************************************
3825 * Return the number of selected items in the DataObject.
3828 static UINT GetNumSelected( IDataObject *doSelected )
3832 FORMATETC formatetc;
3834 TRACE("sv=%p\n", doSelected);
3836 if (!doSelected) return 0;
3838 /* Set the FORMATETC structure*/
3839 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3841 /* Get the pidls from IDataObject */
3842 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3844 LPIDA cida = GlobalLock(medium.u.hGlobal);
3845 retVal = cida->cidl;
3846 COMCTL32_ReleaseStgMedium(medium);
3856 /***********************************************************************
3859 * Get the pidl's display name (relative to folder) and
3860 * put it in lpstrFileName.
3862 * Return NOERROR on success,
3866 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3871 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3875 SHGetDesktopFolder(&lpsf);
3876 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3877 IShellFolder_Release(lpsf);
3881 /* Get the display name of the pidl relative to the folder */
3882 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3884 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3889 /***********************************************************************
3890 * GetShellFolderFromPidl
3892 * pidlRel is the item pidl relative
3893 * Return the IShellFolder of the absolute pidl
3895 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3897 IShellFolder *psf = NULL,*psfParent;
3899 TRACE("%p\n", pidlAbs);
3901 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3904 if(pidlAbs && pidlAbs->mkid.cb)
3906 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3908 IShellFolder_Release(psfParent);
3912 /* return the desktop */
3918 /***********************************************************************
3921 * Return the LPITEMIDLIST to the parent of the pidl in the list
3923 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3925 LPITEMIDLIST pidlParent;
3927 TRACE("%p\n", pidl);
3929 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3930 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3935 /***********************************************************************
3938 * returns the pidl of the file name relative to folder
3939 * NULL if an error occurred
3941 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3943 LPITEMIDLIST pidl = NULL;
3946 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3948 if(!lpcstrFileName) return NULL;
3949 if(!*lpcstrFileName) return NULL;
3953 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3954 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3955 IShellFolder_Release(lpsf);
3960 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3967 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3969 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3972 TRACE("%p, %p\n", psf, pidl);
3974 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3976 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3977 /* see documentation shell 4.1*/
3978 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3981 /***********************************************************************
3982 * BrowseSelectedFolder
3984 static BOOL BrowseSelectedFolder(HWND hwnd)
3986 BOOL bBrowseSelFolder = FALSE;
3987 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3991 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3993 LPITEMIDLIST pidlSelection;
3995 /* get the file selected */
3996 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3997 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3999 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4000 pidlSelection, SBSP_RELATIVE ) ) )
4002 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4003 ' ','n','o','t',' ','e','x','i','s','t',0};
4004 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4006 bBrowseSelFolder = TRUE;
4007 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4008 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4010 COMDLG32_SHFree( pidlSelection );
4013 return bBrowseSelFolder;
4017 * Memory allocation methods */
4018 static void *MemAlloc(UINT size)
4020 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4023 static void MemFree(void *mem)
4025 HeapFree(GetProcessHeap(),0,mem);
4029 * Old-style (win3.1) dialogs */
4031 /***********************************************************************
4032 * FD32_GetTemplate [internal]
4034 * Get a template (or FALSE if failure) when 16 bits dialogs are used
4035 * by a 32 bits application
4038 BOOL FD32_GetTemplate(PFD31_DATA lfs)
4040 LPOPENFILENAMEW ofnW = lfs->ofnW;
4041 LPOPENFILENAMEA ofnA = lfs->ofnA;
4044 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
4046 if (!(lfs->template = LockResource( ofnW->hInstance )))
4048 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4052 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
4056 hResInfo = FindResourceA(ofnA->hInstance,
4057 ofnA->lpTemplateName,
4060 hResInfo = FindResourceW(ofnW->hInstance,
4061 ofnW->lpTemplateName,
4065 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4068 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4070 !(lfs->template = LockResource(hDlgTmpl)))
4072 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4075 } else { /* get it from internal Wine resource */
4077 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4078 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4080 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4083 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4084 !(lfs->template = LockResource( hDlgTmpl )))
4086 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4094 /***********************************************************************
4095 * FD32_WMMeasureItem [internal]
4097 static LONG FD32_WMMeasureItem(LPARAM lParam)
4099 LPMEASUREITEMSTRUCT lpmeasure;
4101 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4102 lpmeasure->itemHeight = FD31_GetFldrHeight();
4107 /***********************************************************************
4108 * FileOpenDlgProc [internal]
4109 * Used for open and save, in fact.
4111 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4112 WPARAM wParam, LPARAM lParam)
4114 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4116 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4117 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4120 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4122 return lRet; /* else continue message processing */
4127 return FD31_WMInitDialog(hWnd, wParam, lParam);
4129 case WM_MEASUREITEM:
4130 return FD32_WMMeasureItem(lParam);
4133 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4136 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4139 SetBkColor((HDC16)wParam, 0x00C0C0C0);
4140 switch (HIWORD(lParam))
4143 SetTextColor((HDC16)wParam, 0x00000000);
4145 case CTLCOLOR_STATIC:
4146 SetTextColor((HDC16)wParam, 0x00000000);
4156 /***********************************************************************
4157 * GetFileName31A [internal]
4159 * Creates a win31 style dialog box for the user to select a file to open/save.
4161 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4162 UINT dlgType /* type dialogue : open/save */
4168 if (!lpofn || !FD31_Init()) return FALSE;
4170 TRACE("ofn flags %08x\n", lpofn->Flags);
4171 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4174 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4175 FD32_FileOpenDlgProc, (LPARAM)lfs);
4176 FD31_DestroyPrivate(lfs);
4179 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4183 /***********************************************************************
4184 * GetFileName31W [internal]
4186 * Creates a win31 style dialog box for the user to select a file to open/save
4188 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4189 UINT dlgType /* type dialogue : open/save */
4195 if (!lpofn || !FD31_Init()) return FALSE;
4197 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4200 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4201 FD32_FileOpenDlgProc, (LPARAM)lfs);
4202 FD31_DestroyPrivate(lfs);
4205 TRACE("file %s, file offset %d, ext offset %d\n",
4206 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4210 static inline BOOL is_win16_looks(DWORD flags)
4212 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4213 !(flags & OFN_EXPLORER));
4216 /* ------------------ APIs ---------------------- */
4218 /***********************************************************************
4219 * GetOpenFileNameA (COMDLG32.@)
4221 * Creates a dialog box for the user to select a file to open.
4224 * TRUE on success: user enters a valid file
4225 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4228 BOOL WINAPI GetOpenFileNameA(
4229 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4231 TRACE("flags %08x\n", ofn->Flags);
4233 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4234 if (ofn->Flags & OFN_FILEMUSTEXIST)
4235 ofn->Flags |= OFN_PATHMUSTEXIST;
4237 if (is_win16_looks(ofn->Flags))
4238 return GetFileName31A(ofn, OPEN_DIALOG);
4240 return GetFileDialog95A(ofn, OPEN_DIALOG);
4243 /***********************************************************************
4244 * GetOpenFileNameW (COMDLG32.@)
4246 * Creates a dialog box for the user to select a file to open.
4249 * TRUE on success: user enters a valid file
4250 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4253 BOOL WINAPI GetOpenFileNameW(
4254 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4256 TRACE("flags %08x\n", ofn->Flags);
4258 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4259 if (ofn->Flags & OFN_FILEMUSTEXIST)
4260 ofn->Flags |= OFN_PATHMUSTEXIST;
4262 if (is_win16_looks(ofn->Flags))
4263 return GetFileName31W(ofn, OPEN_DIALOG);
4265 return GetFileDialog95W(ofn, OPEN_DIALOG);
4269 /***********************************************************************
4270 * GetSaveFileNameA (COMDLG32.@)
4272 * Creates a dialog box for the user to select a file to save.
4275 * TRUE on success: user enters a valid file
4276 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4279 BOOL WINAPI GetSaveFileNameA(
4280 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4282 if (is_win16_looks(ofn->Flags))
4283 return GetFileName31A(ofn, SAVE_DIALOG);
4285 return GetFileDialog95A(ofn, SAVE_DIALOG);
4288 /***********************************************************************
4289 * GetSaveFileNameW (COMDLG32.@)
4291 * Creates a dialog box for the user to select a file to save.
4294 * TRUE on success: user enters a valid file
4295 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4298 BOOL WINAPI GetSaveFileNameW(
4299 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4301 if (is_win16_looks(ofn->Flags))
4302 return GetFileName31W(ofn, SAVE_DIALOG);
4304 return GetFileDialog95W(ofn, SAVE_DIALOG);
4307 /***********************************************************************
4308 * GetFileTitleA (COMDLG32.@)
4310 * See GetFileTitleW.
4312 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4315 UNICODE_STRING strWFile;
4318 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4319 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4320 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4321 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4322 RtlFreeUnicodeString( &strWFile );
4323 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4328 /***********************************************************************
4329 * GetFileTitleW (COMDLG32.@)
4331 * Get the name of a file.
4334 * lpFile [I] name and location of file
4335 * lpTitle [O] returned file name
4336 * cbBuf [I] buffer size of lpTitle
4340 * Failure: negative number.
4342 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4345 static const WCHAR brkpoint[] = {'*','[',']',0};
4346 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4348 if(lpFile == NULL || lpTitle == NULL)
4351 len = lstrlenW(lpFile);
4356 if(strpbrkW(lpFile, brkpoint))
4361 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4364 for(i = len; i >= 0; i--)
4366 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4376 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4378 len = lstrlenW(lpFile+i)+1;
4382 lstrcpyW(lpTitle, &lpFile[i]);