schedsvc/tests: Add the current process id to the test summary line.
[wine.git] / dlls / comdlg32 / filedlg.c
blob0c9f34a84e856c75e21d6e4917c313322be40453
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winternl.h"
63 #include "winnls.h"
64 #include "wingdi.h"
65 #include "winreg.h"
66 #include "winuser.h"
67 #include "commdlg.h"
68 #include "dlgs.h"
69 #include "cdlg.h"
70 #include "cderr.h"
71 #include "shellapi.h"
72 #include "shlobj.h"
73 #include "filedlgbrowser.h"
74 #include "shlwapi.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex; /* Index of picture in image list */
94 HIMAGELIST hImgList;
95 int m_iIndent; /* Indentation index */
96 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
98 } SFOLDER,*LPSFOLDER;
100 typedef struct tagLookInInfo
102 int iMaxIndentation;
103 UINT uSelectedItem;
104 } LookInInfos;
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
114 /* AddItem flags*/
115 #define LISTEND -1
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
119 #define SEARCH_EXP 2
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
125 /* NOTE
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
166 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
168 static const WCHAR LastVisitedMRUW[] =
169 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
172 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
173 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
175 static const WCHAR filedlg_info_propnameW[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
177 FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd)
179 return GetPropW(hwnd, filedlg_info_propnameW);
182 /***********************************************************************
183 * Prototypes
186 /* Internal functions used by the dialog */
187 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
189 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
190 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
191 static BOOL FILEDLG95_OnOpen(HWND hwnd);
192 static LRESULT FILEDLG95_InitControls(HWND hwnd);
193 static void FILEDLG95_Clean(HWND hwnd);
195 /* Functions used by the shell navigation */
196 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
199 static void FILEDLG95_SHELL_Clean(HWND hwnd);
200 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
202 /* Functions used by the EDIT box */
203 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
205 /* Functions used by the filetype combo box */
206 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
207 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
208 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
209 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
211 /* Functions used by the Look In combo box */
212 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
213 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
214 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
215 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
216 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
217 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
218 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
219 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
220 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
222 /* Functions for dealing with the most-recently-used registry keys */
223 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
224 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
225 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
227 /* Miscellaneous tool functions */
228 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
229 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
230 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
231 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
232 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
233 static UINT GetNumSelected( IDataObject *doSelected );
234 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
236 /* Shell memory allocation */
237 static void *MemAlloc(UINT size);
238 static void MemFree(void *mem);
240 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
241 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
242 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
243 static BOOL BrowseSelectedFolder(HWND hwnd);
245 /***********************************************************************
246 * GetFileName95
248 * Creates an Open common dialog box that lets the user select
249 * the drive, directory, and the name of a file or set of files to open.
251 * IN : The FileOpenDlgInfos structure associated with the dialog
252 * OUT : TRUE on success
253 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
255 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
257 LRESULT lRes;
258 void *template;
259 HRSRC hRes;
260 HANDLE hDlgTmpl = 0;
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);
274 return FALSE;
276 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
277 !(template = LockResource( hDlgTmpl )))
279 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
280 return FALSE;
283 /* msdn: explorer style dialogs permit sizing by default.
284 * The OFN_ENABLESIZING flag is only needed when a hook or
285 * custom template is provided */
286 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
287 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
288 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
290 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
292 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
293 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
296 /* old style hook messages */
297 if (IsHooked(fodInfos))
299 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
300 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
301 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
302 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
305 if (fodInfos->unicode)
306 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
307 template,
308 fodInfos->ofnInfos->hwndOwner,
309 FileOpenDlgProc95,
310 (LPARAM) fodInfos);
311 else
312 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
313 template,
314 fodInfos->ofnInfos->hwndOwner,
315 FileOpenDlgProc95,
316 (LPARAM) fodInfos);
317 if (fodInfos->ole_initialized)
318 OleUninitialize();
320 /* Unable to create the dialog */
321 if( lRes == -1)
322 return FALSE;
324 return lRes;
327 static WCHAR *heap_strdupAtoW(const char *str)
329 WCHAR *ret;
330 INT len;
332 if (!str)
333 return NULL;
335 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
336 ret = MemAlloc(len * sizeof(WCHAR));
337 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
339 return ret;
342 static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info)
344 INITCOMMONCONTROLSEX icc;
346 /* Initialize ComboBoxEx32 */
347 icc.dwSize = sizeof(icc);
348 icc.dwICC = ICC_USEREX_CLASSES;
349 InitCommonControlsEx(&icc);
351 /* Initialize CommDlgExtendedError() */
352 COMDLG32_SetCommDlgExtendedError(0);
354 memset(info, 0, sizeof(*info));
356 /* Pass in the original ofn */
357 info->ofnInfos = ofn;
359 info->title = ofn->lpstrTitle;
360 info->defext = ofn->lpstrDefExt;
361 info->filter = ofn->lpstrFilter;
362 info->customfilter = ofn->lpstrCustomFilter;
364 if (ofn->lpstrFile)
366 info->filename = MemAlloc(ofn->nMaxFile * sizeof(WCHAR));
367 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
370 if (ofn->lpstrInitialDir)
372 DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0);
373 if (len)
375 info->initdir = MemAlloc(len * sizeof(WCHAR));
376 ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len);
380 info->unicode = TRUE;
383 static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
385 OPENFILENAMEW ofnW;
387 ofnW = *(OPENFILENAMEW *)ofn;
389 ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir);
390 ofnW.lpstrFile = heap_strdupAtoW(ofn->lpstrFile);
391 ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt);
392 ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle);
394 if (ofn->lpstrFilter)
396 int n, len;
397 LPCSTR s;
399 /* filter is a list... title\0ext\0......\0\0 */
400 s = ofn->lpstrFilter;
401 while (*s) s = s+strlen(s)+1;
402 s++;
403 n = s - ofn->lpstrFilter;
404 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0);
405 ofnW.lpstrFilter = MemAlloc(len * sizeof(WCHAR));
406 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len);
409 /* convert lpstrCustomFilter */
410 if (ofn->lpstrCustomFilter)
412 int n, len;
413 LPCSTR s;
415 /* customfilter contains a pair of strings... title\0ext\0 */
416 s = ofn->lpstrCustomFilter;
417 if (*s) s = s+strlen(s)+1;
418 if (*s) s = s+strlen(s)+1;
419 n = s - ofn->lpstrCustomFilter;
420 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0);
421 ofnW.lpstrCustomFilter = MemAlloc(len * sizeof(WCHAR));
422 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len);
425 init_filedlg_infoW(&ofnW, info);
427 /* fixup A-specific fields */
428 info->ofnInfos = (OPENFILENAMEW *)ofn;
429 info->unicode = FALSE;
431 /* free what was duplicated */
432 MemFree((WCHAR *)ofnW.lpstrInitialDir);
433 MemFree((WCHAR *)ofnW.lpstrFile);
436 /***********************************************************************
437 * GetFileDialog95
439 * Call GetFileName95 with this structure and clean the memory.
441 static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type)
443 WCHAR *current_dir = NULL;
444 BOOL ret;
446 /* save current directory */
447 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
449 current_dir = MemAlloc(MAX_PATH * sizeof(WCHAR));
450 GetCurrentDirectoryW(MAX_PATH, current_dir);
453 switch (dlg_type)
455 case OPEN_DIALOG:
456 ret = GetFileName95(info);
457 break;
458 case SAVE_DIALOG:
459 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
460 ret = GetFileName95(info);
461 break;
462 default:
463 ret = FALSE;
466 if (current_dir)
468 SetCurrentDirectoryW(current_dir);
469 MemFree(current_dir);
472 if (!info->unicode)
474 MemFree((WCHAR *)info->defext);
475 MemFree((WCHAR *)info->title);
476 MemFree((WCHAR *)info->filter);
477 MemFree((WCHAR *)info->customfilter);
480 MemFree(info->filename);
481 MemFree(info->initdir);
482 return ret;
485 /******************************************************************************
486 * COMDLG32_GetDisplayNameOf [internal]
488 * Helper function to get the display name for a pidl.
490 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
491 LPSHELLFOLDER psfDesktop;
492 STRRET strret;
494 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
495 return FALSE;
497 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
498 IShellFolder_Release(psfDesktop);
499 return FALSE;
502 IShellFolder_Release(psfDesktop);
503 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
506 /******************************************************************************
507 * COMDLG32_GetCanonicalPath [internal]
509 * Helper function to get the canonical path.
511 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
512 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
514 WCHAR lpstrTemp[MAX_PATH];
516 /* Get the current directory name */
517 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
519 /* last fallback */
520 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
522 PathAddBackslashW(lpstrPathAndFile);
524 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
526 /* if the user specified a fully qualified path use it */
527 if(PathIsRelativeW(lpstrFile))
529 lstrcatW(lpstrPathAndFile, lpstrFile);
531 else
533 /* does the path have a drive letter? */
534 if (PathGetDriveNumberW(lpstrFile) == -1)
535 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
536 else
537 lstrcpyW(lpstrPathAndFile, lpstrFile);
540 /* resolve "." and ".." */
541 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
542 lstrcpyW(lpstrPathAndFile, lpstrTemp);
543 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
546 /***********************************************************************
547 * COMDLG32_SplitFileNames [internal]
549 * Creates a delimited list of filenames.
551 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
553 UINT nStrCharCount = 0; /* index in src buffer */
554 UINT nFileIndex = 0; /* index in dest buffer */
555 UINT nFileCount = 0; /* number of files */
557 /* we might get single filename without any '"',
558 * so we need nStrLen + terminating \0 + end-of-list \0 */
559 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
560 *sizeUsed = 0;
562 /* build delimited file list from filenames */
563 while ( nStrCharCount <= nStrLen )
565 if ( lpstrEdit[nStrCharCount]=='"' )
567 nStrCharCount++;
568 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
570 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
571 nStrCharCount++;
573 (*lpstrFileList)[nFileIndex++] = 0;
574 nFileCount++;
576 nStrCharCount++;
579 /* single, unquoted string */
580 if ((nStrLen > 0) && (nFileIndex == 0) )
582 lstrcpyW(*lpstrFileList, lpstrEdit);
583 nFileIndex = lstrlenW(lpstrEdit) + 1;
584 nFileCount = 1;
587 /* trailing \0 */
588 (*lpstrFileList)[nFileIndex++] = '\0';
590 *sizeUsed = nFileIndex;
591 return nFileCount;
594 /***********************************************************************
595 * ArrangeCtrlPositions [internal]
597 * NOTE: Make sure to add testcases for any changes made here.
599 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
601 HWND hwndChild, hwndStc32;
602 RECT rectParent, rectChild, rectStc32;
603 INT help_fixup = 0;
604 int chgx, chgy;
606 /* Take into account if open as read only checkbox and help button
607 * are hidden
609 if (hide_help)
611 RECT rectHelp, rectCancel;
612 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
613 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
614 /* subtract the height of the help button plus the space between
615 * the help button and the cancel button to the height of the dialog
617 help_fixup = rectHelp.bottom - rectCancel.bottom;
621 There are two possibilities to add components to the default file dialog box.
623 By default, all the new components are added below the standard dialog box (the else case).
625 However, if there is a static text component with the stc32 id, a special case happens.
626 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
627 in the window and the cx and cy indicate how to size the window.
628 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
629 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
633 GetClientRect(hwndParentDlg, &rectParent);
635 /* when arranging controls we have to use fixed parent size */
636 rectParent.bottom -= help_fixup;
638 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
639 if (hwndStc32)
641 GetWindowRect(hwndStc32, &rectStc32);
642 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
644 /* set the size of the stc32 control according to the size of
645 * client area of the parent dialog
647 SetWindowPos(hwndStc32, 0,
648 0, 0,
649 rectParent.right, rectParent.bottom,
650 SWP_NOMOVE | SWP_NOZORDER);
652 else
653 SetRectEmpty(&rectStc32);
655 /* this part moves controls of the child dialog */
656 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
657 while (hwndChild)
659 if (hwndChild != hwndStc32)
661 GetWindowRect(hwndChild, &rectChild);
662 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
664 /* move only if stc32 exist */
665 if (hwndStc32 && rectChild.left > rectStc32.right)
667 /* move to the right of visible controls of the parent dialog */
668 rectChild.left += rectParent.right;
669 rectChild.left -= rectStc32.right;
671 /* move even if stc32 doesn't exist */
672 if (rectChild.top >= rectStc32.bottom)
674 /* move below visible controls of the parent dialog */
675 rectChild.top += rectParent.bottom;
676 rectChild.top -= rectStc32.bottom - rectStc32.top;
679 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
680 0, 0, SWP_NOSIZE | SWP_NOZORDER);
682 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
685 /* this part moves controls of the parent dialog */
686 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
687 while (hwndChild)
689 if (hwndChild != hwndChildDlg)
691 GetWindowRect(hwndChild, &rectChild);
692 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
694 /* left,top of stc32 marks the position of controls
695 * from the parent dialog
697 rectChild.left += rectStc32.left;
698 rectChild.top += rectStc32.top;
700 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
701 0, 0, SWP_NOSIZE | SWP_NOZORDER);
703 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
706 /* calculate the size of the resulting dialog */
708 /* here we have to use original parent size */
709 GetClientRect(hwndParentDlg, &rectParent);
710 GetClientRect(hwndChildDlg, &rectChild);
711 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
712 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
714 if (hwndStc32)
716 /* width */
717 if (rectParent.right > rectStc32.right - rectStc32.left)
718 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
719 else
720 chgx = rectChild.right - rectParent.right;
721 /* height */
722 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
723 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
724 else
725 /* Unconditionally set new dialog
726 * height to that of the child
728 chgy = rectChild.bottom - rectParent.bottom;
730 else
732 chgx = 0;
733 chgy = rectChild.bottom - help_fixup;
735 /* set the size of the parent dialog */
736 GetWindowRect(hwndParentDlg, &rectParent);
737 SetWindowPos(hwndParentDlg, 0,
738 0, 0,
739 rectParent.right - rectParent.left + chgx,
740 rectParent.bottom - rectParent.top + chgy,
741 SWP_NOMOVE | SWP_NOZORDER);
744 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
746 switch(uMsg) {
747 case WM_INITDIALOG:
748 return TRUE;
750 return FALSE;
753 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
755 LPCVOID template;
756 HRSRC hRes;
757 HANDLE hDlgTmpl = 0;
758 HWND hChildDlg = 0;
760 TRACE("\n");
763 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
764 * structure's hInstance parameter is not a HINSTANCE, but
765 * instead a pointer to a template resource to use.
767 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
769 HINSTANCE hinst;
770 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
772 hinst = COMDLG32_hInstance;
773 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
775 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
776 return NULL;
779 else
781 hinst = fodInfos->ofnInfos->hInstance;
782 if(fodInfos->unicode)
784 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
785 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
787 else
789 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
790 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
792 if (!hRes)
794 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
795 return NULL;
797 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
798 !(template = LockResource( hDlgTmpl )))
800 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
801 return NULL;
804 if (fodInfos->unicode)
805 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
806 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
807 (LPARAM)fodInfos->ofnInfos);
808 else
809 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
810 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
811 (LPARAM)fodInfos->ofnInfos);
812 return hChildDlg;
814 else if( IsHooked(fodInfos))
816 RECT rectHwnd;
817 struct {
818 DLGTEMPLATE tmplate;
819 WORD menu,class,title;
820 } temp;
821 GetClientRect(hwnd,&rectHwnd);
822 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
823 temp.tmplate.dwExtendedStyle = 0;
824 temp.tmplate.cdit = 0;
825 temp.tmplate.x = 0;
826 temp.tmplate.y = 0;
827 temp.tmplate.cx = 0;
828 temp.tmplate.cy = 0;
829 temp.menu = temp.class = temp.title = 0;
831 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
832 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
834 return hChildDlg;
836 return NULL;
839 /***********************************************************************
840 * SendCustomDlgNotificationMessage
842 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
845 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
847 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
848 LRESULT hook_result = 0;
850 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
852 if(!fodInfos) return 0;
854 if(fodInfos->DlgInfos.hwndCustomDlg)
856 TRACE("CALL NOTIFY for %x\n", uCode);
857 if(fodInfos->unicode)
859 OFNOTIFYW ofnNotify;
860 ofnNotify.hdr.hwndFrom=hwndParentDlg;
861 ofnNotify.hdr.idFrom=0;
862 ofnNotify.hdr.code = uCode;
863 ofnNotify.lpOFN = fodInfos->ofnInfos;
864 ofnNotify.pszFile = NULL;
865 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
867 else
869 OFNOTIFYA ofnNotify;
870 ofnNotify.hdr.hwndFrom=hwndParentDlg;
871 ofnNotify.hdr.idFrom=0;
872 ofnNotify.hdr.code = uCode;
873 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
874 ofnNotify.pszFile = NULL;
875 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
877 TRACE("RET NOTIFY\n");
879 TRACE("Retval: 0x%08lx\n", hook_result);
880 return hook_result;
883 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
885 UINT len, total;
886 WCHAR *p, *buffer;
887 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
889 TRACE("CDM_GETFILEPATH:\n");
891 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
892 return -1;
894 /* get path and filenames */
895 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
896 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
897 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
898 if (len)
900 p = buffer + strlenW(buffer);
901 *p++ = '\\';
902 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
904 if (fodInfos->unicode)
906 total = strlenW( buffer) + 1;
907 if (result) lstrcpynW( result, buffer, size );
908 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
910 else
912 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
913 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
914 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
916 HeapFree( GetProcessHeap(), 0, buffer );
917 return total;
920 /***********************************************************************
921 * FILEDLG95_HandleCustomDialogMessages
923 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
925 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
927 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
928 WCHAR lpstrPath[MAX_PATH];
929 INT_PTR retval;
931 if(!fodInfos) return FALSE;
933 switch(uMsg)
935 case CDM_GETFILEPATH:
936 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
937 break;
939 case CDM_GETFOLDERPATH:
940 TRACE("CDM_GETFOLDERPATH:\n");
941 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
942 if (lParam)
944 if (fodInfos->unicode)
945 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
946 else
947 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
948 (LPSTR)lParam, (int)wParam, NULL, NULL);
950 retval = lstrlenW(lpstrPath) + 1;
951 break;
953 case CDM_GETFOLDERIDLIST:
954 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
955 if (retval <= wParam)
956 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
957 break;
959 case CDM_GETSPEC:
960 TRACE("CDM_GETSPEC:\n");
961 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
962 if (lParam)
964 if (fodInfos->unicode)
965 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
966 else
967 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
969 break;
971 case CDM_SETCONTROLTEXT:
972 TRACE("CDM_SETCONTROLTEXT:\n");
973 if ( lParam )
975 if( fodInfos->unicode )
976 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
977 else
978 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
980 retval = TRUE;
981 break;
983 case CDM_HIDECONTROL:
984 /* MSDN states that it should fail for not OFN_EXPLORER case */
985 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
987 HWND control = GetDlgItem( hwnd, wParam );
988 if (control) ShowWindow( control, SW_HIDE );
989 retval = TRUE;
991 else retval = FALSE;
992 break;
994 default:
995 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
996 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
997 return FALSE;
999 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1000 return TRUE;
1003 /***********************************************************************
1004 * FILEDLG95_OnWMGetMMI
1006 * WM_GETMINMAXINFO message handler for resizable dialogs
1008 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1010 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1011 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1012 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1014 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1016 return TRUE;
1019 /***********************************************************************
1020 * FILEDLG95_OnWMSize
1022 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1024 * FIXME: this could be made more elaborate. Now use a simple scheme
1025 * where the file view is enlarged and the controls are either moved
1026 * vertically or horizontally to get out of the way. Only the "grip"
1027 * is moved in both directions to stay in the corner.
1029 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1031 RECT rc, rcview;
1032 int chgx, chgy;
1033 HWND ctrl;
1034 HDWP hdwp;
1035 FileOpenDlgInfos *fodInfos;
1037 if( wParam != SIZE_RESTORED) return FALSE;
1038 fodInfos = get_filedlg_infoptr(hwnd);
1039 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1040 /* get the new dialog rectangle */
1041 GetWindowRect( hwnd, &rc);
1042 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1043 rc.right -rc.left, rc.bottom -rc.top);
1044 /* not initialized yet */
1045 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1046 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1047 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1048 return FALSE;
1049 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1050 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1051 fodInfos->sizedlg.cx = rc.right - rc.left;
1052 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1053 /* change the size of the view window */
1054 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1055 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1056 hdwp = BeginDeferWindowPos( 10);
1057 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1058 rcview.right - rcview.left + chgx,
1059 rcview.bottom - rcview.top + chgy,
1060 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1061 /* change position and sizes of the controls */
1062 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1064 int ctrlid = GetDlgCtrlID( ctrl);
1065 GetWindowRect( ctrl, &rc);
1066 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1067 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1069 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1070 0, 0,
1071 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1073 else if( rc.top > rcview.bottom)
1075 /* if it was below the shell view
1076 * move to bottom */
1077 switch( ctrlid)
1079 /* file name (edit or comboboxex) and file types combo change also width */
1080 case edt1:
1081 case cmb13:
1082 case cmb1:
1083 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1084 rc.right - rc.left + chgx, rc.bottom - rc.top,
1085 SWP_NOACTIVATE | SWP_NOZORDER);
1086 break;
1087 /* then these buttons must move out of the way */
1088 case IDOK:
1089 case IDCANCEL:
1090 case pshHelp:
1091 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1092 0, 0,
1093 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1094 break;
1095 default:
1096 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1097 0, 0,
1098 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1101 else if( rc.left > rcview.right)
1103 /* if it was to the right of the shell view
1104 * move to right */
1105 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1106 0, 0,
1107 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1109 else
1110 /* special cases */
1112 switch( ctrlid)
1114 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1115 case IDC_LOOKIN:
1116 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1117 rc.right - rc.left + chgx, rc.bottom - rc.top,
1118 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1119 break;
1120 case IDC_TOOLBARSTATIC:
1121 case IDC_TOOLBAR:
1122 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1123 0, 0,
1124 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1125 break;
1126 #endif
1127 /* not resized in windows. Since wine uses this invisible control
1128 * to size the browser view it needs to be resized */
1129 case IDC_SHELLSTATIC:
1130 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1131 rc.right - rc.left + chgx,
1132 rc.bottom - rc.top + chgy,
1133 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1134 break;
1138 if(fodInfos->DlgInfos.hwndCustomDlg &&
1139 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1141 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1142 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1144 GetWindowRect( ctrl, &rc);
1145 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1146 if( rc.top > rcview.bottom)
1148 /* if it was below the shell view
1149 * move to bottom */
1150 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1151 rc.right - rc.left, rc.bottom - rc.top,
1152 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1154 else if( rc.left > rcview.right)
1156 /* if it was to the right of the shell view
1157 * move to right */
1158 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1159 rc.right - rc.left, rc.bottom - rc.top,
1160 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1163 /* size the custom dialog at the end: some applications do some
1164 * control re-arranging at this point */
1165 GetClientRect(hwnd, &rc);
1166 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1167 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1169 EndDeferWindowPos( hdwp);
1170 /* should not be needed */
1171 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1172 return TRUE;
1175 /***********************************************************************
1176 * FileOpenDlgProc95
1178 * File open dialog procedure
1180 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1182 #if 0
1183 TRACE("%p 0x%04x\n", hwnd, uMsg);
1184 #endif
1186 switch(uMsg)
1188 case WM_INITDIALOG:
1190 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1191 RECT rc, rcstc;
1192 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1193 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1195 /* Some shell namespace extensions depend on COM being initialized. */
1196 if (SUCCEEDED(OleInitialize(NULL)))
1197 fodInfos->ole_initialized = TRUE;
1199 SetPropW(hwnd, filedlg_info_propnameW, fodInfos);
1201 FILEDLG95_InitControls(hwnd);
1203 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1205 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1206 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1207 RECT client, client_adjusted;
1209 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1211 style |= WS_SIZEBOX;
1212 ex_style |= WS_EX_WINDOWEDGE;
1214 else
1215 style &= ~WS_SIZEBOX;
1216 SetWindowLongW(hwnd, GWL_STYLE, style);
1217 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1219 GetClientRect( hwnd, &client );
1220 GetClientRect( hwnd, &client_adjusted );
1221 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1223 GetWindowRect( hwnd, &rc );
1224 rc.right += client_adjusted.right - client.right;
1225 rc.bottom += client_adjusted.bottom - client.bottom;
1226 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1227 SWP_NOZORDER | SWP_NOMOVE);
1229 GetWindowRect( hwnd, &rc );
1230 fodInfos->DlgInfos.hwndGrip =
1231 CreateWindowExA( 0, "SCROLLBAR", NULL,
1232 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1233 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1234 rc.right - gripx, rc.bottom - gripy,
1235 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1238 fodInfos->DlgInfos.hwndCustomDlg =
1239 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1241 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1242 FILEDLG95_FillControls(hwnd, wParam, lParam);
1244 if( fodInfos->DlgInfos.hwndCustomDlg)
1245 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1247 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1248 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1249 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1252 /* if the app has changed the position of the invisible listbox,
1253 * change that of the listview (browser) as well */
1254 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1255 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1256 if( !EqualRect( &rc, &rcstc))
1258 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1259 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1260 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1261 SWP_NOACTIVATE | SWP_NOZORDER);
1264 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1266 GetWindowRect( hwnd, &rc);
1267 fodInfos->sizedlg.cx = rc.right - rc.left;
1268 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1269 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1270 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1271 GetClientRect( hwnd, &rc);
1272 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1273 rc.right - gripx, rc.bottom - gripy,
1274 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1275 /* resize the dialog to the previous invocation */
1276 if( MemDialogSize.cx && MemDialogSize.cy)
1277 SetWindowPos( hwnd, NULL,
1278 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1279 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1282 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1283 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1285 return 0;
1287 case WM_SIZE:
1288 return FILEDLG95_OnWMSize(hwnd, wParam);
1289 case WM_GETMINMAXINFO:
1290 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1291 case WM_COMMAND:
1292 return FILEDLG95_OnWMCommand(hwnd, wParam);
1293 case WM_DRAWITEM:
1295 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1297 case IDC_LOOKIN:
1298 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1299 return TRUE;
1302 return FALSE;
1304 case WM_GETISHELLBROWSER:
1305 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1307 case WM_DESTROY:
1309 FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1310 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1311 MemDialogSize = fodInfos->sizedlg;
1312 RemovePropW(hwnd, filedlg_info_propnameW);
1313 return FALSE;
1315 case WM_NOTIFY:
1317 LPNMHDR lpnmh = (LPNMHDR)lParam;
1318 UINT stringId = -1;
1320 /* set up the button tooltips strings */
1321 if(TTN_GETDISPINFOA == lpnmh->code )
1323 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1324 switch(lpnmh->idFrom )
1326 /* Up folder button */
1327 case FCIDM_TB_UPFOLDER:
1328 stringId = IDS_UPFOLDER;
1329 break;
1330 /* New folder button */
1331 case FCIDM_TB_NEWFOLDER:
1332 stringId = IDS_NEWFOLDER;
1333 break;
1334 /* List option button */
1335 case FCIDM_TB_SMALLICON:
1336 stringId = IDS_LISTVIEW;
1337 break;
1338 /* Details option button */
1339 case FCIDM_TB_REPORTVIEW:
1340 stringId = IDS_REPORTVIEW;
1341 break;
1342 /* Desktop button */
1343 case FCIDM_TB_DESKTOP:
1344 stringId = IDS_TODESKTOP;
1345 break;
1346 default:
1347 stringId = 0;
1349 lpdi->hinst = COMDLG32_hInstance;
1350 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1352 return FALSE;
1354 default :
1355 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1356 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1357 return FALSE;
1361 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1363 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1364 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1367 /***********************************************************************
1368 * FILEDLG95_InitControls
1370 * WM_INITDIALOG message handler (before hook notification)
1372 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1374 BOOL win2000plus = FALSE;
1375 BOOL win98plus = FALSE;
1376 BOOL handledPath = FALSE;
1377 OSVERSIONINFOW osVi;
1378 static const WCHAR szwSlash[] = { '\\', 0 };
1379 static const WCHAR szwStar[] = { '*',0 };
1381 static const TBBUTTON tbb[] =
1383 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1384 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1385 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1386 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1387 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1388 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1389 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1390 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1391 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1393 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1395 RECT rectTB;
1396 RECT rectlook;
1398 HIMAGELIST toolbarImageList;
1399 SHFILEINFOA shFileInfo;
1400 ITEMIDLIST *desktopPidl;
1402 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1404 TRACE("%p\n", fodInfos);
1406 /* Get windows version emulating */
1407 osVi.dwOSVersionInfoSize = sizeof(osVi);
1408 GetVersionExW(&osVi);
1409 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1410 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1411 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1412 win2000plus = (osVi.dwMajorVersion > 4);
1413 if (win2000plus) win98plus = TRUE;
1415 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1418 /* Use either the edit or the comboboxex for the filename control */
1419 if (filename_is_edit( fodInfos ))
1421 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1422 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1424 else
1426 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1427 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1430 /* Get the hwnd of the controls */
1431 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1432 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1434 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1435 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1437 /* construct the toolbar */
1438 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1439 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1441 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1442 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1443 rectTB.left = rectlook.right;
1444 rectTB.top = rectlook.top-1;
1446 if (fodInfos->unicode)
1447 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1448 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1449 rectTB.left, rectTB.top,
1450 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1451 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1452 else
1453 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1454 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1455 rectTB.left, rectTB.top,
1456 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1457 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1459 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1461 /* FIXME: use TB_LOADIMAGES when implemented */
1462 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1463 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1464 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1466 /* Retrieve and add desktop icon to the toolbar */
1467 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1468 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1469 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1470 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1471 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1473 DestroyIcon(shFileInfo.hIcon);
1474 CoTaskMemFree(desktopPidl);
1476 /* Finish Toolbar Construction */
1477 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1478 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1480 /* Set the window text with the text specified in the OPENFILENAME structure */
1481 if(fodInfos->title)
1483 SetWindowTextW(hwnd,fodInfos->title);
1485 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1487 WCHAR buf[64];
1488 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1489 SetWindowTextW(hwnd, buf);
1492 /* Initialise the file name edit control */
1493 handledPath = FALSE;
1494 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1496 if(fodInfos->filename)
1498 /* 1. If win2000 or higher and filename contains a path, use it
1499 in preference over the lpstrInitialDir */
1500 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1501 WCHAR tmpBuf[MAX_PATH];
1502 WCHAR *nameBit;
1503 DWORD result;
1505 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1506 if (result) {
1508 /* nameBit is always shorter than the original filename. It may be NULL
1509 * when the filename contains only a drive name instead of file name */
1510 if (nameBit)
1512 lstrcpyW(fodInfos->filename,nameBit);
1513 *nameBit = 0x00;
1515 else
1516 *fodInfos->filename = '\0';
1518 MemFree(fodInfos->initdir);
1519 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1520 lstrcpyW(fodInfos->initdir, tmpBuf);
1521 handledPath = TRUE;
1522 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1523 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1525 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1527 } else {
1528 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1532 /* 2. (All platforms) If initdir is not null, then use it */
1533 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1535 /* Work out the proper path as supplied one might be relative */
1536 /* (Here because supplying '.' as dir browses to My Computer) */
1537 WCHAR tmpBuf[MAX_PATH];
1538 WCHAR tmpBuf2[MAX_PATH];
1539 WCHAR *nameBit;
1540 DWORD result;
1542 lstrcpyW(tmpBuf, fodInfos->initdir);
1543 if (PathFileExistsW(tmpBuf)) {
1544 /* initdir does not have to be a directory. If a file is
1545 * specified, the dir part is taken */
1546 if (PathIsDirectoryW(tmpBuf)) {
1547 PathAddBackslashW(tmpBuf);
1548 lstrcatW(tmpBuf, szwStar);
1550 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1551 if (result) {
1552 *nameBit = 0x00;
1553 MemFree(fodInfos->initdir);
1554 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1555 lstrcpyW(fodInfos->initdir, tmpBuf2);
1556 handledPath = TRUE;
1557 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1560 else if (fodInfos->initdir)
1562 MemFree(fodInfos->initdir);
1563 fodInfos->initdir = NULL;
1564 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1568 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1570 /* 3. All except w2k+: if filename contains a path use it */
1571 if (!win2000plus && fodInfos->filename &&
1572 *fodInfos->filename &&
1573 strpbrkW(fodInfos->filename, szwSlash)) {
1574 WCHAR tmpBuf[MAX_PATH];
1575 WCHAR *nameBit;
1576 DWORD result;
1578 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1579 tmpBuf, &nameBit);
1580 if (result) {
1581 int len;
1583 /* nameBit is always shorter than the original filename */
1584 lstrcpyW(fodInfos->filename, nameBit);
1585 *nameBit = 0x00;
1587 len = lstrlenW(tmpBuf);
1588 MemFree(fodInfos->initdir);
1589 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1590 lstrcpyW(fodInfos->initdir, tmpBuf);
1592 handledPath = TRUE;
1593 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1594 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1596 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1599 /* 4. Win2000+: Recently used */
1600 if (!handledPath && win2000plus) {
1601 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1602 fodInfos->initdir[0] = '\0';
1604 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1606 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1607 handledPath = TRUE;
1608 }else{
1609 MemFree(fodInfos->initdir);
1610 fodInfos->initdir = NULL;
1614 /* 5. win98+ and win2000+ if any files of specified filter types in
1615 current directory, use it */
1616 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1618 LPCWSTR lpstrPos = fodInfos->filter;
1619 WIN32_FIND_DATAW FindFileData;
1620 HANDLE hFind;
1622 while (1)
1624 /* filter is a list... title\0ext\0......\0\0 */
1626 /* Skip the title */
1627 if(! *lpstrPos) break; /* end */
1628 lpstrPos += lstrlenW(lpstrPos) + 1;
1630 /* See if any files exist in the current dir with this extension */
1631 if(! *lpstrPos) break; /* end */
1633 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1635 if (hFind == INVALID_HANDLE_VALUE) {
1636 /* None found - continue search */
1637 lpstrPos += lstrlenW(lpstrPos) + 1;
1639 } else {
1641 MemFree(fodInfos->initdir);
1642 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1643 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1645 handledPath = TRUE;
1646 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1647 debugstr_w(lpstrPos));
1648 FindClose(hFind);
1649 break;
1654 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1655 if (!handledPath && (win2000plus || win98plus)) {
1656 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1658 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1660 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1662 /* last fallback */
1663 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1664 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1665 } else {
1666 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1668 } else {
1669 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1671 handledPath = TRUE;
1672 } else if (!handledPath) {
1673 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1674 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1675 handledPath = TRUE;
1676 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1679 SetFocus( fodInfos->DlgInfos.hwndFileName );
1680 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1682 /* Must the open as read only check box be checked ?*/
1683 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1685 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1688 /* Must the open as read only check box be hidden? */
1689 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1691 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1692 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1695 /* Must the help button be hidden? */
1696 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1698 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1699 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1702 /* change Open to Save */
1703 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1705 WCHAR buf[16];
1706 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1707 SetDlgItemTextW(hwnd, IDOK, buf);
1708 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1709 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1712 /* Initialize the filter combo box */
1713 FILEDLG95_FILETYPE_Init(hwnd);
1715 return 0;
1718 /***********************************************************************
1719 * FILEDLG95_ResizeControls
1721 * WM_INITDIALOG message handler (after hook notification)
1723 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1725 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1727 if (fodInfos->DlgInfos.hwndCustomDlg)
1729 RECT rc;
1730 UINT flags = SWP_NOACTIVATE;
1732 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1733 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1735 /* resize the custom dialog to the parent size */
1736 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1737 GetClientRect(hwnd, &rc);
1738 else
1740 /* our own fake template is zero sized and doesn't have children, so
1741 * there is no need to resize it. Picasa depends on it.
1743 flags |= SWP_NOSIZE;
1744 SetRectEmpty(&rc);
1746 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1747 0, 0, rc.right, rc.bottom, flags);
1749 else
1751 /* Resize the height; if opened as read-only, checkbox and help button are
1752 * hidden and we are not using a custom template nor a customDialog
1754 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1755 (!(fodInfos->ofnInfos->Flags &
1756 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1758 RECT rectDlg, rectHelp, rectCancel;
1759 GetWindowRect(hwnd, &rectDlg);
1760 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1761 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1762 /* subtract the height of the help button plus the space between the help
1763 * button and the cancel button to the height of the dialog
1765 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1766 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1767 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1770 return TRUE;
1773 /***********************************************************************
1774 * FILEDLG95_FillControls
1776 * WM_INITDIALOG message handler (after hook notification)
1778 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1780 LPITEMIDLIST pidlItemId = NULL;
1782 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1784 TRACE("dir=%s file=%s\n",
1785 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1787 /* Get the initial directory pidl */
1789 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1791 WCHAR path[MAX_PATH];
1793 GetCurrentDirectoryW(MAX_PATH,path);
1794 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1797 /* Initialise shell objects */
1798 FILEDLG95_SHELL_Init(hwnd);
1800 /* Initialize the Look In combo box */
1801 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1803 /* Browse to the initial directory */
1804 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1806 /* Free pidlItem memory */
1807 COMDLG32_SHFree(pidlItemId);
1809 return TRUE;
1811 /***********************************************************************
1812 * FILEDLG95_Clean
1814 * Regroups all the cleaning functions of the filedlg
1816 void FILEDLG95_Clean(HWND hwnd)
1818 FILEDLG95_FILETYPE_Clean(hwnd);
1819 FILEDLG95_LOOKIN_Clean(hwnd);
1820 FILEDLG95_SHELL_Clean(hwnd);
1822 /***********************************************************************
1823 * FILEDLG95_OnWMCommand
1825 * WM_COMMAND message handler
1827 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1829 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1830 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1831 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1833 switch(wID)
1835 /* OK button */
1836 case IDOK:
1837 FILEDLG95_OnOpen(hwnd);
1838 break;
1839 /* Cancel button */
1840 case IDCANCEL:
1841 FILEDLG95_Clean(hwnd);
1842 EndDialog(hwnd, FALSE);
1843 break;
1844 /* Filetype combo box */
1845 case IDC_FILETYPE:
1846 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1847 break;
1848 /* LookIn combo box */
1849 case IDC_LOOKIN:
1850 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1851 break;
1853 /* --- toolbar --- */
1854 /* Up folder button */
1855 case FCIDM_TB_UPFOLDER:
1856 FILEDLG95_SHELL_UpFolder(hwnd);
1857 break;
1858 /* New folder button */
1859 case FCIDM_TB_NEWFOLDER:
1860 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1861 break;
1862 /* List option button */
1863 case FCIDM_TB_SMALLICON:
1864 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1865 break;
1866 /* Details option button */
1867 case FCIDM_TB_REPORTVIEW:
1868 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1869 break;
1870 /* Details option button */
1871 case FCIDM_TB_DESKTOP:
1872 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1873 break;
1875 case edt1:
1876 case cmb13:
1877 break;
1880 /* Do not use the listview selection anymore */
1881 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1882 return 0;
1885 /***********************************************************************
1886 * FILEDLG95_OnWMGetIShellBrowser
1888 * WM_GETISHELLBROWSER message handler
1890 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1892 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1894 TRACE("\n");
1896 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1898 return TRUE;
1902 /***********************************************************************
1903 * FILEDLG95_SendFileOK
1905 * Sends the CDN_FILEOK notification if required
1907 * RETURNS
1908 * TRUE if the dialog should close
1909 * FALSE if the dialog should not be closed
1911 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1913 /* ask the hook if we can close */
1914 if(IsHooked(fodInfos))
1916 LRESULT retval = 0;
1918 TRACE("---\n");
1919 /* First send CDN_FILEOK as MSDN doc says */
1920 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1921 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1922 if( retval)
1924 TRACE("canceled\n");
1925 return FALSE;
1928 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1929 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1930 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1931 if( retval)
1933 TRACE("canceled\n");
1934 return FALSE;
1937 return TRUE;
1940 /***********************************************************************
1941 * FILEDLG95_OnOpenMultipleFiles
1943 * Handles the opening of multiple files.
1945 * FIXME
1946 * check destination buffer size
1948 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1950 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1951 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1952 UINT nCount, nSizePath;
1954 TRACE("\n");
1956 if(fodInfos->unicode)
1958 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1959 ofn->lpstrFile[0] = '\0';
1961 else
1963 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1964 ofn->lpstrFile[0] = '\0';
1967 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1969 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1970 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1971 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1973 LPWSTR lpstrTemp = lpstrFileList;
1975 for ( nCount = 0; nCount < nFileCount; nCount++ )
1977 LPITEMIDLIST pidl;
1979 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1980 if (!pidl)
1982 WCHAR lpstrNotFound[100];
1983 WCHAR lpstrMsg[100];
1984 WCHAR tmp[400];
1985 static const WCHAR nl[] = {'\n',0};
1987 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1988 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1990 lstrcpyW(tmp, lpstrTemp);
1991 lstrcatW(tmp, nl);
1992 lstrcatW(tmp, lpstrNotFound);
1993 lstrcatW(tmp, nl);
1994 lstrcatW(tmp, lpstrMsg);
1996 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1997 return FALSE;
2000 /* move to the next file in the list of files */
2001 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2002 COMDLG32_SHFree(pidl);
2006 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2007 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2009 /* For "oldstyle" dialog the components have to
2010 be separated by blanks (not '\0'!) and short
2011 filenames have to be used! */
2012 FIXME("Components have to be separated by blanks\n");
2014 if(fodInfos->unicode)
2016 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2017 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2018 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2020 else
2022 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2024 if (ofn->lpstrFile != NULL)
2026 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2027 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2028 if (ofn->nMaxFile > nSizePath)
2030 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2031 ofn->lpstrFile + nSizePath,
2032 ofn->nMaxFile - nSizePath, NULL, NULL);
2037 fodInfos->ofnInfos->nFileOffset = nSizePath;
2038 fodInfos->ofnInfos->nFileExtension = 0;
2040 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2041 return FALSE;
2043 /* clean and exit */
2044 FILEDLG95_Clean(hwnd);
2045 return EndDialog(hwnd,TRUE);
2048 /* Returns the 'slot name' of the given module_name in the registry's
2049 * most-recently-used list. This will be an ASCII value in the
2050 * range ['a','z'). Returns zero on error.
2052 * The slot's value in the registry has the form:
2053 * module_name\0mru_path\0
2055 * If stored_path is given, then stored_path will contain the path name
2056 * stored in the registry's MRU list for the given module_name.
2058 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2059 * MRU list key for the given module_name.
2061 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2063 WCHAR mru_list[32], *cur_mru_slot;
2064 BOOL taken[25] = {0};
2065 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2066 HKEY hkey_tmp, *hkey;
2067 LONG ret;
2069 if(hkey_ret)
2070 hkey = hkey_ret;
2071 else
2072 hkey = &hkey_tmp;
2074 if(stored_path)
2075 *stored_path = '\0';
2077 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2078 if(ret){
2079 WARN("Unable to create MRU key: %d\n", ret);
2080 return 0;
2083 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2084 (LPBYTE)mru_list, &mru_list_size);
2085 if(ret || key_type != REG_SZ){
2086 if(ret == ERROR_FILE_NOT_FOUND)
2087 return 'a';
2089 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2090 RegCloseKey(*hkey);
2091 return 0;
2094 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2095 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2096 DWORD value_data_size = sizeof(value_data);
2098 *value_name = *cur_mru_slot;
2100 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2101 &key_type, (LPBYTE)value_data, &value_data_size);
2102 if(ret || key_type != REG_BINARY){
2103 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2104 continue;
2107 if(!strcmpiW(module_name, value_data)){
2108 if(!hkey_ret)
2109 RegCloseKey(*hkey);
2110 if(stored_path)
2111 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2112 return *value_name;
2116 if(!hkey_ret)
2117 RegCloseKey(*hkey);
2119 /* the module name isn't in the registry, so find the next open slot */
2120 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2121 taken[*cur_mru_slot - 'a'] = TRUE;
2122 for(i = 0; i < 25; ++i){
2123 if(!taken[i])
2124 return i + 'a';
2127 /* all slots are taken, so return the last one in MRUList */
2128 --cur_mru_slot;
2129 return *cur_mru_slot;
2132 /* save the given filename as most-recently-used path for this module */
2133 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2135 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2136 LONG ret;
2137 HKEY hkey;
2139 /* get the current executable's name */
2140 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2141 WARN("GotModuleFileName failed: %d\n", GetLastError());
2142 return;
2144 module_name = strrchrW(module_path, '\\');
2145 if(!module_name)
2146 module_name = module_path;
2147 else
2148 module_name += 1;
2150 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2151 if(!slot)
2152 return;
2153 *slot_name = slot;
2155 { /* update the slot's info */
2156 WCHAR *path_ends, *final;
2157 DWORD path_len, final_len;
2159 /* use only the path segment of `filename' */
2160 path_ends = strrchrW(filename, '\\');
2161 path_len = path_ends - filename;
2163 final_len = path_len + lstrlenW(module_name) + 2;
2165 final = MemAlloc(final_len * sizeof(WCHAR));
2166 if(!final)
2167 return;
2168 lstrcpyW(final, module_name);
2169 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2170 final[final_len-1] = '\0';
2172 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2173 final_len * sizeof(WCHAR));
2174 if(ret){
2175 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2176 MemFree(final);
2177 RegCloseKey(hkey);
2178 return;
2181 MemFree(final);
2184 { /* update MRUList value */
2185 WCHAR old_mru_list[32], new_mru_list[32];
2186 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2187 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2189 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2190 (LPBYTE)old_mru_list, &mru_list_size);
2191 if(ret || key_type != REG_SZ){
2192 if(ret == ERROR_FILE_NOT_FOUND){
2193 new_mru_list[0] = slot;
2194 new_mru_list[1] = '\0';
2195 }else{
2196 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2197 RegCloseKey(hkey);
2198 return;
2200 }else{
2201 /* copy old list data over so that the new slot is at the start
2202 * of the list */
2203 *new_mru_slot++ = slot;
2204 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2205 if(*old_mru_slot != slot)
2206 *new_mru_slot++ = *old_mru_slot;
2208 *new_mru_slot = '\0';
2211 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2212 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2213 if(ret){
2214 WARN("Error saving MRUList data: %d\n", ret);
2215 RegCloseKey(hkey);
2216 return;
2221 /* load the most-recently-used path for this module */
2222 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2224 WCHAR module_path[MAX_PATH], *module_name;
2226 /* get the current executable's name */
2227 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2228 WARN("GotModuleFileName failed: %d\n", GetLastError());
2229 return;
2231 module_name = strrchrW(module_path, '\\');
2232 if(!module_name)
2233 module_name = module_path;
2234 else
2235 module_name += 1;
2237 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2238 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2241 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2243 WCHAR strMsgTitle[MAX_PATH];
2244 WCHAR strMsgText [MAX_PATH];
2245 if (idCaption)
2246 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2247 else
2248 strMsgTitle[0] = '\0';
2249 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2250 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2253 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2254 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2256 int nOpenAction = defAction;
2257 LPWSTR lpszTemp, lpszTemp1;
2258 LPITEMIDLIST pidl = NULL;
2259 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2261 /* check for invalid chars */
2262 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2264 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2265 return FALSE;
2268 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2270 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2271 while (lpszTemp1)
2273 LPSHELLFOLDER lpsfChild;
2274 WCHAR lpwstrTemp[MAX_PATH];
2275 DWORD dwEaten, dwAttributes;
2276 LPWSTR p;
2278 lstrcpyW(lpwstrTemp, lpszTemp);
2279 p = PathFindNextComponentW(lpwstrTemp);
2281 if (!p) break; /* end of path */
2283 *p = 0;
2284 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2286 /* There are no wildcards when OFN_NOVALIDATE is set */
2287 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2289 static const WCHAR wszWild[] = { '*', '?', 0 };
2290 /* if the last element is a wildcard do a search */
2291 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2293 nOpenAction = ONOPEN_SEARCH;
2294 break;
2297 lpszTemp1 = lpszTemp;
2299 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2301 /* append a backslash to drive letters */
2302 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2303 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2304 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2306 PathAddBackslashW(lpwstrTemp);
2309 dwAttributes = SFGAO_FOLDER;
2310 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2312 /* the path component is valid, we have a pidl of the next path component */
2313 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2314 if(dwAttributes & SFGAO_FOLDER)
2316 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2318 ERR("bind to failed\n"); /* should not fail */
2319 break;
2321 IShellFolder_Release(*ppsf);
2322 *ppsf = lpsfChild;
2323 lpsfChild = NULL;
2325 else
2327 TRACE("value\n");
2329 /* end dialog, return value */
2330 nOpenAction = ONOPEN_OPEN;
2331 break;
2333 COMDLG32_SHFree(pidl);
2334 pidl = NULL;
2336 else if (!(flags & OFN_NOVALIDATE))
2338 if(*lpszTemp || /* points to trailing null for last path element */
2339 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2341 if(flags & OFN_PATHMUSTEXIST)
2343 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2344 break;
2347 else
2349 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2351 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2352 break;
2355 /* change to the current folder */
2356 nOpenAction = ONOPEN_OPEN;
2357 break;
2359 else
2361 nOpenAction = ONOPEN_OPEN;
2362 break;
2365 if(pidl) COMDLG32_SHFree(pidl);
2367 return nOpenAction;
2370 /***********************************************************************
2371 * FILEDLG95_OnOpen
2373 * Ok button WM_COMMAND message handler
2375 * If the function succeeds, the return value is nonzero.
2377 BOOL FILEDLG95_OnOpen(HWND hwnd)
2379 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2380 LPWSTR lpstrFileList;
2381 UINT nFileCount = 0;
2382 UINT sizeUsed = 0;
2383 BOOL ret = TRUE;
2384 WCHAR lpstrPathAndFile[MAX_PATH];
2385 LPSHELLFOLDER lpsf = NULL;
2386 int nOpenAction;
2388 TRACE("hwnd=%p\n", hwnd);
2390 /* try to browse the selected item */
2391 if(BrowseSelectedFolder(hwnd))
2392 return FALSE;
2394 /* get the files from the edit control */
2395 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2397 if(nFileCount == 0)
2398 return FALSE;
2400 if(nFileCount > 1)
2402 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2403 goto ret;
2406 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2409 Step 1: Build a complete path name from the current folder and
2410 the filename or path in the edit box.
2411 Special cases:
2412 - the path in the edit box is a root path
2413 (with or without drive letter)
2414 - the edit box contains ".." (or a path with ".." in it)
2417 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2418 MemFree(lpstrFileList);
2421 Step 2: here we have a cleaned up path
2423 We have to parse the path step by step to see if we have to browse
2424 to a folder if the path points to a directory or the last
2425 valid element is a directory.
2427 valid variables:
2428 lpstrPathAndFile: cleaned up path
2431 if (nFileCount &&
2432 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2433 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2434 nOpenAction = ONOPEN_OPEN;
2435 else
2436 nOpenAction = ONOPEN_BROWSE;
2438 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2439 fodInfos->ofnInfos->Flags,
2440 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2441 nOpenAction);
2442 if(!nOpenAction)
2443 goto ret;
2446 Step 3: here we have a cleaned up and validated path
2448 valid variables:
2449 lpsf: ShellFolder bound to the rightmost valid path component
2450 lpstrPathAndFile: cleaned up path
2451 nOpenAction: action to do
2453 TRACE("end validate sf=%p\n", lpsf);
2455 switch(nOpenAction)
2457 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2458 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2460 int iPos;
2461 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2462 DWORD len;
2464 /* replace the current filter */
2465 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2466 len = lstrlenW(lpszTemp)+1;
2467 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2468 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2470 /* set the filter cb to the extension when possible */
2471 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2472 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2474 /* fall through */
2475 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2476 TRACE("ONOPEN_BROWSE\n");
2478 IPersistFolder2 * ppf2;
2479 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2481 LPITEMIDLIST pidlCurrent;
2482 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2483 IPersistFolder2_Release(ppf2);
2484 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2486 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2487 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2489 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2490 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2493 else if( nOpenAction == ONOPEN_SEARCH )
2495 if (fodInfos->Shell.FOIShellView)
2496 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2498 COMDLG32_SHFree(pidlCurrent);
2499 if (filename_is_edit( fodInfos ))
2500 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2501 else
2503 HWND hwnd;
2505 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2506 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2510 ret = FALSE;
2511 break;
2512 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2513 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2515 WCHAR *ext = NULL;
2517 /* update READONLY check box flag */
2518 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2519 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2520 else
2521 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2523 /* Attach the file extension with file name*/
2524 ext = PathFindExtensionW(lpstrPathAndFile);
2525 if (! *ext && fodInfos->defext)
2527 /* if no extension is specified with file name, then */
2528 /* attach the extension from file filter or default one */
2530 WCHAR *filterExt = NULL;
2531 LPWSTR lpstrFilter = NULL;
2532 static const WCHAR szwDot[] = {'.',0};
2533 int PathLength = lstrlenW(lpstrPathAndFile);
2535 /*Get the file extension from file type filter*/
2536 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2537 fodInfos->ofnInfos->nFilterIndex-1);
2539 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2541 WCHAR* filterSearchIndex;
2542 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2543 strcpyW(filterExt, lpstrFilter);
2545 /* if a semicolon-separated list of file extensions was given, do not include the
2546 semicolon or anything after it in the extension.
2547 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2548 filterSearchIndex = strchrW(filterExt, ';');
2549 if (filterSearchIndex)
2551 filterSearchIndex[0] = '\0';
2554 /* find the file extension by searching for the first dot in filterExt */
2555 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2556 /* if the extension is invalid or contains a glob, ignore it */
2557 filterSearchIndex = strchrW(filterExt, '.');
2558 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2560 strcpyW(filterExt, filterSearchIndex);
2562 else
2564 HeapFree(GetProcessHeap(), 0, filterExt);
2565 filterExt = NULL;
2569 if (!filterExt)
2571 /* use the default file extension */
2572 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2573 strcpyW(filterExt, fodInfos->defext);
2576 if (*filterExt) /* ignore filterExt="" */
2578 /* Attach the dot*/
2579 lstrcatW(lpstrPathAndFile, szwDot);
2580 /* Attach the extension */
2581 lstrcatW(lpstrPathAndFile, filterExt);
2584 HeapFree(GetProcessHeap(), 0, filterExt);
2586 /* In Open dialog: if file does not exist try without extension */
2587 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2588 lpstrPathAndFile[PathLength] = '\0';
2590 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2591 if (*ext)
2592 ext++;
2593 if (!lstrcmpiW(fodInfos->defext, ext))
2594 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2595 else
2596 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2599 /* In Save dialog: check if the file already exists */
2600 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2601 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2602 && PathFileExistsW(lpstrPathAndFile))
2604 WCHAR lpstrOverwrite[100];
2605 int answer;
2607 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2608 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2609 MB_YESNO | MB_ICONEXCLAMATION);
2610 if (answer == IDNO || answer == IDCANCEL)
2612 ret = FALSE;
2613 goto ret;
2617 /* In Open dialog: check if it should be created if it doesn't exist */
2618 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2619 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2620 && !PathFileExistsW(lpstrPathAndFile))
2622 WCHAR lpstrCreate[100];
2623 int answer;
2625 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2626 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2627 MB_YESNO | MB_ICONEXCLAMATION);
2628 if (answer == IDNO || answer == IDCANCEL)
2630 ret = FALSE;
2631 goto ret;
2635 /* Check that the size of the file does not exceed buffer size.
2636 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2637 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2638 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2641 /* fill destination buffer */
2642 if (fodInfos->ofnInfos->lpstrFile)
2644 if(fodInfos->unicode)
2646 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2648 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2649 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2650 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2652 else
2654 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2656 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2657 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2658 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2659 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2663 if(fodInfos->unicode)
2665 LPWSTR lpszTemp;
2667 /* set filename offset */
2668 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2669 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2671 /* set extension offset */
2672 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2673 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2675 else
2677 LPSTR lpszTemp;
2678 CHAR tempFileA[MAX_PATH];
2680 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2681 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2682 tempFileA, sizeof(tempFileA), NULL, NULL);
2684 /* set filename offset */
2685 lpszTemp = PathFindFileNameA(tempFileA);
2686 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2688 /* set extension offset */
2689 lpszTemp = PathFindExtensionA(tempFileA);
2690 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2693 /* set the lpstrFileTitle */
2694 if(fodInfos->ofnInfos->lpstrFileTitle)
2696 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2697 if(fodInfos->unicode)
2699 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2700 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2702 else
2704 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2705 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2706 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2710 /* copy currently selected filter to lpstrCustomFilter */
2711 if (fodInfos->ofnInfos->lpstrCustomFilter)
2713 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2714 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2715 NULL, 0, NULL, NULL);
2716 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2718 LPSTR s = ofn->lpstrCustomFilter;
2719 s += strlen(ofn->lpstrCustomFilter)+1;
2720 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2721 s, len, NULL, NULL);
2726 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2727 goto ret;
2729 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2731 TRACE("close\n");
2732 FILEDLG95_Clean(hwnd);
2733 ret = EndDialog(hwnd, TRUE);
2735 else
2737 WORD size;
2739 size = lstrlenW(lpstrPathAndFile) + 1;
2740 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2741 size += 1;
2742 /* return needed size in first two bytes of lpstrFile */
2743 if(fodInfos->ofnInfos->lpstrFile)
2744 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2745 FILEDLG95_Clean(hwnd);
2746 ret = EndDialog(hwnd, FALSE);
2747 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2750 break;
2753 ret:
2754 if(lpsf) IShellFolder_Release(lpsf);
2755 return ret;
2758 /***********************************************************************
2759 * FILEDLG95_SHELL_Init
2761 * Initialisation of the shell objects
2763 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2765 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2767 TRACE("\n");
2770 * Initialisation of the FileOpenDialogInfos structure
2773 /* Shell */
2775 /*ShellInfos */
2776 fodInfos->ShellInfos.hwndOwner = hwnd;
2778 /* Disable multi-select if flag not set */
2779 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2781 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2783 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2784 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2786 /* Construct the IShellBrowser interface */
2787 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2789 return NOERROR;
2792 /***********************************************************************
2793 * FILEDLG95_SHELL_ExecuteCommand
2795 * Change the folder option and refresh the view
2796 * If the function succeeds, the return value is nonzero.
2798 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2800 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2801 IContextMenu * pcm;
2803 TRACE("(%p,%p)\n", hwnd, lpVerb);
2805 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2806 SVGIO_BACKGROUND,
2807 &IID_IContextMenu,
2808 (LPVOID*)&pcm)))
2810 CMINVOKECOMMANDINFO ci;
2811 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2812 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2813 ci.lpVerb = lpVerb;
2814 ci.hwnd = hwnd;
2816 IContextMenu_InvokeCommand(pcm, &ci);
2817 IContextMenu_Release(pcm);
2820 return FALSE;
2823 /***********************************************************************
2824 * FILEDLG95_SHELL_UpFolder
2826 * Browse to the specified object
2827 * If the function succeeds, the return value is nonzero.
2829 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2831 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2833 TRACE("\n");
2835 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2836 NULL,
2837 SBSP_PARENT)))
2839 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2840 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2841 return TRUE;
2843 return FALSE;
2846 /***********************************************************************
2847 * FILEDLG95_SHELL_BrowseToDesktop
2849 * Browse to the Desktop
2850 * If the function succeeds, the return value is nonzero.
2852 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2854 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2855 LPITEMIDLIST pidl;
2856 HRESULT hres;
2858 TRACE("\n");
2860 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2861 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2862 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2863 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2864 COMDLG32_SHFree(pidl);
2865 return SUCCEEDED(hres);
2867 /***********************************************************************
2868 * FILEDLG95_SHELL_Clean
2870 * Cleans the memory used by shell objects
2872 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2874 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2876 TRACE("\n");
2878 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2880 /* clean Shell interfaces */
2881 if (fodInfos->Shell.FOIShellView)
2883 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2884 IShellView_Release(fodInfos->Shell.FOIShellView);
2886 if (fodInfos->Shell.FOIShellFolder)
2887 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2888 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2889 if (fodInfos->Shell.FOIDataObject)
2890 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2893 /***********************************************************************
2894 * FILEDLG95_FILETYPE_Init
2896 * Initialisation of the file type combo box
2898 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2900 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2901 int nFilters = 0; /* number of filters */
2902 int nFilterIndexCB;
2904 TRACE("\n");
2906 if(fodInfos->customfilter)
2908 /* customfilter has one entry... title\0ext\0
2909 * Set first entry of combo box item with customfilter
2911 LPWSTR lpstrExt;
2912 LPCWSTR lpstrPos = fodInfos->customfilter;
2914 /* Get the title */
2915 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2917 /* Copy the extensions */
2918 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2919 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2920 lstrcpyW(lpstrExt,lpstrPos);
2922 /* Add the item at the end of the combo */
2923 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2924 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2925 nFilters++;
2927 if(fodInfos->filter)
2929 LPCWSTR lpstrPos = fodInfos->filter;
2931 for(;;)
2933 /* filter is a list... title\0ext\0......\0\0
2934 * Set the combo item text to the title and the item data
2935 * to the ext
2937 LPCWSTR lpstrDisplay;
2938 LPWSTR lpstrExt;
2940 /* Get the title */
2941 if(! *lpstrPos) break; /* end */
2942 lpstrDisplay = lpstrPos;
2943 lpstrPos += lstrlenW(lpstrPos) + 1;
2945 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2947 nFilters++;
2949 /* Copy the extensions */
2950 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2951 lstrcpyW(lpstrExt,lpstrPos);
2952 lpstrPos += lstrlenW(lpstrPos) + 1;
2954 /* Add the item at the end of the combo */
2955 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2957 /* malformed filters are added anyway... */
2958 if (!*lpstrExt) break;
2963 * Set the current filter to the one specified
2964 * in the initialisation structure
2966 if (fodInfos->filter || fodInfos->customfilter)
2968 LPWSTR lpstrFilter;
2970 /* Check to make sure our index isn't out of bounds. */
2971 if ( fodInfos->ofnInfos->nFilterIndex >
2972 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2973 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2975 /* set default filter index */
2976 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2977 fodInfos->ofnInfos->nFilterIndex = 1;
2979 /* calculate index of Combo Box item */
2980 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2981 if (fodInfos->customfilter == NULL)
2982 nFilterIndexCB--;
2984 /* Set the current index selection. */
2985 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2987 /* Get the corresponding text string from the combo box. */
2988 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2989 nFilterIndexCB);
2991 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2992 lpstrFilter = NULL;
2994 if(lpstrFilter)
2996 DWORD len;
2997 CharLowerW(lpstrFilter); /* lowercase */
2998 len = lstrlenW(lpstrFilter)+1;
2999 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3000 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3002 } else
3003 fodInfos->ofnInfos->nFilterIndex = 0;
3004 return S_OK;
3007 /***********************************************************************
3008 * FILEDLG95_FILETYPE_OnCommand
3010 * WM_COMMAND of the file type combo box
3011 * If the function succeeds, the return value is nonzero.
3013 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3015 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3017 switch(wNotifyCode)
3019 case CBN_SELENDOK:
3021 LPWSTR lpstrFilter;
3023 /* Get the current item of the filetype combo box */
3024 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3026 /* set the current filter index */
3027 fodInfos->ofnInfos->nFilterIndex = iItem +
3028 (fodInfos->customfilter == NULL ? 1 : 0);
3030 /* Set the current filter with the current selection */
3031 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3033 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3034 iItem);
3035 if((INT_PTR)lpstrFilter != CB_ERR)
3037 DWORD len;
3038 CharLowerW(lpstrFilter); /* lowercase */
3039 len = lstrlenW(lpstrFilter)+1;
3040 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3041 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3042 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3043 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3046 /* Refresh the actual view to display the included items*/
3047 if (fodInfos->Shell.FOIShellView)
3048 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3051 return FALSE;
3053 /***********************************************************************
3054 * FILEDLG95_FILETYPE_SearchExt
3056 * searches for an extension in the filetype box
3058 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3060 int i, iCount = CBGetCount(hwnd);
3062 TRACE("%s\n", debugstr_w(lpstrExt));
3064 if(iCount != CB_ERR)
3066 for(i=0;i<iCount;i++)
3068 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3069 return i;
3072 return -1;
3075 /***********************************************************************
3076 * FILEDLG95_FILETYPE_Clean
3078 * Clean the memory used by the filetype combo box
3080 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3082 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3083 int iPos;
3084 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3086 TRACE("\n");
3088 /* Delete each string of the combo and their associated data */
3089 if(iCount != CB_ERR)
3091 for(iPos = iCount-1;iPos>=0;iPos--)
3093 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3094 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3097 /* Current filter */
3098 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3102 /***********************************************************************
3103 * FILEDLG95_LOOKIN_Init
3105 * Initialisation of the look in combo box
3108 /* Small helper function, to determine if the unixfs shell extension is rooted
3109 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3111 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3112 HKEY hKey;
3113 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3114 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3115 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3116 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3117 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3118 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3119 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3121 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3122 return FALSE;
3124 RegCloseKey(hKey);
3125 return TRUE;
3128 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3130 IShellFolder *psfRoot, *psfDrives;
3131 IEnumIDList *lpeRoot, *lpeDrives;
3132 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3133 HDC hdc;
3134 TEXTMETRICW tm;
3135 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3137 TRACE("\n");
3139 liInfos->iMaxIndentation = 0;
3141 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3143 hdc = GetDC( hwndCombo );
3144 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3145 GetTextMetricsW( hdc, &tm );
3146 ReleaseDC( hwndCombo, hdc );
3148 /* set item height for both text field and listbox */
3149 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3150 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3152 /* Turn on the extended UI for the combo box like Windows does */
3153 CBSetExtendedUI(hwndCombo, TRUE);
3155 /* Initialise data of Desktop folder */
3156 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3157 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3158 COMDLG32_SHFree(pidlTmp);
3160 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3162 SHGetDesktopFolder(&psfRoot);
3164 if (psfRoot)
3166 /* enumerate the contents of the desktop */
3167 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3169 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3171 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3173 /* If the unixfs extension is rooted, we don't expand the drives by default */
3174 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3176 /* special handling for CSIDL_DRIVES */
3177 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3179 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3181 /* enumerate the drives */
3182 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3184 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3186 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3187 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3188 COMDLG32_SHFree(pidlAbsTmp);
3189 COMDLG32_SHFree(pidlTmp1);
3191 IEnumIDList_Release(lpeDrives);
3193 IShellFolder_Release(psfDrives);
3198 COMDLG32_SHFree(pidlTmp);
3200 IEnumIDList_Release(lpeRoot);
3202 IShellFolder_Release(psfRoot);
3205 COMDLG32_SHFree(pidlDrives);
3208 /***********************************************************************
3209 * FILEDLG95_LOOKIN_DrawItem
3211 * WM_DRAWITEM message handler
3213 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3215 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3216 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3217 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3218 RECT rectText;
3219 RECT rectIcon;
3220 SHFILEINFOW sfi;
3221 HIMAGELIST ilItemImage;
3222 int iIndentation;
3223 TEXTMETRICW tm;
3224 LPSFOLDER tmpFolder;
3225 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3226 UINT icon_width, icon_height;
3228 TRACE("\n");
3230 if(pDIStruct->itemID == -1)
3231 return 0;
3233 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3234 pDIStruct->itemID)))
3235 return 0;
3238 icon_width = GetSystemMetrics(SM_CXICON);
3239 icon_height = GetSystemMetrics(SM_CYICON);
3240 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3242 icon_width = GetSystemMetrics(SM_CXSMICON);
3243 icon_height = GetSystemMetrics(SM_CYSMICON);
3244 shgfi_flags |= SHGFI_SMALLICON;
3247 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3248 0, &sfi, sizeof (sfi), shgfi_flags );
3250 /* Is this item selected ? */
3251 if(pDIStruct->itemState & ODS_SELECTED)
3253 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3254 SetBkColor(pDIStruct->hDC,crHighLight);
3255 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3257 else
3259 SetTextColor(pDIStruct->hDC,crText);
3260 SetBkColor(pDIStruct->hDC,crWin);
3261 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3264 /* Do not indent item if drawing in the edit of the combo */
3265 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3266 iIndentation = 0;
3267 else
3268 iIndentation = tmpFolder->m_iIndent;
3270 /* Draw text and icon */
3272 /* Initialise the icon display area */
3273 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3274 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3275 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3276 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3278 /* Initialise the text display area */
3279 GetTextMetricsW(pDIStruct->hDC, &tm);
3280 rectText.left = rectIcon.right;
3281 rectText.top =
3282 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3283 rectText.right = pDIStruct->rcItem.right;
3284 rectText.bottom =
3285 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3287 /* Draw the icon from the image list */
3288 ImageList_Draw(ilItemImage,
3289 sfi.iIcon,
3290 pDIStruct->hDC,
3291 rectIcon.left,
3292 rectIcon.top,
3293 ILD_TRANSPARENT );
3295 /* Draw the associated text */
3296 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3297 return NOERROR;
3300 /***********************************************************************
3301 * FILEDLG95_LOOKIN_OnCommand
3303 * LookIn combo box WM_COMMAND message handler
3304 * If the function succeeds, the return value is nonzero.
3306 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3308 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3310 TRACE("%p\n", fodInfos);
3312 switch(wNotifyCode)
3314 case CBN_SELENDOK:
3316 LPSFOLDER tmpFolder;
3317 int iItem;
3319 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3321 if( iItem == CB_ERR) return FALSE;
3323 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3324 iItem)))
3325 return FALSE;
3328 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3329 tmpFolder->pidlItem,
3330 SBSP_ABSOLUTE)))
3332 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3333 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3334 return TRUE;
3336 break;
3340 return FALSE;
3343 /***********************************************************************
3344 * FILEDLG95_LOOKIN_AddItem
3346 * Adds an absolute pidl item to the lookin combo box
3347 * returns the index of the inserted item
3349 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3351 LPITEMIDLIST pidlNext;
3352 SHFILEINFOW sfi;
3353 SFOLDER *tmpFolder;
3354 LookInInfos *liInfos;
3356 TRACE("%08x\n", iInsertId);
3358 if(!pidl)
3359 return -1;
3361 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3362 return -1;
3364 tmpFolder = MemAlloc(sizeof(SFOLDER));
3365 tmpFolder->m_iIndent = 0;
3367 /* Calculate the indentation of the item in the lookin*/
3368 pidlNext = pidl;
3369 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3371 tmpFolder->m_iIndent++;
3374 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3376 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3377 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3379 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3380 SHGetFileInfoW((LPCWSTR)pidl,
3382 &sfi,
3383 sizeof(sfi),
3384 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3385 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3387 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3389 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3391 int iItemID;
3393 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3395 /* Add the item at the end of the list */
3396 if(iInsertId < 0)
3398 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3400 /* Insert the item at the iInsertId position*/
3401 else
3403 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3406 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3407 return iItemID;
3410 COMDLG32_SHFree( tmpFolder->pidlItem );
3411 MemFree( tmpFolder );
3412 return -1;
3416 /***********************************************************************
3417 * FILEDLG95_LOOKIN_InsertItemAfterParent
3419 * Insert an item below its parent
3421 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3424 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3425 int iParentPos;
3427 TRACE("\n");
3429 if (pidl == pidlParent)
3430 return -1;
3432 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3434 if(iParentPos < 0)
3436 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3439 /* Free pidlParent memory */
3440 COMDLG32_SHFree(pidlParent);
3442 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3445 /***********************************************************************
3446 * FILEDLG95_LOOKIN_SelectItem
3448 * Adds an absolute pidl item to the lookin combo box
3449 * returns the index of the inserted item
3451 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3453 int iItemPos;
3454 LookInInfos *liInfos;
3456 TRACE("\n");
3458 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3460 liInfos = GetPropA(hwnd,LookInInfosStr);
3462 if(iItemPos < 0)
3464 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3465 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3468 else
3470 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3471 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3473 int iRemovedItem;
3475 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3476 break;
3477 if(iRemovedItem < iItemPos)
3478 iItemPos--;
3482 CBSetCurSel(hwnd,iItemPos);
3483 liInfos->uSelectedItem = iItemPos;
3485 return 0;
3489 /***********************************************************************
3490 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3492 * Remove the item with an expansion level over iExpansionLevel
3494 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3496 int iItemPos;
3497 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3499 TRACE("\n");
3501 if(liInfos->iMaxIndentation <= 2)
3502 return -1;
3504 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3506 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3507 COMDLG32_SHFree(tmpFolder->pidlItem);
3508 MemFree(tmpFolder);
3509 CBDeleteString(hwnd,iItemPos);
3510 liInfos->iMaxIndentation--;
3512 return iItemPos;
3515 return -1;
3518 /***********************************************************************
3519 * FILEDLG95_LOOKIN_SearchItem
3521 * Search for pidl in the lookin combo box
3522 * returns the index of the found item
3524 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3526 int i = 0;
3527 int iCount = CBGetCount(hwnd);
3529 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3531 if (iCount != CB_ERR)
3533 for(;i<iCount;i++)
3535 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3537 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3538 return i;
3539 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3540 return i;
3544 return -1;
3547 /***********************************************************************
3548 * FILEDLG95_LOOKIN_Clean
3550 * Clean the memory used by the lookin combo box
3552 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3554 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3555 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3556 int iPos;
3557 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3559 TRACE("\n");
3561 /* Delete each string of the combo and their associated data */
3562 if (iCount != CB_ERR)
3564 for(iPos = iCount-1;iPos>=0;iPos--)
3566 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3567 COMDLG32_SHFree(tmpFolder->pidlItem);
3568 MemFree(tmpFolder);
3569 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3573 /* LookInInfos structure */
3574 MemFree(liInfos);
3575 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3578 /***********************************************************************
3579 * get_def_format
3581 * Fill the FORMATETC used in the shell id list
3583 static FORMATETC get_def_format(void)
3585 static CLIPFORMAT cfFormat;
3586 FORMATETC formatetc;
3588 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3589 formatetc.cfFormat = cfFormat;
3590 formatetc.ptd = 0;
3591 formatetc.dwAspect = DVASPECT_CONTENT;
3592 formatetc.lindex = -1;
3593 formatetc.tymed = TYMED_HGLOBAL;
3594 return formatetc;
3597 /***********************************************************************
3598 * FILEDLG95_FILENAME_FillFromSelection
3600 * fills the edit box from the cached DataObject
3602 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3604 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3605 LPITEMIDLIST pidl;
3606 LPWSTR lpstrAllFiles, lpstrTmp;
3607 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3608 STGMEDIUM medium;
3609 LPIDA cida;
3610 FORMATETC formatetc = get_def_format();
3612 TRACE("\n");
3614 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3615 return;
3617 cida = GlobalLock(medium.u.hGlobal);
3618 nFileSelected = cida->cidl;
3620 /* Allocate a buffer */
3621 nAllFilesMaxLength = MAX_PATH + 3;
3622 lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nAllFilesMaxLength * sizeof(WCHAR));
3623 if (!lpstrAllFiles)
3624 goto ret;
3626 /* Loop through the selection, handle only files (not folders) */
3627 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3629 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3630 if (pidl)
3632 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3634 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3636 nAllFilesMaxLength *= 2;
3637 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3638 if (!lpstrTmp)
3639 goto ret;
3640 lpstrAllFiles = lpstrTmp;
3642 nFiles += 1;
3643 lpstrAllFiles[nAllFilesLength++] = '"';
3644 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3645 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3646 nAllFilesLength += nThisFileLength;
3647 lpstrAllFiles[nAllFilesLength++] = '"';
3648 lpstrAllFiles[nAllFilesLength++] = ' ';
3653 if (nFiles != 0)
3655 /* If there's only one file, use the name as-is without quotes */
3656 lpstrTmp = lpstrAllFiles;
3657 if (nFiles == 1)
3659 lpstrTmp += 1;
3660 lpstrTmp[nThisFileLength] = 0;
3662 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3663 /* Select the file name like Windows does */
3664 if (filename_is_edit(fodInfos))
3665 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3668 ret:
3669 HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
3670 COMCTL32_ReleaseStgMedium(medium);
3674 /* copied from shell32 to avoid linking to it
3675 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3676 * is dependent on whether emulated OS is unicode or not.
3678 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3680 switch (src->uType)
3682 case STRRET_WSTR:
3683 lstrcpynW(dest, src->u.pOleStr, len);
3684 COMDLG32_SHFree(src->u.pOleStr);
3685 break;
3687 case STRRET_CSTR:
3688 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3689 dest[len-1] = 0;
3690 break;
3692 case STRRET_OFFSET:
3693 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3694 dest[len-1] = 0;
3695 break;
3697 default:
3698 FIXME("unknown type %x!\n", src->uType);
3699 if (len) *dest = '\0';
3700 return E_FAIL;
3702 return S_OK;
3705 /***********************************************************************
3706 * FILEDLG95_FILENAME_GetFileNames
3708 * Copies the filenames to a delimited string list.
3710 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3712 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3713 UINT nFileCount = 0; /* number of files */
3714 UINT nStrLen = 0; /* length of string in edit control */
3715 LPWSTR lpstrEdit; /* buffer for string from edit control */
3717 TRACE("\n");
3719 /* get the filenames from the filename control */
3720 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3721 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3722 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3724 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3726 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3727 MemFree(lpstrEdit);
3728 return nFileCount;
3732 * DATAOBJECT Helper functions
3735 /***********************************************************************
3736 * COMCTL32_ReleaseStgMedium
3738 * like ReleaseStgMedium from ole32
3740 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3742 if(medium.pUnkForRelease)
3744 IUnknown_Release(medium.pUnkForRelease);
3746 else
3748 GlobalUnlock(medium.u.hGlobal);
3749 GlobalFree(medium.u.hGlobal);
3753 /***********************************************************************
3754 * GetPidlFromDataObject
3756 * Return pidl(s) by number from the cached DataObject
3758 * nPidlIndex=0 gets the fully qualified root path
3760 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3763 STGMEDIUM medium;
3764 FORMATETC formatetc = get_def_format();
3765 LPITEMIDLIST pidl = NULL;
3767 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3769 if (!doSelected)
3770 return NULL;
3772 /* Get the pidls from IDataObject */
3773 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3775 LPIDA cida = GlobalLock(medium.u.hGlobal);
3776 if(nPidlIndex <= cida->cidl)
3778 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3780 COMCTL32_ReleaseStgMedium(medium);
3782 return pidl;
3785 /***********************************************************************
3786 * GetNumSelected
3788 * Return the number of selected items in the DataObject.
3791 static UINT GetNumSelected( IDataObject *doSelected )
3793 UINT retVal = 0;
3794 STGMEDIUM medium;
3795 FORMATETC formatetc = get_def_format();
3797 TRACE("sv=%p\n", doSelected);
3799 if (!doSelected) return 0;
3801 /* Get the pidls from IDataObject */
3802 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3804 LPIDA cida = GlobalLock(medium.u.hGlobal);
3805 retVal = cida->cidl;
3806 COMCTL32_ReleaseStgMedium(medium);
3807 return retVal;
3809 return 0;
3813 * TOOLS
3816 /***********************************************************************
3817 * GetName
3819 * Get the pidl's display name (relative to folder) and
3820 * put it in lpstrFileName.
3822 * Return NOERROR on success,
3823 * E_FAIL otherwise
3826 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3828 STRRET str;
3829 HRESULT hRes;
3831 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3833 if(!lpsf)
3835 SHGetDesktopFolder(&lpsf);
3836 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3837 IShellFolder_Release(lpsf);
3838 return hRes;
3841 /* Get the display name of the pidl relative to the folder */
3842 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3844 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3846 return E_FAIL;
3849 /***********************************************************************
3850 * GetShellFolderFromPidl
3852 * pidlRel is the item pidl relative
3853 * Return the IShellFolder of the absolute pidl
3855 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3857 IShellFolder *psf = NULL,*psfParent;
3859 TRACE("%p\n", pidlAbs);
3861 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3863 psf = psfParent;
3864 if(pidlAbs && pidlAbs->mkid.cb)
3866 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3868 IShellFolder_Release(psfParent);
3869 return psf;
3872 /* return the desktop */
3873 return psfParent;
3875 return NULL;
3878 /***********************************************************************
3879 * GetParentPidl
3881 * Return the LPITEMIDLIST to the parent of the pidl in the list
3883 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3885 LPITEMIDLIST pidlParent;
3887 TRACE("%p\n", pidl);
3889 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3890 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3892 return pidlParent;
3895 /***********************************************************************
3896 * GetPidlFromName
3898 * returns the pidl of the file name relative to folder
3899 * NULL if an error occurred
3901 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3903 LPITEMIDLIST pidl = NULL;
3904 ULONG ulEaten;
3906 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3908 if(!lpcstrFileName) return NULL;
3909 if(!*lpcstrFileName) return NULL;
3911 if(!lpsf)
3913 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3914 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3915 IShellFolder_Release(lpsf);
3918 else
3920 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3922 return pidl;
3927 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3929 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3930 HRESULT ret;
3932 TRACE("%p, %p\n", psf, pidl);
3934 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3936 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3937 /* see documentation shell 4.1*/
3938 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3941 /***********************************************************************
3942 * BrowseSelectedFolder
3944 static BOOL BrowseSelectedFolder(HWND hwnd)
3946 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3947 BOOL bBrowseSelFolder = FALSE;
3949 TRACE("\n");
3951 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3953 LPITEMIDLIST pidlSelection;
3955 /* get the file selected */
3956 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3957 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3959 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3960 pidlSelection, SBSP_RELATIVE ) ) )
3962 WCHAR buf[64];
3963 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, sizeof(buf)/sizeof(WCHAR) );
3964 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3966 bBrowseSelFolder = TRUE;
3967 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3968 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3970 COMDLG32_SHFree( pidlSelection );
3973 return bBrowseSelFolder;
3977 * Memory allocation methods */
3978 static void *MemAlloc(UINT size)
3980 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3983 static void MemFree(void *mem)
3985 HeapFree(GetProcessHeap(),0,mem);
3988 static inline BOOL valid_struct_size( DWORD size )
3990 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
3991 (size == sizeof( OPENFILENAMEW ));
3994 static inline BOOL is_win16_looks(DWORD flags)
3996 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
3997 !(flags & OFN_EXPLORER));
4000 /* ------------------ APIs ---------------------- */
4002 /***********************************************************************
4003 * GetOpenFileNameA (COMDLG32.@)
4005 * Creates a dialog box for the user to select a file to open.
4007 * RETURNS
4008 * TRUE on success: user enters a valid file
4009 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4012 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4014 TRACE("flags %08x\n", ofn->Flags);
4016 if (!valid_struct_size( ofn->lStructSize ))
4018 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4019 return FALSE;
4022 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4023 if (ofn->Flags & OFN_FILEMUSTEXIST)
4024 ofn->Flags |= OFN_PATHMUSTEXIST;
4026 if (is_win16_looks(ofn->Flags))
4027 return GetFileName31A(ofn, OPEN_DIALOG);
4028 else
4030 FileOpenDlgInfos info;
4032 init_filedlg_infoA(ofn, &info);
4033 return GetFileDialog95(&info, OPEN_DIALOG);
4037 /***********************************************************************
4038 * GetOpenFileNameW (COMDLG32.@)
4040 * Creates a dialog box for the user to select a file to open.
4042 * RETURNS
4043 * TRUE on success: user enters a valid file
4044 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4047 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4049 TRACE("flags %08x\n", ofn->Flags);
4051 if (!valid_struct_size( ofn->lStructSize ))
4053 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4054 return FALSE;
4057 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4058 if (ofn->Flags & OFN_FILEMUSTEXIST)
4059 ofn->Flags |= OFN_PATHMUSTEXIST;
4061 if (is_win16_looks(ofn->Flags))
4062 return GetFileName31W(ofn, OPEN_DIALOG);
4063 else
4065 FileOpenDlgInfos info;
4067 init_filedlg_infoW(ofn, &info);
4068 return GetFileDialog95(&info, OPEN_DIALOG);
4073 /***********************************************************************
4074 * GetSaveFileNameA (COMDLG32.@)
4076 * Creates a dialog box for the user to select a file to save.
4078 * RETURNS
4079 * TRUE on success: user enters a valid file
4080 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4083 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4085 if (!valid_struct_size( ofn->lStructSize ))
4087 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4088 return FALSE;
4091 if (is_win16_looks(ofn->Flags))
4092 return GetFileName31A(ofn, SAVE_DIALOG);
4093 else
4095 FileOpenDlgInfos info;
4097 init_filedlg_infoA(ofn, &info);
4098 return GetFileDialog95(&info, SAVE_DIALOG);
4102 /***********************************************************************
4103 * GetSaveFileNameW (COMDLG32.@)
4105 * Creates a dialog box for the user to select a file to save.
4107 * RETURNS
4108 * TRUE on success: user enters a valid file
4109 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4112 BOOL WINAPI GetSaveFileNameW(
4113 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4115 if (!valid_struct_size( ofn->lStructSize ))
4117 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4118 return FALSE;
4121 if (is_win16_looks(ofn->Flags))
4122 return GetFileName31W(ofn, SAVE_DIALOG);
4123 else
4125 FileOpenDlgInfos info;
4127 init_filedlg_infoW(ofn, &info);
4128 return GetFileDialog95(&info, SAVE_DIALOG);
4132 /***********************************************************************
4133 * GetFileTitleA (COMDLG32.@)
4135 * See GetFileTitleW.
4137 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4139 int ret;
4140 UNICODE_STRING strWFile;
4141 LPWSTR lpWTitle;
4143 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4144 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4145 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4146 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4147 RtlFreeUnicodeString( &strWFile );
4148 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4149 return ret;
4153 /***********************************************************************
4154 * GetFileTitleW (COMDLG32.@)
4156 * Get the name of a file.
4158 * PARAMS
4159 * lpFile [I] name and location of file
4160 * lpTitle [O] returned file name
4161 * cbBuf [I] buffer size of lpTitle
4163 * RETURNS
4164 * Success: zero
4165 * Failure: negative number.
4167 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4169 int i, len;
4170 static const WCHAR brkpoint[] = {'*','[',']',0};
4171 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4173 if(lpFile == NULL || lpTitle == NULL)
4174 return -1;
4176 len = lstrlenW(lpFile);
4178 if (len == 0)
4179 return -1;
4181 if(strpbrkW(lpFile, brkpoint))
4182 return -1;
4184 len--;
4186 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4187 return -1;
4189 for(i = len; i >= 0; i--)
4191 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4193 i++;
4194 break;
4198 if(i == -1)
4199 i++;
4201 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4203 len = lstrlenW(lpFile+i)+1;
4204 if(cbBuf < len)
4205 return len;
4207 lstrcpyW(lpTitle, &lpFile[i]);
4208 return 0;