include: Update the PEB and TEB structures.
[wine.git] / dlls / comdlg32 / filedlg.c
blob415c0580461a955752c140366b7233228baf9f0b
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 #define NONAMELESSUNION
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winternl.h"
60 #include "winnls.h"
61 #include "wingdi.h"
62 #include "winreg.h"
63 #include "winuser.h"
64 #include "commdlg.h"
65 #include "dlgs.h"
66 #include "cdlg.h"
67 #include "cderr.h"
68 #include "shellapi.h"
69 #include "shlobj.h"
70 #include "filedlgbrowser.h"
71 #include "shlwapi.h"
73 #include "wine/debug.h"
74 #include "wine/heap.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
78 #define UNIMPLEMENTED_FLAGS \
79 (OFN_DONTADDTORECENT |\
80 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
81 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
83 /***********************************************************************
84 * Data structure and global variables
86 typedef struct SFolder
88 int m_iImageIndex; /* Index of picture in image list */
89 HIMAGELIST hImgList;
90 int m_iIndent; /* Indentation index */
91 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
93 } SFOLDER,*LPSFOLDER;
95 typedef struct tagLookInInfo
97 int iMaxIndentation;
98 UINT uSelectedItem;
99 } LookInInfos;
102 /***********************************************************************
103 * Defines and global variables
106 /* Draw item constant */
107 #define XTEXTOFFSET 3
109 /* AddItem flags*/
110 #define LISTEND -1
112 /* SearchItem methods */
113 #define SEARCH_PIDL 1
114 #define SEARCH_EXP 2
115 #define ITEM_NOTFOUND -1
117 /* Undefined windows message sent by CreateViewObject*/
118 #define WM_GETISHELLBROWSER WM_USER+7
120 #define TBPLACES_CMDID_PLACE0 0xa064
121 #define TBPLACES_CMDID_PLACE1 0xa065
122 #define TBPLACES_CMDID_PLACE2 0xa066
123 #define TBPLACES_CMDID_PLACE3 0xa067
124 #define TBPLACES_CMDID_PLACE4 0xa068
126 /* NOTE
127 * Those macros exist in windowsx.h. However, you can't really use them since
128 * they rely on the UNICODE defines and can't be used inside Wine itself.
131 /* Combo box macros */
132 #define CBGetItemDataPtr(hwnd,iItemId) \
133 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
135 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
136 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
138 FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd)
140 return GetPropW(hwnd, L"FileOpenDlgInfos");
143 static BOOL is_dialog_hooked(const FileOpenDlgInfos *info)
145 return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
148 static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info)
150 return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG);
153 /***********************************************************************
154 * Prototypes
157 /* Internal functions used by the dialog */
158 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
159 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
160 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
161 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
162 static BOOL FILEDLG95_OnOpen(HWND hwnd);
163 static LRESULT FILEDLG95_InitControls(HWND hwnd);
164 static void FILEDLG95_Clean(HWND hwnd);
166 /* Functions used by the shell navigation */
167 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
168 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
169 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
170 static void FILEDLG95_SHELL_Clean(HWND hwnd);
172 /* Functions used by the EDIT box */
173 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
175 /* Functions used by the filetype combo box */
176 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
177 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
178 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
179 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
181 /* Functions used by the Look In combo box */
182 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
183 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
184 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
185 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
186 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
187 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
188 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
189 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
190 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
192 /* Functions for dealing with the most-recently-used registry keys */
193 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
194 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
195 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
197 /* Miscellaneous tool functions */
198 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
199 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
200 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
201 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
202 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
203 static UINT GetNumSelected( IDataObject *doSelected );
204 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
206 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
207 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
208 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
209 static BOOL BrowseSelectedFolder(HWND hwnd);
211 static BOOL get_config_key_as_dword(HKEY hkey, const WCHAR *name, DWORD *value)
213 DWORD type, data, size;
215 size = sizeof(data);
216 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size))
218 *value = data;
219 return TRUE;
222 return FALSE;
225 static BOOL get_config_key_dword(HKEY hkey, const WCHAR *name, DWORD *value)
227 DWORD type, data, size;
229 size = sizeof(data);
230 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
232 *value = data;
233 return TRUE;
236 return FALSE;
239 static BOOL get_config_key_string(HKEY hkey, const WCHAR *name, WCHAR **value)
241 DWORD type, size;
242 WCHAR *str;
244 if (RegQueryValueExW(hkey, name, 0, &type, NULL, &size))
245 return FALSE;
246 if (type != REG_SZ && type != REG_EXPAND_SZ)
247 return FALSE;
249 str = heap_alloc(size);
250 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size))
252 heap_free(str);
253 return FALSE;
256 *value = str;
257 return TRUE;
260 static BOOL is_places_bar_enabled(const FileOpenDlgInfos *fodInfos)
262 DWORD value;
263 HKEY hkey;
265 if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) ||
266 (fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) ||
267 !(fodInfos->ofnInfos->Flags & OFN_EXPLORER))
269 return FALSE;
272 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey))
273 return TRUE;
275 value = 0;
276 get_config_key_as_dword(hkey, L"NoPlacesBar", &value);
277 RegCloseKey(hkey);
278 return value == 0;
281 static void filedlg_collect_places_pidls(FileOpenDlgInfos *fodInfos)
283 static const int default_places[] =
285 CSIDL_DESKTOP,
286 CSIDL_MYDOCUMENTS,
287 CSIDL_DRIVES,
289 unsigned int i;
290 HKEY hkey;
292 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
293 &hkey))
295 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
297 WCHAR nameW[8];
298 DWORD value;
299 HRESULT hr;
300 WCHAR *str;
302 swprintf(nameW, ARRAY_SIZE(nameW), L"Place%d", i);
303 if (get_config_key_dword(hkey, nameW, &value))
305 hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]);
306 if (FAILED(hr))
307 WARN("Unrecognized special folder %lu.\n", value);
309 else if (get_config_key_string(hkey, nameW, &str))
311 hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL);
312 if (FAILED(hr))
313 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str));
314 heap_free(str);
318 /* FIXME: eliminate duplicates. */
320 RegCloseKey(hkey);
321 return;
324 for (i = 0; i < ARRAY_SIZE(default_places); i++)
325 SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]);
328 /***********************************************************************
329 * GetFileName95
331 * Creates an Open common dialog box that lets the user select
332 * the drive, directory, and the name of a file or set of files to open.
334 * IN : The FileOpenDlgInfos structure associated with the dialog
335 * OUT : TRUE on success
336 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
338 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
340 LRESULT lRes;
341 void *template;
342 HRSRC hRes;
343 HANDLE hDlgTmpl = 0;
344 WORD templateid;
346 /* test for missing functionality */
347 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
349 FIXME("Flags 0x%08lx not yet implemented\n",
350 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
353 /* Create the dialog from a template */
355 if (is_places_bar_enabled(fodInfos))
356 templateid = NEWFILEOPENV2ORD;
357 else
358 templateid = NEWFILEOPENORD;
360 if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG)))
362 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
363 return FALSE;
365 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
366 !(template = LockResource( hDlgTmpl )))
368 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
369 return FALSE;
372 /* msdn: explorer style dialogs permit sizing by default.
373 * The OFN_ENABLESIZING flag is only needed when a hook or
374 * custom template is provided */
375 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
376 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
377 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
379 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
381 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
382 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
385 /* old style hook messages */
386 if (is_dialog_hooked(fodInfos))
388 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
389 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
390 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
391 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
394 if (fodInfos->unicode)
395 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
396 template,
397 fodInfos->ofnInfos->hwndOwner,
398 FileOpenDlgProc95,
399 (LPARAM) fodInfos);
400 else
401 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
402 template,
403 fodInfos->ofnInfos->hwndOwner,
404 FileOpenDlgProc95,
405 (LPARAM) fodInfos);
406 if (fodInfos->ole_initialized)
407 OleUninitialize();
409 /* Unable to create the dialog */
410 if( lRes == -1)
411 return FALSE;
413 return lRes;
416 static WCHAR *heap_strdupAtoW(const char *str)
418 WCHAR *ret;
419 INT len;
421 if (!str)
422 return NULL;
424 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
425 ret = heap_alloc(len * sizeof(WCHAR));
426 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
428 return ret;
431 static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info)
433 INITCOMMONCONTROLSEX icc;
435 /* Initialize ComboBoxEx32 */
436 icc.dwSize = sizeof(icc);
437 icc.dwICC = ICC_USEREX_CLASSES;
438 InitCommonControlsEx(&icc);
440 /* Initialize CommDlgExtendedError() */
441 COMDLG32_SetCommDlgExtendedError(0);
443 memset(info, 0, sizeof(*info));
445 /* Pass in the original ofn */
446 info->ofnInfos = ofn;
448 info->title = ofn->lpstrTitle;
449 info->defext = ofn->lpstrDefExt;
450 info->filter = ofn->lpstrFilter;
451 info->customfilter = ofn->lpstrCustomFilter;
453 if (ofn->lpstrFile)
455 info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
456 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
459 if (ofn->lpstrInitialDir)
461 DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0);
462 if (len)
464 info->initdir = heap_alloc(len * sizeof(WCHAR));
465 ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len);
469 info->unicode = TRUE;
472 static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
474 OPENFILENAMEW ofnW;
475 int len;
477 ofnW = *(OPENFILENAMEW *)ofn;
479 ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir);
480 ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt);
481 ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle);
483 if (ofn->lpstrFile)
485 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, NULL, 0);
486 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
487 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, ofnW.lpstrFile, len);
488 ofnW.nMaxFile = len;
491 if (ofn->lpstrFilter)
493 LPCSTR s;
494 int n;
496 /* filter is a list... title\0ext\0......\0\0 */
497 s = ofn->lpstrFilter;
498 while (*s) s = s+strlen(s)+1;
499 s++;
500 n = s - ofn->lpstrFilter;
501 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0);
502 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
503 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len);
506 /* convert lpstrCustomFilter */
507 if (ofn->lpstrCustomFilter)
509 int n, len;
510 LPCSTR s;
512 /* customfilter contains a pair of strings... title\0ext\0 */
513 s = ofn->lpstrCustomFilter;
514 if (*s) s = s+strlen(s)+1;
515 if (*s) s = s+strlen(s)+1;
516 n = s - ofn->lpstrCustomFilter;
517 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0);
518 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
519 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len);
522 init_filedlg_infoW(&ofnW, info);
524 /* fixup A-specific fields */
525 info->ofnInfos = (OPENFILENAMEW *)ofn;
526 info->unicode = FALSE;
528 /* free what was duplicated */
529 heap_free((void *)ofnW.lpstrInitialDir);
530 heap_free(ofnW.lpstrFile);
533 /***********************************************************************
534 * GetFileDialog95
536 * Call GetFileName95 with this structure and clean the memory.
538 static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type)
540 WCHAR *current_dir = NULL;
541 unsigned int i;
542 BOOL ret;
544 /* save current directory */
545 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
547 current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
548 GetCurrentDirectoryW(MAX_PATH, current_dir);
551 switch (dlg_type)
553 case OPEN_DIALOG:
554 ret = GetFileName95(info);
555 break;
556 case SAVE_DIALOG:
557 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
558 ret = GetFileName95(info);
559 break;
560 default:
561 ret = FALSE;
564 if (current_dir)
566 SetCurrentDirectoryW(current_dir);
567 heap_free(current_dir);
570 if (!info->unicode)
572 heap_free((void *)info->defext);
573 heap_free((void *)info->title);
574 heap_free((void *)info->filter);
575 heap_free((void *)info->customfilter);
578 heap_free(info->filename);
579 heap_free(info->initdir);
581 for (i = 0; i < ARRAY_SIZE(info->places); i++)
582 ILFree(info->places[i]);
584 return ret;
587 /******************************************************************************
588 * COMDLG32_GetDisplayNameOf [internal]
590 * Helper function to get the display name for a pidl.
592 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
593 LPSHELLFOLDER psfDesktop;
594 STRRET strret;
596 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
597 return FALSE;
599 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
600 IShellFolder_Release(psfDesktop);
601 return FALSE;
604 IShellFolder_Release(psfDesktop);
605 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
608 /******************************************************************************
609 * COMDLG32_GetCanonicalPath [internal]
611 * Helper function to get the canonical path.
613 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
614 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
616 WCHAR lpstrTemp[MAX_PATH];
618 /* Get the current directory name */
619 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
621 /* last fallback */
622 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
624 PathAddBackslashW(lpstrPathAndFile);
626 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
628 /* if the user specified a fully qualified path use it */
629 if(PathIsRelativeW(lpstrFile))
631 lstrcatW(lpstrPathAndFile, lpstrFile);
633 else
635 /* does the path have a drive letter? */
636 if (PathGetDriveNumberW(lpstrFile) == -1)
637 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
638 else
639 lstrcpyW(lpstrPathAndFile, lpstrFile);
642 /* resolve "." and ".." */
643 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
644 lstrcpyW(lpstrPathAndFile, lpstrTemp);
645 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
648 /***********************************************************************
649 * COMDLG32_SplitFileNames [internal]
651 * Creates a delimited list of filenames.
653 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
655 UINT nStrCharCount = 0; /* index in src buffer */
656 UINT nFileIndex = 0; /* index in dest buffer */
657 UINT nFileCount = 0; /* number of files */
659 /* we might get single filename without any '"',
660 * so we need nStrLen + terminating \0 + end-of-list \0 */
661 *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
662 *sizeUsed = 0;
664 /* build delimited file list from filenames */
665 while ( nStrCharCount <= nStrLen )
667 if ( lpstrEdit[nStrCharCount]=='"' )
669 nStrCharCount++;
670 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
672 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
673 nStrCharCount++;
675 (*lpstrFileList)[nFileIndex++] = 0;
676 nFileCount++;
678 nStrCharCount++;
681 /* single, unquoted string */
682 if ((nStrLen > 0) && (nFileIndex == 0) )
684 lstrcpyW(*lpstrFileList, lpstrEdit);
685 nFileIndex = lstrlenW(lpstrEdit) + 1;
686 nFileCount = 1;
689 /* trailing \0 */
690 (*lpstrFileList)[nFileIndex++] = '\0';
692 *sizeUsed = nFileIndex;
693 return nFileCount;
696 /***********************************************************************
697 * ArrangeCtrlPositions [internal]
699 * NOTE: Make sure to add testcases for any changes made here.
701 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
703 HWND hwndChild, hwndStc32;
704 RECT rectParent, rectChild, rectStc32;
705 INT help_fixup = 0;
706 int chgx, chgy;
708 /* Take into account if open as read only checkbox and help button
709 * are hidden
711 if (hide_help)
713 RECT rectHelp, rectCancel;
714 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
715 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
716 /* subtract the height of the help button plus the space between
717 * the help button and the cancel button to the height of the dialog
719 help_fixup = rectHelp.bottom - rectCancel.bottom;
723 There are two possibilities to add components to the default file dialog box.
725 By default, all the new components are added below the standard dialog box (the else case).
727 However, if there is a static text component with the stc32 id, a special case happens.
728 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
729 in the window and the cx and cy indicate how to size the window.
730 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
731 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
735 GetClientRect(hwndParentDlg, &rectParent);
737 /* when arranging controls we have to use fixed parent size */
738 rectParent.bottom -= help_fixup;
740 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
741 if (hwndStc32)
743 GetWindowRect(hwndStc32, &rectStc32);
744 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
746 /* set the size of the stc32 control according to the size of
747 * client area of the parent dialog
749 SetWindowPos(hwndStc32, 0,
750 0, 0,
751 rectParent.right, rectParent.bottom,
752 SWP_NOMOVE | SWP_NOZORDER);
754 else
755 SetRectEmpty(&rectStc32);
757 /* this part moves controls of the child dialog */
758 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
759 while (hwndChild)
761 if (hwndChild != hwndStc32)
763 GetWindowRect(hwndChild, &rectChild);
764 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
766 /* move only if stc32 exist */
767 if (hwndStc32 && rectChild.left > rectStc32.right)
769 /* move to the right of visible controls of the parent dialog */
770 rectChild.left += rectParent.right;
771 rectChild.left -= rectStc32.right;
773 /* move even if stc32 doesn't exist */
774 if (rectChild.top >= rectStc32.bottom)
776 /* move below visible controls of the parent dialog */
777 rectChild.top += rectParent.bottom;
778 rectChild.top -= rectStc32.bottom - rectStc32.top;
781 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
782 0, 0, SWP_NOSIZE | SWP_NOZORDER);
784 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
787 /* this part moves controls of the parent dialog */
788 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
789 while (hwndChild)
791 if (hwndChild != hwndChildDlg)
793 GetWindowRect(hwndChild, &rectChild);
794 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
796 /* left,top of stc32 marks the position of controls
797 * from the parent dialog
799 rectChild.left += rectStc32.left;
800 rectChild.top += rectStc32.top;
802 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
803 0, 0, SWP_NOSIZE | SWP_NOZORDER);
805 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
808 /* calculate the size of the resulting dialog */
810 /* here we have to use original parent size */
811 GetClientRect(hwndParentDlg, &rectParent);
812 GetClientRect(hwndChildDlg, &rectChild);
813 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
814 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
816 if (hwndStc32)
818 /* width */
819 if (rectParent.right > rectStc32.right - rectStc32.left)
820 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
821 else
822 chgx = rectChild.right - rectParent.right;
823 /* height */
824 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
825 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
826 else
827 /* Unconditionally set new dialog
828 * height to that of the child
830 chgy = rectChild.bottom - rectParent.bottom;
832 else
834 chgx = 0;
835 chgy = rectChild.bottom - help_fixup;
837 /* set the size of the parent dialog */
838 GetWindowRect(hwndParentDlg, &rectParent);
839 SetWindowPos(hwndParentDlg, 0,
840 0, 0,
841 rectParent.right - rectParent.left + chgx,
842 rectParent.bottom - rectParent.top + chgy,
843 SWP_NOMOVE | SWP_NOZORDER);
846 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
848 switch(uMsg) {
849 case WM_INITDIALOG:
850 return TRUE;
852 return FALSE;
855 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
857 LPCVOID template;
858 HRSRC hRes;
859 HANDLE hDlgTmpl = 0;
860 HWND hChildDlg = 0;
862 TRACE("%p, %p\n", fodInfos, hwnd);
865 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
866 * structure's hInstance parameter is not a HINSTANCE, but
867 * instead a pointer to a template resource to use.
869 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
871 HINSTANCE hinst;
872 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
874 hinst = COMDLG32_hInstance;
875 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
877 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
878 return NULL;
881 else
883 hinst = fodInfos->ofnInfos->hInstance;
884 if(fodInfos->unicode)
886 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
887 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
889 else
891 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
892 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
894 if (!hRes)
896 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
897 return NULL;
899 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
900 !(template = LockResource( hDlgTmpl )))
902 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
903 return NULL;
906 if (fodInfos->unicode)
907 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
908 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
909 (LPARAM)fodInfos->ofnInfos);
910 else
911 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
912 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
913 (LPARAM)fodInfos->ofnInfos);
914 return hChildDlg;
916 else if (is_dialog_hooked(fodInfos))
918 RECT rectHwnd;
919 struct {
920 DLGTEMPLATE tmplate;
921 WORD menu,class,title;
922 } temp;
923 GetClientRect(hwnd,&rectHwnd);
924 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
925 temp.tmplate.dwExtendedStyle = 0;
926 temp.tmplate.cdit = 0;
927 temp.tmplate.x = 0;
928 temp.tmplate.y = 0;
929 temp.tmplate.cx = 0;
930 temp.tmplate.cy = 0;
931 temp.menu = temp.class = temp.title = 0;
933 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
934 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
936 return hChildDlg;
938 return NULL;
941 /***********************************************************************
942 * SendCustomDlgNotificationMessage
944 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
947 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
949 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
950 LRESULT hook_result;
951 OFNOTIFYW ofnNotify;
953 TRACE("%p %d\n", hwndParentDlg, uCode);
955 if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
956 return 0;
958 TRACE("CALL NOTIFY for %d\n", uCode);
960 ofnNotify.hdr.hwndFrom = hwndParentDlg;
961 ofnNotify.hdr.idFrom = 0;
962 ofnNotify.hdr.code = uCode;
963 ofnNotify.lpOFN = fodInfos->ofnInfos;
964 ofnNotify.pszFile = NULL;
966 if (fodInfos->unicode)
967 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
968 else
969 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
971 TRACE("RET NOTIFY retval %#Ix\n", hook_result);
973 return hook_result;
976 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
978 UINT len, total;
979 WCHAR *p, *buffer;
980 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
982 TRACE("CDM_GETFILEPATH:\n");
984 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
985 return -1;
987 /* get path and filenames */
988 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
989 buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
990 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
991 if (len)
993 p = buffer + lstrlenW(buffer);
994 *p++ = '\\';
995 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
997 if (fodInfos->unicode)
999 total = lstrlenW( buffer) + 1;
1000 if (result) lstrcpynW( result, buffer, size );
1001 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1003 else
1005 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1006 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1007 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1009 heap_free( buffer );
1010 return total;
1013 /***********************************************************************
1014 * FILEDLG95_HandleCustomDialogMessages
1016 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1018 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1020 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1021 WCHAR lpstrPath[MAX_PATH];
1022 INT_PTR retval;
1024 if(!fodInfos) return FALSE;
1026 switch(uMsg)
1028 case CDM_GETFILEPATH:
1029 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1030 break;
1032 case CDM_GETFOLDERPATH:
1033 TRACE("CDM_GETFOLDERPATH:\n");
1034 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1035 if (lParam)
1037 if (fodInfos->unicode)
1038 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1039 else
1040 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1041 (LPSTR)lParam, (int)wParam, NULL, NULL);
1043 retval = lstrlenW(lpstrPath) + 1;
1044 break;
1046 case CDM_GETFOLDERIDLIST:
1047 retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1048 if (retval <= wParam)
1049 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1050 break;
1052 case CDM_GETSPEC:
1053 TRACE("CDM_GETSPEC:\n");
1054 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1055 if (lParam)
1057 if (fodInfos->unicode)
1058 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1059 else
1060 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1062 break;
1064 case CDM_SETCONTROLTEXT:
1065 TRACE("CDM_SETCONTROLTEXT:\n");
1066 if ( lParam )
1068 if( fodInfos->unicode )
1069 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1070 else
1071 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1073 retval = TRUE;
1074 break;
1076 case CDM_HIDECONTROL:
1077 /* MSDN states that it should fail for not OFN_EXPLORER case */
1078 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1080 HWND control = GetDlgItem( hwnd, wParam );
1081 if (control) ShowWindow( control, SW_HIDE );
1082 retval = TRUE;
1084 else retval = FALSE;
1085 break;
1087 default:
1088 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1089 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1090 return FALSE;
1092 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1093 return TRUE;
1096 /***********************************************************************
1097 * FILEDLG95_OnWMGetMMI
1099 * WM_GETMINMAXINFO message handler for resizable dialogs
1101 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1103 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1104 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1105 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1107 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1109 return TRUE;
1112 /***********************************************************************
1113 * FILEDLG95_OnWMSize
1115 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1117 * FIXME: this could be made more elaborate. Now use a simple scheme
1118 * where the file view is enlarged and the controls are either moved
1119 * vertically or horizontally to get out of the way. Only the "grip"
1120 * is moved in both directions to stay in the corner.
1122 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1124 RECT rc, rcview;
1125 int chgx, chgy;
1126 HWND ctrl;
1127 HDWP hdwp;
1128 FileOpenDlgInfos *fodInfos;
1130 if( wParam != SIZE_RESTORED) return FALSE;
1131 fodInfos = get_filedlg_infoptr(hwnd);
1132 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1133 /* get the new dialog rectangle */
1134 GetWindowRect( hwnd, &rc);
1135 TRACE("%p, size from %ld,%ld to %ld,%ld\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1136 rc.right -rc.left, rc.bottom -rc.top);
1137 /* not initialized yet */
1138 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1139 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1140 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1141 return FALSE;
1142 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1143 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1144 fodInfos->sizedlg.cx = rc.right - rc.left;
1145 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1146 /* change the size of the view window */
1147 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1148 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1149 hdwp = BeginDeferWindowPos( 10);
1150 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1151 rcview.right - rcview.left + chgx,
1152 rcview.bottom - rcview.top + chgy,
1153 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1154 /* change position and sizes of the controls */
1155 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1157 int ctrlid = GetDlgCtrlID( ctrl);
1158 GetWindowRect( ctrl, &rc);
1159 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1160 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1162 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1163 0, 0,
1164 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1166 else if( rc.top > rcview.bottom)
1168 /* if it was below the shell view
1169 * move to bottom */
1170 switch( ctrlid)
1172 /* file name (edit or comboboxex) and file types combo change also width */
1173 case edt1:
1174 case cmb13:
1175 case cmb1:
1176 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1177 rc.right - rc.left + chgx, rc.bottom - rc.top,
1178 SWP_NOACTIVATE | SWP_NOZORDER);
1179 break;
1180 /* then these buttons must move out of the way */
1181 case IDOK:
1182 case IDCANCEL:
1183 case pshHelp:
1184 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1185 0, 0,
1186 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1187 break;
1188 default:
1189 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1190 0, 0,
1191 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1194 else if( rc.left > rcview.right)
1196 /* if it was to the right of the shell view
1197 * move to right */
1198 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1199 0, 0,
1200 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1202 else
1203 /* special cases */
1205 switch( ctrlid)
1207 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1208 case IDC_LOOKIN:
1209 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1210 rc.right - rc.left + chgx, rc.bottom - rc.top,
1211 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1212 break;
1213 case IDC_TOOLBARSTATIC:
1214 case IDC_TOOLBAR:
1215 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1216 0, 0,
1217 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 break;
1219 #endif
1220 /* not resized in windows. Since wine uses this invisible control
1221 * to size the browser view it needs to be resized */
1222 case IDC_SHELLSTATIC:
1223 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1224 rc.right - rc.left + chgx,
1225 rc.bottom - rc.top + chgy,
1226 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1227 break;
1228 case IDC_TOOLBARPLACES:
1229 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1230 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1231 break;
1235 if(fodInfos->DlgInfos.hwndCustomDlg &&
1236 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1238 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1239 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1241 GetWindowRect( ctrl, &rc);
1242 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1243 if( rc.top > rcview.bottom)
1245 /* if it was below the shell view
1246 * move to bottom */
1247 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1248 rc.right - rc.left, rc.bottom - rc.top,
1249 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1251 else if( rc.left > rcview.right)
1253 /* if it was to the right of the shell view
1254 * move to right */
1255 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1256 rc.right - rc.left, rc.bottom - rc.top,
1257 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1260 /* size the custom dialog at the end: some applications do some
1261 * control re-arranging at this point */
1262 GetClientRect(hwnd, &rc);
1263 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1264 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1266 EndDeferWindowPos( hdwp);
1267 /* should not be needed */
1268 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1269 return TRUE;
1272 /***********************************************************************
1273 * FileOpenDlgProc95
1275 * File open dialog procedure
1277 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1279 #if 0
1280 TRACE("%p 0x%04x\n", hwnd, uMsg);
1281 #endif
1283 switch(uMsg)
1285 case WM_INITDIALOG:
1287 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1288 RECT rc, rcstc;
1289 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1290 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1292 /* Some shell namespace extensions depend on COM being initialized. */
1293 if (SUCCEEDED(OleInitialize(NULL)))
1294 fodInfos->ole_initialized = TRUE;
1296 SetPropW(hwnd, L"FileOpenDlgInfos", fodInfos);
1298 FILEDLG95_InitControls(hwnd);
1300 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1302 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1303 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1304 RECT client, client_adjusted;
1306 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1308 style |= WS_SIZEBOX;
1309 ex_style |= WS_EX_WINDOWEDGE;
1311 else
1312 style &= ~WS_SIZEBOX;
1313 SetWindowLongW(hwnd, GWL_STYLE, style);
1314 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1316 GetClientRect( hwnd, &client );
1317 GetClientRect( hwnd, &client_adjusted );
1318 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1320 GetWindowRect( hwnd, &rc );
1321 rc.right += client_adjusted.right - client.right;
1322 rc.bottom += client_adjusted.bottom - client.bottom;
1323 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1324 SWP_NOZORDER | SWP_NOMOVE);
1326 GetWindowRect( hwnd, &rc );
1327 fodInfos->DlgInfos.hwndGrip =
1328 CreateWindowExA( 0, "SCROLLBAR", NULL,
1329 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1330 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1331 rc.right - gripx, rc.bottom - gripy,
1332 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1335 fodInfos->DlgInfos.hwndCustomDlg =
1336 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1338 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1339 FILEDLG95_FillControls(hwnd, wParam, lParam);
1341 if( fodInfos->DlgInfos.hwndCustomDlg)
1342 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1344 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1345 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1346 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1349 /* if the app has changed the position of the invisible listbox,
1350 * change that of the listview (browser) as well */
1351 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1352 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1353 if( !EqualRect( &rc, &rcstc))
1355 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1356 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1357 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1358 SWP_NOACTIVATE | SWP_NOZORDER);
1361 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1363 GetWindowRect( hwnd, &rc);
1364 fodInfos->sizedlg.cx = rc.right - rc.left;
1365 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1366 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1367 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1368 GetClientRect( hwnd, &rc);
1369 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1370 rc.right - gripx, rc.bottom - gripy,
1371 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1372 /* resize the dialog to the previous invocation */
1373 if( MemDialogSize.cx && MemDialogSize.cy)
1374 SetWindowPos( hwnd, NULL,
1375 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1376 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1379 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1380 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1382 return 0;
1384 case WM_SIZE:
1385 return FILEDLG95_OnWMSize(hwnd, wParam);
1386 case WM_GETMINMAXINFO:
1387 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1388 case WM_COMMAND:
1389 return FILEDLG95_OnWMCommand(hwnd, wParam);
1390 case WM_DRAWITEM:
1392 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1394 case IDC_LOOKIN:
1395 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1396 return TRUE;
1399 return FALSE;
1401 case WM_GETISHELLBROWSER:
1402 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1404 case WM_DESTROY:
1406 FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1407 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1408 HIMAGELIST himl;
1410 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1411 MemDialogSize = fodInfos->sizedlg;
1413 if (places_bar)
1415 himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0);
1416 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0);
1417 ImageList_Destroy(himl);
1419 return FALSE;
1422 case WM_NCDESTROY:
1423 RemovePropW(hwnd, L"FileOpenDlgInfos");
1424 return 0;
1426 case WM_NOTIFY:
1428 LPNMHDR lpnmh = (LPNMHDR)lParam;
1429 UINT stringId = -1;
1431 /* set up the button tooltips strings */
1432 if(TTN_GETDISPINFOA == lpnmh->code )
1434 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1435 switch(lpnmh->idFrom )
1437 /* Up folder button */
1438 case FCIDM_TB_UPFOLDER:
1439 stringId = IDS_UPFOLDER;
1440 break;
1441 /* New folder button */
1442 case FCIDM_TB_NEWFOLDER:
1443 stringId = IDS_NEWFOLDER;
1444 break;
1445 /* List option button */
1446 case FCIDM_TB_SMALLICON:
1447 stringId = IDS_LISTVIEW;
1448 break;
1449 /* Details option button */
1450 case FCIDM_TB_REPORTVIEW:
1451 stringId = IDS_REPORTVIEW;
1452 break;
1453 /* Desktop button */
1454 case FCIDM_TB_DESKTOP:
1455 stringId = IDS_TODESKTOP;
1456 break;
1457 default:
1458 stringId = 0;
1460 lpdi->hinst = COMDLG32_hInstance;
1461 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1463 return FALSE;
1465 default :
1466 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1467 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1468 return FALSE;
1472 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1474 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1475 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1478 /***********************************************************************
1479 * FILEDLG95_InitControls
1481 * WM_INITDIALOG message handler (before hook notification)
1483 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1485 BOOL win2000plus = FALSE;
1486 BOOL win98plus = FALSE;
1487 BOOL handledPath = FALSE;
1488 OSVERSIONINFOW osVi;
1490 static const TBBUTTON tbb[] =
1492 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1493 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1494 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1495 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1496 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1497 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1498 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1499 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1500 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1502 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1504 RECT rectTB;
1505 RECT rectlook;
1507 HIMAGELIST toolbarImageList;
1508 ITEMIDLIST *desktopPidl;
1509 SHFILEINFOW fileinfo;
1511 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1513 TRACE("%p\n", fodInfos);
1515 /* Get windows version emulating */
1516 osVi.dwOSVersionInfoSize = sizeof(osVi);
1517 GetVersionExW(&osVi);
1518 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1519 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1520 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1521 win2000plus = (osVi.dwMajorVersion > 4);
1522 if (win2000plus) win98plus = TRUE;
1524 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1527 /* Use either the edit or the comboboxex for the filename control */
1528 if (filename_is_edit( fodInfos ))
1530 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1531 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1533 else
1535 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1536 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1539 /* Get the hwnd of the controls */
1540 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1541 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1543 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1544 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1546 /* construct the toolbar */
1547 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1548 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1550 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1551 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1552 rectTB.left = rectlook.right;
1553 rectTB.top = rectlook.top-1;
1555 if (fodInfos->unicode)
1556 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1557 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1558 rectTB.left, rectTB.top,
1559 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1560 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1561 else
1562 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1563 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1564 rectTB.left, rectTB.top,
1565 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1566 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1568 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1570 /* FIXME: use TB_LOADIMAGES when implemented */
1571 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1572 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1573 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1575 /* Retrieve and add desktop icon to the toolbar */
1576 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1577 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1578 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1579 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1580 ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1582 DestroyIcon(fileinfo.hIcon);
1583 CoTaskMemFree(desktopPidl);
1585 /* Finish Toolbar Construction */
1586 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1587 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1589 if (is_places_bar_enabled(fodInfos))
1591 TBBUTTON tb = { 0 };
1592 HIMAGELIST himl;
1593 RECT rect;
1594 int i, cx;
1596 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0);
1597 GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect);
1598 cx = rect.right - rect.left;
1600 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx));
1601 himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1);
1603 filedlg_collect_places_pidls(fodInfos);
1604 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1606 int index;
1608 if (!fodInfos->places[i])
1609 continue;
1611 memset(&fileinfo, 0, sizeof(fileinfo));
1612 SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1613 SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON);
1614 index = ImageList_AddIcon(himl, fileinfo.hIcon);
1616 tb.iBitmap = index;
1617 tb.iString = (INT_PTR)fileinfo.szDisplayName;
1618 tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1619 tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1620 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb);
1622 DestroyIcon(fileinfo.hIcon);
1625 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl);
1626 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4));
1629 /* Set the window text with the text specified in the OPENFILENAME structure */
1630 if(fodInfos->title)
1632 SetWindowTextW(hwnd,fodInfos->title);
1634 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1636 WCHAR buf[64];
1637 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf));
1638 SetWindowTextW(hwnd, buf);
1641 /* Initialise the file name edit control */
1642 handledPath = FALSE;
1643 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1645 if(fodInfos->filename)
1647 /* 1. If win2000 or higher and filename contains a path, use it
1648 in preference over the lpstrInitialDir */
1649 if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, L"\\")) {
1650 WCHAR tmpBuf[MAX_PATH];
1651 WCHAR *nameBit;
1652 DWORD result;
1654 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1655 if (result) {
1657 /* nameBit is always shorter than the original filename. It may be NULL
1658 * when the filename contains only a drive name instead of file name */
1659 if (nameBit)
1661 lstrcpyW(fodInfos->filename,nameBit);
1662 *nameBit = 0x00;
1664 else
1665 *fodInfos->filename = '\0';
1667 heap_free(fodInfos->initdir);
1668 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1669 lstrcpyW(fodInfos->initdir, tmpBuf);
1670 handledPath = TRUE;
1671 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1672 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1674 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1676 } else {
1677 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1681 /* 2. (All platforms) If initdir is not null, then use it */
1682 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1684 /* Work out the proper path as supplied one might be relative */
1685 /* (Here because supplying '.' as dir browses to My Computer) */
1686 WCHAR tmpBuf[MAX_PATH];
1687 WCHAR tmpBuf2[MAX_PATH];
1688 WCHAR *nameBit;
1689 DWORD result;
1691 lstrcpyW(tmpBuf, fodInfos->initdir);
1692 if (PathFileExistsW(tmpBuf)) {
1693 /* initdir does not have to be a directory. If a file is
1694 * specified, the dir part is taken */
1695 if (PathIsDirectoryW(tmpBuf)) {
1696 PathAddBackslashW(tmpBuf);
1697 lstrcatW(tmpBuf, L"*");
1699 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1700 if (result) {
1701 *nameBit = 0x00;
1702 heap_free(fodInfos->initdir);
1703 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1704 lstrcpyW(fodInfos->initdir, tmpBuf2);
1705 handledPath = TRUE;
1706 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1709 else if (fodInfos->initdir)
1711 heap_free(fodInfos->initdir);
1712 fodInfos->initdir = NULL;
1713 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1717 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1719 /* 3. All except w2k+: if filename contains a path use it */
1720 if (!win2000plus && fodInfos->filename && *fodInfos->filename &&
1721 wcspbrk(fodInfos->filename, L"\\")) {
1722 WCHAR tmpBuf[MAX_PATH];
1723 WCHAR *nameBit;
1724 DWORD result;
1726 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1727 tmpBuf, &nameBit);
1728 if (result) {
1729 int len;
1731 /* nameBit is always shorter than the original filename */
1732 lstrcpyW(fodInfos->filename, nameBit);
1733 *nameBit = 0x00;
1735 len = lstrlenW(tmpBuf);
1736 heap_free(fodInfos->initdir);
1737 fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1738 lstrcpyW(fodInfos->initdir, tmpBuf);
1740 handledPath = TRUE;
1741 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1742 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1744 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1747 /* 4. Win2000+: Recently used */
1748 if (!handledPath && win2000plus) {
1749 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1750 fodInfos->initdir[0] = '\0';
1752 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1754 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1755 handledPath = TRUE;
1756 }else{
1757 heap_free(fodInfos->initdir);
1758 fodInfos->initdir = NULL;
1762 /* 5. win98+ and win2000+ if any files of specified filter types in
1763 current directory, use it */
1764 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1766 LPCWSTR lpstrPos = fodInfos->filter;
1767 WIN32_FIND_DATAW FindFileData;
1768 HANDLE hFind;
1770 while (1)
1772 /* filter is a list... title\0ext\0......\0\0 */
1774 /* Skip the title */
1775 if(! *lpstrPos) break; /* end */
1776 lpstrPos += lstrlenW(lpstrPos) + 1;
1778 /* See if any files exist in the current dir with this extension */
1779 if(! *lpstrPos) break; /* end */
1781 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1783 if (hFind == INVALID_HANDLE_VALUE) {
1784 /* None found - continue search */
1785 lpstrPos += lstrlenW(lpstrPos) + 1;
1787 } else {
1789 heap_free(fodInfos->initdir);
1790 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1791 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1793 handledPath = TRUE;
1794 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1795 debugstr_w(lpstrPos));
1796 FindClose(hFind);
1797 break;
1802 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1803 if (!handledPath && (win2000plus || win98plus)) {
1804 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1806 if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1808 if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK)
1810 /* last fallback */
1811 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1812 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1814 else
1815 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1817 else
1818 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1820 handledPath = TRUE;
1821 } else if (!handledPath) {
1822 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1823 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1824 handledPath = TRUE;
1825 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1828 SetFocus( fodInfos->DlgInfos.hwndFileName );
1829 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1831 /* Must the open as read only check box be checked ?*/
1832 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1834 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1837 /* Must the open as read only check box be hidden? */
1838 if (filedialog_is_readonly_hidden(fodInfos))
1840 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1841 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1844 /* Must the help button be hidden? */
1845 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1847 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1848 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1851 /* change Open to Save */
1852 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1854 WCHAR buf[16];
1855 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
1856 SetDlgItemTextW(hwnd, IDOK, buf);
1857 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
1858 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1861 /* Initialize the filter combo box */
1862 FILEDLG95_FILETYPE_Init(hwnd);
1864 return 0;
1867 /***********************************************************************
1868 * FILEDLG95_ResizeControls
1870 * WM_INITDIALOG message handler (after hook notification)
1872 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1874 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1876 if (fodInfos->DlgInfos.hwndCustomDlg)
1878 RECT rc;
1879 UINT flags = SWP_NOACTIVATE;
1881 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1882 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1884 /* resize the custom dialog to the parent size */
1885 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1886 GetClientRect(hwnd, &rc);
1887 else
1889 /* our own fake template is zero sized and doesn't have children, so
1890 * there is no need to resize it. Picasa depends on it.
1892 flags |= SWP_NOSIZE;
1893 SetRectEmpty(&rc);
1895 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1896 0, 0, rc.right, rc.bottom, flags);
1898 else
1900 /* Resize the height; if opened as read-only, checkbox and help button are
1901 * hidden and we are not using a custom template nor a customDialog
1903 if (filedialog_is_readonly_hidden(fodInfos) &&
1904 (!(fodInfos->ofnInfos->Flags &
1905 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1907 RECT rectDlg, rectHelp, rectCancel;
1908 GetWindowRect(hwnd, &rectDlg);
1909 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1910 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1911 /* subtract the height of the help button plus the space between the help
1912 * button and the cancel button to the height of the dialog
1914 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1915 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1916 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1919 return TRUE;
1922 /***********************************************************************
1923 * FILEDLG95_FillControls
1925 * WM_INITDIALOG message handler (after hook notification)
1927 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1929 LPITEMIDLIST pidlItemId = NULL;
1931 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1933 TRACE("dir=%s file=%s\n",
1934 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1936 /* Get the initial directory pidl */
1938 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1940 WCHAR path[MAX_PATH];
1942 GetCurrentDirectoryW(MAX_PATH,path);
1943 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1946 /* Initialise shell objects */
1947 FILEDLG95_SHELL_Init(hwnd);
1949 /* Initialize the Look In combo box */
1950 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1952 /* Browse to the initial directory */
1953 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1955 ILFree(pidlItemId);
1957 return TRUE;
1959 /***********************************************************************
1960 * FILEDLG95_Clean
1962 * Regroups all the cleaning functions of the filedlg
1964 void FILEDLG95_Clean(HWND hwnd)
1966 FILEDLG95_FILETYPE_Clean(hwnd);
1967 FILEDLG95_LOOKIN_Clean(hwnd);
1968 FILEDLG95_SHELL_Clean(hwnd);
1972 /***********************************************************************
1973 * Browse to arbitrary pidl
1975 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl)
1977 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
1979 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
1980 if (info->ofnInfos->Flags & OFN_EXPLORER)
1981 SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
1984 /***********************************************************************
1985 * FILEDLG95_OnWMCommand
1987 * WM_COMMAND message handler
1989 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1991 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1992 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1993 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
1995 switch (id)
1997 /* OK button */
1998 case IDOK:
1999 FILEDLG95_OnOpen(hwnd);
2000 break;
2001 /* Cancel button */
2002 case IDCANCEL:
2003 FILEDLG95_Clean(hwnd);
2004 EndDialog(hwnd, FALSE);
2005 break;
2006 /* Filetype combo box */
2007 case IDC_FILETYPE:
2008 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2009 break;
2010 /* LookIn combo box */
2011 case IDC_LOOKIN:
2012 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2013 break;
2015 /* --- toolbar --- */
2016 /* Up folder button */
2017 case FCIDM_TB_UPFOLDER:
2018 FILEDLG95_SHELL_UpFolder(hwnd);
2019 break;
2020 /* New folder button */
2021 case FCIDM_TB_NEWFOLDER:
2022 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2023 break;
2024 /* List option button */
2025 case FCIDM_TB_SMALLICON:
2026 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2027 break;
2028 /* Details option button */
2029 case FCIDM_TB_REPORTVIEW:
2030 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2031 break;
2033 case FCIDM_TB_DESKTOP:
2035 LPITEMIDLIST pidl;
2037 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl);
2038 filedlg_browse_to_pidl(fodInfos, pidl);
2039 ILFree(pidl);
2040 break;
2043 /* Places bar */
2044 case TBPLACES_CMDID_PLACE0:
2045 case TBPLACES_CMDID_PLACE1:
2046 case TBPLACES_CMDID_PLACE2:
2047 case TBPLACES_CMDID_PLACE3:
2048 case TBPLACES_CMDID_PLACE4:
2049 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2050 break;
2052 case edt1:
2053 case cmb13:
2054 break;
2057 /* Do not use the listview selection anymore */
2058 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2059 return 0;
2062 /***********************************************************************
2063 * FILEDLG95_OnWMGetIShellBrowser
2065 * WM_GETISHELLBROWSER message handler
2067 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
2069 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2071 TRACE("\n");
2073 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2075 return TRUE;
2079 /***********************************************************************
2080 * FILEDLG95_SendFileOK
2082 * Sends the CDN_FILEOK notification if required
2084 * RETURNS
2085 * TRUE if the dialog should close
2086 * FALSE if the dialog should not be closed
2088 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
2090 /* ask the hook if we can close */
2091 if (is_dialog_hooked(fodInfos))
2093 LRESULT retval = 0;
2095 TRACE("---\n");
2096 /* First send CDN_FILEOK as MSDN doc says */
2097 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2098 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
2099 if( retval)
2101 TRACE("canceled\n");
2102 return FALSE;
2105 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2106 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2107 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2108 if( retval)
2110 TRACE("canceled\n");
2111 return FALSE;
2114 return TRUE;
2117 /***********************************************************************
2118 * FILEDLG95_OnOpenMultipleFiles
2120 * Handles the opening of multiple files.
2122 * FIXME
2123 * check destination buffer size
2125 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2127 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2128 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2129 UINT nCount, nSizePath;
2131 TRACE("\n");
2133 if(fodInfos->unicode)
2135 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2136 ofn->lpstrFile[0] = '\0';
2138 else
2140 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2141 ofn->lpstrFile[0] = '\0';
2144 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2146 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2147 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2148 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2150 LPWSTR lpstrTemp = lpstrFileList;
2152 for ( nCount = 0; nCount < nFileCount; nCount++ )
2154 LPITEMIDLIST pidl;
2156 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2157 if (!pidl)
2159 WCHAR lpstrNotFound[100];
2160 WCHAR lpstrMsg[100];
2161 WCHAR tmp[400];
2163 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2164 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2166 lstrcpyW(tmp, lpstrTemp);
2167 lstrcatW(tmp, L"\n");
2168 lstrcatW(tmp, lpstrNotFound);
2169 lstrcatW(tmp, L"\n");
2170 lstrcatW(tmp, lpstrMsg);
2172 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2173 return FALSE;
2176 /* move to the next file in the list of files */
2177 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2178 ILFree(pidl);
2182 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2183 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2185 /* For "oldstyle" dialog the components have to
2186 be separated by blanks (not '\0'!) and short
2187 filenames have to be used! */
2188 FIXME("Components have to be separated by blanks\n");
2190 if(fodInfos->unicode)
2192 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2193 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2194 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2196 else
2198 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2200 if (ofn->lpstrFile != NULL)
2202 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2203 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2204 if (ofn->nMaxFile > nSizePath)
2206 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2207 ofn->lpstrFile + nSizePath,
2208 ofn->nMaxFile - nSizePath, NULL, NULL);
2213 fodInfos->ofnInfos->nFileOffset = nSizePath;
2214 fodInfos->ofnInfos->nFileExtension = 0;
2216 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2217 return FALSE;
2219 /* clean and exit */
2220 FILEDLG95_Clean(hwnd);
2221 return EndDialog(hwnd,TRUE);
2224 /* Returns the 'slot name' of the given module_name in the registry's
2225 * most-recently-used list. This will be an ASCII value in the
2226 * range ['a','z'). Returns zero on error.
2228 * The slot's value in the registry has the form:
2229 * module_name\0mru_path\0
2231 * If stored_path is given, then stored_path will contain the path name
2232 * stored in the registry's MRU list for the given module_name.
2234 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2235 * MRU list key for the given module_name.
2237 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2239 WCHAR mru_list[32], *cur_mru_slot;
2240 BOOL taken[25] = {0};
2241 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2242 HKEY hkey_tmp, *hkey;
2243 LONG ret;
2245 if(hkey_ret)
2246 hkey = hkey_ret;
2247 else
2248 hkey = &hkey_tmp;
2250 if(stored_path)
2251 *stored_path = '\0';
2253 ret = RegCreateKeyW(HKEY_CURRENT_USER,
2254 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", hkey);
2255 if(ret){
2256 WARN("Unable to create MRU key: %ld\n", ret);
2257 return 0;
2260 ret = RegGetValueW(*hkey, NULL, L"MRUList", RRF_RT_REG_SZ, &key_type,
2261 (LPBYTE)mru_list, &mru_list_size);
2262 if(ret || key_type != REG_SZ){
2263 if(ret == ERROR_FILE_NOT_FOUND)
2264 return 'a';
2266 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2267 RegCloseKey(*hkey);
2268 return 0;
2271 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2272 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2273 DWORD value_data_size = sizeof(value_data);
2275 *value_name = *cur_mru_slot;
2277 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2278 &key_type, (LPBYTE)value_data, &value_data_size);
2279 if(ret || key_type != REG_BINARY){
2280 WARN("Error getting MRU slot data: type: %ld, ret: %ld\n", key_type, ret);
2281 continue;
2284 if(!wcsicmp(module_name, value_data)){
2285 if(!hkey_ret)
2286 RegCloseKey(*hkey);
2287 if(stored_path)
2288 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2289 return *value_name;
2293 if(!hkey_ret)
2294 RegCloseKey(*hkey);
2296 /* the module name isn't in the registry, so find the next open slot */
2297 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2298 taken[*cur_mru_slot - 'a'] = TRUE;
2299 for(i = 0; i < 25; ++i){
2300 if(!taken[i])
2301 return i + 'a';
2304 /* all slots are taken, so return the last one in MRUList */
2305 --cur_mru_slot;
2306 return *cur_mru_slot;
2309 /* save the given filename as most-recently-used path for this module */
2310 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2312 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2313 LONG ret;
2314 HKEY hkey;
2316 /* get the current executable's name */
2317 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2319 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2320 return;
2322 module_name = wcsrchr(module_path, '\\');
2323 if(!module_name)
2324 module_name = module_path;
2325 else
2326 module_name += 1;
2328 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2329 if(!slot)
2330 return;
2331 *slot_name = slot;
2333 { /* update the slot's info */
2334 WCHAR *path_ends, *final;
2335 DWORD path_len, final_len;
2337 /* use only the path segment of `filename' */
2338 path_ends = wcsrchr(filename, '\\');
2339 path_len = path_ends - filename;
2341 final_len = path_len + lstrlenW(module_name) + 2;
2343 final = heap_alloc(final_len * sizeof(WCHAR));
2344 if(!final)
2345 return;
2346 lstrcpyW(final, module_name);
2347 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2348 final[final_len-1] = '\0';
2350 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2351 final_len * sizeof(WCHAR));
2352 if(ret){
2353 WARN("Error saving MRU data to slot %s: %ld\n", wine_dbgstr_w(slot_name), ret);
2354 heap_free(final);
2355 RegCloseKey(hkey);
2356 return;
2359 heap_free(final);
2362 { /* update MRUList value */
2363 WCHAR old_mru_list[32], new_mru_list[32];
2364 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2365 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2367 ret = RegGetValueW(hkey, NULL, L"MRUList", RRF_RT_ANY, &key_type,
2368 (LPBYTE)old_mru_list, &mru_list_size);
2369 if(ret || key_type != REG_SZ){
2370 if(ret == ERROR_FILE_NOT_FOUND){
2371 new_mru_list[0] = slot;
2372 new_mru_list[1] = '\0';
2373 }else{
2374 WARN("Error getting MRUList data: type: %ld, ret: %ld\n", key_type, ret);
2375 RegCloseKey(hkey);
2376 return;
2378 }else{
2379 /* copy old list data over so that the new slot is at the start
2380 * of the list */
2381 *new_mru_slot++ = slot;
2382 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2383 if(*old_mru_slot != slot)
2384 *new_mru_slot++ = *old_mru_slot;
2386 *new_mru_slot = '\0';
2389 ret = RegSetValueExW(hkey, L"MRUList", 0, REG_SZ, (LPBYTE)new_mru_list,
2390 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2391 if(ret){
2392 WARN("Error saving MRUList data: %ld\n", ret);
2393 RegCloseKey(hkey);
2394 return;
2399 /* load the most-recently-used path for this module */
2400 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2402 WCHAR module_path[MAX_PATH], *module_name;
2404 /* get the current executable's name */
2405 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2407 WARN("GotModuleFileName failed: %ld\n", GetLastError());
2408 return;
2410 module_name = wcsrchr(module_path, '\\');
2411 if(!module_name)
2412 module_name = module_path;
2413 else
2414 module_name += 1;
2416 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2417 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2420 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2422 WCHAR strMsgTitle[MAX_PATH];
2423 WCHAR strMsgText [MAX_PATH];
2424 if (idCaption)
2425 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2426 else
2427 strMsgTitle[0] = '\0';
2428 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2429 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2432 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2433 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2435 int nOpenAction = defAction;
2436 LPWSTR lpszTemp, lpszTemp1;
2437 LPITEMIDLIST pidl = NULL;
2439 /* check for invalid chars */
2440 if((wcspbrk(lpstrPathAndFile+3, L"/:<>|") != NULL) && !(flags & OFN_NOVALIDATE))
2442 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2443 return FALSE;
2446 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2448 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2449 while (lpszTemp1)
2451 LPSHELLFOLDER lpsfChild;
2452 WCHAR lpwstrTemp[MAX_PATH];
2453 DWORD dwEaten, dwAttributes;
2454 LPWSTR p;
2456 lstrcpyW(lpwstrTemp, lpszTemp);
2457 if (lpszTemp == lpstrPathAndFile && (p = PathSkipRootW(lpwstrTemp)))
2459 *p = 0;
2461 else
2463 p = PathFindNextComponentW(lpwstrTemp);
2464 if (!p) break; /* end of path */
2465 *p = 0;
2467 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2469 /* There are no wildcards when OFN_NOVALIDATE is set */
2470 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2472 /* if the last element is a wildcard do a search */
2473 if(wcspbrk(lpszTemp1, L"*?") != NULL)
2475 nOpenAction = ONOPEN_SEARCH;
2476 break;
2479 lpszTemp1 = lpszTemp;
2481 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2483 /* append a backslash to drive letters */
2484 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2485 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2486 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2488 PathAddBackslashW(lpwstrTemp);
2491 dwAttributes = SFGAO_FOLDER;
2492 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2494 /* the path component is valid, we have a pidl of the next path component */
2495 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
2496 if(dwAttributes & SFGAO_FOLDER)
2498 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2500 ERR("bind to failed\n"); /* should not fail */
2501 break;
2503 IShellFolder_Release(*ppsf);
2504 *ppsf = lpsfChild;
2505 lpsfChild = NULL;
2507 else
2509 TRACE("value\n");
2511 /* end dialog, return value */
2512 nOpenAction = ONOPEN_OPEN;
2513 break;
2515 ILFree(pidl);
2516 pidl = NULL;
2518 else if (!(flags & OFN_NOVALIDATE))
2520 if(*lpszTemp || /* points to trailing null for last path element */
2521 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2523 if(flags & OFN_PATHMUSTEXIST)
2525 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2526 break;
2529 else
2531 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2533 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2534 break;
2537 /* change to the current folder */
2538 nOpenAction = ONOPEN_OPEN;
2539 break;
2541 else
2543 nOpenAction = ONOPEN_OPEN;
2544 break;
2547 ILFree(pidl);
2549 return nOpenAction;
2552 /***********************************************************************
2553 * FILEDLG95_OnOpen
2555 * Ok button WM_COMMAND message handler
2557 * If the function succeeds, the return value is nonzero.
2559 BOOL FILEDLG95_OnOpen(HWND hwnd)
2561 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2562 LPWSTR lpstrFileList;
2563 UINT nFileCount = 0;
2564 UINT sizeUsed = 0;
2565 BOOL ret = TRUE;
2566 WCHAR lpstrPathAndFile[MAX_PATH];
2567 LPSHELLFOLDER lpsf = NULL;
2568 int nOpenAction;
2570 TRACE("hwnd=%p\n", hwnd);
2572 /* try to browse the selected item */
2573 if(BrowseSelectedFolder(hwnd))
2574 return FALSE;
2576 /* get the files from the edit control */
2577 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2579 if(nFileCount == 0)
2580 return FALSE;
2582 if(nFileCount > 1)
2584 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2585 goto ret;
2588 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2591 Step 1: Build a complete path name from the current folder and
2592 the filename or path in the edit box.
2593 Special cases:
2594 - the path in the edit box is a root path
2595 (with or without drive letter)
2596 - the edit box contains ".." (or a path with ".." in it)
2599 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2600 heap_free(lpstrFileList);
2603 Step 2: here we have a cleaned up path
2605 We have to parse the path step by step to see if we have to browse
2606 to a folder if the path points to a directory or the last
2607 valid element is a directory.
2609 valid variables:
2610 lpstrPathAndFile: cleaned up path
2613 if (nFileCount &&
2614 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2615 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2616 nOpenAction = ONOPEN_OPEN;
2617 else
2618 nOpenAction = ONOPEN_BROWSE;
2620 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2621 fodInfos->ofnInfos->Flags,
2622 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2623 nOpenAction);
2624 if(!nOpenAction)
2625 goto ret;
2628 Step 3: here we have a cleaned up and validated path
2630 valid variables:
2631 lpsf: ShellFolder bound to the rightmost valid path component
2632 lpstrPathAndFile: cleaned up path
2633 nOpenAction: action to do
2635 TRACE("end validate sf=%p\n", lpsf);
2637 switch(nOpenAction)
2639 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2640 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2642 int iPos;
2643 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2644 DWORD len;
2646 /* replace the current filter */
2647 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2648 len = lstrlenW(lpszTemp)+1;
2649 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2650 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2652 /* set the filter cb to the extension when possible */
2653 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2654 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2656 /* fall through */
2657 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2658 TRACE("ONOPEN_BROWSE\n");
2660 IPersistFolder2 * ppf2;
2661 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2663 LPITEMIDLIST pidlCurrent;
2664 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2665 IPersistFolder2_Release(ppf2);
2666 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2668 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2669 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2671 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2672 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2675 else if( nOpenAction == ONOPEN_SEARCH )
2677 if (fodInfos->Shell.FOIShellView)
2678 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2680 ILFree(pidlCurrent);
2681 if (filename_is_edit( fodInfos ))
2682 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2683 else
2685 HWND hwnd;
2687 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2688 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2692 ret = FALSE;
2693 break;
2694 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2695 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2697 WCHAR *ext = NULL;
2699 /* update READONLY check box flag */
2700 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2701 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2702 else
2703 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2705 /* Attach the file extension with file name*/
2706 ext = PathFindExtensionW(lpstrPathAndFile);
2707 if (! *ext && fodInfos->defext)
2709 /* if no extension is specified with file name, then */
2710 /* attach the extension from file filter or default one */
2712 WCHAR *filterExt = NULL;
2713 LPWSTR lpstrFilter = NULL;
2714 int PathLength = lstrlenW(lpstrPathAndFile);
2716 /*Get the file extension from file type filter*/
2717 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2718 fodInfos->ofnInfos->nFilterIndex-1);
2720 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2722 WCHAR* filterSearchIndex;
2723 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2724 lstrcpyW(filterExt, lpstrFilter);
2726 /* if a semicolon-separated list of file extensions was given, do not include the
2727 semicolon or anything after it in the extension.
2728 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2729 filterSearchIndex = wcschr(filterExt, ';');
2730 if (filterSearchIndex)
2732 filterSearchIndex[0] = '\0';
2735 /* find the file extension by searching for the first dot in filterExt */
2736 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2737 /* if the extension is invalid or contains a glob, ignore it */
2738 filterSearchIndex = wcschr(filterExt, '.');
2739 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
2741 lstrcpyW(filterExt, filterSearchIndex);
2743 else
2745 heap_free(filterExt);
2746 filterExt = NULL;
2750 if (!filterExt)
2752 /* use the default file extension */
2753 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2754 lstrcpyW(filterExt, fodInfos->defext);
2757 if (*filterExt) /* ignore filterExt="" */
2759 /* Attach the dot*/
2760 lstrcatW(lpstrPathAndFile, L".");
2761 /* Attach the extension */
2762 lstrcatW(lpstrPathAndFile, filterExt);
2765 heap_free(filterExt);
2767 /* In Open dialog: if file does not exist try without extension */
2768 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2769 lpstrPathAndFile[PathLength] = '\0';
2771 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2772 if (*ext)
2773 ext++;
2774 if (!lstrcmpiW(fodInfos->defext, ext))
2775 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2776 else
2777 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2780 /* In Save dialog: check if the file already exists */
2781 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2782 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2783 && PathFileExistsW(lpstrPathAndFile))
2785 WCHAR lpstrOverwrite[100];
2786 int answer;
2788 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2789 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2790 MB_YESNO | MB_ICONEXCLAMATION);
2791 if (answer == IDNO || answer == IDCANCEL)
2793 ret = FALSE;
2794 goto ret;
2798 /* In Open dialog: check if it should be created if it doesn't exist */
2799 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2800 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2801 && !PathFileExistsW(lpstrPathAndFile))
2803 WCHAR lpstrCreate[100];
2804 int answer;
2806 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2807 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2808 MB_YESNO | MB_ICONEXCLAMATION);
2809 if (answer == IDNO || answer == IDCANCEL)
2811 ret = FALSE;
2812 goto ret;
2816 /* Check that the size of the file does not exceed buffer size.
2817 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2818 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2819 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2822 /* fill destination buffer */
2823 if (fodInfos->ofnInfos->lpstrFile)
2825 if(fodInfos->unicode)
2827 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2829 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2830 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2831 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2833 else
2835 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2837 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2838 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2839 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2840 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2844 if(fodInfos->unicode)
2846 LPWSTR lpszTemp;
2848 /* set filename offset */
2849 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2850 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2852 /* set extension offset */
2853 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2854 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2856 else
2858 LPSTR lpszTemp;
2859 CHAR tempFileA[MAX_PATH];
2861 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2862 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2863 tempFileA, sizeof(tempFileA), NULL, NULL);
2865 /* set filename offset */
2866 lpszTemp = PathFindFileNameA(tempFileA);
2867 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2869 /* set extension offset */
2870 lpszTemp = PathFindExtensionA(tempFileA);
2871 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2874 /* set the lpstrFileTitle */
2875 if(fodInfos->ofnInfos->lpstrFileTitle)
2877 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2878 if(fodInfos->unicode)
2880 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2881 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2883 else
2885 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2886 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2887 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2891 /* copy currently selected filter to lpstrCustomFilter */
2892 if (fodInfos->ofnInfos->lpstrCustomFilter)
2894 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2895 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2896 NULL, 0, NULL, NULL);
2897 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2899 LPSTR s = ofn->lpstrCustomFilter;
2900 s += strlen(ofn->lpstrCustomFilter)+1;
2901 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2902 s, len, NULL, NULL);
2907 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2908 goto ret;
2910 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2912 TRACE("close\n");
2913 FILEDLG95_Clean(hwnd);
2914 ret = EndDialog(hwnd, TRUE);
2916 else
2918 WORD size;
2920 size = lstrlenW(lpstrPathAndFile) + 1;
2921 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2922 size += 1;
2923 /* return needed size in first two bytes of lpstrFile */
2924 if(fodInfos->ofnInfos->lpstrFile)
2925 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2926 FILEDLG95_Clean(hwnd);
2927 ret = EndDialog(hwnd, FALSE);
2928 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2931 break;
2934 ret:
2935 if(lpsf) IShellFolder_Release(lpsf);
2936 return ret;
2939 /***********************************************************************
2940 * FILEDLG95_SHELL_Init
2942 * Initialisation of the shell objects
2944 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2946 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2948 TRACE("%p\n", hwnd);
2951 * Initialisation of the FileOpenDialogInfos structure
2954 /* Shell */
2956 /*ShellInfos */
2957 fodInfos->ShellInfos.hwndOwner = hwnd;
2959 /* Disable multi-select if flag not set */
2960 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2962 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2964 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2965 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2967 /* Construct the IShellBrowser interface */
2968 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2970 return NOERROR;
2973 /***********************************************************************
2974 * FILEDLG95_SHELL_ExecuteCommand
2976 * Change the folder option and refresh the view
2977 * If the function succeeds, the return value is nonzero.
2979 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2981 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2982 IContextMenu * pcm;
2984 TRACE("(%p,%p)\n", hwnd, lpVerb);
2986 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2987 SVGIO_BACKGROUND,
2988 &IID_IContextMenu,
2989 (LPVOID*)&pcm)))
2991 CMINVOKECOMMANDINFO ci;
2992 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2993 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2994 ci.lpVerb = lpVerb;
2995 ci.hwnd = hwnd;
2997 IContextMenu_InvokeCommand(pcm, &ci);
2998 IContextMenu_Release(pcm);
3001 return FALSE;
3004 /***********************************************************************
3005 * FILEDLG95_SHELL_UpFolder
3007 * Browse to the specified object
3008 * If the function succeeds, the return value is nonzero.
3010 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3012 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3014 TRACE("\n");
3016 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3017 NULL,
3018 SBSP_PARENT)))
3020 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3021 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3022 return TRUE;
3024 return FALSE;
3026 /***********************************************************************
3027 * FILEDLG95_SHELL_Clean
3029 * Cleans the memory used by shell objects
3031 static void FILEDLG95_SHELL_Clean(HWND hwnd)
3033 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3035 TRACE("\n");
3037 ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3039 /* clean Shell interfaces */
3040 if (fodInfos->Shell.FOIShellView)
3042 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3043 IShellView_Release(fodInfos->Shell.FOIShellView);
3045 if (fodInfos->Shell.FOIShellFolder)
3046 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3047 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3048 if (fodInfos->Shell.FOIDataObject)
3049 IDataObject_Release(fodInfos->Shell.FOIDataObject);
3052 /***********************************************************************
3053 * FILEDLG95_FILETYPE_Init
3055 * Initialisation of the file type combo box
3057 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3059 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3060 int nFilters = 0; /* number of filters */
3061 int nFilterIndexCB;
3063 TRACE("%p\n", hwnd);
3065 if(fodInfos->customfilter)
3067 /* customfilter has one entry... title\0ext\0
3068 * Set first entry of combo box item with customfilter
3070 LPWSTR lpstrExt;
3071 LPCWSTR lpstrPos = fodInfos->customfilter;
3073 /* Get the title */
3074 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3076 /* Copy the extensions */
3077 if (! *lpstrPos) return E_FAIL; /* malformed filter */
3078 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3079 lstrcpyW(lpstrExt,lpstrPos);
3081 /* Add the item at the end of the combo */
3082 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3083 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3085 nFilters++;
3087 if(fodInfos->filter)
3089 LPCWSTR lpstrPos = fodInfos->filter;
3091 for(;;)
3093 /* filter is a list... title\0ext\0......\0\0
3094 * Set the combo item text to the title and the item data
3095 * to the ext
3097 LPCWSTR lpstrDisplay;
3098 LPWSTR lpstrExt;
3100 /* Get the title */
3101 if(! *lpstrPos) break; /* end */
3102 lpstrDisplay = lpstrPos;
3103 lpstrPos += lstrlenW(lpstrPos) + 1;
3105 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3107 nFilters++;
3109 /* Copy the extensions */
3110 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3111 lstrcpyW(lpstrExt,lpstrPos);
3112 lpstrPos += lstrlenW(lpstrPos) + 1;
3114 /* Add the item at the end of the combo */
3115 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3117 /* malformed filters are added anyway... */
3118 if (!*lpstrExt) break;
3123 * Set the current filter to the one specified
3124 * in the initialisation structure
3126 if (fodInfos->filter || fodInfos->customfilter)
3128 LPWSTR lpstrFilter;
3130 /* Check to make sure our index isn't out of bounds. */
3131 if ( fodInfos->ofnInfos->nFilterIndex >
3132 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3133 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3135 /* set default filter index */
3136 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3137 fodInfos->ofnInfos->nFilterIndex = 1;
3139 /* calculate index of Combo Box item */
3140 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3141 if (fodInfos->customfilter == NULL)
3142 nFilterIndexCB--;
3144 /* Set the current index selection. */
3145 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3147 /* Get the corresponding text string from the combo box. */
3148 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3149 nFilterIndexCB);
3151 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3152 lpstrFilter = NULL;
3154 if(lpstrFilter)
3156 DWORD len;
3157 CharLowerW(lpstrFilter); /* lowercase */
3158 len = lstrlenW(lpstrFilter)+1;
3159 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3160 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3162 } else
3163 fodInfos->ofnInfos->nFilterIndex = 0;
3164 return S_OK;
3167 /***********************************************************************
3168 * FILEDLG95_FILETYPE_OnCommand
3170 * WM_COMMAND of the file type combo box
3171 * If the function succeeds, the return value is nonzero.
3173 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3175 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3177 switch(wNotifyCode)
3179 case CBN_SELENDOK:
3181 LPWSTR lpstrFilter;
3183 /* Get the current item of the filetype combo box */
3184 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3186 /* set the current filter index */
3187 fodInfos->ofnInfos->nFilterIndex = iItem +
3188 (fodInfos->customfilter == NULL ? 1 : 0);
3190 /* Set the current filter with the current selection */
3191 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3193 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3194 iItem);
3195 if((INT_PTR)lpstrFilter != CB_ERR)
3197 DWORD len;
3198 CharLowerW(lpstrFilter); /* lowercase */
3199 len = lstrlenW(lpstrFilter)+1;
3200 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3201 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3202 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3203 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3206 /* Refresh the actual view to display the included items*/
3207 if (fodInfos->Shell.FOIShellView)
3208 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3211 return FALSE;
3213 /***********************************************************************
3214 * FILEDLG95_FILETYPE_SearchExt
3216 * searches for an extension in the filetype box
3218 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3220 int i, iCount;
3222 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3224 TRACE("%s\n", debugstr_w(lpstrExt));
3226 if(iCount != CB_ERR)
3228 for(i=0;i<iCount;i++)
3230 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3231 return i;
3234 return -1;
3237 /***********************************************************************
3238 * FILEDLG95_FILETYPE_Clean
3240 * Clean the memory used by the filetype combo box
3242 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3244 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3245 int iPos;
3246 int iCount;
3248 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3250 TRACE("\n");
3252 /* Delete each string of the combo and their associated data */
3253 if(iCount != CB_ERR)
3255 for(iPos = iCount-1;iPos>=0;iPos--)
3257 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3258 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3261 /* Current filter */
3262 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3265 /***********************************************************************
3266 * FILEDLG95_LOOKIN_Init
3268 * Initialisation of the look in combo box
3271 /* Small helper function, to determine if the unixfs shell extension is rooted
3272 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3274 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3275 HKEY hKey;
3277 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3278 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\"
3279 "{9D20AAE8-0625-44B0-9CA7-71889C2254D9}", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3280 return FALSE;
3282 RegCloseKey(hKey);
3283 return TRUE;
3286 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3288 IShellFolder *psfRoot, *psfDrives;
3289 IEnumIDList *lpeRoot, *lpeDrives;
3290 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3291 HDC hdc;
3292 TEXTMETRICW tm;
3293 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3295 TRACE("%p\n", hwndCombo);
3297 liInfos->iMaxIndentation = 0;
3299 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3301 hdc = GetDC( hwndCombo );
3302 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3303 GetTextMetricsW( hdc, &tm );
3304 ReleaseDC( hwndCombo, hdc );
3306 /* set item height for both text field and listbox */
3307 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3308 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3310 /* Turn on the extended UI for the combo box like Windows does */
3311 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3313 /* Initialise data of Desktop folder */
3314 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3315 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3316 ILFree(pidlTmp);
3318 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3320 SHGetDesktopFolder(&psfRoot);
3322 if (psfRoot)
3324 /* enumerate the contents of the desktop */
3325 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3327 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3329 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3331 /* If the unixfs extension is rooted, we don't expand the drives by default */
3332 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3334 /* special handling for CSIDL_DRIVES */
3335 if (ILIsEqual(pidlTmp, pidlDrives))
3337 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3339 /* enumerate the drives */
3340 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3342 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3344 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3345 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3346 ILFree(pidlAbsTmp);
3347 ILFree(pidlTmp1);
3349 IEnumIDList_Release(lpeDrives);
3351 IShellFolder_Release(psfDrives);
3356 ILFree(pidlTmp);
3358 IEnumIDList_Release(lpeRoot);
3360 IShellFolder_Release(psfRoot);
3363 ILFree(pidlDrives);
3366 /***********************************************************************
3367 * FILEDLG95_LOOKIN_DrawItem
3369 * WM_DRAWITEM message handler
3371 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3373 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3374 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3375 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3376 RECT rectText;
3377 RECT rectIcon;
3378 SHFILEINFOW sfi;
3379 HIMAGELIST ilItemImage;
3380 int iIndentation;
3381 TEXTMETRICW tm;
3382 LPSFOLDER tmpFolder;
3383 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3384 UINT icon_width, icon_height;
3386 TRACE("\n");
3388 if(pDIStruct->itemID == -1)
3389 return 0;
3391 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3392 pDIStruct->itemID)))
3393 return 0;
3396 icon_width = GetSystemMetrics(SM_CXICON);
3397 icon_height = GetSystemMetrics(SM_CYICON);
3398 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3400 icon_width = GetSystemMetrics(SM_CXSMICON);
3401 icon_height = GetSystemMetrics(SM_CYSMICON);
3402 shgfi_flags |= SHGFI_SMALLICON;
3405 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3406 0, &sfi, sizeof (sfi), shgfi_flags );
3408 /* Is this item selected ? */
3409 if(pDIStruct->itemState & ODS_SELECTED)
3411 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3412 SetBkColor(pDIStruct->hDC,crHighLight);
3413 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3415 else
3417 SetTextColor(pDIStruct->hDC,crText);
3418 SetBkColor(pDIStruct->hDC,crWin);
3419 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3422 /* Do not indent item if drawing in the edit of the combo */
3423 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3424 iIndentation = 0;
3425 else
3426 iIndentation = tmpFolder->m_iIndent;
3428 /* Draw text and icon */
3430 /* Initialise the icon display area */
3431 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3432 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3433 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3434 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3436 /* Initialise the text display area */
3437 GetTextMetricsW(pDIStruct->hDC, &tm);
3438 rectText.left = rectIcon.right;
3439 rectText.top =
3440 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3441 rectText.right = pDIStruct->rcItem.right;
3442 rectText.bottom =
3443 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3445 /* Draw the icon from the image list */
3446 ImageList_Draw(ilItemImage,
3447 sfi.iIcon,
3448 pDIStruct->hDC,
3449 rectIcon.left,
3450 rectIcon.top,
3451 ILD_TRANSPARENT );
3453 /* Draw the associated text */
3454 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3455 return NOERROR;
3458 /***********************************************************************
3459 * FILEDLG95_LOOKIN_OnCommand
3461 * LookIn combo box WM_COMMAND message handler
3462 * If the function succeeds, the return value is nonzero.
3464 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3466 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3468 TRACE("%p\n", fodInfos);
3470 switch(wNotifyCode)
3472 case CBN_SELENDOK:
3474 LPSFOLDER tmpFolder;
3475 int iItem;
3477 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3479 if( iItem == CB_ERR) return FALSE;
3481 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3482 iItem)))
3483 return FALSE;
3486 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3487 tmpFolder->pidlItem,
3488 SBSP_ABSOLUTE)))
3490 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3491 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3492 return TRUE;
3494 break;
3498 return FALSE;
3501 /***********************************************************************
3502 * FILEDLG95_LOOKIN_AddItem
3504 * Adds an absolute pidl item to the lookin combo box
3505 * returns the index of the inserted item
3507 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3509 LPITEMIDLIST pidlNext;
3510 SHFILEINFOW sfi;
3511 SFOLDER *tmpFolder;
3512 LookInInfos *liInfos;
3514 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3516 if(!pidl)
3517 return -1;
3519 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3520 return -1;
3522 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3523 tmpFolder->m_iIndent = 0;
3525 /* Calculate the indentation of the item in the lookin*/
3526 pidlNext = pidl;
3527 while ((pidlNext = ILGetNext(pidlNext)))
3529 tmpFolder->m_iIndent++;
3532 tmpFolder->pidlItem = ILClone(pidl);
3534 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3535 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3537 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3538 SHGetFileInfoW((LPCWSTR)pidl,
3540 &sfi,
3541 sizeof(sfi),
3542 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3544 TRACE("-- Add %s attr=0x%08lx\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3546 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3548 int iItemID;
3550 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3552 /* Add the item at the end of the list */
3553 if(iInsertId < 0)
3555 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3557 /* Insert the item at the iInsertId position*/
3558 else
3560 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3563 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3564 return iItemID;
3567 ILFree( tmpFolder->pidlItem );
3568 heap_free( tmpFolder );
3569 return -1;
3573 /***********************************************************************
3574 * FILEDLG95_LOOKIN_InsertItemAfterParent
3576 * Insert an item below its parent
3578 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3581 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3582 int iParentPos;
3584 TRACE("\n");
3586 if (pidl == pidlParent)
3587 return -1;
3589 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3591 if(iParentPos < 0)
3593 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3596 ILFree(pidlParent);
3598 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3601 /***********************************************************************
3602 * FILEDLG95_LOOKIN_SelectItem
3604 * Adds an absolute pidl item to the lookin combo box
3605 * returns the index of the inserted item
3607 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3609 int iItemPos;
3610 LookInInfos *liInfos;
3612 TRACE("%p, %p\n", hwnd, pidl);
3614 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3616 liInfos = GetPropA(hwnd,LookInInfosStr);
3618 if(iItemPos < 0)
3620 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3621 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3624 else
3626 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3627 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3629 int iRemovedItem;
3631 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3632 break;
3633 if(iRemovedItem < iItemPos)
3634 iItemPos--;
3638 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3639 liInfos->uSelectedItem = iItemPos;
3641 return 0;
3645 /***********************************************************************
3646 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3648 * Remove the item with an expansion level over iExpansionLevel
3650 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3652 int iItemPos;
3653 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3655 TRACE("\n");
3657 if(liInfos->iMaxIndentation <= 2)
3658 return -1;
3660 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3662 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3663 ILFree(tmpFolder->pidlItem);
3664 heap_free(tmpFolder);
3665 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3666 liInfos->iMaxIndentation--;
3668 return iItemPos;
3671 return -1;
3674 /***********************************************************************
3675 * FILEDLG95_LOOKIN_SearchItem
3677 * Search for pidl in the lookin combo box
3678 * returns the index of the found item
3680 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3682 int i = 0;
3683 int iCount;
3685 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3687 TRACE("0x%08Ix 0x%x\n",searchArg, iSearchMethod);
3689 if (iCount != CB_ERR)
3691 for(;i<iCount;i++)
3693 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3695 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3696 return i;
3697 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3698 return i;
3702 return -1;
3705 /***********************************************************************
3706 * FILEDLG95_LOOKIN_Clean
3708 * Clean the memory used by the lookin combo box
3710 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3712 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3713 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3714 int iPos, iCount;
3716 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3718 TRACE("\n");
3720 /* Delete each string of the combo and their associated data */
3721 if (iCount != CB_ERR)
3723 for(iPos = iCount-1;iPos>=0;iPos--)
3725 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3726 ILFree(tmpFolder->pidlItem);
3727 heap_free(tmpFolder);
3728 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3732 /* LookInInfos structure */
3733 heap_free(liInfos);
3734 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3737 /***********************************************************************
3738 * get_def_format
3740 * Fill the FORMATETC used in the shell id list
3742 static FORMATETC get_def_format(void)
3744 static CLIPFORMAT cfFormat;
3745 FORMATETC formatetc;
3747 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3748 formatetc.cfFormat = cfFormat;
3749 formatetc.ptd = 0;
3750 formatetc.dwAspect = DVASPECT_CONTENT;
3751 formatetc.lindex = -1;
3752 formatetc.tymed = TYMED_HGLOBAL;
3753 return formatetc;
3756 /***********************************************************************
3757 * FILEDLG95_FILENAME_FillFromSelection
3759 * fills the edit box from the cached DataObject
3761 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3763 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3764 LPITEMIDLIST pidl;
3765 LPWSTR lpstrAllFiles, lpstrTmp;
3766 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3767 STGMEDIUM medium;
3768 LPIDA cida;
3769 FORMATETC formatetc = get_def_format();
3771 TRACE("\n");
3773 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3774 return;
3776 cida = GlobalLock(medium.u.hGlobal);
3777 nFileSelected = cida->cidl;
3779 /* Allocate a buffer */
3780 nAllFilesMaxLength = MAX_PATH + 3;
3781 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3782 if (!lpstrAllFiles)
3783 goto ret;
3785 /* Loop through the selection, handle only files (not folders) */
3786 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3788 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3789 if (pidl)
3791 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3793 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3795 nAllFilesMaxLength *= 2;
3796 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3797 if (!lpstrTmp)
3798 goto ret;
3799 lpstrAllFiles = lpstrTmp;
3801 nFiles += 1;
3802 lpstrAllFiles[nAllFilesLength++] = '"';
3803 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3804 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3805 nAllFilesLength += nThisFileLength;
3806 lpstrAllFiles[nAllFilesLength++] = '"';
3807 lpstrAllFiles[nAllFilesLength++] = ' ';
3812 if (nFiles != 0)
3814 /* If there's only one file, use the name as-is without quotes */
3815 lpstrTmp = lpstrAllFiles;
3816 if (nFiles == 1)
3818 lpstrTmp += 1;
3819 lpstrTmp[nThisFileLength] = 0;
3821 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3822 /* Select the file name like Windows does */
3823 if (filename_is_edit(fodInfos))
3824 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3827 ret:
3828 heap_free(lpstrAllFiles);
3829 COMCTL32_ReleaseStgMedium(medium);
3833 /* copied from shell32 to avoid linking to it
3834 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3835 * is dependent on whether emulated OS is unicode or not.
3837 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3839 switch (src->uType)
3841 case STRRET_WSTR:
3842 lstrcpynW(dest, src->u.pOleStr, len);
3843 CoTaskMemFree(src->u.pOleStr);
3844 break;
3846 case STRRET_CSTR:
3847 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3848 dest[len-1] = 0;
3849 break;
3851 case STRRET_OFFSET:
3852 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3853 dest[len-1] = 0;
3854 break;
3856 default:
3857 FIXME("unknown type %x!\n", src->uType);
3858 if (len) *dest = '\0';
3859 return E_FAIL;
3861 return S_OK;
3864 /***********************************************************************
3865 * FILEDLG95_FILENAME_GetFileNames
3867 * Copies the filenames to a delimited string list.
3869 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3871 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3872 UINT nFileCount = 0; /* number of files */
3873 UINT nStrLen = 0; /* length of string in edit control */
3874 LPWSTR lpstrEdit; /* buffer for string from edit control */
3876 TRACE("\n");
3878 /* get the filenames from the filename control */
3879 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3880 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3881 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3883 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3885 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3886 heap_free(lpstrEdit);
3887 return nFileCount;
3891 * DATAOBJECT Helper functions
3894 /***********************************************************************
3895 * COMCTL32_ReleaseStgMedium
3897 * like ReleaseStgMedium from ole32
3899 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3901 if(medium.pUnkForRelease)
3903 IUnknown_Release(medium.pUnkForRelease);
3905 else
3907 GlobalUnlock(medium.u.hGlobal);
3908 GlobalFree(medium.u.hGlobal);
3912 /***********************************************************************
3913 * GetPidlFromDataObject
3915 * Return pidl(s) by number from the cached DataObject
3917 * nPidlIndex=0 gets the fully qualified root path
3919 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3922 STGMEDIUM medium;
3923 FORMATETC formatetc = get_def_format();
3924 LPITEMIDLIST pidl = NULL;
3926 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3928 if (!doSelected)
3929 return NULL;
3931 /* Get the pidls from IDataObject */
3932 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3934 LPIDA cida = GlobalLock(medium.u.hGlobal);
3935 if(nPidlIndex <= cida->cidl)
3937 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3939 COMCTL32_ReleaseStgMedium(medium);
3941 return pidl;
3944 /***********************************************************************
3945 * GetNumSelected
3947 * Return the number of selected items in the DataObject.
3950 static UINT GetNumSelected( IDataObject *doSelected )
3952 UINT retVal = 0;
3953 STGMEDIUM medium;
3954 FORMATETC formatetc = get_def_format();
3956 TRACE("sv=%p\n", doSelected);
3958 if (!doSelected) return 0;
3960 /* Get the pidls from IDataObject */
3961 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3963 LPIDA cida = GlobalLock(medium.u.hGlobal);
3964 retVal = cida->cidl;
3965 COMCTL32_ReleaseStgMedium(medium);
3966 return retVal;
3968 return 0;
3972 * TOOLS
3975 /***********************************************************************
3976 * GetName
3978 * Get the pidl's display name (relative to folder) and
3979 * put it in lpstrFileName.
3981 * Return NOERROR on success,
3982 * E_FAIL otherwise
3985 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3987 STRRET str;
3988 HRESULT hRes;
3990 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3992 if(!lpsf)
3994 SHGetDesktopFolder(&lpsf);
3995 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3996 IShellFolder_Release(lpsf);
3997 return hRes;
4000 /* Get the display name of the pidl relative to the folder */
4001 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4003 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4005 return E_FAIL;
4008 /***********************************************************************
4009 * GetShellFolderFromPidl
4011 * pidlRel is the item pidl relative
4012 * Return the IShellFolder of the absolute pidl
4014 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
4016 IShellFolder *psf = NULL,*psfParent;
4018 TRACE("%p\n", pidlAbs);
4020 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4022 psf = psfParent;
4023 if(pidlAbs && pidlAbs->mkid.cb)
4025 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4027 IShellFolder_Release(psfParent);
4028 return psf;
4031 /* return the desktop */
4032 return psfParent;
4034 return NULL;
4037 /***********************************************************************
4038 * GetParentPidl
4040 * Return the LPITEMIDLIST to the parent of the pidl in the list
4042 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4044 LPITEMIDLIST pidlParent;
4046 TRACE("%p\n", pidl);
4048 pidlParent = ILClone(pidl);
4049 ILRemoveLastID(pidlParent);
4051 return pidlParent;
4054 /***********************************************************************
4055 * GetPidlFromName
4057 * returns the pidl of the file name relative to folder
4058 * NULL if an error occurred
4060 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4062 LPITEMIDLIST pidl = NULL;
4063 ULONG ulEaten;
4065 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4067 if(!lpcstrFileName) return NULL;
4068 if(!*lpcstrFileName) return NULL;
4070 if(!lpsf)
4072 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4073 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4074 IShellFolder_Release(lpsf);
4077 else
4079 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4081 return pidl;
4086 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4088 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4089 HRESULT ret;
4091 TRACE("%p, %p\n", psf, pidl);
4093 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4095 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
4096 /* see documentation shell 4.1*/
4097 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4100 /***********************************************************************
4101 * BrowseSelectedFolder
4103 static BOOL BrowseSelectedFolder(HWND hwnd)
4105 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4106 BOOL bBrowseSelFolder = FALSE;
4108 TRACE("\n");
4110 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4112 LPITEMIDLIST pidlSelection;
4114 /* get the file selected */
4115 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4116 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4118 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4119 pidlSelection, SBSP_RELATIVE ) ) )
4121 WCHAR buf[64];
4122 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4123 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4125 bBrowseSelFolder = TRUE;
4126 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4127 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4129 ILFree( pidlSelection );
4132 return bBrowseSelFolder;
4135 static inline BOOL valid_struct_size( DWORD size )
4137 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4138 (size == sizeof( OPENFILENAMEW ));
4141 static inline BOOL is_win16_looks(DWORD flags)
4143 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4144 !(flags & OFN_EXPLORER));
4147 /* ------------------ APIs ---------------------- */
4149 /***********************************************************************
4150 * GetOpenFileNameA (COMDLG32.@)
4152 * Creates a dialog box for the user to select a file to open.
4154 * RETURNS
4155 * TRUE on success: user enters a valid file
4156 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4159 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4161 TRACE("flags 0x%08lx\n", ofn->Flags);
4163 if (!valid_struct_size( ofn->lStructSize ))
4165 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4166 return FALSE;
4169 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4170 if (ofn->Flags & OFN_FILEMUSTEXIST)
4171 ofn->Flags |= OFN_PATHMUSTEXIST;
4173 if (is_win16_looks(ofn->Flags))
4174 return GetFileName31A(ofn, OPEN_DIALOG);
4175 else
4177 FileOpenDlgInfos info;
4179 init_filedlg_infoA(ofn, &info);
4180 return GetFileDialog95(&info, OPEN_DIALOG);
4184 /***********************************************************************
4185 * GetOpenFileNameW (COMDLG32.@)
4187 * Creates a dialog box for the user to select a file to open.
4189 * RETURNS
4190 * TRUE on success: user enters a valid file
4191 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4194 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4196 TRACE("flags 0x%08lx\n", ofn->Flags);
4198 if (!valid_struct_size( ofn->lStructSize ))
4200 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4201 return FALSE;
4204 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4205 if (ofn->Flags & OFN_FILEMUSTEXIST)
4206 ofn->Flags |= OFN_PATHMUSTEXIST;
4208 if (is_win16_looks(ofn->Flags))
4209 return GetFileName31W(ofn, OPEN_DIALOG);
4210 else
4212 FileOpenDlgInfos info;
4214 init_filedlg_infoW(ofn, &info);
4215 return GetFileDialog95(&info, OPEN_DIALOG);
4220 /***********************************************************************
4221 * GetSaveFileNameA (COMDLG32.@)
4223 * Creates a dialog box for the user to select a file to save.
4225 * RETURNS
4226 * TRUE on success: user enters a valid file
4227 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4230 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4232 if (!valid_struct_size( ofn->lStructSize ))
4234 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4235 return FALSE;
4238 if (is_win16_looks(ofn->Flags))
4239 return GetFileName31A(ofn, SAVE_DIALOG);
4240 else
4242 FileOpenDlgInfos info;
4244 init_filedlg_infoA(ofn, &info);
4245 return GetFileDialog95(&info, SAVE_DIALOG);
4249 /***********************************************************************
4250 * GetSaveFileNameW (COMDLG32.@)
4252 * Creates a dialog box for the user to select a file to save.
4254 * RETURNS
4255 * TRUE on success: user enters a valid file
4256 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4259 BOOL WINAPI GetSaveFileNameW(
4260 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4262 if (!valid_struct_size( ofn->lStructSize ))
4264 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4265 return FALSE;
4268 if (is_win16_looks(ofn->Flags))
4269 return GetFileName31W(ofn, SAVE_DIALOG);
4270 else
4272 FileOpenDlgInfos info;
4274 init_filedlg_infoW(ofn, &info);
4275 return GetFileDialog95(&info, SAVE_DIALOG);
4279 /***********************************************************************
4280 * GetFileTitleA (COMDLG32.@)
4282 * See GetFileTitleW.
4284 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4286 int ret;
4287 UNICODE_STRING strWFile;
4288 LPWSTR lpWTitle;
4290 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4291 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4292 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4293 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4294 RtlFreeUnicodeString( &strWFile );
4295 heap_free( lpWTitle );
4296 return ret;
4300 /***********************************************************************
4301 * GetFileTitleW (COMDLG32.@)
4303 * Get the name of a file.
4305 * PARAMS
4306 * lpFile [I] name and location of file
4307 * lpTitle [O] returned file name
4308 * cbBuf [I] buffer size of lpTitle
4310 * RETURNS
4311 * Success: zero
4312 * Failure: negative number.
4314 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4316 int i, len;
4317 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4319 if(lpFile == NULL || lpTitle == NULL)
4320 return -1;
4322 len = lstrlenW(lpFile);
4324 if (len == 0)
4325 return -1;
4327 if(wcspbrk(lpFile, L"*[]"))
4328 return -1;
4330 len--;
4332 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4333 return -1;
4335 for(i = len; i >= 0; i--)
4337 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4339 i++;
4340 break;
4344 if(i == -1)
4345 i++;
4347 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4349 len = lstrlenW(lpFile+i)+1;
4350 if(cbBuf < len)
4351 return len;
4353 lstrcpyW(lpTitle, &lpFile[i]);
4354 return 0;