cmd: DIR command outputs free space for the path.
[wine.git] / dlls / comdlg32 / filedlg.c
blob441f203fe7ba9effa973ed8dd9895188721686c3
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 <ctype.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <string.h>
54 #define COBJMACROS
55 #include "windef.h"
56 #include "winbase.h"
57 #include "winternl.h"
58 #include "winnls.h"
59 #include "wingdi.h"
60 #include "winreg.h"
61 #include "winuser.h"
62 #include "commdlg.h"
63 #include "dlgs.h"
64 #include "cdlg.h"
65 #include "cderr.h"
66 #include "shellapi.h"
67 #include "shlobj.h"
68 #include "filedlgbrowser.h"
69 #include "shlwapi.h"
71 #include "wine/debug.h"
72 #include "wine/heap.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
76 #define UNIMPLEMENTED_FLAGS \
77 (OFN_DONTADDTORECENT |\
78 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
79 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
81 /***********************************************************************
82 * Data structure and global variables
84 typedef struct SFolder
86 int m_iImageIndex; /* Index of picture in image list */
87 HIMAGELIST hImgList;
88 int m_iIndent; /* Indentation index */
89 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
91 } SFOLDER,*LPSFOLDER;
93 typedef struct tagLookInInfo
95 int iMaxIndentation;
96 UINT uSelectedItem;
97 } LookInInfos;
100 /***********************************************************************
101 * Defines and global variables
104 /* Draw item constant */
105 #define XTEXTOFFSET 3
107 /* AddItem flags*/
108 #define LISTEND -1
110 /* SearchItem methods */
111 #define SEARCH_PIDL 1
112 #define SEARCH_EXP 2
113 #define ITEM_NOTFOUND -1
115 /* Undefined windows message sent by CreateViewObject*/
116 #define WM_GETISHELLBROWSER WM_USER+7
118 #define TBPLACES_CMDID_PLACE0 0xa064
119 #define TBPLACES_CMDID_PLACE1 0xa065
120 #define TBPLACES_CMDID_PLACE2 0xa066
121 #define TBPLACES_CMDID_PLACE3 0xa067
122 #define TBPLACES_CMDID_PLACE4 0xa068
124 /* NOTE
125 * Those macros exist in windowsx.h. However, you can't really use them since
126 * they rely on the UNICODE defines and can't be used inside Wine itself.
129 /* Combo box macros */
130 #define CBGetItemDataPtr(hwnd,iItemId) \
131 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
133 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
134 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
136 FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd)
138 return GetPropW(hwnd, L"FileOpenDlgInfos");
141 static BOOL is_dialog_hooked(const FileOpenDlgInfos *info)
143 return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
146 static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info)
148 return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG);
151 /***********************************************************************
152 * Prototypes
155 /* Internal functions used by the dialog */
156 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
157 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
158 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
159 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
160 static BOOL FILEDLG95_OnOpen(HWND hwnd);
161 static LRESULT FILEDLG95_InitControls(HWND hwnd);
162 static void FILEDLG95_Clean(HWND hwnd);
164 /* Functions used by the shell navigation */
165 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
166 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
167 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
168 static void FILEDLG95_SHELL_Clean(HWND hwnd);
170 /* Functions used by the EDIT box */
171 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
173 /* Functions used by the filetype combo box */
174 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
175 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
176 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
177 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
179 /* Functions used by the Look In combo box */
180 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
181 static LRESULT FILEDLG95_LOOKIN_DrawItem(HWND hwnd, LPDRAWITEMSTRUCT pDIStruct);
182 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
183 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
184 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
185 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
186 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
187 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
188 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
190 /* Functions for dealing with the most-recently-used registry keys */
191 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
192 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
193 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
195 /* Miscellaneous tool functions */
196 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
197 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
198 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
199 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
200 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
201 static UINT GetNumSelected( IDataObject *doSelected );
202 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
204 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
205 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
206 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
207 static BOOL BrowseSelectedFolder(HWND hwnd);
209 static BOOL get_config_key_as_dword(HKEY hkey, const WCHAR *name, DWORD *value)
211 DWORD type, data, size;
213 size = sizeof(data);
214 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size))
216 *value = data;
217 return TRUE;
220 return FALSE;
223 static BOOL get_config_key_dword(HKEY hkey, const WCHAR *name, DWORD *value)
225 DWORD type, data, size;
227 size = sizeof(data);
228 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
230 *value = data;
231 return TRUE;
234 return FALSE;
237 static BOOL get_config_key_string(HKEY hkey, const WCHAR *name, WCHAR **value)
239 DWORD type, size;
240 WCHAR *str;
242 if (RegQueryValueExW(hkey, name, 0, &type, NULL, &size))
243 return FALSE;
244 if (type != REG_SZ && type != REG_EXPAND_SZ)
245 return FALSE;
247 str = heap_alloc(size);
248 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size))
250 heap_free(str);
251 return FALSE;
254 *value = str;
255 return TRUE;
258 static BOOL is_places_bar_enabled(const FileOpenDlgInfos *fodInfos)
260 DWORD value;
261 HKEY hkey;
263 if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) ||
264 (fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) ||
265 !(fodInfos->ofnInfos->Flags & OFN_EXPLORER))
267 return FALSE;
270 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey))
271 return TRUE;
273 value = 0;
274 get_config_key_as_dword(hkey, L"NoPlacesBar", &value);
275 RegCloseKey(hkey);
276 return value == 0;
279 static void filedlg_collect_places_pidls(FileOpenDlgInfos *fodInfos)
281 static const int default_places[] =
283 CSIDL_DESKTOP,
284 CSIDL_MYDOCUMENTS,
285 CSIDL_DRIVES,
287 unsigned int i;
288 HKEY hkey;
290 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
291 &hkey))
293 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
295 WCHAR nameW[8];
296 DWORD value;
297 HRESULT hr;
298 WCHAR *str;
300 swprintf(nameW, ARRAY_SIZE(nameW), L"Place%d", i);
301 if (get_config_key_dword(hkey, nameW, &value))
303 hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]);
304 if (FAILED(hr))
305 WARN("Unrecognized special folder %lu.\n", value);
307 else if (get_config_key_string(hkey, nameW, &str))
309 hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL);
310 if (FAILED(hr))
311 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str));
312 heap_free(str);
316 /* FIXME: eliminate duplicates. */
318 RegCloseKey(hkey);
319 return;
322 for (i = 0; i < ARRAY_SIZE(default_places); i++)
323 SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]);
326 /***********************************************************************
327 * GetFileName95
329 * Creates an Open common dialog box that lets the user select
330 * the drive, directory, and the name of a file or set of files to open.
332 * IN : The FileOpenDlgInfos structure associated with the dialog
333 * OUT : TRUE on success
334 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
336 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
338 LRESULT lRes;
339 void *template;
340 HRSRC hRes;
341 HANDLE hDlgTmpl = 0;
342 WORD templateid;
344 /* test for missing functionality */
345 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
347 FIXME("Flags 0x%08lx not yet implemented\n",
348 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
351 /* Create the dialog from a template */
353 if (is_places_bar_enabled(fodInfos))
354 templateid = NEWFILEOPENV2ORD;
355 else
356 templateid = NEWFILEOPENORD;
358 if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG)))
360 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
361 return FALSE;
363 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
364 !(template = LockResource( hDlgTmpl )))
366 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
367 return FALSE;
370 /* msdn: explorer style dialogs permit sizing by default.
371 * The OFN_ENABLESIZING flag is only needed when a hook or
372 * custom template is provided */
373 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
374 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
375 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
377 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
379 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
380 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
383 /* old style hook messages */
384 if (is_dialog_hooked(fodInfos))
386 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
387 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
388 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
389 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
392 if (fodInfos->unicode)
393 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
394 template,
395 fodInfos->ofnInfos->hwndOwner,
396 FileOpenDlgProc95,
397 (LPARAM) fodInfos);
398 else
399 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
400 template,
401 fodInfos->ofnInfos->hwndOwner,
402 FileOpenDlgProc95,
403 (LPARAM) fodInfos);
404 if (fodInfos->ole_initialized)
405 OleUninitialize();
407 /* Unable to create the dialog */
408 if( lRes == -1)
409 return FALSE;
411 return lRes;
414 static WCHAR *heap_strdupAtoW(const char *str)
416 WCHAR *ret;
417 INT len;
419 if (!str)
420 return NULL;
422 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
423 ret = heap_alloc(len * sizeof(WCHAR));
424 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
426 return ret;
429 static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info)
431 INITCOMMONCONTROLSEX icc;
433 /* Initialize ComboBoxEx32 */
434 icc.dwSize = sizeof(icc);
435 icc.dwICC = ICC_USEREX_CLASSES;
436 InitCommonControlsEx(&icc);
438 /* Initialize CommDlgExtendedError() */
439 COMDLG32_SetCommDlgExtendedError(0);
441 memset(info, 0, sizeof(*info));
443 /* Pass in the original ofn */
444 info->ofnInfos = ofn;
446 info->title = ofn->lpstrTitle;
447 info->defext = ofn->lpstrDefExt;
448 info->filter = ofn->lpstrFilter;
449 info->customfilter = ofn->lpstrCustomFilter;
451 if (ofn->lpstrFile)
453 info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
454 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
457 if (ofn->lpstrInitialDir)
459 DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0);
460 if (len)
462 info->initdir = heap_alloc(len * sizeof(WCHAR));
463 ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len);
467 info->unicode = TRUE;
470 static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
472 OPENFILENAMEW ofnW;
473 int len;
475 ofnW = *(OPENFILENAMEW *)ofn;
477 ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir);
478 ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt);
479 ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle);
481 if (ofn->lpstrFile)
483 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, NULL, 0);
484 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
485 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, ofnW.lpstrFile, len);
486 ofnW.nMaxFile = len;
489 if (ofn->lpstrFilter)
491 LPCSTR s;
492 int n;
494 /* filter is a list... title\0ext\0......\0\0 */
495 s = ofn->lpstrFilter;
496 while (*s) s = s+strlen(s)+1;
497 s++;
498 n = s - ofn->lpstrFilter;
499 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0);
500 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
501 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len);
504 /* convert lpstrCustomFilter */
505 if (ofn->lpstrCustomFilter)
507 int n, len;
508 LPCSTR s;
510 /* customfilter contains a pair of strings... title\0ext\0 */
511 s = ofn->lpstrCustomFilter;
512 if (*s) s = s+strlen(s)+1;
513 if (*s) s = s+strlen(s)+1;
514 n = s - ofn->lpstrCustomFilter;
515 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0);
516 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
517 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len);
520 init_filedlg_infoW(&ofnW, info);
522 /* fixup A-specific fields */
523 info->ofnInfos = (OPENFILENAMEW *)ofn;
524 info->unicode = FALSE;
526 /* free what was duplicated */
527 heap_free((void *)ofnW.lpstrInitialDir);
528 heap_free(ofnW.lpstrFile);
531 /***********************************************************************
532 * GetFileDialog95
534 * Call GetFileName95 with this structure and clean the memory.
536 static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type)
538 WCHAR *current_dir = NULL;
539 unsigned int i;
540 BOOL ret;
542 /* save current directory */
543 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
545 current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
546 GetCurrentDirectoryW(MAX_PATH, current_dir);
549 switch (dlg_type)
551 case OPEN_DIALOG:
552 ret = GetFileName95(info);
553 break;
554 case SAVE_DIALOG:
555 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
556 ret = GetFileName95(info);
557 break;
558 default:
559 ret = FALSE;
562 if (current_dir)
564 SetCurrentDirectoryW(current_dir);
565 heap_free(current_dir);
568 if (!info->unicode)
570 heap_free((void *)info->defext);
571 heap_free((void *)info->title);
572 heap_free((void *)info->filter);
573 heap_free((void *)info->customfilter);
576 heap_free(info->filename);
577 heap_free(info->initdir);
579 for (i = 0; i < ARRAY_SIZE(info->places); i++)
580 ILFree(info->places[i]);
582 return ret;
585 /******************************************************************************
586 * COMDLG32_GetDisplayNameOf [internal]
588 * Helper function to get the display name for a pidl.
590 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
591 LPSHELLFOLDER psfDesktop;
592 STRRET strret;
594 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
595 return FALSE;
597 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
598 IShellFolder_Release(psfDesktop);
599 return FALSE;
602 IShellFolder_Release(psfDesktop);
603 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
606 /******************************************************************************
607 * COMDLG32_GetCanonicalPath [internal]
609 * Helper function to get the canonical path.
611 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
612 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
614 WCHAR lpstrTemp[MAX_PATH];
616 /* Get the current directory name */
617 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
619 /* last fallback */
620 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
622 PathAddBackslashW(lpstrPathAndFile);
624 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
626 /* if the user specified a fully qualified path use it */
627 if(PathIsRelativeW(lpstrFile))
629 lstrcatW(lpstrPathAndFile, lpstrFile);
631 else
633 /* does the path have a drive letter? */
634 if (PathGetDriveNumberW(lpstrFile) == -1)
635 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
636 else
637 lstrcpyW(lpstrPathAndFile, lpstrFile);
640 /* resolve "." and ".." */
641 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
642 lstrcpyW(lpstrPathAndFile, lpstrTemp);
643 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
646 /***********************************************************************
647 * COMDLG32_SplitFileNames [internal]
649 * Creates a delimited list of filenames.
651 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
653 UINT nStrCharCount = 0; /* index in src buffer */
654 UINT nFileIndex = 0; /* index in dest buffer */
655 UINT nFileCount = 0; /* number of files */
657 /* we might get single filename without any '"',
658 * so we need nStrLen + terminating \0 + end-of-list \0 */
659 *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
660 *sizeUsed = 0;
662 /* build delimited file list from filenames */
663 while ( nStrCharCount <= nStrLen )
665 if ( lpstrEdit[nStrCharCount]=='"' )
667 nStrCharCount++;
668 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
670 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
671 nStrCharCount++;
673 (*lpstrFileList)[nFileIndex++] = 0;
674 nFileCount++;
676 nStrCharCount++;
679 /* single, unquoted string */
680 if ((nStrLen > 0) && (nFileIndex == 0) )
682 lstrcpyW(*lpstrFileList, lpstrEdit);
683 nFileIndex = lstrlenW(lpstrEdit) + 1;
684 nFileCount = 1;
687 /* trailing \0 */
688 (*lpstrFileList)[nFileIndex++] = '\0';
690 *sizeUsed = nFileIndex;
691 return nFileCount;
694 /***********************************************************************
695 * ArrangeCtrlPositions [internal]
697 * NOTE: Make sure to add testcases for any changes made here.
699 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
701 HWND hwndChild, hwndStc32;
702 RECT rectParent, rectChild, rectStc32;
703 INT help_fixup = 0;
704 int chgx, chgy;
706 /* Take into account if open as read only checkbox and help button
707 * are hidden
709 if (hide_help)
711 RECT rectHelp, rectCancel;
712 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
713 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
714 /* subtract the height of the help button plus the space between
715 * the help button and the cancel button to the height of the dialog
717 help_fixup = rectHelp.bottom - rectCancel.bottom;
721 There are two possibilities to add components to the default file dialog box.
723 By default, all the new components are added below the standard dialog box (the else case).
725 However, if there is a static text component with the stc32 id, a special case happens.
726 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
727 in the window and the cx and cy indicate how to size the window.
728 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
729 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
733 GetClientRect(hwndParentDlg, &rectParent);
735 /* when arranging controls we have to use fixed parent size */
736 rectParent.bottom -= help_fixup;
738 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
739 if (hwndStc32)
741 GetWindowRect(hwndStc32, &rectStc32);
742 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
744 /* set the size of the stc32 control according to the size of
745 * client area of the parent dialog
747 SetWindowPos(hwndStc32, 0,
748 0, 0,
749 rectParent.right, rectParent.bottom,
750 SWP_NOMOVE | SWP_NOZORDER);
752 else
753 SetRectEmpty(&rectStc32);
755 /* this part moves controls of the child dialog */
756 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
757 while (hwndChild)
759 if (hwndChild != hwndStc32)
761 GetWindowRect(hwndChild, &rectChild);
762 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
764 /* move only if stc32 exist */
765 if (hwndStc32 && rectChild.left > rectStc32.right)
767 /* move to the right of visible controls of the parent dialog */
768 rectChild.left += rectParent.right;
769 rectChild.left -= rectStc32.right;
771 /* move even if stc32 doesn't exist */
772 if (rectChild.top >= rectStc32.bottom)
774 /* move below visible controls of the parent dialog */
775 rectChild.top += rectParent.bottom;
776 rectChild.top -= rectStc32.bottom - rectStc32.top;
779 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
780 0, 0, SWP_NOSIZE | SWP_NOZORDER);
782 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
785 /* this part moves controls of the parent dialog */
786 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
787 while (hwndChild)
789 if (hwndChild != hwndChildDlg)
791 GetWindowRect(hwndChild, &rectChild);
792 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
794 /* left,top of stc32 marks the position of controls
795 * from the parent dialog
797 rectChild.left += rectStc32.left;
798 rectChild.top += rectStc32.top;
800 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
801 0, 0, SWP_NOSIZE | SWP_NOZORDER);
803 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
806 /* calculate the size of the resulting dialog */
808 /* here we have to use original parent size */
809 GetClientRect(hwndParentDlg, &rectParent);
810 GetClientRect(hwndChildDlg, &rectChild);
811 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
812 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
814 if (hwndStc32)
816 /* width */
817 if (rectParent.right > rectStc32.right - rectStc32.left)
818 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
819 else
820 chgx = rectChild.right - rectParent.right;
821 /* height */
822 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
823 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
824 else
825 /* Unconditionally set new dialog
826 * height to that of the child
828 chgy = rectChild.bottom - rectParent.bottom;
830 else
832 chgx = 0;
833 chgy = rectChild.bottom - help_fixup;
835 /* set the size of the parent dialog */
836 GetWindowRect(hwndParentDlg, &rectParent);
837 SetWindowPos(hwndParentDlg, 0,
838 0, 0,
839 rectParent.right - rectParent.left + chgx,
840 rectParent.bottom - rectParent.top + chgy,
841 SWP_NOMOVE | SWP_NOZORDER);
844 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
846 switch(uMsg) {
847 case WM_INITDIALOG:
848 return TRUE;
850 return FALSE;
853 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
855 LPCVOID template;
856 HRSRC hRes;
857 HANDLE hDlgTmpl = 0;
858 HWND hChildDlg = 0;
860 TRACE("%p, %p\n", fodInfos, hwnd);
863 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
864 * structure's hInstance parameter is not a HINSTANCE, but
865 * instead a pointer to a template resource to use.
867 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
869 HINSTANCE hinst;
870 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
872 hinst = COMDLG32_hInstance;
873 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
875 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
876 return NULL;
879 else
881 hinst = fodInfos->ofnInfos->hInstance;
882 if(fodInfos->unicode)
884 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
885 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
887 else
889 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
890 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
892 if (!hRes)
894 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
895 return NULL;
897 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
898 !(template = LockResource( hDlgTmpl )))
900 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
901 return NULL;
904 if (fodInfos->unicode)
905 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
906 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
907 (LPARAM)fodInfos->ofnInfos);
908 else
909 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
910 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
911 (LPARAM)fodInfos->ofnInfos);
912 return hChildDlg;
914 else if (is_dialog_hooked(fodInfos))
916 RECT rectHwnd;
917 struct {
918 DLGTEMPLATE tmplate;
919 WORD menu,class,title;
920 } temp;
921 GetClientRect(hwnd,&rectHwnd);
922 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
923 temp.tmplate.dwExtendedStyle = 0;
924 temp.tmplate.cdit = 0;
925 temp.tmplate.x = 0;
926 temp.tmplate.y = 0;
927 temp.tmplate.cx = 0;
928 temp.tmplate.cy = 0;
929 temp.menu = temp.class = temp.title = 0;
931 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
932 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
934 return hChildDlg;
936 return NULL;
939 /***********************************************************************
940 * SendCustomDlgNotificationMessage
942 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
945 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
947 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
948 LRESULT hook_result;
949 OFNOTIFYW ofnNotify;
951 TRACE("%p %d\n", hwndParentDlg, uCode);
953 if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
954 return 0;
956 TRACE("CALL NOTIFY for %d\n", uCode);
958 ofnNotify.hdr.hwndFrom = hwndParentDlg;
959 ofnNotify.hdr.idFrom = 0;
960 ofnNotify.hdr.code = uCode;
961 ofnNotify.lpOFN = fodInfos->ofnInfos;
962 ofnNotify.pszFile = NULL;
964 if (fodInfos->unicode)
965 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
966 else
967 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
969 TRACE("RET NOTIFY retval %#Ix\n", hook_result);
971 return hook_result;
974 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
976 UINT len, total;
977 WCHAR *p, *buffer;
978 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
980 TRACE("CDM_GETFILEPATH:\n");
982 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
983 return -1;
985 /* get path and filenames */
986 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
987 buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
988 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
989 if (len)
991 p = buffer + lstrlenW(buffer);
992 *p++ = '\\';
993 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
995 if (fodInfos->unicode)
997 total = lstrlenW( buffer) + 1;
998 if (result) lstrcpynW( result, buffer, size );
999 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1001 else
1003 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1004 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1005 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1007 heap_free( buffer );
1008 return total;
1011 /***********************************************************************
1012 * FILEDLG95_HandleCustomDialogMessages
1014 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1016 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1018 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1019 WCHAR lpstrPath[MAX_PATH];
1020 INT_PTR retval;
1022 if(!fodInfos) return FALSE;
1024 switch(uMsg)
1026 case CDM_GETFILEPATH:
1027 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1028 break;
1030 case CDM_GETFOLDERPATH:
1031 TRACE("CDM_GETFOLDERPATH:\n");
1032 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1033 if (lParam)
1035 if (fodInfos->unicode)
1036 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1037 else
1038 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1039 (LPSTR)lParam, (int)wParam, NULL, NULL);
1041 retval = lstrlenW(lpstrPath) + 1;
1042 break;
1044 case CDM_GETFOLDERIDLIST:
1045 retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1046 if (retval <= wParam)
1047 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1048 break;
1050 case CDM_GETSPEC:
1051 TRACE("CDM_GETSPEC:\n");
1052 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1053 if (lParam)
1055 if (fodInfos->unicode)
1056 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1057 else
1058 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1060 break;
1062 case CDM_SETCONTROLTEXT:
1063 TRACE("CDM_SETCONTROLTEXT:\n");
1064 if ( lParam )
1066 if( fodInfos->unicode )
1067 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1068 else
1069 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1071 retval = TRUE;
1072 break;
1074 case CDM_HIDECONTROL:
1075 /* MSDN states that it should fail for not OFN_EXPLORER case */
1076 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1078 HWND control = GetDlgItem( hwnd, wParam );
1079 if (control) ShowWindow( control, SW_HIDE );
1080 retval = TRUE;
1082 else retval = FALSE;
1083 break;
1085 default:
1086 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1087 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1088 return FALSE;
1090 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1091 return TRUE;
1094 /***********************************************************************
1095 * FILEDLG95_OnWMGetMMI
1097 * WM_GETMINMAXINFO message handler for resizable dialogs
1099 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1101 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1102 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1103 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1105 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1107 return TRUE;
1110 /***********************************************************************
1111 * FILEDLG95_OnWMSize
1113 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1115 * FIXME: this could be made more elaborate. Now use a simple scheme
1116 * where the file view is enlarged and the controls are either moved
1117 * vertically or horizontally to get out of the way. Only the "grip"
1118 * is moved in both directions to stay in the corner.
1120 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1122 RECT rc, rcview;
1123 int chgx, chgy;
1124 HWND ctrl;
1125 HDWP hdwp;
1126 FileOpenDlgInfos *fodInfos;
1128 if( wParam != SIZE_RESTORED) return FALSE;
1129 fodInfos = get_filedlg_infoptr(hwnd);
1130 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1131 /* get the new dialog rectangle */
1132 GetWindowRect( hwnd, &rc);
1133 TRACE("%p, size from %ld,%ld to %ld,%ld\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1134 rc.right -rc.left, rc.bottom -rc.top);
1135 /* not initialized yet */
1136 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1137 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1138 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1139 return FALSE;
1140 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1141 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1142 fodInfos->sizedlg.cx = rc.right - rc.left;
1143 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1144 /* change the size of the view window */
1145 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1146 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1147 hdwp = BeginDeferWindowPos( 10);
1148 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1149 rcview.right - rcview.left + chgx,
1150 rcview.bottom - rcview.top + chgy,
1151 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1152 /* change position and sizes of the controls */
1153 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1155 int ctrlid = GetDlgCtrlID( ctrl);
1156 GetWindowRect( ctrl, &rc);
1157 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1158 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1160 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1161 0, 0,
1162 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1164 else if( rc.top > rcview.bottom)
1166 /* if it was below the shell view
1167 * move to bottom */
1168 switch( ctrlid)
1170 /* file name (edit or comboboxex) and file types combo change also width */
1171 case edt1:
1172 case cmb13:
1173 case cmb1:
1174 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1175 rc.right - rc.left + chgx, rc.bottom - rc.top,
1176 SWP_NOACTIVATE | SWP_NOZORDER);
1177 break;
1178 /* then these buttons must move out of the way */
1179 case IDOK:
1180 case IDCANCEL:
1181 case pshHelp:
1182 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1183 0, 0,
1184 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1185 break;
1186 default:
1187 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1188 0, 0,
1189 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1192 else if( rc.left > rcview.right)
1194 /* if it was to the right of the shell view
1195 * move to right */
1196 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1197 0, 0,
1198 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1200 else
1201 /* special cases */
1203 switch( ctrlid)
1205 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1206 case IDC_LOOKIN:
1207 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1208 rc.right - rc.left + chgx, rc.bottom - rc.top,
1209 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1210 break;
1211 case IDC_TOOLBARSTATIC:
1212 case IDC_TOOLBAR:
1213 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1214 0, 0,
1215 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1216 break;
1217 #endif
1218 /* not resized in windows. Since wine uses this invisible control
1219 * to size the browser view it needs to be resized */
1220 case IDC_SHELLSTATIC:
1221 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1222 rc.right - rc.left + chgx,
1223 rc.bottom - rc.top + chgy,
1224 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1225 break;
1226 case IDC_TOOLBARPLACES:
1227 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1228 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1229 break;
1233 if(fodInfos->DlgInfos.hwndCustomDlg &&
1234 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1236 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1237 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1239 GetWindowRect( ctrl, &rc);
1240 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1241 if( rc.top > rcview.bottom)
1243 /* if it was below the shell view
1244 * move to bottom */
1245 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1246 rc.right - rc.left, rc.bottom - rc.top,
1247 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1249 else if( rc.left > rcview.right)
1251 /* if it was to the right of the shell view
1252 * move to right */
1253 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1254 rc.right - rc.left, rc.bottom - rc.top,
1255 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1258 /* size the custom dialog at the end: some applications do some
1259 * control re-arranging at this point */
1260 GetClientRect(hwnd, &rc);
1261 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1262 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1264 EndDeferWindowPos( hdwp);
1265 /* should not be needed */
1266 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1267 return TRUE;
1270 /***********************************************************************
1271 * FileOpenDlgProc95
1273 * File open dialog procedure
1275 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1277 #if 0
1278 TRACE("%p 0x%04x\n", hwnd, uMsg);
1279 #endif
1281 switch(uMsg)
1283 case WM_INITDIALOG:
1285 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1286 RECT rc, rcstc;
1287 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1288 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1290 /* Some shell namespace extensions depend on COM being initialized. */
1291 if (SUCCEEDED(OleInitialize(NULL)))
1292 fodInfos->ole_initialized = TRUE;
1294 SetPropW(hwnd, L"FileOpenDlgInfos", fodInfos);
1296 FILEDLG95_InitControls(hwnd);
1298 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1300 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1301 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1302 RECT client, client_adjusted;
1304 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1306 style |= WS_SIZEBOX;
1307 ex_style |= WS_EX_WINDOWEDGE;
1309 else
1310 style &= ~WS_SIZEBOX;
1311 SetWindowLongW(hwnd, GWL_STYLE, style);
1312 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1314 GetClientRect( hwnd, &client );
1315 GetClientRect( hwnd, &client_adjusted );
1316 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1318 GetWindowRect( hwnd, &rc );
1319 rc.right += client_adjusted.right - client.right;
1320 rc.bottom += client_adjusted.bottom - client.bottom;
1321 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1322 SWP_NOZORDER | SWP_NOMOVE);
1324 GetWindowRect( hwnd, &rc );
1325 fodInfos->DlgInfos.hwndGrip =
1326 CreateWindowExA( 0, "SCROLLBAR", NULL,
1327 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1328 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1329 rc.right - gripx, rc.bottom - gripy,
1330 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1333 fodInfos->DlgInfos.hwndCustomDlg =
1334 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1336 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1337 FILEDLG95_FillControls(hwnd, wParam, lParam);
1339 if( fodInfos->DlgInfos.hwndCustomDlg)
1340 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1342 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1343 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1344 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1347 /* if the app has changed the position of the invisible listbox,
1348 * change that of the listview (browser) as well */
1349 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1350 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1351 if( !EqualRect( &rc, &rcstc))
1353 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1354 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1355 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1356 SWP_NOACTIVATE | SWP_NOZORDER);
1359 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1361 GetWindowRect( hwnd, &rc);
1362 fodInfos->sizedlg.cx = rc.right - rc.left;
1363 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1364 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1365 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1366 GetClientRect( hwnd, &rc);
1367 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1368 rc.right - gripx, rc.bottom - gripy,
1369 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1370 /* resize the dialog to the previous invocation */
1371 if( MemDialogSize.cx && MemDialogSize.cy)
1372 SetWindowPos( hwnd, NULL,
1373 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1374 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1377 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1378 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1380 return 0;
1382 case WM_SIZE:
1383 return FILEDLG95_OnWMSize(hwnd, wParam);
1384 case WM_GETMINMAXINFO:
1385 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1386 case WM_COMMAND:
1387 return FILEDLG95_OnWMCommand(hwnd, wParam);
1388 case WM_DRAWITEM:
1390 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1392 case IDC_LOOKIN:
1393 FILEDLG95_LOOKIN_DrawItem(hwnd, (LPDRAWITEMSTRUCT)lParam);
1394 return TRUE;
1397 return FALSE;
1399 case WM_GETISHELLBROWSER:
1400 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1402 case WM_DESTROY:
1404 FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1405 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1406 HIMAGELIST himl;
1408 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1409 MemDialogSize = fodInfos->sizedlg;
1411 if (places_bar)
1413 himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0);
1414 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0);
1415 ImageList_Destroy(himl);
1417 return FALSE;
1420 case WM_NCDESTROY:
1421 RemovePropW(hwnd, L"FileOpenDlgInfos");
1422 return 0;
1424 case WM_NOTIFY:
1426 LPNMHDR lpnmh = (LPNMHDR)lParam;
1427 UINT stringId = -1;
1429 /* set up the button tooltips strings */
1430 if(TTN_GETDISPINFOA == lpnmh->code )
1432 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1433 switch(lpnmh->idFrom )
1435 /* Up folder button */
1436 case FCIDM_TB_UPFOLDER:
1437 stringId = IDS_UPFOLDER;
1438 break;
1439 /* New folder button */
1440 case FCIDM_TB_NEWFOLDER:
1441 stringId = IDS_NEWFOLDER;
1442 break;
1443 /* List option button */
1444 case FCIDM_TB_SMALLICON:
1445 stringId = IDS_LISTVIEW;
1446 break;
1447 /* Details option button */
1448 case FCIDM_TB_REPORTVIEW:
1449 stringId = IDS_REPORTVIEW;
1450 break;
1451 /* Desktop button */
1452 case FCIDM_TB_DESKTOP:
1453 stringId = IDS_TODESKTOP;
1454 break;
1455 default:
1456 stringId = 0;
1458 lpdi->hinst = COMDLG32_hInstance;
1459 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1461 return FALSE;
1463 default :
1464 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1465 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1466 return FALSE;
1470 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1472 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1473 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1476 /***********************************************************************
1477 * FILEDLG95_InitControls
1479 * WM_INITDIALOG message handler (before hook notification)
1481 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1483 BOOL win2000plus = FALSE;
1484 BOOL win98plus = FALSE;
1485 BOOL handledPath = FALSE;
1486 OSVERSIONINFOW osVi;
1488 static const TBBUTTON tbb[] =
1490 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1491 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1492 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1493 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1494 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1495 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1496 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1497 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1498 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1500 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1502 RECT rectTB;
1503 RECT rectlook;
1505 HIMAGELIST toolbarImageList;
1506 ITEMIDLIST *desktopPidl;
1507 SHFILEINFOW fileinfo;
1509 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1511 TRACE("%p\n", fodInfos);
1513 /* Get windows version emulating */
1514 osVi.dwOSVersionInfoSize = sizeof(osVi);
1515 GetVersionExW(&osVi);
1516 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1517 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1518 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1519 win2000plus = (osVi.dwMajorVersion > 4);
1520 if (win2000plus) win98plus = TRUE;
1522 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1525 /* Use either the edit or the comboboxex for the filename control */
1526 if (filename_is_edit( fodInfos ))
1528 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1529 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1531 else
1533 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1534 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1537 /* Get the hwnd of the controls */
1538 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1539 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1541 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1542 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1544 /* construct the toolbar */
1545 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1546 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1548 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1549 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1550 rectTB.left = rectlook.right;
1551 rectTB.top = rectlook.top-1;
1553 if (fodInfos->unicode)
1554 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1555 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1556 rectTB.left, rectTB.top,
1557 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1558 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1559 else
1560 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1561 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1562 rectTB.left, rectTB.top,
1563 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1564 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1566 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1568 /* FIXME: use TB_LOADIMAGES when implemented */
1569 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1570 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1571 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1573 /* Retrieve and add desktop icon to the toolbar */
1574 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1575 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1576 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1577 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1578 ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1580 DestroyIcon(fileinfo.hIcon);
1581 CoTaskMemFree(desktopPidl);
1583 /* Finish Toolbar Construction */
1584 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1585 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1587 if (is_places_bar_enabled(fodInfos))
1589 TBBUTTON tb = { 0 };
1590 HIMAGELIST himl;
1591 RECT rect;
1592 int i, cx;
1594 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0);
1595 GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect);
1596 cx = rect.right - rect.left;
1598 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx));
1599 himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1);
1601 filedlg_collect_places_pidls(fodInfos);
1602 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1604 int index;
1606 if (!fodInfos->places[i])
1607 continue;
1609 memset(&fileinfo, 0, sizeof(fileinfo));
1610 SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1611 SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON);
1612 index = ImageList_AddIcon(himl, fileinfo.hIcon);
1614 tb.iBitmap = index;
1615 tb.iString = (INT_PTR)fileinfo.szDisplayName;
1616 tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1617 tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1618 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb);
1620 DestroyIcon(fileinfo.hIcon);
1623 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl);
1624 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4));
1627 /* Set the window text with the text specified in the OPENFILENAME structure */
1628 if(fodInfos->title)
1630 SetWindowTextW(hwnd,fodInfos->title);
1632 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1634 WCHAR buf[64];
1635 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf));
1636 SetWindowTextW(hwnd, buf);
1639 /* Initialise the file name edit control */
1640 handledPath = FALSE;
1641 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1643 if(fodInfos->filename)
1645 /* 1. If win2000 or higher and filename contains a path, use it
1646 in preference over the lpstrInitialDir */
1647 if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, L"\\")) {
1648 WCHAR tmpBuf[MAX_PATH];
1649 WCHAR *nameBit;
1650 DWORD result;
1652 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1653 if (result) {
1655 /* nameBit is always shorter than the original filename. It may be NULL
1656 * when the filename contains only a drive name instead of file name */
1657 if (nameBit)
1659 lstrcpyW(fodInfos->filename,nameBit);
1660 *nameBit = 0x00;
1662 else
1663 *fodInfos->filename = '\0';
1665 heap_free(fodInfos->initdir);
1666 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1667 lstrcpyW(fodInfos->initdir, tmpBuf);
1668 handledPath = TRUE;
1669 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1670 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1672 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1674 } else {
1675 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1679 /* 2. (All platforms) If initdir is not null, then use it */
1680 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1682 /* Work out the proper path as supplied one might be relative */
1683 /* (Here because supplying '.' as dir browses to My Computer) */
1684 WCHAR tmpBuf[MAX_PATH];
1685 WCHAR tmpBuf2[MAX_PATH];
1686 WCHAR *nameBit;
1687 DWORD result;
1689 lstrcpyW(tmpBuf, fodInfos->initdir);
1690 if (PathFileExistsW(tmpBuf)) {
1691 /* initdir does not have to be a directory. If a file is
1692 * specified, the dir part is taken */
1693 if (PathIsDirectoryW(tmpBuf)) {
1694 PathAddBackslashW(tmpBuf);
1695 lstrcatW(tmpBuf, L"*");
1697 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1698 if (result) {
1699 *nameBit = 0x00;
1700 heap_free(fodInfos->initdir);
1701 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1702 lstrcpyW(fodInfos->initdir, tmpBuf2);
1703 handledPath = TRUE;
1704 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1707 else if (fodInfos->initdir)
1709 heap_free(fodInfos->initdir);
1710 fodInfos->initdir = NULL;
1711 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1715 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1717 /* 3. All except w2k+: if filename contains a path use it */
1718 if (!win2000plus && fodInfos->filename && *fodInfos->filename &&
1719 wcspbrk(fodInfos->filename, L"\\")) {
1720 WCHAR tmpBuf[MAX_PATH];
1721 WCHAR *nameBit;
1722 DWORD result;
1724 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1725 tmpBuf, &nameBit);
1726 if (result) {
1727 int len;
1729 /* nameBit is always shorter than the original filename */
1730 lstrcpyW(fodInfos->filename, nameBit);
1731 *nameBit = 0x00;
1733 len = lstrlenW(tmpBuf);
1734 heap_free(fodInfos->initdir);
1735 fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1736 lstrcpyW(fodInfos->initdir, tmpBuf);
1738 handledPath = TRUE;
1739 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1740 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1742 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1745 /* 4. Win2000+: Recently used */
1746 if (!handledPath && win2000plus) {
1747 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1748 fodInfos->initdir[0] = '\0';
1750 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1752 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1753 handledPath = TRUE;
1754 }else{
1755 heap_free(fodInfos->initdir);
1756 fodInfos->initdir = NULL;
1760 /* 5. win98+ and win2000+ if any files of specified filter types in
1761 current directory, use it */
1762 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1764 LPCWSTR lpstrPos = fodInfos->filter;
1765 WIN32_FIND_DATAW FindFileData;
1766 HANDLE hFind;
1768 while (1)
1770 /* filter is a list... title\0ext\0......\0\0 */
1772 /* Skip the title */
1773 if(! *lpstrPos) break; /* end */
1774 lpstrPos += lstrlenW(lpstrPos) + 1;
1776 /* See if any files exist in the current dir with this extension */
1777 if(! *lpstrPos) break; /* end */
1779 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1781 if (hFind == INVALID_HANDLE_VALUE) {
1782 /* None found - continue search */
1783 lpstrPos += lstrlenW(lpstrPos) + 1;
1785 } else {
1787 heap_free(fodInfos->initdir);
1788 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1789 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1791 handledPath = TRUE;
1792 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1793 debugstr_w(lpstrPos));
1794 FindClose(hFind);
1795 break;
1800 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1801 if (!handledPath && (win2000plus || win98plus)) {
1802 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1804 if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1806 if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK)
1808 /* last fallback */
1809 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1810 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1812 else
1813 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1815 else
1816 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1818 handledPath = TRUE;
1819 } else if (!handledPath) {
1820 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1821 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1822 handledPath = TRUE;
1823 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1826 SetFocus( fodInfos->DlgInfos.hwndFileName );
1827 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1829 /* Must the open as read only check box be checked ?*/
1830 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1832 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1835 /* Must the open as read only check box be hidden? */
1836 if (filedialog_is_readonly_hidden(fodInfos))
1838 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1839 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1842 /* Must the help button be hidden? */
1843 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1845 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1846 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1849 /* change Open to Save */
1850 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1852 WCHAR buf[16];
1853 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
1854 SetDlgItemTextW(hwnd, IDOK, buf);
1855 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
1856 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1859 /* Initialize the filter combo box */
1860 FILEDLG95_FILETYPE_Init(hwnd);
1862 return 0;
1865 /***********************************************************************
1866 * FILEDLG95_ResizeControls
1868 * WM_INITDIALOG message handler (after hook notification)
1870 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1872 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1874 if (fodInfos->DlgInfos.hwndCustomDlg)
1876 RECT rc;
1877 UINT flags = SWP_NOACTIVATE;
1879 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1880 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1882 /* resize the custom dialog to the parent size */
1883 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1884 GetClientRect(hwnd, &rc);
1885 else
1887 /* our own fake template is zero sized and doesn't have children, so
1888 * there is no need to resize it. Picasa depends on it.
1890 flags |= SWP_NOSIZE;
1891 SetRectEmpty(&rc);
1893 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1894 0, 0, rc.right, rc.bottom, flags);
1896 else
1898 /* Resize the height; if opened as read-only, checkbox and help button are
1899 * hidden and we are not using a custom template nor a customDialog
1901 if (filedialog_is_readonly_hidden(fodInfos) &&
1902 (!(fodInfos->ofnInfos->Flags &
1903 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1905 RECT rectDlg, rectHelp, rectCancel;
1906 GetWindowRect(hwnd, &rectDlg);
1907 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1908 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1909 /* subtract the height of the help button plus the space between the help
1910 * button and the cancel button to the height of the dialog
1912 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1913 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1914 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1917 return TRUE;
1920 /***********************************************************************
1921 * FILEDLG95_FillControls
1923 * WM_INITDIALOG message handler (after hook notification)
1925 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1927 LPITEMIDLIST pidlItemId = NULL;
1929 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1931 TRACE("dir=%s file=%s\n",
1932 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1934 /* Get the initial directory pidl */
1936 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1938 WCHAR path[MAX_PATH];
1940 GetCurrentDirectoryW(MAX_PATH,path);
1941 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1944 /* Initialise shell objects */
1945 FILEDLG95_SHELL_Init(hwnd);
1947 /* Initialize the Look In combo box */
1948 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1950 /* Browse to the initial directory */
1951 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1953 ILFree(pidlItemId);
1955 return TRUE;
1957 /***********************************************************************
1958 * FILEDLG95_Clean
1960 * Regroups all the cleaning functions of the filedlg
1962 void FILEDLG95_Clean(HWND hwnd)
1964 FILEDLG95_FILETYPE_Clean(hwnd);
1965 FILEDLG95_LOOKIN_Clean(hwnd);
1966 FILEDLG95_SHELL_Clean(hwnd);
1970 /***********************************************************************
1971 * Browse to arbitrary pidl
1973 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl)
1975 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
1977 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
1978 if (info->ofnInfos->Flags & OFN_EXPLORER)
1979 SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
1982 /***********************************************************************
1983 * FILEDLG95_OnWMCommand
1985 * WM_COMMAND message handler
1987 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1989 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1990 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1991 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
1993 switch (id)
1995 /* OK button */
1996 case IDOK:
1997 FILEDLG95_OnOpen(hwnd);
1998 break;
1999 /* Cancel button */
2000 case IDCANCEL:
2001 FILEDLG95_Clean(hwnd);
2002 EndDialog(hwnd, FALSE);
2003 break;
2004 /* Filetype combo box */
2005 case IDC_FILETYPE:
2006 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2007 break;
2008 /* LookIn combo box */
2009 case IDC_LOOKIN:
2010 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2011 break;
2013 /* --- toolbar --- */
2014 /* Up folder button */
2015 case FCIDM_TB_UPFOLDER:
2016 FILEDLG95_SHELL_UpFolder(hwnd);
2017 break;
2018 /* New folder button */
2019 case FCIDM_TB_NEWFOLDER:
2020 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2021 break;
2022 /* List option button */
2023 case FCIDM_TB_SMALLICON:
2024 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2025 break;
2026 /* Details option button */
2027 case FCIDM_TB_REPORTVIEW:
2028 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2029 break;
2031 case FCIDM_TB_DESKTOP:
2033 LPITEMIDLIST pidl;
2035 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl);
2036 filedlg_browse_to_pidl(fodInfos, pidl);
2037 ILFree(pidl);
2038 break;
2041 /* Places bar */
2042 case TBPLACES_CMDID_PLACE0:
2043 case TBPLACES_CMDID_PLACE1:
2044 case TBPLACES_CMDID_PLACE2:
2045 case TBPLACES_CMDID_PLACE3:
2046 case TBPLACES_CMDID_PLACE4:
2047 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2048 break;
2050 case edt1:
2051 case cmb13:
2052 break;
2055 /* Do not use the listview selection anymore */
2056 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2057 return 0;
2060 /***********************************************************************
2061 * FILEDLG95_OnWMGetIShellBrowser
2063 * WM_GETISHELLBROWSER message handler
2065 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
2067 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2069 TRACE("\n");
2071 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2073 return TRUE;
2077 /***********************************************************************
2078 * FILEDLG95_SendFileOK
2080 * Sends the CDN_FILEOK notification if required
2082 * RETURNS
2083 * TRUE if the dialog should close
2084 * FALSE if the dialog should not be closed
2086 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
2088 /* ask the hook if we can close */
2089 if (is_dialog_hooked(fodInfos))
2091 LRESULT retval = 0;
2093 TRACE("---\n");
2094 /* First send CDN_FILEOK as MSDN doc says */
2095 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2096 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
2097 if( retval)
2099 TRACE("canceled\n");
2100 return FALSE;
2103 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2104 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2105 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2106 if( retval)
2108 TRACE("canceled\n");
2109 return FALSE;
2112 return TRUE;
2115 /***********************************************************************
2116 * FILEDLG95_OnOpenMultipleFiles
2118 * Handles the opening of multiple files.
2120 * FIXME
2121 * check destination buffer size
2123 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2125 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2126 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2127 UINT nCount, nSizePath;
2129 TRACE("\n");
2131 if(fodInfos->unicode)
2133 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2134 ofn->lpstrFile[0] = '\0';
2136 else
2138 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2139 ofn->lpstrFile[0] = '\0';
2142 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2144 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2145 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2146 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2148 LPWSTR lpstrTemp = lpstrFileList;
2150 for ( nCount = 0; nCount < nFileCount; nCount++ )
2152 LPITEMIDLIST pidl;
2154 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2155 if (!pidl)
2157 WCHAR lpstrNotFound[100];
2158 WCHAR lpstrMsg[100];
2159 WCHAR tmp[400];
2161 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2162 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2164 lstrcpyW(tmp, lpstrTemp);
2165 lstrcatW(tmp, L"\n");
2166 lstrcatW(tmp, lpstrNotFound);
2167 lstrcatW(tmp, L"\n");
2168 lstrcatW(tmp, lpstrMsg);
2170 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2171 return FALSE;
2174 /* move to the next file in the list of files */
2175 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2176 ILFree(pidl);
2180 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2181 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2183 /* For "oldstyle" dialog the components have to
2184 be separated by blanks (not '\0'!) and short
2185 filenames have to be used! */
2186 FIXME("Components have to be separated by blanks\n");
2188 if(fodInfos->unicode)
2190 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2191 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2192 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2194 else
2196 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2198 if (ofn->lpstrFile != NULL)
2200 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2201 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2202 if (ofn->nMaxFile > nSizePath)
2204 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2205 ofn->lpstrFile + nSizePath,
2206 ofn->nMaxFile - nSizePath, NULL, NULL);
2211 fodInfos->ofnInfos->nFileOffset = nSizePath;
2212 fodInfos->ofnInfos->nFileExtension = 0;
2214 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2215 return FALSE;
2217 /* clean and exit */
2218 FILEDLG95_Clean(hwnd);
2219 return EndDialog(hwnd,TRUE);
2222 /* Returns the 'slot name' of the given module_name in the registry's
2223 * most-recently-used list. This will be an ASCII value in the
2224 * range ['a','z'). Returns zero on error.
2226 * The slot's value in the registry has the form:
2227 * module_name\0mru_path\0
2229 * If stored_path is given, then stored_path will contain the path name
2230 * stored in the registry's MRU list for the given module_name.
2232 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2233 * MRU list key for the given module_name.
2235 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2237 WCHAR mru_list[32], *cur_mru_slot;
2238 BOOL taken[25] = {0};
2239 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2240 HKEY hkey_tmp, *hkey;
2241 LONG ret;
2243 if(hkey_ret)
2244 hkey = hkey_ret;
2245 else
2246 hkey = &hkey_tmp;
2248 if(stored_path)
2249 *stored_path = '\0';
2251 ret = RegCreateKeyW(HKEY_CURRENT_USER,
2252 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", hkey);
2253 if(ret){
2254 WARN("Unable to create MRU key: %ld\n", ret);
2255 return 0;
2258 ret = RegGetValueW(*hkey, NULL, L"MRUList", RRF_RT_REG_SZ, &key_type,
2259 (LPBYTE)mru_list, &mru_list_size);
2260 if(ret || key_type != REG_SZ){
2261 if(ret == ERROR_FILE_NOT_FOUND)
2262 return 'a';
2264 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2265 RegCloseKey(*hkey);
2266 return 0;
2269 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2270 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2271 DWORD value_data_size = sizeof(value_data);
2273 *value_name = *cur_mru_slot;
2275 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2276 &key_type, (LPBYTE)value_data, &value_data_size);
2277 if(ret || key_type != REG_BINARY){
2278 WARN("Error getting MRU slot data: type: %ld, ret: %ld\n", key_type, ret);
2279 continue;
2282 if(!wcsicmp(module_name, value_data)){
2283 if(!hkey_ret)
2284 RegCloseKey(*hkey);
2285 if(stored_path)
2286 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2287 return *value_name;
2291 if(!hkey_ret)
2292 RegCloseKey(*hkey);
2294 /* the module name isn't in the registry, so find the next open slot */
2295 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2296 taken[*cur_mru_slot - 'a'] = TRUE;
2297 for(i = 0; i < 25; ++i){
2298 if(!taken[i])
2299 return i + 'a';
2302 /* all slots are taken, so return the last one in MRUList */
2303 --cur_mru_slot;
2304 return *cur_mru_slot;
2307 /* save the given filename as most-recently-used path for this module */
2308 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2310 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2311 LONG ret;
2312 HKEY hkey;
2314 /* get the current executable's name */
2315 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2317 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2318 return;
2320 module_name = wcsrchr(module_path, '\\');
2321 if(!module_name)
2322 module_name = module_path;
2323 else
2324 module_name += 1;
2326 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2327 if(!slot)
2328 return;
2329 *slot_name = slot;
2331 { /* update the slot's info */
2332 WCHAR *path_ends, *final;
2333 DWORD path_len, final_len;
2335 /* use only the path segment of `filename' */
2336 path_ends = wcsrchr(filename, '\\');
2337 path_len = path_ends - filename;
2339 final_len = path_len + lstrlenW(module_name) + 2;
2341 final = heap_alloc(final_len * sizeof(WCHAR));
2342 if(!final)
2343 return;
2344 lstrcpyW(final, module_name);
2345 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2346 final[final_len-1] = '\0';
2348 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2349 final_len * sizeof(WCHAR));
2350 if(ret){
2351 WARN("Error saving MRU data to slot %s: %ld\n", wine_dbgstr_w(slot_name), ret);
2352 heap_free(final);
2353 RegCloseKey(hkey);
2354 return;
2357 heap_free(final);
2360 { /* update MRUList value */
2361 WCHAR old_mru_list[32], new_mru_list[32];
2362 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2363 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2365 ret = RegGetValueW(hkey, NULL, L"MRUList", RRF_RT_ANY, &key_type,
2366 (LPBYTE)old_mru_list, &mru_list_size);
2367 if(ret || key_type != REG_SZ){
2368 if(ret == ERROR_FILE_NOT_FOUND){
2369 new_mru_list[0] = slot;
2370 new_mru_list[1] = '\0';
2371 }else{
2372 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2373 RegCloseKey(hkey);
2374 return;
2376 }else{
2377 /* copy old list data over so that the new slot is at the start
2378 * of the list */
2379 *new_mru_slot++ = slot;
2380 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2381 if(*old_mru_slot != slot)
2382 *new_mru_slot++ = *old_mru_slot;
2384 *new_mru_slot = '\0';
2387 ret = RegSetValueExW(hkey, L"MRUList", 0, REG_SZ, (LPBYTE)new_mru_list,
2388 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2389 if(ret){
2390 WARN("Error saving MRUList data: %ld\n", ret);
2391 RegCloseKey(hkey);
2392 return;
2397 /* load the most-recently-used path for this module */
2398 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2400 WCHAR module_path[MAX_PATH], *module_name;
2402 /* get the current executable's name */
2403 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2405 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2406 return;
2408 module_name = wcsrchr(module_path, '\\');
2409 if(!module_name)
2410 module_name = module_path;
2411 else
2412 module_name += 1;
2414 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2415 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2418 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2420 WCHAR strMsgTitle[MAX_PATH];
2421 WCHAR strMsgText [MAX_PATH];
2422 if (idCaption)
2423 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2424 else
2425 strMsgTitle[0] = '\0';
2426 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2427 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2430 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2431 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2433 int nOpenAction = defAction;
2434 LPWSTR lpszTemp, lpszTemp1;
2435 LPITEMIDLIST pidl = NULL;
2437 /* check for invalid chars */
2438 if((wcspbrk(lpstrPathAndFile+3, L"/:<>|") != NULL) && !(flags & OFN_NOVALIDATE))
2440 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2441 return FALSE;
2444 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2446 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2447 while (lpszTemp1)
2449 LPSHELLFOLDER lpsfChild;
2450 WCHAR lpwstrTemp[MAX_PATH];
2451 DWORD dwEaten, dwAttributes;
2452 LPWSTR p;
2454 lstrcpyW(lpwstrTemp, lpszTemp);
2455 if (lpszTemp == lpstrPathAndFile && (p = PathSkipRootW(lpwstrTemp)))
2457 *p = 0;
2459 else
2461 p = PathFindNextComponentW(lpwstrTemp);
2462 if (!p) break; /* end of path */
2463 *p = 0;
2465 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2467 /* There are no wildcards when OFN_NOVALIDATE is set */
2468 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2470 /* if the last element is a wildcard do a search */
2471 if(wcspbrk(lpszTemp1, L"*?") != NULL)
2473 nOpenAction = ONOPEN_SEARCH;
2474 break;
2477 lpszTemp1 = lpszTemp;
2479 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2481 /* append a backslash to drive letters */
2482 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2483 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2484 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2486 PathAddBackslashW(lpwstrTemp);
2489 dwAttributes = SFGAO_FOLDER;
2490 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2492 /* the path component is valid, we have a pidl of the next path component */
2493 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
2494 if(dwAttributes & SFGAO_FOLDER)
2496 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2498 ERR("bind to failed\n"); /* should not fail */
2499 break;
2501 IShellFolder_Release(*ppsf);
2502 *ppsf = lpsfChild;
2503 lpsfChild = NULL;
2505 else
2507 TRACE("value\n");
2509 /* end dialog, return value */
2510 nOpenAction = ONOPEN_OPEN;
2511 break;
2513 ILFree(pidl);
2514 pidl = NULL;
2516 else if (!(flags & OFN_NOVALIDATE))
2518 if(*lpszTemp || /* points to trailing null for last path element */
2519 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2521 if(flags & OFN_PATHMUSTEXIST)
2523 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2524 break;
2527 else
2529 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2531 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2532 break;
2535 /* change to the current folder */
2536 nOpenAction = ONOPEN_OPEN;
2537 break;
2539 else
2541 nOpenAction = ONOPEN_OPEN;
2542 break;
2545 ILFree(pidl);
2547 return nOpenAction;
2550 /***********************************************************************
2551 * FILEDLG95_OnOpen
2553 * Ok button WM_COMMAND message handler
2555 * If the function succeeds, the return value is nonzero.
2557 BOOL FILEDLG95_OnOpen(HWND hwnd)
2559 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2560 LPWSTR lpstrFileList;
2561 UINT nFileCount = 0;
2562 UINT sizeUsed = 0;
2563 BOOL ret = TRUE;
2564 WCHAR lpstrPathAndFile[MAX_PATH];
2565 LPSHELLFOLDER lpsf = NULL;
2566 int nOpenAction;
2568 TRACE("hwnd=%p\n", hwnd);
2570 /* try to browse the selected item */
2571 if(BrowseSelectedFolder(hwnd))
2572 return FALSE;
2574 /* get the files from the edit control */
2575 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2577 if(nFileCount == 0)
2578 return FALSE;
2580 if(nFileCount > 1)
2582 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2583 goto ret;
2586 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2589 Step 1: Build a complete path name from the current folder and
2590 the filename or path in the edit box.
2591 Special cases:
2592 - the path in the edit box is a root path
2593 (with or without drive letter)
2594 - the edit box contains ".." (or a path with ".." in it)
2597 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2598 heap_free(lpstrFileList);
2601 Step 2: here we have a cleaned up path
2603 We have to parse the path step by step to see if we have to browse
2604 to a folder if the path points to a directory or the last
2605 valid element is a directory.
2607 valid variables:
2608 lpstrPathAndFile: cleaned up path
2611 if (nFileCount &&
2612 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2613 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2614 nOpenAction = ONOPEN_OPEN;
2615 else
2616 nOpenAction = ONOPEN_BROWSE;
2618 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2619 fodInfos->ofnInfos->Flags,
2620 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2621 nOpenAction);
2622 if(!nOpenAction)
2623 goto ret;
2626 Step 3: here we have a cleaned up and validated path
2628 valid variables:
2629 lpsf: ShellFolder bound to the rightmost valid path component
2630 lpstrPathAndFile: cleaned up path
2631 nOpenAction: action to do
2633 TRACE("end validate sf=%p\n", lpsf);
2635 switch(nOpenAction)
2637 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2638 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2640 int iPos;
2641 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2642 DWORD len;
2644 /* replace the current filter */
2645 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2646 len = lstrlenW(lpszTemp)+1;
2647 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2648 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2650 /* set the filter cb to the extension when possible */
2651 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2652 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2654 /* fall through */
2655 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2656 TRACE("ONOPEN_BROWSE\n");
2658 IPersistFolder2 * ppf2;
2659 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2661 LPITEMIDLIST pidlCurrent;
2662 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2663 IPersistFolder2_Release(ppf2);
2664 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2666 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2667 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2669 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2670 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2673 else if( nOpenAction == ONOPEN_SEARCH )
2675 if (fodInfos->Shell.FOIShellView)
2676 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2678 ILFree(pidlCurrent);
2679 if (filename_is_edit( fodInfos ))
2680 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2681 else
2683 HWND hwnd;
2685 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2686 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2690 ret = FALSE;
2691 break;
2692 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2693 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2695 WCHAR *ext = NULL;
2697 /* update READONLY check box flag */
2698 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2699 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2700 else
2701 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2703 /* Attach the file extension with file name*/
2704 ext = PathFindExtensionW(lpstrPathAndFile);
2705 if (! *ext && fodInfos->defext)
2707 /* if no extension is specified with file name, then */
2708 /* attach the extension from file filter or default one */
2710 WCHAR *filterExt = NULL;
2711 LPWSTR lpstrFilter = NULL;
2712 int PathLength = lstrlenW(lpstrPathAndFile);
2714 /*Get the file extension from file type filter*/
2715 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2716 fodInfos->ofnInfos->nFilterIndex-1);
2718 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2720 WCHAR* filterSearchIndex;
2721 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2722 lstrcpyW(filterExt, lpstrFilter);
2724 /* if a semicolon-separated list of file extensions was given, do not include the
2725 semicolon or anything after it in the extension.
2726 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2727 filterSearchIndex = wcschr(filterExt, ';');
2728 if (filterSearchIndex)
2730 filterSearchIndex[0] = '\0';
2733 /* find the file extension by searching for the first dot in filterExt */
2734 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2735 /* if the extension is invalid or contains a glob, ignore it */
2736 filterSearchIndex = wcschr(filterExt, '.');
2737 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
2739 lstrcpyW(filterExt, filterSearchIndex);
2741 else
2743 heap_free(filterExt);
2744 filterExt = NULL;
2748 if (!filterExt)
2750 /* use the default file extension */
2751 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2752 lstrcpyW(filterExt, fodInfos->defext);
2755 if (*filterExt) /* ignore filterExt="" */
2757 /* Attach the dot*/
2758 lstrcatW(lpstrPathAndFile, L".");
2759 /* Attach the extension */
2760 lstrcatW(lpstrPathAndFile, filterExt);
2763 heap_free(filterExt);
2765 /* In Open dialog: if file does not exist try without extension */
2766 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2767 lpstrPathAndFile[PathLength] = '\0';
2769 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2770 if (*ext)
2771 ext++;
2772 if (!lstrcmpiW(fodInfos->defext, ext))
2773 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2774 else
2775 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2778 /* In Save dialog: check if the file already exists */
2779 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2780 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2781 && PathFileExistsW(lpstrPathAndFile))
2783 WCHAR lpstrOverwrite[100];
2784 int answer;
2786 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2787 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2788 MB_YESNO | MB_ICONEXCLAMATION);
2789 if (answer == IDNO || answer == IDCANCEL)
2791 ret = FALSE;
2792 goto ret;
2796 /* In Open dialog: check if it should be created if it doesn't exist */
2797 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2798 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2799 && !PathFileExistsW(lpstrPathAndFile))
2801 WCHAR lpstrCreate[100];
2802 int answer;
2804 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2805 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2806 MB_YESNO | MB_ICONEXCLAMATION);
2807 if (answer == IDNO || answer == IDCANCEL)
2809 ret = FALSE;
2810 goto ret;
2814 /* Check that the size of the file does not exceed buffer size.
2815 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2816 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2817 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2820 /* fill destination buffer */
2821 if (fodInfos->ofnInfos->lpstrFile)
2823 if(fodInfos->unicode)
2825 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2827 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2828 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2829 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2831 else
2833 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2835 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2836 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2837 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2838 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2842 if(fodInfos->unicode)
2844 LPWSTR lpszTemp;
2846 /* set filename offset */
2847 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2848 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2850 /* set extension offset */
2851 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2852 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2854 else
2856 LPSTR lpszTemp;
2857 CHAR tempFileA[MAX_PATH];
2859 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2860 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2861 tempFileA, sizeof(tempFileA), NULL, NULL);
2863 /* set filename offset */
2864 lpszTemp = PathFindFileNameA(tempFileA);
2865 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2867 /* set extension offset */
2868 lpszTemp = PathFindExtensionA(tempFileA);
2869 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2872 /* set the lpstrFileTitle */
2873 if(fodInfos->ofnInfos->lpstrFileTitle)
2875 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2876 if(fodInfos->unicode)
2878 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2879 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2881 else
2883 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2884 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2885 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2889 /* copy currently selected filter to lpstrCustomFilter */
2890 if (fodInfos->ofnInfos->lpstrCustomFilter)
2892 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2893 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2894 NULL, 0, NULL, NULL);
2895 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2897 LPSTR s = ofn->lpstrCustomFilter;
2898 s += strlen(ofn->lpstrCustomFilter)+1;
2899 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2900 s, len, NULL, NULL);
2905 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2906 goto ret;
2908 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2910 TRACE("close\n");
2911 FILEDLG95_Clean(hwnd);
2912 ret = EndDialog(hwnd, TRUE);
2914 else
2916 WORD size;
2918 size = lstrlenW(lpstrPathAndFile) + 1;
2919 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2920 size += 1;
2921 /* return needed size in first two bytes of lpstrFile */
2922 if(fodInfos->ofnInfos->lpstrFile)
2923 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2924 FILEDLG95_Clean(hwnd);
2925 ret = EndDialog(hwnd, FALSE);
2926 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2929 break;
2932 ret:
2933 if(lpsf) IShellFolder_Release(lpsf);
2934 return ret;
2937 /***********************************************************************
2938 * FILEDLG95_SHELL_Init
2940 * Initialisation of the shell objects
2942 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2944 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2946 TRACE("%p\n", hwnd);
2949 * Initialisation of the FileOpenDialogInfos structure
2952 /* Shell */
2954 /*ShellInfos */
2955 fodInfos->ShellInfos.hwndOwner = hwnd;
2957 /* Disable multi-select if flag not set */
2958 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2960 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2962 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2963 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2965 /* Construct the IShellBrowser interface */
2966 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2968 return NOERROR;
2971 /***********************************************************************
2972 * FILEDLG95_SHELL_ExecuteCommand
2974 * Change the folder option and refresh the view
2975 * If the function succeeds, the return value is nonzero.
2977 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2979 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2980 IContextMenu * pcm;
2982 TRACE("(%p,%p)\n", hwnd, lpVerb);
2984 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2985 SVGIO_BACKGROUND,
2986 &IID_IContextMenu,
2987 (LPVOID*)&pcm)))
2989 CMINVOKECOMMANDINFO ci;
2990 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2991 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2992 ci.lpVerb = lpVerb;
2993 ci.hwnd = hwnd;
2995 IContextMenu_InvokeCommand(pcm, &ci);
2996 IContextMenu_Release(pcm);
2999 return FALSE;
3002 /***********************************************************************
3003 * FILEDLG95_SHELL_UpFolder
3005 * Browse to the specified object
3006 * If the function succeeds, the return value is nonzero.
3008 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3010 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3012 TRACE("\n");
3014 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3015 NULL,
3016 SBSP_PARENT)))
3018 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3019 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3020 return TRUE;
3022 return FALSE;
3024 /***********************************************************************
3025 * FILEDLG95_SHELL_Clean
3027 * Cleans the memory used by shell objects
3029 static void FILEDLG95_SHELL_Clean(HWND hwnd)
3031 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3033 TRACE("\n");
3035 ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3037 /* clean Shell interfaces */
3038 if (fodInfos->Shell.FOIShellView)
3040 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3041 IShellView_Release(fodInfos->Shell.FOIShellView);
3043 if (fodInfos->Shell.FOIShellFolder)
3044 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3045 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3046 if (fodInfos->Shell.FOIDataObject)
3047 IDataObject_Release(fodInfos->Shell.FOIDataObject);
3050 /***********************************************************************
3051 * FILEDLG95_FILETYPE_Init
3053 * Initialisation of the file type combo box
3055 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3057 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3058 int nFilters = 0; /* number of filters */
3059 int nFilterIndexCB;
3061 TRACE("%p\n", hwnd);
3063 if(fodInfos->customfilter)
3065 /* customfilter has one entry... title\0ext\0
3066 * Set first entry of combo box item with customfilter
3068 LPWSTR lpstrExt;
3069 LPCWSTR lpstrPos = fodInfos->customfilter;
3071 /* Get the title */
3072 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3074 /* Copy the extensions */
3075 if (! *lpstrPos) return E_FAIL; /* malformed filter */
3076 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3077 lstrcpyW(lpstrExt,lpstrPos);
3079 /* Add the item at the end of the combo */
3080 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3081 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3083 nFilters++;
3085 if(fodInfos->filter)
3087 LPCWSTR lpstrPos = fodInfos->filter;
3089 for(;;)
3091 /* filter is a list... title\0ext\0......\0\0
3092 * Set the combo item text to the title and the item data
3093 * to the ext
3095 LPCWSTR lpstrDisplay;
3096 LPWSTR lpstrExt;
3098 /* Get the title */
3099 if(! *lpstrPos) break; /* end */
3100 lpstrDisplay = lpstrPos;
3101 lpstrPos += lstrlenW(lpstrPos) + 1;
3103 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3105 nFilters++;
3107 /* Copy the extensions */
3108 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3109 lstrcpyW(lpstrExt,lpstrPos);
3110 lpstrPos += lstrlenW(lpstrPos) + 1;
3112 /* Add the item at the end of the combo */
3113 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3115 /* malformed filters are added anyway... */
3116 if (!*lpstrExt) break;
3121 * Set the current filter to the one specified
3122 * in the initialisation structure
3124 if (fodInfos->filter || fodInfos->customfilter)
3126 LPWSTR lpstrFilter;
3128 /* Check to make sure our index isn't out of bounds. */
3129 if ( fodInfos->ofnInfos->nFilterIndex >
3130 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3131 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3133 /* set default filter index */
3134 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3135 fodInfos->ofnInfos->nFilterIndex = 1;
3137 /* calculate index of Combo Box item */
3138 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3139 if (fodInfos->customfilter == NULL)
3140 nFilterIndexCB--;
3142 /* Set the current index selection. */
3143 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3145 /* Get the corresponding text string from the combo box. */
3146 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3147 nFilterIndexCB);
3149 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3150 lpstrFilter = NULL;
3152 if(lpstrFilter)
3154 DWORD len;
3155 CharLowerW(lpstrFilter); /* lowercase */
3156 len = lstrlenW(lpstrFilter)+1;
3157 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3158 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3160 } else
3161 fodInfos->ofnInfos->nFilterIndex = 0;
3162 return S_OK;
3165 /***********************************************************************
3166 * FILEDLG95_FILETYPE_OnCommand
3168 * WM_COMMAND of the file type combo box
3169 * If the function succeeds, the return value is nonzero.
3171 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3173 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3175 switch(wNotifyCode)
3177 case CBN_SELENDOK:
3179 LPWSTR lpstrFilter;
3181 /* Get the current item of the filetype combo box */
3182 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3184 /* set the current filter index */
3185 fodInfos->ofnInfos->nFilterIndex = iItem +
3186 (fodInfos->customfilter == NULL ? 1 : 0);
3188 /* Set the current filter with the current selection */
3189 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3191 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3192 iItem);
3193 if((INT_PTR)lpstrFilter != CB_ERR)
3195 DWORD len;
3196 CharLowerW(lpstrFilter); /* lowercase */
3197 len = lstrlenW(lpstrFilter)+1;
3198 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3199 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3200 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3201 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3204 /* Refresh the actual view to display the included items*/
3205 if (fodInfos->Shell.FOIShellView)
3206 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3209 return FALSE;
3211 /***********************************************************************
3212 * FILEDLG95_FILETYPE_SearchExt
3214 * searches for an extension in the filetype box
3216 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3218 int i, iCount;
3220 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3222 TRACE("%s\n", debugstr_w(lpstrExt));
3224 if(iCount != CB_ERR)
3226 for(i=0;i<iCount;i++)
3228 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3229 return i;
3232 return -1;
3235 /***********************************************************************
3236 * FILEDLG95_FILETYPE_Clean
3238 * Clean the memory used by the filetype combo box
3240 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3242 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3243 int iPos;
3244 int iCount;
3246 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3248 TRACE("\n");
3250 /* Delete each string of the combo and their associated data */
3251 if(iCount != CB_ERR)
3253 for(iPos = iCount-1;iPos>=0;iPos--)
3255 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3256 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3259 /* Current filter */
3260 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3263 /***********************************************************************
3264 * FILEDLG95_LOOKIN_Init
3266 * Initialisation of the look in combo box
3269 /* Small helper function, to determine if the unixfs shell extension is rooted
3270 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3272 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3273 HKEY hKey;
3275 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3276 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3277 "{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3278 return FALSE;
3280 RegCloseKey(hKey);
3281 return TRUE;
3284 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3286 IShellFolder *psfRoot, *psfDrives;
3287 IEnumIDList *lpeRoot, *lpeDrives;
3288 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3289 HDC hdc;
3290 TEXTMETRICW tm;
3291 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3293 TRACE("%p\n", hwndCombo);
3295 liInfos->iMaxIndentation = 0;
3297 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3299 hdc = GetDC( hwndCombo );
3300 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3301 GetTextMetricsW( hdc, &tm );
3302 ReleaseDC( hwndCombo, hdc );
3304 /* set item height for both text field and listbox */
3305 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3306 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3308 /* Turn on the extended UI for the combo box like Windows does */
3309 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3311 /* Initialise data of Desktop folder */
3312 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3313 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3314 ILFree(pidlTmp);
3316 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3318 SHGetDesktopFolder(&psfRoot);
3320 if (psfRoot)
3322 /* enumerate the contents of the desktop */
3323 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3325 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3327 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3329 /* If the unixfs extension is rooted, we don't expand the drives by default */
3330 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3332 /* special handling for CSIDL_DRIVES */
3333 if (ILIsEqual(pidlTmp, pidlDrives))
3335 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3337 /* enumerate the drives */
3338 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3340 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3342 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3343 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3344 ILFree(pidlAbsTmp);
3345 ILFree(pidlTmp1);
3347 IEnumIDList_Release(lpeDrives);
3349 IShellFolder_Release(psfDrives);
3354 ILFree(pidlTmp);
3356 IEnumIDList_Release(lpeRoot);
3358 IShellFolder_Release(psfRoot);
3361 ILFree(pidlDrives);
3364 /***********************************************************************
3365 * FILEDLG95_LOOKIN_DrawItem
3367 * WM_DRAWITEM message handler
3369 static LRESULT FILEDLG95_LOOKIN_DrawItem(HWND hwnd, LPDRAWITEMSTRUCT pDIStruct)
3371 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3372 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3373 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3374 RECT rectText, rectIcon, lookin_rect;
3375 SHFILEINFOW sfi;
3376 HIMAGELIST ilItemImage;
3377 int iIndentation;
3378 TEXTMETRICW tm;
3379 LPSFOLDER tmpFolder;
3380 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3381 UINT icon_width, icon_height;
3382 FileOpenDlgInfos *dialog;
3383 int height;
3385 TRACE("\n");
3387 if(pDIStruct->itemID == -1)
3388 return 0;
3390 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3391 pDIStruct->itemID)))
3392 return 0;
3395 icon_width = GetSystemMetrics(SM_CXICON);
3396 icon_height = GetSystemMetrics(SM_CYICON);
3397 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3399 icon_width = GetSystemMetrics(SM_CXSMICON);
3400 icon_height = GetSystemMetrics(SM_CYSMICON);
3401 shgfi_flags |= SHGFI_SMALLICON;
3404 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3405 0, &sfi, sizeof (sfi), shgfi_flags );
3407 /* Is this item selected ? */
3408 if(pDIStruct->itemState & ODS_SELECTED)
3410 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3411 SetBkColor(pDIStruct->hDC,crHighLight);
3412 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3414 else
3416 SetTextColor(pDIStruct->hDC,crText);
3417 SetBkColor(pDIStruct->hDC,crWin);
3418 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3421 /* Do not indent item if drawing in the edit of the combo */
3422 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3423 iIndentation = 0;
3424 else
3425 iIndentation = tmpFolder->m_iIndent;
3427 /* Draw text and icon */
3429 /* Initialise the icon display area */
3430 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3431 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3432 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3433 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3435 /* Initialise the text display area */
3436 GetTextMetricsW(pDIStruct->hDC, &tm);
3437 rectText.left = rectIcon.right;
3438 rectText.top =
3439 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3440 rectText.right = pDIStruct->rcItem.right;
3441 rectText.bottom =
3442 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3444 /* Draw the icon from the image list */
3445 ImageList_Draw(ilItemImage,
3446 sfi.iIcon,
3447 pDIStruct->hDC,
3448 rectIcon.left,
3449 rectIcon.top,
3450 ILD_TRANSPARENT );
3452 /* Draw the associated text */
3453 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3455 dialog = get_filedlg_infoptr(hwnd);
3456 GetWindowRect(dialog->DlgInfos.hwndLookInCB, &lookin_rect);
3457 height = lookin_rect.bottom - lookin_rect.top;
3458 SendMessageW(dialog->DlgInfos.hwndTB, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
3460 return NOERROR;
3463 /***********************************************************************
3464 * FILEDLG95_LOOKIN_OnCommand
3466 * LookIn combo box WM_COMMAND message handler
3467 * If the function succeeds, the return value is nonzero.
3469 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3471 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3473 TRACE("%p\n", fodInfos);
3475 switch(wNotifyCode)
3477 case CBN_SELENDOK:
3479 LPSFOLDER tmpFolder;
3480 int iItem;
3482 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3484 if( iItem == CB_ERR) return FALSE;
3486 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3487 iItem)))
3488 return FALSE;
3491 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3492 tmpFolder->pidlItem,
3493 SBSP_ABSOLUTE)))
3495 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3496 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3497 return TRUE;
3499 break;
3503 return FALSE;
3506 /***********************************************************************
3507 * FILEDLG95_LOOKIN_AddItem
3509 * Adds an absolute pidl item to the lookin combo box
3510 * returns the index of the inserted item
3512 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3514 LPITEMIDLIST pidlNext;
3515 SHFILEINFOW sfi;
3516 SFOLDER *tmpFolder;
3517 LookInInfos *liInfos;
3519 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3521 if(!pidl)
3522 return -1;
3524 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3525 return -1;
3527 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3528 tmpFolder->m_iIndent = 0;
3530 /* Calculate the indentation of the item in the lookin*/
3531 pidlNext = pidl;
3532 while ((pidlNext = ILGetNext(pidlNext)))
3534 tmpFolder->m_iIndent++;
3537 tmpFolder->pidlItem = ILClone(pidl);
3539 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3540 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3542 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3543 SHGetFileInfoW((LPCWSTR)pidl,
3545 &sfi,
3546 sizeof(sfi),
3547 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3549 TRACE("-- Add %s attr=0x%08lx\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3551 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3553 int iItemID;
3555 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3557 /* Add the item at the end of the list */
3558 if(iInsertId < 0)
3560 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3562 /* Insert the item at the iInsertId position*/
3563 else
3565 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3568 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3569 return iItemID;
3572 ILFree( tmpFolder->pidlItem );
3573 heap_free( tmpFolder );
3574 return -1;
3578 /***********************************************************************
3579 * FILEDLG95_LOOKIN_InsertItemAfterParent
3581 * Insert an item below its parent
3583 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3586 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3587 int iParentPos;
3589 TRACE("\n");
3591 if (pidl == pidlParent)
3592 return -1;
3594 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3596 if(iParentPos < 0)
3598 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3601 ILFree(pidlParent);
3603 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3606 /***********************************************************************
3607 * FILEDLG95_LOOKIN_SelectItem
3609 * Adds an absolute pidl item to the lookin combo box
3610 * returns the index of the inserted item
3612 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3614 int iItemPos;
3615 LookInInfos *liInfos;
3617 TRACE("%p, %p\n", hwnd, pidl);
3619 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3621 liInfos = GetPropA(hwnd,LookInInfosStr);
3623 if(iItemPos < 0)
3625 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3626 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3629 else
3631 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3632 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3634 int iRemovedItem;
3636 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3637 break;
3638 if(iRemovedItem < iItemPos)
3639 iItemPos--;
3643 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3644 liInfos->uSelectedItem = iItemPos;
3646 return 0;
3650 /***********************************************************************
3651 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3653 * Remove the item with an expansion level over iExpansionLevel
3655 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3657 int iItemPos;
3658 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3660 TRACE("\n");
3662 if(liInfos->iMaxIndentation <= 2)
3663 return -1;
3665 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3667 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3668 ILFree(tmpFolder->pidlItem);
3669 heap_free(tmpFolder);
3670 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3671 liInfos->iMaxIndentation--;
3673 return iItemPos;
3676 return -1;
3679 /***********************************************************************
3680 * FILEDLG95_LOOKIN_SearchItem
3682 * Search for pidl in the lookin combo box
3683 * returns the index of the found item
3685 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3687 int i = 0;
3688 int iCount;
3690 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3692 TRACE("0x%08Ix 0x%x\n",searchArg, iSearchMethod);
3694 if (iCount != CB_ERR)
3696 for(;i<iCount;i++)
3698 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3700 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3701 return i;
3702 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3703 return i;
3707 return -1;
3710 /***********************************************************************
3711 * FILEDLG95_LOOKIN_Clean
3713 * Clean the memory used by the lookin combo box
3715 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3717 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3718 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3719 int iPos, iCount;
3721 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3723 TRACE("\n");
3725 /* Delete each string of the combo and their associated data */
3726 if (iCount != CB_ERR)
3728 for(iPos = iCount-1;iPos>=0;iPos--)
3730 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3731 ILFree(tmpFolder->pidlItem);
3732 heap_free(tmpFolder);
3733 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3737 /* LookInInfos structure */
3738 heap_free(liInfos);
3739 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3742 /***********************************************************************
3743 * get_def_format
3745 * Fill the FORMATETC used in the shell id list
3747 static FORMATETC get_def_format(void)
3749 static CLIPFORMAT cfFormat;
3750 FORMATETC formatetc;
3752 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3753 formatetc.cfFormat = cfFormat;
3754 formatetc.ptd = 0;
3755 formatetc.dwAspect = DVASPECT_CONTENT;
3756 formatetc.lindex = -1;
3757 formatetc.tymed = TYMED_HGLOBAL;
3758 return formatetc;
3761 /***********************************************************************
3762 * FILEDLG95_FILENAME_FillFromSelection
3764 * fills the edit box from the cached DataObject
3766 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3768 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3769 LPITEMIDLIST pidl;
3770 LPWSTR lpstrAllFiles, lpstrTmp;
3771 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3772 STGMEDIUM medium;
3773 LPIDA cida;
3774 FORMATETC formatetc = get_def_format();
3776 TRACE("\n");
3778 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3779 return;
3781 cida = GlobalLock(medium.hGlobal);
3782 nFileSelected = cida->cidl;
3784 /* Allocate a buffer */
3785 nAllFilesMaxLength = MAX_PATH + 3;
3786 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3787 if (!lpstrAllFiles)
3788 goto ret;
3790 /* Loop through the selection, handle only files (not folders) */
3791 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3793 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3794 if (pidl)
3796 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3798 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3800 nAllFilesMaxLength *= 2;
3801 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3802 if (!lpstrTmp)
3803 goto ret;
3804 lpstrAllFiles = lpstrTmp;
3806 nFiles += 1;
3807 lpstrAllFiles[nAllFilesLength++] = '"';
3808 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3809 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3810 nAllFilesLength += nThisFileLength;
3811 lpstrAllFiles[nAllFilesLength++] = '"';
3812 lpstrAllFiles[nAllFilesLength++] = ' ';
3817 if (nFiles != 0)
3819 /* If there's only one file, use the name as-is without quotes */
3820 lpstrTmp = lpstrAllFiles;
3821 if (nFiles == 1)
3823 lpstrTmp += 1;
3824 lpstrTmp[nThisFileLength] = 0;
3826 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3827 /* Select the file name like Windows does */
3828 if (filename_is_edit(fodInfos))
3829 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3832 ret:
3833 heap_free(lpstrAllFiles);
3834 COMCTL32_ReleaseStgMedium(medium);
3838 /* copied from shell32 to avoid linking to it
3839 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3840 * is dependent on whether emulated OS is unicode or not.
3842 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3844 switch (src->uType)
3846 case STRRET_WSTR:
3847 lstrcpynW(dest, src->pOleStr, len);
3848 CoTaskMemFree(src->pOleStr);
3849 break;
3851 case STRRET_CSTR:
3852 if (!MultiByteToWideChar( CP_ACP, 0, src->cStr, -1, dest, len ) && len)
3853 dest[len-1] = 0;
3854 break;
3856 case STRRET_OFFSET:
3857 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->uOffset, -1, dest, len ) && len)
3858 dest[len-1] = 0;
3859 break;
3861 default:
3862 FIXME("unknown type %x!\n", src->uType);
3863 if (len) *dest = '\0';
3864 return E_FAIL;
3866 return S_OK;
3869 /***********************************************************************
3870 * FILEDLG95_FILENAME_GetFileNames
3872 * Copies the filenames to a delimited string list.
3874 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3876 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3877 UINT nFileCount = 0; /* number of files */
3878 UINT nStrLen = 0; /* length of string in edit control */
3879 LPWSTR lpstrEdit; /* buffer for string from edit control */
3881 TRACE("\n");
3883 /* get the filenames from the filename control */
3884 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3885 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3886 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3888 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3890 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3891 heap_free(lpstrEdit);
3892 return nFileCount;
3896 * DATAOBJECT Helper functions
3899 /***********************************************************************
3900 * COMCTL32_ReleaseStgMedium
3902 * like ReleaseStgMedium from ole32
3904 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3906 if(medium.pUnkForRelease)
3908 IUnknown_Release(medium.pUnkForRelease);
3910 else
3912 GlobalUnlock(medium.hGlobal);
3913 GlobalFree(medium.hGlobal);
3917 /***********************************************************************
3918 * GetPidlFromDataObject
3920 * Return pidl(s) by number from the cached DataObject
3922 * nPidlIndex=0 gets the fully qualified root path
3924 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3927 STGMEDIUM medium;
3928 FORMATETC formatetc = get_def_format();
3929 LPITEMIDLIST pidl = NULL;
3931 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3933 if (!doSelected)
3934 return NULL;
3936 /* Get the pidls from IDataObject */
3937 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3939 LPIDA cida = GlobalLock(medium.hGlobal);
3940 if(nPidlIndex <= cida->cidl)
3942 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3944 COMCTL32_ReleaseStgMedium(medium);
3946 return pidl;
3949 /***********************************************************************
3950 * GetNumSelected
3952 * Return the number of selected items in the DataObject.
3955 static UINT GetNumSelected( IDataObject *doSelected )
3957 UINT retVal = 0;
3958 STGMEDIUM medium;
3959 FORMATETC formatetc = get_def_format();
3961 TRACE("sv=%p\n", doSelected);
3963 if (!doSelected) return 0;
3965 /* Get the pidls from IDataObject */
3966 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3968 LPIDA cida = GlobalLock(medium.hGlobal);
3969 retVal = cida->cidl;
3970 COMCTL32_ReleaseStgMedium(medium);
3971 return retVal;
3973 return 0;
3977 * TOOLS
3980 /***********************************************************************
3981 * GetName
3983 * Get the pidl's display name (relative to folder) and
3984 * put it in lpstrFileName.
3986 * Return NOERROR on success,
3987 * E_FAIL otherwise
3990 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3992 STRRET str;
3993 HRESULT hRes;
3995 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3997 if(!lpsf)
3999 SHGetDesktopFolder(&lpsf);
4000 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
4001 IShellFolder_Release(lpsf);
4002 return hRes;
4005 /* Get the display name of the pidl relative to the folder */
4006 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4008 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4010 return E_FAIL;
4013 /***********************************************************************
4014 * GetShellFolderFromPidl
4016 * pidlRel is the item pidl relative
4017 * Return the IShellFolder of the absolute pidl
4019 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
4021 IShellFolder *psf = NULL,*psfParent;
4023 TRACE("%p\n", pidlAbs);
4025 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4027 psf = psfParent;
4028 if(pidlAbs && pidlAbs->mkid.cb)
4030 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4032 IShellFolder_Release(psfParent);
4033 return psf;
4036 /* return the desktop */
4037 return psfParent;
4039 return NULL;
4042 /***********************************************************************
4043 * GetParentPidl
4045 * Return the LPITEMIDLIST to the parent of the pidl in the list
4047 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4049 LPITEMIDLIST pidlParent;
4051 TRACE("%p\n", pidl);
4053 pidlParent = ILClone(pidl);
4054 ILRemoveLastID(pidlParent);
4056 return pidlParent;
4059 /***********************************************************************
4060 * GetPidlFromName
4062 * returns the pidl of the file name relative to folder
4063 * NULL if an error occurred
4065 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4067 LPITEMIDLIST pidl = NULL;
4068 ULONG ulEaten;
4070 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4072 if(!lpcstrFileName) return NULL;
4073 if(!*lpcstrFileName) return NULL;
4075 if(!lpsf)
4077 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4078 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4079 IShellFolder_Release(lpsf);
4082 else
4084 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4086 return pidl;
4091 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4093 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4094 HRESULT ret;
4096 TRACE("%p, %p\n", psf, pidl);
4098 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4100 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
4101 /* see documentation shell 4.1*/
4102 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4105 /***********************************************************************
4106 * BrowseSelectedFolder
4108 static BOOL BrowseSelectedFolder(HWND hwnd)
4110 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4111 BOOL bBrowseSelFolder = FALSE;
4113 TRACE("\n");
4115 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4117 LPITEMIDLIST pidlSelection;
4119 /* get the file selected */
4120 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4121 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4123 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4124 pidlSelection, SBSP_RELATIVE ) ) )
4126 WCHAR buf[64];
4127 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4128 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4130 bBrowseSelFolder = TRUE;
4131 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4132 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4134 ILFree( pidlSelection );
4137 return bBrowseSelFolder;
4140 static inline BOOL valid_struct_size( DWORD size )
4142 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4143 (size == sizeof( OPENFILENAMEW ));
4146 static inline BOOL is_win16_looks(DWORD flags)
4148 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4149 !(flags & OFN_EXPLORER));
4152 /* ------------------ APIs ---------------------- */
4154 /***********************************************************************
4155 * GetOpenFileNameA (COMDLG32.@)
4157 * Creates a dialog box for the user to select a file to open.
4159 * RETURNS
4160 * TRUE on success: user enters a valid file
4161 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4164 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4166 TRACE("flags 0x%08lx\n", ofn->Flags);
4168 if (!valid_struct_size( ofn->lStructSize ))
4170 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4171 return FALSE;
4174 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4175 if (ofn->Flags & OFN_FILEMUSTEXIST)
4176 ofn->Flags |= OFN_PATHMUSTEXIST;
4178 if (is_win16_looks(ofn->Flags))
4179 return GetFileName31A(ofn, OPEN_DIALOG);
4180 else
4182 FileOpenDlgInfos info;
4184 init_filedlg_infoA(ofn, &info);
4185 return GetFileDialog95(&info, OPEN_DIALOG);
4189 /***********************************************************************
4190 * GetOpenFileNameW (COMDLG32.@)
4192 * Creates a dialog box for the user to select a file to open.
4194 * RETURNS
4195 * TRUE on success: user enters a valid file
4196 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4199 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4201 TRACE("flags 0x%08lx\n", ofn->Flags);
4203 if (!valid_struct_size( ofn->lStructSize ))
4205 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4206 return FALSE;
4209 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4210 if (ofn->Flags & OFN_FILEMUSTEXIST)
4211 ofn->Flags |= OFN_PATHMUSTEXIST;
4213 if (is_win16_looks(ofn->Flags))
4214 return GetFileName31W(ofn, OPEN_DIALOG);
4215 else
4217 FileOpenDlgInfos info;
4219 init_filedlg_infoW(ofn, &info);
4220 return GetFileDialog95(&info, OPEN_DIALOG);
4225 /***********************************************************************
4226 * GetSaveFileNameA (COMDLG32.@)
4228 * Creates a dialog box for the user to select a file to save.
4230 * RETURNS
4231 * TRUE on success: user enters a valid file
4232 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4235 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4237 if (!valid_struct_size( ofn->lStructSize ))
4239 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4240 return FALSE;
4243 if (is_win16_looks(ofn->Flags))
4244 return GetFileName31A(ofn, SAVE_DIALOG);
4245 else
4247 FileOpenDlgInfos info;
4249 init_filedlg_infoA(ofn, &info);
4250 return GetFileDialog95(&info, SAVE_DIALOG);
4254 /***********************************************************************
4255 * GetSaveFileNameW (COMDLG32.@)
4257 * Creates a dialog box for the user to select a file to save.
4259 * RETURNS
4260 * TRUE on success: user enters a valid file
4261 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4264 BOOL WINAPI GetSaveFileNameW(
4265 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4267 if (!valid_struct_size( ofn->lStructSize ))
4269 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4270 return FALSE;
4273 if (is_win16_looks(ofn->Flags))
4274 return GetFileName31W(ofn, SAVE_DIALOG);
4275 else
4277 FileOpenDlgInfos info;
4279 init_filedlg_infoW(ofn, &info);
4280 return GetFileDialog95(&info, SAVE_DIALOG);
4284 /***********************************************************************
4285 * GetFileTitleA (COMDLG32.@)
4287 * See GetFileTitleW.
4289 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4291 int ret;
4292 UNICODE_STRING strWFile;
4293 LPWSTR lpWTitle;
4295 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4296 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4297 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4298 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4299 RtlFreeUnicodeString( &strWFile );
4300 heap_free( lpWTitle );
4301 return ret;
4305 /***********************************************************************
4306 * GetFileTitleW (COMDLG32.@)
4308 * Get the name of a file.
4310 * PARAMS
4311 * lpFile [I] name and location of file
4312 * lpTitle [O] returned file name
4313 * cbBuf [I] buffer size of lpTitle
4315 * RETURNS
4316 * Success: zero
4317 * Failure: negative number.
4319 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4321 int i, len;
4322 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4324 if(lpFile == NULL || lpTitle == NULL)
4325 return -1;
4327 len = lstrlenW(lpFile);
4329 if (len == 0)
4330 return -1;
4332 if(wcspbrk(lpFile, L"*[]"))
4333 return -1;
4335 len--;
4337 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4338 return -1;
4340 for(i = len; i >= 0; i--)
4342 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4344 i++;
4345 break;
4349 if(i == -1)
4350 i++;
4352 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4354 len = lstrlenW(lpFile+i)+1;
4355 if(cbBuf < len)
4356 return len;
4358 lstrcpyW(lpTitle, &lpFile[i]);
4359 return 0;