kernel32: Get rid of the last parameter to PROFILE_CopyEntry().
[wine.git] / dlls / comdlg32 / filedlg.c
blob538358bd5f91c8a00d7ea5f401313539fafeac05
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 static const WCHAR LastVisitedMRUW[] =
139 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
140 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
142 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
143 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
145 static const WCHAR filedlg_info_propnameW[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
147 FileOpenDlgInfos *get_filedlg_infoptr(HWND hwnd)
149 return GetPropW(hwnd, filedlg_info_propnameW);
152 static BOOL is_dialog_hooked(const FileOpenDlgInfos *info)
154 return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
157 static BOOL filedialog_is_readonly_hidden(const FileOpenDlgInfos *info)
159 return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG);
162 /***********************************************************************
163 * Prototypes
166 /* Internal functions used by the dialog */
167 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
168 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
169 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
170 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
171 static BOOL FILEDLG95_OnOpen(HWND hwnd);
172 static LRESULT FILEDLG95_InitControls(HWND hwnd);
173 static void FILEDLG95_Clean(HWND hwnd);
175 /* Functions used by the shell navigation */
176 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
177 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
178 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
179 static void FILEDLG95_SHELL_Clean(HWND hwnd);
181 /* Functions used by the EDIT box */
182 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
184 /* Functions used by the filetype combo box */
185 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
186 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
187 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
188 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
190 /* Functions used by the Look In combo box */
191 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
192 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
193 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
194 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
195 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
196 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
197 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
198 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
199 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
201 /* Functions for dealing with the most-recently-used registry keys */
202 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
203 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
204 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
206 /* Miscellaneous tool functions */
207 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
208 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
209 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
210 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
211 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
212 static UINT GetNumSelected( IDataObject *doSelected );
213 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
215 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
216 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
217 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
218 static BOOL BrowseSelectedFolder(HWND hwnd);
220 static BOOL get_config_key_as_dword(HKEY hkey, const WCHAR *name, DWORD *value)
222 DWORD type, data, size;
224 size = sizeof(data);
225 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size))
227 *value = data;
228 return TRUE;
231 return FALSE;
234 static BOOL get_config_key_dword(HKEY hkey, const WCHAR *name, DWORD *value)
236 DWORD type, data, size;
238 size = sizeof(data);
239 if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
241 *value = data;
242 return TRUE;
245 return FALSE;
248 static BOOL get_config_key_string(HKEY hkey, const WCHAR *name, WCHAR **value)
250 DWORD type, size;
251 WCHAR *str;
253 if (RegQueryValueExW(hkey, name, 0, &type, NULL, &size))
254 return FALSE;
255 if (type != REG_SZ && type != REG_EXPAND_SZ)
256 return FALSE;
258 str = heap_alloc(size);
259 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size))
261 heap_free(str);
262 return FALSE;
265 *value = str;
266 return TRUE;
269 static BOOL is_places_bar_enabled(const FileOpenDlgInfos *fodInfos)
271 static const WCHAR noplacesbarW[] = {'N','o','P','l','a','c','e','s','B','a','r',0};
272 DWORD value;
273 HKEY hkey;
275 if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) ||
276 (fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) ||
277 !(fodInfos->ofnInfos->Flags & OFN_EXPLORER))
279 return FALSE;
282 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey))
283 return TRUE;
285 value = 0;
286 get_config_key_as_dword(hkey, noplacesbarW, &value);
287 RegCloseKey(hkey);
288 return value == 0;
291 static void filedlg_collect_places_pidls(FileOpenDlgInfos *fodInfos)
293 static const int default_places[] =
295 CSIDL_DESKTOP,
296 CSIDL_MYDOCUMENTS,
297 CSIDL_DRIVES,
299 unsigned int i;
300 HKEY hkey;
302 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
303 &hkey))
305 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
307 static const WCHAR placeW[] = {'P','l','a','c','e','%','d',0};
308 WCHAR nameW[8];
309 DWORD value;
310 HRESULT hr;
311 WCHAR *str;
313 swprintf(nameW, ARRAY_SIZE(nameW), placeW, i);
314 if (get_config_key_dword(hkey, nameW, &value))
316 hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]);
317 if (FAILED(hr))
318 WARN("Unrecognized special folder %u.\n", value);
320 else if (get_config_key_string(hkey, nameW, &str))
322 hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL);
323 if (FAILED(hr))
324 WARN("Failed to parse custom places location, %s.\n", debugstr_w(str));
325 heap_free(str);
329 /* FIXME: eliminate duplicates. */
331 RegCloseKey(hkey);
332 return;
335 for (i = 0; i < ARRAY_SIZE(default_places); i++)
336 SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]);
339 /***********************************************************************
340 * GetFileName95
342 * Creates an Open common dialog box that lets the user select
343 * the drive, directory, and the name of a file or set of files to open.
345 * IN : The FileOpenDlgInfos structure associated with the dialog
346 * OUT : TRUE on success
347 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
349 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
351 LRESULT lRes;
352 void *template;
353 HRSRC hRes;
354 HANDLE hDlgTmpl = 0;
355 WORD templateid;
357 /* test for missing functionality */
358 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
360 FIXME("Flags 0x%08x not yet implemented\n",
361 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
364 /* Create the dialog from a template */
366 if (is_places_bar_enabled(fodInfos))
367 templateid = NEWFILEOPENV2ORD;
368 else
369 templateid = NEWFILEOPENORD;
371 if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG)))
373 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
374 return FALSE;
376 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
377 !(template = LockResource( hDlgTmpl )))
379 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
380 return FALSE;
383 /* msdn: explorer style dialogs permit sizing by default.
384 * The OFN_ENABLESIZING flag is only needed when a hook or
385 * custom template is provided */
386 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
387 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
388 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
390 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
392 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
393 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
396 /* old style hook messages */
397 if (is_dialog_hooked(fodInfos))
399 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
400 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
401 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
402 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
405 if (fodInfos->unicode)
406 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
407 template,
408 fodInfos->ofnInfos->hwndOwner,
409 FileOpenDlgProc95,
410 (LPARAM) fodInfos);
411 else
412 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
413 template,
414 fodInfos->ofnInfos->hwndOwner,
415 FileOpenDlgProc95,
416 (LPARAM) fodInfos);
417 if (fodInfos->ole_initialized)
418 OleUninitialize();
420 /* Unable to create the dialog */
421 if( lRes == -1)
422 return FALSE;
424 return lRes;
427 static WCHAR *heap_strdupAtoW(const char *str)
429 WCHAR *ret;
430 INT len;
432 if (!str)
433 return NULL;
435 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
436 ret = heap_alloc(len * sizeof(WCHAR));
437 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
439 return ret;
442 static void init_filedlg_infoW(OPENFILENAMEW *ofn, FileOpenDlgInfos *info)
444 INITCOMMONCONTROLSEX icc;
446 /* Initialize ComboBoxEx32 */
447 icc.dwSize = sizeof(icc);
448 icc.dwICC = ICC_USEREX_CLASSES;
449 InitCommonControlsEx(&icc);
451 /* Initialize CommDlgExtendedError() */
452 COMDLG32_SetCommDlgExtendedError(0);
454 memset(info, 0, sizeof(*info));
456 /* Pass in the original ofn */
457 info->ofnInfos = ofn;
459 info->title = ofn->lpstrTitle;
460 info->defext = ofn->lpstrDefExt;
461 info->filter = ofn->lpstrFilter;
462 info->customfilter = ofn->lpstrCustomFilter;
464 if (ofn->lpstrFile)
466 info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
467 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
470 if (ofn->lpstrInitialDir)
472 DWORD len = ExpandEnvironmentStringsW(ofn->lpstrInitialDir, NULL, 0);
473 if (len)
475 info->initdir = heap_alloc(len * sizeof(WCHAR));
476 ExpandEnvironmentStringsW(ofn->lpstrInitialDir, info->initdir, len);
480 info->unicode = TRUE;
483 static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
485 OPENFILENAMEW ofnW;
486 int len;
488 ofnW = *(OPENFILENAMEW *)ofn;
490 ofnW.lpstrInitialDir = heap_strdupAtoW(ofn->lpstrInitialDir);
491 ofnW.lpstrDefExt = heap_strdupAtoW(ofn->lpstrDefExt);
492 ofnW.lpstrTitle = heap_strdupAtoW(ofn->lpstrTitle);
494 if (ofn->lpstrFile)
496 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, NULL, 0);
497 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
498 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFile, ofn->nMaxFile, ofnW.lpstrFile, len);
499 ofnW.nMaxFile = len;
502 if (ofn->lpstrFilter)
504 LPCSTR s;
505 int n;
507 /* filter is a list... title\0ext\0......\0\0 */
508 s = ofn->lpstrFilter;
509 while (*s) s = s+strlen(s)+1;
510 s++;
511 n = s - ofn->lpstrFilter;
512 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0);
513 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
514 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrFilter, n, (WCHAR *)ofnW.lpstrFilter, len);
517 /* convert lpstrCustomFilter */
518 if (ofn->lpstrCustomFilter)
520 int n, len;
521 LPCSTR s;
523 /* customfilter contains a pair of strings... title\0ext\0 */
524 s = ofn->lpstrCustomFilter;
525 if (*s) s = s+strlen(s)+1;
526 if (*s) s = s+strlen(s)+1;
527 n = s - ofn->lpstrCustomFilter;
528 len = MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0);
529 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
530 MultiByteToWideChar(CP_ACP, 0, ofn->lpstrCustomFilter, n, ofnW.lpstrCustomFilter, len);
533 init_filedlg_infoW(&ofnW, info);
535 /* fixup A-specific fields */
536 info->ofnInfos = (OPENFILENAMEW *)ofn;
537 info->unicode = FALSE;
539 /* free what was duplicated */
540 heap_free((void *)ofnW.lpstrInitialDir);
541 heap_free(ofnW.lpstrFile);
544 /***********************************************************************
545 * GetFileDialog95
547 * Call GetFileName95 with this structure and clean the memory.
549 static BOOL GetFileDialog95(FileOpenDlgInfos *info, UINT dlg_type)
551 WCHAR *current_dir = NULL;
552 unsigned int i;
553 BOOL ret;
555 /* save current directory */
556 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
558 current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
559 GetCurrentDirectoryW(MAX_PATH, current_dir);
562 switch (dlg_type)
564 case OPEN_DIALOG:
565 ret = GetFileName95(info);
566 break;
567 case SAVE_DIALOG:
568 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
569 ret = GetFileName95(info);
570 break;
571 default:
572 ret = FALSE;
575 if (current_dir)
577 SetCurrentDirectoryW(current_dir);
578 heap_free(current_dir);
581 if (!info->unicode)
583 heap_free((void *)info->defext);
584 heap_free((void *)info->title);
585 heap_free((void *)info->filter);
586 heap_free((void *)info->customfilter);
589 heap_free(info->filename);
590 heap_free(info->initdir);
592 for (i = 0; i < ARRAY_SIZE(info->places); i++)
593 ILFree(info->places[i]);
595 return ret;
598 /******************************************************************************
599 * COMDLG32_GetDisplayNameOf [internal]
601 * Helper function to get the display name for a pidl.
603 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
604 LPSHELLFOLDER psfDesktop;
605 STRRET strret;
607 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
608 return FALSE;
610 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
611 IShellFolder_Release(psfDesktop);
612 return FALSE;
615 IShellFolder_Release(psfDesktop);
616 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
619 /******************************************************************************
620 * COMDLG32_GetCanonicalPath [internal]
622 * Helper function to get the canonical path.
624 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
625 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
627 WCHAR lpstrTemp[MAX_PATH];
629 /* Get the current directory name */
630 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
632 /* last fallback */
633 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
635 PathAddBackslashW(lpstrPathAndFile);
637 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
639 /* if the user specified a fully qualified path use it */
640 if(PathIsRelativeW(lpstrFile))
642 lstrcatW(lpstrPathAndFile, lpstrFile);
644 else
646 /* does the path have a drive letter? */
647 if (PathGetDriveNumberW(lpstrFile) == -1)
648 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
649 else
650 lstrcpyW(lpstrPathAndFile, lpstrFile);
653 /* resolve "." and ".." */
654 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
655 lstrcpyW(lpstrPathAndFile, lpstrTemp);
656 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
659 /***********************************************************************
660 * COMDLG32_SplitFileNames [internal]
662 * Creates a delimited list of filenames.
664 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
666 UINT nStrCharCount = 0; /* index in src buffer */
667 UINT nFileIndex = 0; /* index in dest buffer */
668 UINT nFileCount = 0; /* number of files */
670 /* we might get single filename without any '"',
671 * so we need nStrLen + terminating \0 + end-of-list \0 */
672 *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
673 *sizeUsed = 0;
675 /* build delimited file list from filenames */
676 while ( nStrCharCount <= nStrLen )
678 if ( lpstrEdit[nStrCharCount]=='"' )
680 nStrCharCount++;
681 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
683 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
684 nStrCharCount++;
686 (*lpstrFileList)[nFileIndex++] = 0;
687 nFileCount++;
689 nStrCharCount++;
692 /* single, unquoted string */
693 if ((nStrLen > 0) && (nFileIndex == 0) )
695 lstrcpyW(*lpstrFileList, lpstrEdit);
696 nFileIndex = lstrlenW(lpstrEdit) + 1;
697 nFileCount = 1;
700 /* trailing \0 */
701 (*lpstrFileList)[nFileIndex++] = '\0';
703 *sizeUsed = nFileIndex;
704 return nFileCount;
707 /***********************************************************************
708 * ArrangeCtrlPositions [internal]
710 * NOTE: Make sure to add testcases for any changes made here.
712 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
714 HWND hwndChild, hwndStc32;
715 RECT rectParent, rectChild, rectStc32;
716 INT help_fixup = 0;
717 int chgx, chgy;
719 /* Take into account if open as read only checkbox and help button
720 * are hidden
722 if (hide_help)
724 RECT rectHelp, rectCancel;
725 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
726 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
727 /* subtract the height of the help button plus the space between
728 * the help button and the cancel button to the height of the dialog
730 help_fixup = rectHelp.bottom - rectCancel.bottom;
734 There are two possibilities to add components to the default file dialog box.
736 By default, all the new components are added below the standard dialog box (the else case).
738 However, if there is a static text component with the stc32 id, a special case happens.
739 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
740 in the window and the cx and cy indicate how to size the window.
741 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
742 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
746 GetClientRect(hwndParentDlg, &rectParent);
748 /* when arranging controls we have to use fixed parent size */
749 rectParent.bottom -= help_fixup;
751 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
752 if (hwndStc32)
754 GetWindowRect(hwndStc32, &rectStc32);
755 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
757 /* set the size of the stc32 control according to the size of
758 * client area of the parent dialog
760 SetWindowPos(hwndStc32, 0,
761 0, 0,
762 rectParent.right, rectParent.bottom,
763 SWP_NOMOVE | SWP_NOZORDER);
765 else
766 SetRectEmpty(&rectStc32);
768 /* this part moves controls of the child dialog */
769 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
770 while (hwndChild)
772 if (hwndChild != hwndStc32)
774 GetWindowRect(hwndChild, &rectChild);
775 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
777 /* move only if stc32 exist */
778 if (hwndStc32 && rectChild.left > rectStc32.right)
780 /* move to the right of visible controls of the parent dialog */
781 rectChild.left += rectParent.right;
782 rectChild.left -= rectStc32.right;
784 /* move even if stc32 doesn't exist */
785 if (rectChild.top >= rectStc32.bottom)
787 /* move below visible controls of the parent dialog */
788 rectChild.top += rectParent.bottom;
789 rectChild.top -= rectStc32.bottom - rectStc32.top;
792 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
793 0, 0, SWP_NOSIZE | SWP_NOZORDER);
795 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
798 /* this part moves controls of the parent dialog */
799 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
800 while (hwndChild)
802 if (hwndChild != hwndChildDlg)
804 GetWindowRect(hwndChild, &rectChild);
805 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
807 /* left,top of stc32 marks the position of controls
808 * from the parent dialog
810 rectChild.left += rectStc32.left;
811 rectChild.top += rectStc32.top;
813 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
814 0, 0, SWP_NOSIZE | SWP_NOZORDER);
816 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
819 /* calculate the size of the resulting dialog */
821 /* here we have to use original parent size */
822 GetClientRect(hwndParentDlg, &rectParent);
823 GetClientRect(hwndChildDlg, &rectChild);
824 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
825 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
827 if (hwndStc32)
829 /* width */
830 if (rectParent.right > rectStc32.right - rectStc32.left)
831 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
832 else
833 chgx = rectChild.right - rectParent.right;
834 /* height */
835 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
836 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
837 else
838 /* Unconditionally set new dialog
839 * height to that of the child
841 chgy = rectChild.bottom - rectParent.bottom;
843 else
845 chgx = 0;
846 chgy = rectChild.bottom - help_fixup;
848 /* set the size of the parent dialog */
849 GetWindowRect(hwndParentDlg, &rectParent);
850 SetWindowPos(hwndParentDlg, 0,
851 0, 0,
852 rectParent.right - rectParent.left + chgx,
853 rectParent.bottom - rectParent.top + chgy,
854 SWP_NOMOVE | SWP_NOZORDER);
857 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
859 switch(uMsg) {
860 case WM_INITDIALOG:
861 return TRUE;
863 return FALSE;
866 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
868 LPCVOID template;
869 HRSRC hRes;
870 HANDLE hDlgTmpl = 0;
871 HWND hChildDlg = 0;
873 TRACE("%p, %p\n", fodInfos, hwnd);
876 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
877 * structure's hInstance parameter is not a HINSTANCE, but
878 * instead a pointer to a template resource to use.
880 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
882 HINSTANCE hinst;
883 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
885 hinst = COMDLG32_hInstance;
886 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
888 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
889 return NULL;
892 else
894 hinst = fodInfos->ofnInfos->hInstance;
895 if(fodInfos->unicode)
897 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
898 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
900 else
902 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
903 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
905 if (!hRes)
907 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
908 return NULL;
910 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
911 !(template = LockResource( hDlgTmpl )))
913 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
914 return NULL;
917 if (fodInfos->unicode)
918 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
919 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
920 (LPARAM)fodInfos->ofnInfos);
921 else
922 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
923 is_dialog_hooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
924 (LPARAM)fodInfos->ofnInfos);
925 return hChildDlg;
927 else if (is_dialog_hooked(fodInfos))
929 RECT rectHwnd;
930 struct {
931 DLGTEMPLATE tmplate;
932 WORD menu,class,title;
933 } temp;
934 GetClientRect(hwnd,&rectHwnd);
935 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
936 temp.tmplate.dwExtendedStyle = 0;
937 temp.tmplate.cdit = 0;
938 temp.tmplate.x = 0;
939 temp.tmplate.y = 0;
940 temp.tmplate.cx = 0;
941 temp.tmplate.cy = 0;
942 temp.menu = temp.class = temp.title = 0;
944 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
945 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
947 return hChildDlg;
949 return NULL;
952 /***********************************************************************
953 * SendCustomDlgNotificationMessage
955 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
958 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
960 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
961 LRESULT hook_result;
962 OFNOTIFYW ofnNotify;
964 TRACE("%p %d\n", hwndParentDlg, uCode);
966 if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
967 return 0;
969 TRACE("CALL NOTIFY for %d\n", uCode);
971 ofnNotify.hdr.hwndFrom = hwndParentDlg;
972 ofnNotify.hdr.idFrom = 0;
973 ofnNotify.hdr.code = uCode;
974 ofnNotify.lpOFN = fodInfos->ofnInfos;
975 ofnNotify.pszFile = NULL;
977 if (fodInfos->unicode)
978 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
979 else
980 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
982 TRACE("RET NOTIFY retval %#lx\n", hook_result);
984 return hook_result;
987 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
989 UINT len, total;
990 WCHAR *p, *buffer;
991 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
993 TRACE("CDM_GETFILEPATH:\n");
995 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
996 return -1;
998 /* get path and filenames */
999 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
1000 buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
1001 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
1002 if (len)
1004 p = buffer + lstrlenW(buffer);
1005 *p++ = '\\';
1006 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
1008 if (fodInfos->unicode)
1010 total = lstrlenW( buffer) + 1;
1011 if (result) lstrcpynW( result, buffer, size );
1012 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1014 else
1016 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1017 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1018 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1020 heap_free( buffer );
1021 return total;
1024 /***********************************************************************
1025 * FILEDLG95_HandleCustomDialogMessages
1027 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1029 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1031 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1032 WCHAR lpstrPath[MAX_PATH];
1033 INT_PTR retval;
1035 if(!fodInfos) return FALSE;
1037 switch(uMsg)
1039 case CDM_GETFILEPATH:
1040 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1041 break;
1043 case CDM_GETFOLDERPATH:
1044 TRACE("CDM_GETFOLDERPATH:\n");
1045 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1046 if (lParam)
1048 if (fodInfos->unicode)
1049 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1050 else
1051 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1052 (LPSTR)lParam, (int)wParam, NULL, NULL);
1054 retval = lstrlenW(lpstrPath) + 1;
1055 break;
1057 case CDM_GETFOLDERIDLIST:
1058 retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1059 if (retval <= wParam)
1060 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1061 break;
1063 case CDM_GETSPEC:
1064 TRACE("CDM_GETSPEC:\n");
1065 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1066 if (lParam)
1068 if (fodInfos->unicode)
1069 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1070 else
1071 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1073 break;
1075 case CDM_SETCONTROLTEXT:
1076 TRACE("CDM_SETCONTROLTEXT:\n");
1077 if ( lParam )
1079 if( fodInfos->unicode )
1080 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1081 else
1082 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1084 retval = TRUE;
1085 break;
1087 case CDM_HIDECONTROL:
1088 /* MSDN states that it should fail for not OFN_EXPLORER case */
1089 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1091 HWND control = GetDlgItem( hwnd, wParam );
1092 if (control) ShowWindow( control, SW_HIDE );
1093 retval = TRUE;
1095 else retval = FALSE;
1096 break;
1098 default:
1099 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1100 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1101 return FALSE;
1103 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1104 return TRUE;
1107 /***********************************************************************
1108 * FILEDLG95_OnWMGetMMI
1110 * WM_GETMINMAXINFO message handler for resizable dialogs
1112 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1114 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1115 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1116 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1118 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1120 return TRUE;
1123 /***********************************************************************
1124 * FILEDLG95_OnWMSize
1126 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1128 * FIXME: this could be made more elaborate. Now use a simple scheme
1129 * where the file view is enlarged and the controls are either moved
1130 * vertically or horizontally to get out of the way. Only the "grip"
1131 * is moved in both directions to stay in the corner.
1133 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1135 RECT rc, rcview;
1136 int chgx, chgy;
1137 HWND ctrl;
1138 HDWP hdwp;
1139 FileOpenDlgInfos *fodInfos;
1141 if( wParam != SIZE_RESTORED) return FALSE;
1142 fodInfos = get_filedlg_infoptr(hwnd);
1143 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1144 /* get the new dialog rectangle */
1145 GetWindowRect( hwnd, &rc);
1146 TRACE("%p, size from %d,%d to %d,%d\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1147 rc.right -rc.left, rc.bottom -rc.top);
1148 /* not initialized yet */
1149 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1150 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1151 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1152 return FALSE;
1153 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1154 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1155 fodInfos->sizedlg.cx = rc.right - rc.left;
1156 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1157 /* change the size of the view window */
1158 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1159 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1160 hdwp = BeginDeferWindowPos( 10);
1161 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1162 rcview.right - rcview.left + chgx,
1163 rcview.bottom - rcview.top + chgy,
1164 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1165 /* change position and sizes of the controls */
1166 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1168 int ctrlid = GetDlgCtrlID( ctrl);
1169 GetWindowRect( ctrl, &rc);
1170 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1171 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1173 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1174 0, 0,
1175 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1177 else if( rc.top > rcview.bottom)
1179 /* if it was below the shell view
1180 * move to bottom */
1181 switch( ctrlid)
1183 /* file name (edit or comboboxex) and file types combo change also width */
1184 case edt1:
1185 case cmb13:
1186 case cmb1:
1187 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1188 rc.right - rc.left + chgx, rc.bottom - rc.top,
1189 SWP_NOACTIVATE | SWP_NOZORDER);
1190 break;
1191 /* then these buttons must move out of the way */
1192 case IDOK:
1193 case IDCANCEL:
1194 case pshHelp:
1195 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1196 0, 0,
1197 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1198 break;
1199 default:
1200 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1201 0, 0,
1202 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1205 else if( rc.left > rcview.right)
1207 /* if it was to the right of the shell view
1208 * move to right */
1209 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1210 0, 0,
1211 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1213 else
1214 /* special cases */
1216 switch( ctrlid)
1218 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1219 case IDC_LOOKIN:
1220 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1221 rc.right - rc.left + chgx, rc.bottom - rc.top,
1222 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1223 break;
1224 case IDC_TOOLBARSTATIC:
1225 case IDC_TOOLBAR:
1226 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1227 0, 0,
1228 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1229 break;
1230 #endif
1231 /* not resized in windows. Since wine uses this invisible control
1232 * to size the browser view it needs to be resized */
1233 case IDC_SHELLSTATIC:
1234 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1235 rc.right - rc.left + chgx,
1236 rc.bottom - rc.top + chgy,
1237 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1238 break;
1239 case IDC_TOOLBARPLACES:
1240 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1241 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1242 break;
1246 if(fodInfos->DlgInfos.hwndCustomDlg &&
1247 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1249 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1250 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1252 GetWindowRect( ctrl, &rc);
1253 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1254 if( rc.top > rcview.bottom)
1256 /* if it was below the shell view
1257 * move to bottom */
1258 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1259 rc.right - rc.left, rc.bottom - rc.top,
1260 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1262 else if( rc.left > rcview.right)
1264 /* if it was to the right of the shell view
1265 * move to right */
1266 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1267 rc.right - rc.left, rc.bottom - rc.top,
1268 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1271 /* size the custom dialog at the end: some applications do some
1272 * control re-arranging at this point */
1273 GetClientRect(hwnd, &rc);
1274 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1275 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1277 EndDeferWindowPos( hdwp);
1278 /* should not be needed */
1279 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1280 return TRUE;
1283 /***********************************************************************
1284 * FileOpenDlgProc95
1286 * File open dialog procedure
1288 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1290 #if 0
1291 TRACE("%p 0x%04x\n", hwnd, uMsg);
1292 #endif
1294 switch(uMsg)
1296 case WM_INITDIALOG:
1298 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1299 RECT rc, rcstc;
1300 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1301 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1303 /* Some shell namespace extensions depend on COM being initialized. */
1304 if (SUCCEEDED(OleInitialize(NULL)))
1305 fodInfos->ole_initialized = TRUE;
1307 SetPropW(hwnd, filedlg_info_propnameW, fodInfos);
1309 FILEDLG95_InitControls(hwnd);
1311 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1313 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1314 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1315 RECT client, client_adjusted;
1317 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1319 style |= WS_SIZEBOX;
1320 ex_style |= WS_EX_WINDOWEDGE;
1322 else
1323 style &= ~WS_SIZEBOX;
1324 SetWindowLongW(hwnd, GWL_STYLE, style);
1325 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1327 GetClientRect( hwnd, &client );
1328 GetClientRect( hwnd, &client_adjusted );
1329 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1331 GetWindowRect( hwnd, &rc );
1332 rc.right += client_adjusted.right - client.right;
1333 rc.bottom += client_adjusted.bottom - client.bottom;
1334 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1335 SWP_NOZORDER | SWP_NOMOVE);
1337 GetWindowRect( hwnd, &rc );
1338 fodInfos->DlgInfos.hwndGrip =
1339 CreateWindowExA( 0, "SCROLLBAR", NULL,
1340 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1341 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1342 rc.right - gripx, rc.bottom - gripy,
1343 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1346 fodInfos->DlgInfos.hwndCustomDlg =
1347 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1349 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1350 FILEDLG95_FillControls(hwnd, wParam, lParam);
1352 if( fodInfos->DlgInfos.hwndCustomDlg)
1353 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1355 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1356 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1357 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1360 /* if the app has changed the position of the invisible listbox,
1361 * change that of the listview (browser) as well */
1362 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1363 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1364 if( !EqualRect( &rc, &rcstc))
1366 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1367 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1368 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1369 SWP_NOACTIVATE | SWP_NOZORDER);
1372 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1374 GetWindowRect( hwnd, &rc);
1375 fodInfos->sizedlg.cx = rc.right - rc.left;
1376 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1377 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1378 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1379 GetClientRect( hwnd, &rc);
1380 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1381 rc.right - gripx, rc.bottom - gripy,
1382 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1383 /* resize the dialog to the previous invocation */
1384 if( MemDialogSize.cx && MemDialogSize.cy)
1385 SetWindowPos( hwnd, NULL,
1386 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1387 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1390 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1391 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1393 return 0;
1395 case WM_SIZE:
1396 return FILEDLG95_OnWMSize(hwnd, wParam);
1397 case WM_GETMINMAXINFO:
1398 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1399 case WM_COMMAND:
1400 return FILEDLG95_OnWMCommand(hwnd, wParam);
1401 case WM_DRAWITEM:
1403 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1405 case IDC_LOOKIN:
1406 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1407 return TRUE;
1410 return FALSE;
1412 case WM_GETISHELLBROWSER:
1413 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1415 case WM_DESTROY:
1417 FileOpenDlgInfos * fodInfos = get_filedlg_infoptr(hwnd);
1418 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1419 HIMAGELIST himl;
1421 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1422 MemDialogSize = fodInfos->sizedlg;
1424 if (places_bar)
1426 himl = (HIMAGELIST)SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_GETIMAGELIST, 0, 0);
1427 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, 0);
1428 ImageList_Destroy(himl);
1430 return FALSE;
1433 case WM_NCDESTROY:
1434 RemovePropW(hwnd, filedlg_info_propnameW);
1435 return 0;
1437 case WM_NOTIFY:
1439 LPNMHDR lpnmh = (LPNMHDR)lParam;
1440 UINT stringId = -1;
1442 /* set up the button tooltips strings */
1443 if(TTN_GETDISPINFOA == lpnmh->code )
1445 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1446 switch(lpnmh->idFrom )
1448 /* Up folder button */
1449 case FCIDM_TB_UPFOLDER:
1450 stringId = IDS_UPFOLDER;
1451 break;
1452 /* New folder button */
1453 case FCIDM_TB_NEWFOLDER:
1454 stringId = IDS_NEWFOLDER;
1455 break;
1456 /* List option button */
1457 case FCIDM_TB_SMALLICON:
1458 stringId = IDS_LISTVIEW;
1459 break;
1460 /* Details option button */
1461 case FCIDM_TB_REPORTVIEW:
1462 stringId = IDS_REPORTVIEW;
1463 break;
1464 /* Desktop button */
1465 case FCIDM_TB_DESKTOP:
1466 stringId = IDS_TODESKTOP;
1467 break;
1468 default:
1469 stringId = 0;
1471 lpdi->hinst = COMDLG32_hInstance;
1472 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1474 return FALSE;
1476 default :
1477 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1478 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1479 return FALSE;
1483 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1485 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1486 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1489 /***********************************************************************
1490 * FILEDLG95_InitControls
1492 * WM_INITDIALOG message handler (before hook notification)
1494 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1496 BOOL win2000plus = FALSE;
1497 BOOL win98plus = FALSE;
1498 BOOL handledPath = FALSE;
1499 OSVERSIONINFOW osVi;
1500 static const WCHAR szwSlash[] = { '\\', 0 };
1501 static const WCHAR szwStar[] = { '*',0 };
1503 static const TBBUTTON tbb[] =
1505 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1506 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1507 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1508 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1509 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1510 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1511 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1512 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1513 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1515 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1517 RECT rectTB;
1518 RECT rectlook;
1520 HIMAGELIST toolbarImageList;
1521 ITEMIDLIST *desktopPidl;
1522 SHFILEINFOW fileinfo;
1524 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
1526 TRACE("%p\n", fodInfos);
1528 /* Get windows version emulating */
1529 osVi.dwOSVersionInfoSize = sizeof(osVi);
1530 GetVersionExW(&osVi);
1531 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1532 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1533 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1534 win2000plus = (osVi.dwMajorVersion > 4);
1535 if (win2000plus) win98plus = TRUE;
1537 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1540 /* Use either the edit or the comboboxex for the filename control */
1541 if (filename_is_edit( fodInfos ))
1543 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1544 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1546 else
1548 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1549 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1552 /* Get the hwnd of the controls */
1553 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1554 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1556 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1557 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1559 /* construct the toolbar */
1560 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1561 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1563 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1564 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1565 rectTB.left = rectlook.right;
1566 rectTB.top = rectlook.top-1;
1568 if (fodInfos->unicode)
1569 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1570 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1571 rectTB.left, rectTB.top,
1572 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1573 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1574 else
1575 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1576 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE,
1577 rectTB.left, rectTB.top,
1578 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1579 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1581 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1583 /* FIXME: use TB_LOADIMAGES when implemented */
1584 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1585 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1586 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1588 /* Retrieve and add desktop icon to the toolbar */
1589 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1590 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1591 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1592 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1593 ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1595 DestroyIcon(fileinfo.hIcon);
1596 CoTaskMemFree(desktopPidl);
1598 /* Finish Toolbar Construction */
1599 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1600 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1602 if (is_places_bar_enabled(fodInfos))
1604 TBBUTTON tb = { 0 };
1605 HIMAGELIST himl;
1606 RECT rect;
1607 int i, cx;
1609 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_BUTTONSTRUCTSIZE, 0, 0);
1610 GetClientRect(GetDlgItem(hwnd, IDC_TOOLBARPLACES), &rect);
1611 cx = rect.right - rect.left;
1613 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cx, cx));
1614 himl = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 4, 1);
1616 filedlg_collect_places_pidls(fodInfos);
1617 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1619 int index;
1621 if (!fodInfos->places[i])
1622 continue;
1624 memset(&fileinfo, 0, sizeof(fileinfo));
1625 SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1626 SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON);
1627 index = ImageList_AddIcon(himl, fileinfo.hIcon);
1629 tb.iBitmap = index;
1630 tb.iString = (INT_PTR)fileinfo.szDisplayName;
1631 tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1632 tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1633 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_ADDBUTTONSW, 1, (LPARAM)&tb);
1635 DestroyIcon(fileinfo.hIcon);
1638 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETIMAGELIST, 0, (LPARAM)himl);
1639 SendDlgItemMessageW(hwnd, IDC_TOOLBARPLACES, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cx * 3 / 4));
1642 /* Set the window text with the text specified in the OPENFILENAME structure */
1643 if(fodInfos->title)
1645 SetWindowTextW(hwnd,fodInfos->title);
1647 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1649 WCHAR buf[64];
1650 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, ARRAY_SIZE(buf));
1651 SetWindowTextW(hwnd, buf);
1654 /* Initialise the file name edit control */
1655 handledPath = FALSE;
1656 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1658 if(fodInfos->filename)
1660 /* 1. If win2000 or higher and filename contains a path, use it
1661 in preference over the lpstrInitialDir */
1662 if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, szwSlash)) {
1663 WCHAR tmpBuf[MAX_PATH];
1664 WCHAR *nameBit;
1665 DWORD result;
1667 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1668 if (result) {
1670 /* nameBit is always shorter than the original filename. It may be NULL
1671 * when the filename contains only a drive name instead of file name */
1672 if (nameBit)
1674 lstrcpyW(fodInfos->filename,nameBit);
1675 *nameBit = 0x00;
1677 else
1678 *fodInfos->filename = '\0';
1680 heap_free(fodInfos->initdir);
1681 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1682 lstrcpyW(fodInfos->initdir, tmpBuf);
1683 handledPath = TRUE;
1684 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1685 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1687 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1689 } else {
1690 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1694 /* 2. (All platforms) If initdir is not null, then use it */
1695 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1697 /* Work out the proper path as supplied one might be relative */
1698 /* (Here because supplying '.' as dir browses to My Computer) */
1699 WCHAR tmpBuf[MAX_PATH];
1700 WCHAR tmpBuf2[MAX_PATH];
1701 WCHAR *nameBit;
1702 DWORD result;
1704 lstrcpyW(tmpBuf, fodInfos->initdir);
1705 if (PathFileExistsW(tmpBuf)) {
1706 /* initdir does not have to be a directory. If a file is
1707 * specified, the dir part is taken */
1708 if (PathIsDirectoryW(tmpBuf)) {
1709 PathAddBackslashW(tmpBuf);
1710 lstrcatW(tmpBuf, szwStar);
1712 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1713 if (result) {
1714 *nameBit = 0x00;
1715 heap_free(fodInfos->initdir);
1716 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1717 lstrcpyW(fodInfos->initdir, tmpBuf2);
1718 handledPath = TRUE;
1719 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1722 else if (fodInfos->initdir)
1724 heap_free(fodInfos->initdir);
1725 fodInfos->initdir = NULL;
1726 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1730 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1732 /* 3. All except w2k+: if filename contains a path use it */
1733 if (!win2000plus && fodInfos->filename &&
1734 *fodInfos->filename &&
1735 wcspbrk(fodInfos->filename, szwSlash)) {
1736 WCHAR tmpBuf[MAX_PATH];
1737 WCHAR *nameBit;
1738 DWORD result;
1740 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1741 tmpBuf, &nameBit);
1742 if (result) {
1743 int len;
1745 /* nameBit is always shorter than the original filename */
1746 lstrcpyW(fodInfos->filename, nameBit);
1747 *nameBit = 0x00;
1749 len = lstrlenW(tmpBuf);
1750 heap_free(fodInfos->initdir);
1751 fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1752 lstrcpyW(fodInfos->initdir, tmpBuf);
1754 handledPath = TRUE;
1755 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1756 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1758 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1761 /* 4. Win2000+: Recently used */
1762 if (!handledPath && win2000plus) {
1763 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1764 fodInfos->initdir[0] = '\0';
1766 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1768 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1769 handledPath = TRUE;
1770 }else{
1771 heap_free(fodInfos->initdir);
1772 fodInfos->initdir = NULL;
1776 /* 5. win98+ and win2000+ if any files of specified filter types in
1777 current directory, use it */
1778 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1780 LPCWSTR lpstrPos = fodInfos->filter;
1781 WIN32_FIND_DATAW FindFileData;
1782 HANDLE hFind;
1784 while (1)
1786 /* filter is a list... title\0ext\0......\0\0 */
1788 /* Skip the title */
1789 if(! *lpstrPos) break; /* end */
1790 lpstrPos += lstrlenW(lpstrPos) + 1;
1792 /* See if any files exist in the current dir with this extension */
1793 if(! *lpstrPos) break; /* end */
1795 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1797 if (hFind == INVALID_HANDLE_VALUE) {
1798 /* None found - continue search */
1799 lpstrPos += lstrlenW(lpstrPos) + 1;
1801 } else {
1803 heap_free(fodInfos->initdir);
1804 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1805 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1807 handledPath = TRUE;
1808 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1809 debugstr_w(lpstrPos));
1810 FindClose(hFind);
1811 break;
1816 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1817 if (!handledPath && (win2000plus || win98plus)) {
1818 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1820 if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1822 if (SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir) == S_OK)
1824 /* last fallback */
1825 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1826 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1828 else
1829 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1831 else
1832 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1834 handledPath = TRUE;
1835 } else if (!handledPath) {
1836 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1837 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1838 handledPath = TRUE;
1839 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1842 SetFocus( fodInfos->DlgInfos.hwndFileName );
1843 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1845 /* Must the open as read only check box be checked ?*/
1846 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1848 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1851 /* Must the open as read only check box be hidden? */
1852 if (filedialog_is_readonly_hidden(fodInfos))
1854 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1855 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1858 /* Must the help button be hidden? */
1859 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1861 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1862 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1865 /* change Open to Save */
1866 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1868 WCHAR buf[16];
1869 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, ARRAY_SIZE(buf));
1870 SetDlgItemTextW(hwnd, IDOK, buf);
1871 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, ARRAY_SIZE(buf));
1872 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1875 /* Initialize the filter combo box */
1876 FILEDLG95_FILETYPE_Init(hwnd);
1878 return 0;
1881 /***********************************************************************
1882 * FILEDLG95_ResizeControls
1884 * WM_INITDIALOG message handler (after hook notification)
1886 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1888 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1890 if (fodInfos->DlgInfos.hwndCustomDlg)
1892 RECT rc;
1893 UINT flags = SWP_NOACTIVATE;
1895 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1896 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1898 /* resize the custom dialog to the parent size */
1899 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1900 GetClientRect(hwnd, &rc);
1901 else
1903 /* our own fake template is zero sized and doesn't have children, so
1904 * there is no need to resize it. Picasa depends on it.
1906 flags |= SWP_NOSIZE;
1907 SetRectEmpty(&rc);
1909 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1910 0, 0, rc.right, rc.bottom, flags);
1912 else
1914 /* Resize the height; if opened as read-only, checkbox and help button are
1915 * hidden and we are not using a custom template nor a customDialog
1917 if (filedialog_is_readonly_hidden(fodInfos) &&
1918 (!(fodInfos->ofnInfos->Flags &
1919 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1921 RECT rectDlg, rectHelp, rectCancel;
1922 GetWindowRect(hwnd, &rectDlg);
1923 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1924 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1925 /* subtract the height of the help button plus the space between the help
1926 * button and the cancel button to the height of the dialog
1928 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1929 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1930 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1933 return TRUE;
1936 /***********************************************************************
1937 * FILEDLG95_FillControls
1939 * WM_INITDIALOG message handler (after hook notification)
1941 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1943 LPITEMIDLIST pidlItemId = NULL;
1945 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1947 TRACE("dir=%s file=%s\n",
1948 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1950 /* Get the initial directory pidl */
1952 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1954 WCHAR path[MAX_PATH];
1956 GetCurrentDirectoryW(MAX_PATH,path);
1957 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1960 /* Initialise shell objects */
1961 FILEDLG95_SHELL_Init(hwnd);
1963 /* Initialize the Look In combo box */
1964 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1966 /* Browse to the initial directory */
1967 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1969 ILFree(pidlItemId);
1971 return TRUE;
1973 /***********************************************************************
1974 * FILEDLG95_Clean
1976 * Regroups all the cleaning functions of the filedlg
1978 void FILEDLG95_Clean(HWND hwnd)
1980 FILEDLG95_FILETYPE_Clean(hwnd);
1981 FILEDLG95_LOOKIN_Clean(hwnd);
1982 FILEDLG95_SHELL_Clean(hwnd);
1986 /***********************************************************************
1987 * Browse to arbitrary pidl
1989 static void filedlg_browse_to_pidl(const FileOpenDlgInfos *info, LPITEMIDLIST pidl)
1991 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
1993 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
1994 if (info->ofnInfos->Flags & OFN_EXPLORER)
1995 SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
1998 /***********************************************************************
1999 * FILEDLG95_OnWMCommand
2001 * WM_COMMAND message handler
2003 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
2005 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2006 WORD wNotifyCode = HIWORD(wParam); /* notification code */
2007 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
2009 switch (id)
2011 /* OK button */
2012 case IDOK:
2013 FILEDLG95_OnOpen(hwnd);
2014 break;
2015 /* Cancel button */
2016 case IDCANCEL:
2017 FILEDLG95_Clean(hwnd);
2018 EndDialog(hwnd, FALSE);
2019 break;
2020 /* Filetype combo box */
2021 case IDC_FILETYPE:
2022 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2023 break;
2024 /* LookIn combo box */
2025 case IDC_LOOKIN:
2026 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2027 break;
2029 /* --- toolbar --- */
2030 /* Up folder button */
2031 case FCIDM_TB_UPFOLDER:
2032 FILEDLG95_SHELL_UpFolder(hwnd);
2033 break;
2034 /* New folder button */
2035 case FCIDM_TB_NEWFOLDER:
2036 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2037 break;
2038 /* List option button */
2039 case FCIDM_TB_SMALLICON:
2040 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2041 break;
2042 /* Details option button */
2043 case FCIDM_TB_REPORTVIEW:
2044 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2045 break;
2047 case FCIDM_TB_DESKTOP:
2049 LPITEMIDLIST pidl;
2051 SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidl);
2052 filedlg_browse_to_pidl(fodInfos, pidl);
2053 ILFree(pidl);
2054 break;
2057 /* Places bar */
2058 case TBPLACES_CMDID_PLACE0:
2059 case TBPLACES_CMDID_PLACE1:
2060 case TBPLACES_CMDID_PLACE2:
2061 case TBPLACES_CMDID_PLACE3:
2062 case TBPLACES_CMDID_PLACE4:
2063 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2064 break;
2066 case edt1:
2067 case cmb13:
2068 break;
2071 /* Do not use the listview selection anymore */
2072 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2073 return 0;
2076 /***********************************************************************
2077 * FILEDLG95_OnWMGetIShellBrowser
2079 * WM_GETISHELLBROWSER message handler
2081 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
2083 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2085 TRACE("\n");
2087 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2089 return TRUE;
2093 /***********************************************************************
2094 * FILEDLG95_SendFileOK
2096 * Sends the CDN_FILEOK notification if required
2098 * RETURNS
2099 * TRUE if the dialog should close
2100 * FALSE if the dialog should not be closed
2102 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
2104 /* ask the hook if we can close */
2105 if (is_dialog_hooked(fodInfos))
2107 LRESULT retval = 0;
2109 TRACE("---\n");
2110 /* First send CDN_FILEOK as MSDN doc says */
2111 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2112 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
2113 if( retval)
2115 TRACE("canceled\n");
2116 return FALSE;
2119 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2120 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2121 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2122 if( retval)
2124 TRACE("canceled\n");
2125 return FALSE;
2128 return TRUE;
2131 /***********************************************************************
2132 * FILEDLG95_OnOpenMultipleFiles
2134 * Handles the opening of multiple files.
2136 * FIXME
2137 * check destination buffer size
2139 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2141 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2142 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2143 UINT nCount, nSizePath;
2145 TRACE("\n");
2147 if(fodInfos->unicode)
2149 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2150 ofn->lpstrFile[0] = '\0';
2152 else
2154 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2155 ofn->lpstrFile[0] = '\0';
2158 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2160 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2161 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2162 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2164 LPWSTR lpstrTemp = lpstrFileList;
2166 for ( nCount = 0; nCount < nFileCount; nCount++ )
2168 LPITEMIDLIST pidl;
2170 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2171 if (!pidl)
2173 WCHAR lpstrNotFound[100];
2174 WCHAR lpstrMsg[100];
2175 WCHAR tmp[400];
2176 static const WCHAR nl[] = {'\n',0};
2178 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2179 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2181 lstrcpyW(tmp, lpstrTemp);
2182 lstrcatW(tmp, nl);
2183 lstrcatW(tmp, lpstrNotFound);
2184 lstrcatW(tmp, nl);
2185 lstrcatW(tmp, lpstrMsg);
2187 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2188 return FALSE;
2191 /* move to the next file in the list of files */
2192 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2193 ILFree(pidl);
2197 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2198 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2200 /* For "oldstyle" dialog the components have to
2201 be separated by blanks (not '\0'!) and short
2202 filenames have to be used! */
2203 FIXME("Components have to be separated by blanks\n");
2205 if(fodInfos->unicode)
2207 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2208 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2209 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2211 else
2213 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2215 if (ofn->lpstrFile != NULL)
2217 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2218 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2219 if (ofn->nMaxFile > nSizePath)
2221 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2222 ofn->lpstrFile + nSizePath,
2223 ofn->nMaxFile - nSizePath, NULL, NULL);
2228 fodInfos->ofnInfos->nFileOffset = nSizePath;
2229 fodInfos->ofnInfos->nFileExtension = 0;
2231 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2232 return FALSE;
2234 /* clean and exit */
2235 FILEDLG95_Clean(hwnd);
2236 return EndDialog(hwnd,TRUE);
2239 /* Returns the 'slot name' of the given module_name in the registry's
2240 * most-recently-used list. This will be an ASCII value in the
2241 * range ['a','z'). Returns zero on error.
2243 * The slot's value in the registry has the form:
2244 * module_name\0mru_path\0
2246 * If stored_path is given, then stored_path will contain the path name
2247 * stored in the registry's MRU list for the given module_name.
2249 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2250 * MRU list key for the given module_name.
2252 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2254 WCHAR mru_list[32], *cur_mru_slot;
2255 BOOL taken[25] = {0};
2256 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2257 HKEY hkey_tmp, *hkey;
2258 LONG ret;
2260 if(hkey_ret)
2261 hkey = hkey_ret;
2262 else
2263 hkey = &hkey_tmp;
2265 if(stored_path)
2266 *stored_path = '\0';
2268 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2269 if(ret){
2270 WARN("Unable to create MRU key: %d\n", ret);
2271 return 0;
2274 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2275 (LPBYTE)mru_list, &mru_list_size);
2276 if(ret || key_type != REG_SZ){
2277 if(ret == ERROR_FILE_NOT_FOUND)
2278 return 'a';
2280 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2281 RegCloseKey(*hkey);
2282 return 0;
2285 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2286 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2287 DWORD value_data_size = sizeof(value_data);
2289 *value_name = *cur_mru_slot;
2291 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2292 &key_type, (LPBYTE)value_data, &value_data_size);
2293 if(ret || key_type != REG_BINARY){
2294 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2295 continue;
2298 if(!wcsicmp(module_name, value_data)){
2299 if(!hkey_ret)
2300 RegCloseKey(*hkey);
2301 if(stored_path)
2302 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2303 return *value_name;
2307 if(!hkey_ret)
2308 RegCloseKey(*hkey);
2310 /* the module name isn't in the registry, so find the next open slot */
2311 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2312 taken[*cur_mru_slot - 'a'] = TRUE;
2313 for(i = 0; i < 25; ++i){
2314 if(!taken[i])
2315 return i + 'a';
2318 /* all slots are taken, so return the last one in MRUList */
2319 --cur_mru_slot;
2320 return *cur_mru_slot;
2323 /* save the given filename as most-recently-used path for this module */
2324 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2326 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2327 LONG ret;
2328 HKEY hkey;
2330 /* get the current executable's name */
2331 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2333 WARN("GotModuleFileName failed: %d\n", GetLastError());
2334 return;
2336 module_name = wcsrchr(module_path, '\\');
2337 if(!module_name)
2338 module_name = module_path;
2339 else
2340 module_name += 1;
2342 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2343 if(!slot)
2344 return;
2345 *slot_name = slot;
2347 { /* update the slot's info */
2348 WCHAR *path_ends, *final;
2349 DWORD path_len, final_len;
2351 /* use only the path segment of `filename' */
2352 path_ends = wcsrchr(filename, '\\');
2353 path_len = path_ends - filename;
2355 final_len = path_len + lstrlenW(module_name) + 2;
2357 final = heap_alloc(final_len * sizeof(WCHAR));
2358 if(!final)
2359 return;
2360 lstrcpyW(final, module_name);
2361 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2362 final[final_len-1] = '\0';
2364 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2365 final_len * sizeof(WCHAR));
2366 if(ret){
2367 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2368 heap_free(final);
2369 RegCloseKey(hkey);
2370 return;
2373 heap_free(final);
2376 { /* update MRUList value */
2377 WCHAR old_mru_list[32], new_mru_list[32];
2378 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2379 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2381 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2382 (LPBYTE)old_mru_list, &mru_list_size);
2383 if(ret || key_type != REG_SZ){
2384 if(ret == ERROR_FILE_NOT_FOUND){
2385 new_mru_list[0] = slot;
2386 new_mru_list[1] = '\0';
2387 }else{
2388 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2389 RegCloseKey(hkey);
2390 return;
2392 }else{
2393 /* copy old list data over so that the new slot is at the start
2394 * of the list */
2395 *new_mru_slot++ = slot;
2396 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2397 if(*old_mru_slot != slot)
2398 *new_mru_slot++ = *old_mru_slot;
2400 *new_mru_slot = '\0';
2403 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2404 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2405 if(ret){
2406 WARN("Error saving MRUList data: %d\n", ret);
2407 RegCloseKey(hkey);
2408 return;
2413 /* load the most-recently-used path for this module */
2414 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2416 WCHAR module_path[MAX_PATH], *module_name;
2418 /* get the current executable's name */
2419 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2421 WARN("GotModuleFileName failed: %d\n", GetLastError());
2422 return;
2424 module_name = wcsrchr(module_path, '\\');
2425 if(!module_name)
2426 module_name = module_path;
2427 else
2428 module_name += 1;
2430 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2431 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2434 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2436 WCHAR strMsgTitle[MAX_PATH];
2437 WCHAR strMsgText [MAX_PATH];
2438 if (idCaption)
2439 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2440 else
2441 strMsgTitle[0] = '\0';
2442 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2443 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2446 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2447 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2449 int nOpenAction = defAction;
2450 LPWSTR lpszTemp, lpszTemp1;
2451 LPITEMIDLIST pidl = NULL;
2452 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2454 /* check for invalid chars */
2455 if((wcspbrk(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2457 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2458 return FALSE;
2461 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2463 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2464 while (lpszTemp1)
2466 LPSHELLFOLDER lpsfChild;
2467 WCHAR lpwstrTemp[MAX_PATH];
2468 DWORD dwEaten, dwAttributes;
2469 LPWSTR p;
2471 lstrcpyW(lpwstrTemp, lpszTemp);
2472 p = PathFindNextComponentW(lpwstrTemp);
2474 if (!p) break; /* end of path */
2476 *p = 0;
2477 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2479 /* There are no wildcards when OFN_NOVALIDATE is set */
2480 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2482 static const WCHAR wszWild[] = { '*', '?', 0 };
2483 /* if the last element is a wildcard do a search */
2484 if(wcspbrk(lpszTemp1, wszWild) != NULL)
2486 nOpenAction = ONOPEN_SEARCH;
2487 break;
2490 lpszTemp1 = lpszTemp;
2492 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2494 /* append a backslash to drive letters */
2495 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2496 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2497 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2499 PathAddBackslashW(lpwstrTemp);
2502 dwAttributes = SFGAO_FOLDER;
2503 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2505 /* the path component is valid, we have a pidl of the next path component */
2506 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2507 if(dwAttributes & SFGAO_FOLDER)
2509 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2511 ERR("bind to failed\n"); /* should not fail */
2512 break;
2514 IShellFolder_Release(*ppsf);
2515 *ppsf = lpsfChild;
2516 lpsfChild = NULL;
2518 else
2520 TRACE("value\n");
2522 /* end dialog, return value */
2523 nOpenAction = ONOPEN_OPEN;
2524 break;
2526 ILFree(pidl);
2527 pidl = NULL;
2529 else if (!(flags & OFN_NOVALIDATE))
2531 if(*lpszTemp || /* points to trailing null for last path element */
2532 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2534 if(flags & OFN_PATHMUSTEXIST)
2536 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2537 break;
2540 else
2542 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2544 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2545 break;
2548 /* change to the current folder */
2549 nOpenAction = ONOPEN_OPEN;
2550 break;
2552 else
2554 nOpenAction = ONOPEN_OPEN;
2555 break;
2558 ILFree(pidl);
2560 return nOpenAction;
2563 /***********************************************************************
2564 * FILEDLG95_OnOpen
2566 * Ok button WM_COMMAND message handler
2568 * If the function succeeds, the return value is nonzero.
2570 BOOL FILEDLG95_OnOpen(HWND hwnd)
2572 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2573 LPWSTR lpstrFileList;
2574 UINT nFileCount = 0;
2575 UINT sizeUsed = 0;
2576 BOOL ret = TRUE;
2577 WCHAR lpstrPathAndFile[MAX_PATH];
2578 LPSHELLFOLDER lpsf = NULL;
2579 int nOpenAction;
2581 TRACE("hwnd=%p\n", hwnd);
2583 /* try to browse the selected item */
2584 if(BrowseSelectedFolder(hwnd))
2585 return FALSE;
2587 /* get the files from the edit control */
2588 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2590 if(nFileCount == 0)
2591 return FALSE;
2593 if(nFileCount > 1)
2595 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2596 goto ret;
2599 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2602 Step 1: Build a complete path name from the current folder and
2603 the filename or path in the edit box.
2604 Special cases:
2605 - the path in the edit box is a root path
2606 (with or without drive letter)
2607 - the edit box contains ".." (or a path with ".." in it)
2610 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2611 heap_free(lpstrFileList);
2614 Step 2: here we have a cleaned up path
2616 We have to parse the path step by step to see if we have to browse
2617 to a folder if the path points to a directory or the last
2618 valid element is a directory.
2620 valid variables:
2621 lpstrPathAndFile: cleaned up path
2624 if (nFileCount &&
2625 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2626 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2627 nOpenAction = ONOPEN_OPEN;
2628 else
2629 nOpenAction = ONOPEN_BROWSE;
2631 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2632 fodInfos->ofnInfos->Flags,
2633 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2634 nOpenAction);
2635 if(!nOpenAction)
2636 goto ret;
2639 Step 3: here we have a cleaned up and validated path
2641 valid variables:
2642 lpsf: ShellFolder bound to the rightmost valid path component
2643 lpstrPathAndFile: cleaned up path
2644 nOpenAction: action to do
2646 TRACE("end validate sf=%p\n", lpsf);
2648 switch(nOpenAction)
2650 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2651 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2653 int iPos;
2654 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2655 DWORD len;
2657 /* replace the current filter */
2658 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2659 len = lstrlenW(lpszTemp)+1;
2660 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2661 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2663 /* set the filter cb to the extension when possible */
2664 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2665 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2667 /* fall through */
2668 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2669 TRACE("ONOPEN_BROWSE\n");
2671 IPersistFolder2 * ppf2;
2672 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2674 LPITEMIDLIST pidlCurrent;
2675 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2676 IPersistFolder2_Release(ppf2);
2677 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2679 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2680 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2682 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2683 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2686 else if( nOpenAction == ONOPEN_SEARCH )
2688 if (fodInfos->Shell.FOIShellView)
2689 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2691 ILFree(pidlCurrent);
2692 if (filename_is_edit( fodInfos ))
2693 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2694 else
2696 HWND hwnd;
2698 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2699 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2703 ret = FALSE;
2704 break;
2705 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2706 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2708 WCHAR *ext = NULL;
2710 /* update READONLY check box flag */
2711 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2712 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2713 else
2714 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2716 /* Attach the file extension with file name*/
2717 ext = PathFindExtensionW(lpstrPathAndFile);
2718 if (! *ext && fodInfos->defext)
2720 /* if no extension is specified with file name, then */
2721 /* attach the extension from file filter or default one */
2723 WCHAR *filterExt = NULL;
2724 LPWSTR lpstrFilter = NULL;
2725 static const WCHAR szwDot[] = {'.',0};
2726 int PathLength = lstrlenW(lpstrPathAndFile);
2728 /*Get the file extension from file type filter*/
2729 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2730 fodInfos->ofnInfos->nFilterIndex-1);
2732 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2734 WCHAR* filterSearchIndex;
2735 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2736 lstrcpyW(filterExt, lpstrFilter);
2738 /* if a semicolon-separated list of file extensions was given, do not include the
2739 semicolon or anything after it in the extension.
2740 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2741 filterSearchIndex = wcschr(filterExt, ';');
2742 if (filterSearchIndex)
2744 filterSearchIndex[0] = '\0';
2747 /* find the file extension by searching for the first dot in filterExt */
2748 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2749 /* if the extension is invalid or contains a glob, ignore it */
2750 filterSearchIndex = wcschr(filterExt, '.');
2751 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
2753 lstrcpyW(filterExt, filterSearchIndex);
2755 else
2757 heap_free(filterExt);
2758 filterExt = NULL;
2762 if (!filterExt)
2764 /* use the default file extension */
2765 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2766 lstrcpyW(filterExt, fodInfos->defext);
2769 if (*filterExt) /* ignore filterExt="" */
2771 /* Attach the dot*/
2772 lstrcatW(lpstrPathAndFile, szwDot);
2773 /* Attach the extension */
2774 lstrcatW(lpstrPathAndFile, filterExt);
2777 heap_free(filterExt);
2779 /* In Open dialog: if file does not exist try without extension */
2780 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2781 lpstrPathAndFile[PathLength] = '\0';
2783 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2784 if (*ext)
2785 ext++;
2786 if (!lstrcmpiW(fodInfos->defext, ext))
2787 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2788 else
2789 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2792 /* In Save dialog: check if the file already exists */
2793 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2794 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2795 && PathFileExistsW(lpstrPathAndFile))
2797 WCHAR lpstrOverwrite[100];
2798 int answer;
2800 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2801 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2802 MB_YESNO | MB_ICONEXCLAMATION);
2803 if (answer == IDNO || answer == IDCANCEL)
2805 ret = FALSE;
2806 goto ret;
2810 /* In Open dialog: check if it should be created if it doesn't exist */
2811 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2812 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2813 && !PathFileExistsW(lpstrPathAndFile))
2815 WCHAR lpstrCreate[100];
2816 int answer;
2818 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2819 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2820 MB_YESNO | MB_ICONEXCLAMATION);
2821 if (answer == IDNO || answer == IDCANCEL)
2823 ret = FALSE;
2824 goto ret;
2828 /* Check that the size of the file does not exceed buffer size.
2829 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2830 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2831 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2834 /* fill destination buffer */
2835 if (fodInfos->ofnInfos->lpstrFile)
2837 if(fodInfos->unicode)
2839 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2841 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2842 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2843 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2845 else
2847 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2849 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2850 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2851 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2852 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2856 if(fodInfos->unicode)
2858 LPWSTR lpszTemp;
2860 /* set filename offset */
2861 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2862 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2864 /* set extension offset */
2865 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2866 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2868 else
2870 LPSTR lpszTemp;
2871 CHAR tempFileA[MAX_PATH];
2873 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2874 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2875 tempFileA, sizeof(tempFileA), NULL, NULL);
2877 /* set filename offset */
2878 lpszTemp = PathFindFileNameA(tempFileA);
2879 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2881 /* set extension offset */
2882 lpszTemp = PathFindExtensionA(tempFileA);
2883 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2886 /* set the lpstrFileTitle */
2887 if(fodInfos->ofnInfos->lpstrFileTitle)
2889 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2890 if(fodInfos->unicode)
2892 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2893 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2895 else
2897 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2898 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2899 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2903 /* copy currently selected filter to lpstrCustomFilter */
2904 if (fodInfos->ofnInfos->lpstrCustomFilter)
2906 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2907 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2908 NULL, 0, NULL, NULL);
2909 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2911 LPSTR s = ofn->lpstrCustomFilter;
2912 s += strlen(ofn->lpstrCustomFilter)+1;
2913 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2914 s, len, NULL, NULL);
2919 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2920 goto ret;
2922 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2924 TRACE("close\n");
2925 FILEDLG95_Clean(hwnd);
2926 ret = EndDialog(hwnd, TRUE);
2928 else
2930 WORD size;
2932 size = lstrlenW(lpstrPathAndFile) + 1;
2933 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2934 size += 1;
2935 /* return needed size in first two bytes of lpstrFile */
2936 if(fodInfos->ofnInfos->lpstrFile)
2937 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2938 FILEDLG95_Clean(hwnd);
2939 ret = EndDialog(hwnd, FALSE);
2940 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2943 break;
2946 ret:
2947 if(lpsf) IShellFolder_Release(lpsf);
2948 return ret;
2951 /***********************************************************************
2952 * FILEDLG95_SHELL_Init
2954 * Initialisation of the shell objects
2956 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2958 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2960 TRACE("%p\n", hwnd);
2963 * Initialisation of the FileOpenDialogInfos structure
2966 /* Shell */
2968 /*ShellInfos */
2969 fodInfos->ShellInfos.hwndOwner = hwnd;
2971 /* Disable multi-select if flag not set */
2972 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2974 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2976 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2977 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2979 /* Construct the IShellBrowser interface */
2980 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2982 return NOERROR;
2985 /***********************************************************************
2986 * FILEDLG95_SHELL_ExecuteCommand
2988 * Change the folder option and refresh the view
2989 * If the function succeeds, the return value is nonzero.
2991 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2993 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
2994 IContextMenu * pcm;
2996 TRACE("(%p,%p)\n", hwnd, lpVerb);
2998 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2999 SVGIO_BACKGROUND,
3000 &IID_IContextMenu,
3001 (LPVOID*)&pcm)))
3003 CMINVOKECOMMANDINFO ci;
3004 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
3005 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
3006 ci.lpVerb = lpVerb;
3007 ci.hwnd = hwnd;
3009 IContextMenu_InvokeCommand(pcm, &ci);
3010 IContextMenu_Release(pcm);
3013 return FALSE;
3016 /***********************************************************************
3017 * FILEDLG95_SHELL_UpFolder
3019 * Browse to the specified object
3020 * If the function succeeds, the return value is nonzero.
3022 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
3024 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3026 TRACE("\n");
3028 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3029 NULL,
3030 SBSP_PARENT)))
3032 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3033 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3034 return TRUE;
3036 return FALSE;
3038 /***********************************************************************
3039 * FILEDLG95_SHELL_Clean
3041 * Cleans the memory used by shell objects
3043 static void FILEDLG95_SHELL_Clean(HWND hwnd)
3045 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3047 TRACE("\n");
3049 ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3051 /* clean Shell interfaces */
3052 if (fodInfos->Shell.FOIShellView)
3054 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3055 IShellView_Release(fodInfos->Shell.FOIShellView);
3057 if (fodInfos->Shell.FOIShellFolder)
3058 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3059 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3060 if (fodInfos->Shell.FOIDataObject)
3061 IDataObject_Release(fodInfos->Shell.FOIDataObject);
3064 /***********************************************************************
3065 * FILEDLG95_FILETYPE_Init
3067 * Initialisation of the file type combo box
3069 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
3071 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3072 int nFilters = 0; /* number of filters */
3073 int nFilterIndexCB;
3075 TRACE("%p\n", hwnd);
3077 if(fodInfos->customfilter)
3079 /* customfilter has one entry... title\0ext\0
3080 * Set first entry of combo box item with customfilter
3082 LPWSTR lpstrExt;
3083 LPCWSTR lpstrPos = fodInfos->customfilter;
3085 /* Get the title */
3086 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3088 /* Copy the extensions */
3089 if (! *lpstrPos) return E_FAIL; /* malformed filter */
3090 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3091 lstrcpyW(lpstrExt,lpstrPos);
3093 /* Add the item at the end of the combo */
3094 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3095 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3097 nFilters++;
3099 if(fodInfos->filter)
3101 LPCWSTR lpstrPos = fodInfos->filter;
3103 for(;;)
3105 /* filter is a list... title\0ext\0......\0\0
3106 * Set the combo item text to the title and the item data
3107 * to the ext
3109 LPCWSTR lpstrDisplay;
3110 LPWSTR lpstrExt;
3112 /* Get the title */
3113 if(! *lpstrPos) break; /* end */
3114 lpstrDisplay = lpstrPos;
3115 lpstrPos += lstrlenW(lpstrPos) + 1;
3117 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3119 nFilters++;
3121 /* Copy the extensions */
3122 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3123 lstrcpyW(lpstrExt,lpstrPos);
3124 lpstrPos += lstrlenW(lpstrPos) + 1;
3126 /* Add the item at the end of the combo */
3127 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3129 /* malformed filters are added anyway... */
3130 if (!*lpstrExt) break;
3135 * Set the current filter to the one specified
3136 * in the initialisation structure
3138 if (fodInfos->filter || fodInfos->customfilter)
3140 LPWSTR lpstrFilter;
3142 /* Check to make sure our index isn't out of bounds. */
3143 if ( fodInfos->ofnInfos->nFilterIndex >
3144 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3145 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3147 /* set default filter index */
3148 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3149 fodInfos->ofnInfos->nFilterIndex = 1;
3151 /* calculate index of Combo Box item */
3152 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3153 if (fodInfos->customfilter == NULL)
3154 nFilterIndexCB--;
3156 /* Set the current index selection. */
3157 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3159 /* Get the corresponding text string from the combo box. */
3160 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3161 nFilterIndexCB);
3163 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3164 lpstrFilter = NULL;
3166 if(lpstrFilter)
3168 DWORD len;
3169 CharLowerW(lpstrFilter); /* lowercase */
3170 len = lstrlenW(lpstrFilter)+1;
3171 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3172 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3174 } else
3175 fodInfos->ofnInfos->nFilterIndex = 0;
3176 return S_OK;
3179 /***********************************************************************
3180 * FILEDLG95_FILETYPE_OnCommand
3182 * WM_COMMAND of the file type combo box
3183 * If the function succeeds, the return value is nonzero.
3185 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3187 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3189 switch(wNotifyCode)
3191 case CBN_SELENDOK:
3193 LPWSTR lpstrFilter;
3195 /* Get the current item of the filetype combo box */
3196 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3198 /* set the current filter index */
3199 fodInfos->ofnInfos->nFilterIndex = iItem +
3200 (fodInfos->customfilter == NULL ? 1 : 0);
3202 /* Set the current filter with the current selection */
3203 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3205 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3206 iItem);
3207 if((INT_PTR)lpstrFilter != CB_ERR)
3209 DWORD len;
3210 CharLowerW(lpstrFilter); /* lowercase */
3211 len = lstrlenW(lpstrFilter)+1;
3212 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3213 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3214 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3215 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3218 /* Refresh the actual view to display the included items*/
3219 if (fodInfos->Shell.FOIShellView)
3220 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3223 return FALSE;
3225 /***********************************************************************
3226 * FILEDLG95_FILETYPE_SearchExt
3228 * searches for an extension in the filetype box
3230 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3232 int i, iCount;
3234 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3236 TRACE("%s\n", debugstr_w(lpstrExt));
3238 if(iCount != CB_ERR)
3240 for(i=0;i<iCount;i++)
3242 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3243 return i;
3246 return -1;
3249 /***********************************************************************
3250 * FILEDLG95_FILETYPE_Clean
3252 * Clean the memory used by the filetype combo box
3254 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3256 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3257 int iPos;
3258 int iCount;
3260 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3262 TRACE("\n");
3264 /* Delete each string of the combo and their associated data */
3265 if(iCount != CB_ERR)
3267 for(iPos = iCount-1;iPos>=0;iPos--)
3269 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3270 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3273 /* Current filter */
3274 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3277 /***********************************************************************
3278 * FILEDLG95_LOOKIN_Init
3280 * Initialisation of the look in combo box
3283 /* Small helper function, to determine if the unixfs shell extension is rooted
3284 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3286 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3287 HKEY hKey;
3288 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3289 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3290 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3291 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3292 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3293 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3294 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3296 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3297 return FALSE;
3299 RegCloseKey(hKey);
3300 return TRUE;
3303 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3305 IShellFolder *psfRoot, *psfDrives;
3306 IEnumIDList *lpeRoot, *lpeDrives;
3307 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3308 HDC hdc;
3309 TEXTMETRICW tm;
3310 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3312 TRACE("%p\n", hwndCombo);
3314 liInfos->iMaxIndentation = 0;
3316 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3318 hdc = GetDC( hwndCombo );
3319 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3320 GetTextMetricsW( hdc, &tm );
3321 ReleaseDC( hwndCombo, hdc );
3323 /* set item height for both text field and listbox */
3324 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3325 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3327 /* Turn on the extended UI for the combo box like Windows does */
3328 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3330 /* Initialise data of Desktop folder */
3331 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3332 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3333 ILFree(pidlTmp);
3335 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3337 SHGetDesktopFolder(&psfRoot);
3339 if (psfRoot)
3341 /* enumerate the contents of the desktop */
3342 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3344 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3346 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3348 /* If the unixfs extension is rooted, we don't expand the drives by default */
3349 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3351 /* special handling for CSIDL_DRIVES */
3352 if (ILIsEqual(pidlTmp, pidlDrives))
3354 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3356 /* enumerate the drives */
3357 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3359 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3361 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3362 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3363 ILFree(pidlAbsTmp);
3364 ILFree(pidlTmp1);
3366 IEnumIDList_Release(lpeDrives);
3368 IShellFolder_Release(psfDrives);
3373 ILFree(pidlTmp);
3375 IEnumIDList_Release(lpeRoot);
3377 IShellFolder_Release(psfRoot);
3380 ILFree(pidlDrives);
3383 /***********************************************************************
3384 * FILEDLG95_LOOKIN_DrawItem
3386 * WM_DRAWITEM message handler
3388 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3390 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3391 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3392 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3393 RECT rectText;
3394 RECT rectIcon;
3395 SHFILEINFOW sfi;
3396 HIMAGELIST ilItemImage;
3397 int iIndentation;
3398 TEXTMETRICW tm;
3399 LPSFOLDER tmpFolder;
3400 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3401 UINT icon_width, icon_height;
3403 TRACE("\n");
3405 if(pDIStruct->itemID == -1)
3406 return 0;
3408 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3409 pDIStruct->itemID)))
3410 return 0;
3413 icon_width = GetSystemMetrics(SM_CXICON);
3414 icon_height = GetSystemMetrics(SM_CYICON);
3415 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3417 icon_width = GetSystemMetrics(SM_CXSMICON);
3418 icon_height = GetSystemMetrics(SM_CYSMICON);
3419 shgfi_flags |= SHGFI_SMALLICON;
3422 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3423 0, &sfi, sizeof (sfi), shgfi_flags );
3425 /* Is this item selected ? */
3426 if(pDIStruct->itemState & ODS_SELECTED)
3428 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3429 SetBkColor(pDIStruct->hDC,crHighLight);
3430 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3432 else
3434 SetTextColor(pDIStruct->hDC,crText);
3435 SetBkColor(pDIStruct->hDC,crWin);
3436 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3439 /* Do not indent item if drawing in the edit of the combo */
3440 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3441 iIndentation = 0;
3442 else
3443 iIndentation = tmpFolder->m_iIndent;
3445 /* Draw text and icon */
3447 /* Initialise the icon display area */
3448 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3449 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3450 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3451 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3453 /* Initialise the text display area */
3454 GetTextMetricsW(pDIStruct->hDC, &tm);
3455 rectText.left = rectIcon.right;
3456 rectText.top =
3457 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3458 rectText.right = pDIStruct->rcItem.right;
3459 rectText.bottom =
3460 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3462 /* Draw the icon from the image list */
3463 ImageList_Draw(ilItemImage,
3464 sfi.iIcon,
3465 pDIStruct->hDC,
3466 rectIcon.left,
3467 rectIcon.top,
3468 ILD_TRANSPARENT );
3470 /* Draw the associated text */
3471 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3472 return NOERROR;
3475 /***********************************************************************
3476 * FILEDLG95_LOOKIN_OnCommand
3478 * LookIn combo box WM_COMMAND message handler
3479 * If the function succeeds, the return value is nonzero.
3481 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3483 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3485 TRACE("%p\n", fodInfos);
3487 switch(wNotifyCode)
3489 case CBN_SELENDOK:
3491 LPSFOLDER tmpFolder;
3492 int iItem;
3494 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3496 if( iItem == CB_ERR) return FALSE;
3498 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3499 iItem)))
3500 return FALSE;
3503 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3504 tmpFolder->pidlItem,
3505 SBSP_ABSOLUTE)))
3507 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3508 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3509 return TRUE;
3511 break;
3515 return FALSE;
3518 /***********************************************************************
3519 * FILEDLG95_LOOKIN_AddItem
3521 * Adds an absolute pidl item to the lookin combo box
3522 * returns the index of the inserted item
3524 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3526 LPITEMIDLIST pidlNext;
3527 SHFILEINFOW sfi;
3528 SFOLDER *tmpFolder;
3529 LookInInfos *liInfos;
3531 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3533 if(!pidl)
3534 return -1;
3536 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3537 return -1;
3539 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3540 tmpFolder->m_iIndent = 0;
3542 /* Calculate the indentation of the item in the lookin*/
3543 pidlNext = pidl;
3544 while ((pidlNext = ILGetNext(pidlNext)))
3546 tmpFolder->m_iIndent++;
3549 tmpFolder->pidlItem = ILClone(pidl);
3551 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3552 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3554 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3555 SHGetFileInfoW((LPCWSTR)pidl,
3557 &sfi,
3558 sizeof(sfi),
3559 SHGFI_DISPLAYNAME | SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3561 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3563 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3565 int iItemID;
3567 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3569 /* Add the item at the end of the list */
3570 if(iInsertId < 0)
3572 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3574 /* Insert the item at the iInsertId position*/
3575 else
3577 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3580 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3581 return iItemID;
3584 ILFree( tmpFolder->pidlItem );
3585 heap_free( tmpFolder );
3586 return -1;
3590 /***********************************************************************
3591 * FILEDLG95_LOOKIN_InsertItemAfterParent
3593 * Insert an item below its parent
3595 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3598 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3599 int iParentPos;
3601 TRACE("\n");
3603 if (pidl == pidlParent)
3604 return -1;
3606 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3608 if(iParentPos < 0)
3610 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3613 ILFree(pidlParent);
3615 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3618 /***********************************************************************
3619 * FILEDLG95_LOOKIN_SelectItem
3621 * Adds an absolute pidl item to the lookin combo box
3622 * returns the index of the inserted item
3624 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3626 int iItemPos;
3627 LookInInfos *liInfos;
3629 TRACE("%p, %p\n", hwnd, pidl);
3631 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3633 liInfos = GetPropA(hwnd,LookInInfosStr);
3635 if(iItemPos < 0)
3637 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3638 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3641 else
3643 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3644 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3646 int iRemovedItem;
3648 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3649 break;
3650 if(iRemovedItem < iItemPos)
3651 iItemPos--;
3655 SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3656 liInfos->uSelectedItem = iItemPos;
3658 return 0;
3662 /***********************************************************************
3663 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3665 * Remove the item with an expansion level over iExpansionLevel
3667 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3669 int iItemPos;
3670 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3672 TRACE("\n");
3674 if(liInfos->iMaxIndentation <= 2)
3675 return -1;
3677 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3679 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3680 ILFree(tmpFolder->pidlItem);
3681 heap_free(tmpFolder);
3682 SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3683 liInfos->iMaxIndentation--;
3685 return iItemPos;
3688 return -1;
3691 /***********************************************************************
3692 * FILEDLG95_LOOKIN_SearchItem
3694 * Search for pidl in the lookin combo box
3695 * returns the index of the found item
3697 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3699 int i = 0;
3700 int iCount;
3702 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3704 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3706 if (iCount != CB_ERR)
3708 for(;i<iCount;i++)
3710 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3712 if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3713 return i;
3714 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3715 return i;
3719 return -1;
3722 /***********************************************************************
3723 * FILEDLG95_LOOKIN_Clean
3725 * Clean the memory used by the lookin combo box
3727 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3729 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3730 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3731 int iPos, iCount;
3733 iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3735 TRACE("\n");
3737 /* Delete each string of the combo and their associated data */
3738 if (iCount != CB_ERR)
3740 for(iPos = iCount-1;iPos>=0;iPos--)
3742 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3743 ILFree(tmpFolder->pidlItem);
3744 heap_free(tmpFolder);
3745 SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3749 /* LookInInfos structure */
3750 heap_free(liInfos);
3751 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3754 /***********************************************************************
3755 * get_def_format
3757 * Fill the FORMATETC used in the shell id list
3759 static FORMATETC get_def_format(void)
3761 static CLIPFORMAT cfFormat;
3762 FORMATETC formatetc;
3764 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3765 formatetc.cfFormat = cfFormat;
3766 formatetc.ptd = 0;
3767 formatetc.dwAspect = DVASPECT_CONTENT;
3768 formatetc.lindex = -1;
3769 formatetc.tymed = TYMED_HGLOBAL;
3770 return formatetc;
3773 /***********************************************************************
3774 * FILEDLG95_FILENAME_FillFromSelection
3776 * fills the edit box from the cached DataObject
3778 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3780 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3781 LPITEMIDLIST pidl;
3782 LPWSTR lpstrAllFiles, lpstrTmp;
3783 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3784 STGMEDIUM medium;
3785 LPIDA cida;
3786 FORMATETC formatetc = get_def_format();
3788 TRACE("\n");
3790 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3791 return;
3793 cida = GlobalLock(medium.u.hGlobal);
3794 nFileSelected = cida->cidl;
3796 /* Allocate a buffer */
3797 nAllFilesMaxLength = MAX_PATH + 3;
3798 lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3799 if (!lpstrAllFiles)
3800 goto ret;
3802 /* Loop through the selection, handle only files (not folders) */
3803 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3805 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3806 if (pidl)
3808 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3810 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3812 nAllFilesMaxLength *= 2;
3813 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3814 if (!lpstrTmp)
3815 goto ret;
3816 lpstrAllFiles = lpstrTmp;
3818 nFiles += 1;
3819 lpstrAllFiles[nAllFilesLength++] = '"';
3820 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3821 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3822 nAllFilesLength += nThisFileLength;
3823 lpstrAllFiles[nAllFilesLength++] = '"';
3824 lpstrAllFiles[nAllFilesLength++] = ' ';
3829 if (nFiles != 0)
3831 /* If there's only one file, use the name as-is without quotes */
3832 lpstrTmp = lpstrAllFiles;
3833 if (nFiles == 1)
3835 lpstrTmp += 1;
3836 lpstrTmp[nThisFileLength] = 0;
3838 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3839 /* Select the file name like Windows does */
3840 if (filename_is_edit(fodInfos))
3841 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3844 ret:
3845 heap_free(lpstrAllFiles);
3846 COMCTL32_ReleaseStgMedium(medium);
3850 /* copied from shell32 to avoid linking to it
3851 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3852 * is dependent on whether emulated OS is unicode or not.
3854 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3856 switch (src->uType)
3858 case STRRET_WSTR:
3859 lstrcpynW(dest, src->u.pOleStr, len);
3860 CoTaskMemFree(src->u.pOleStr);
3861 break;
3863 case STRRET_CSTR:
3864 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3865 dest[len-1] = 0;
3866 break;
3868 case STRRET_OFFSET:
3869 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3870 dest[len-1] = 0;
3871 break;
3873 default:
3874 FIXME("unknown type %x!\n", src->uType);
3875 if (len) *dest = '\0';
3876 return E_FAIL;
3878 return S_OK;
3881 /***********************************************************************
3882 * FILEDLG95_FILENAME_GetFileNames
3884 * Copies the filenames to a delimited string list.
3886 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3888 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
3889 UINT nFileCount = 0; /* number of files */
3890 UINT nStrLen = 0; /* length of string in edit control */
3891 LPWSTR lpstrEdit; /* buffer for string from edit control */
3893 TRACE("\n");
3895 /* get the filenames from the filename control */
3896 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3897 lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3898 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3900 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3902 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3903 heap_free(lpstrEdit);
3904 return nFileCount;
3908 * DATAOBJECT Helper functions
3911 /***********************************************************************
3912 * COMCTL32_ReleaseStgMedium
3914 * like ReleaseStgMedium from ole32
3916 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3918 if(medium.pUnkForRelease)
3920 IUnknown_Release(medium.pUnkForRelease);
3922 else
3924 GlobalUnlock(medium.u.hGlobal);
3925 GlobalFree(medium.u.hGlobal);
3929 /***********************************************************************
3930 * GetPidlFromDataObject
3932 * Return pidl(s) by number from the cached DataObject
3934 * nPidlIndex=0 gets the fully qualified root path
3936 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3939 STGMEDIUM medium;
3940 FORMATETC formatetc = get_def_format();
3941 LPITEMIDLIST pidl = NULL;
3943 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3945 if (!doSelected)
3946 return NULL;
3948 /* Get the pidls from IDataObject */
3949 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3951 LPIDA cida = GlobalLock(medium.u.hGlobal);
3952 if(nPidlIndex <= cida->cidl)
3954 pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3956 COMCTL32_ReleaseStgMedium(medium);
3958 return pidl;
3961 /***********************************************************************
3962 * GetNumSelected
3964 * Return the number of selected items in the DataObject.
3967 static UINT GetNumSelected( IDataObject *doSelected )
3969 UINT retVal = 0;
3970 STGMEDIUM medium;
3971 FORMATETC formatetc = get_def_format();
3973 TRACE("sv=%p\n", doSelected);
3975 if (!doSelected) return 0;
3977 /* Get the pidls from IDataObject */
3978 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3980 LPIDA cida = GlobalLock(medium.u.hGlobal);
3981 retVal = cida->cidl;
3982 COMCTL32_ReleaseStgMedium(medium);
3983 return retVal;
3985 return 0;
3989 * TOOLS
3992 /***********************************************************************
3993 * GetName
3995 * Get the pidl's display name (relative to folder) and
3996 * put it in lpstrFileName.
3998 * Return NOERROR on success,
3999 * E_FAIL otherwise
4002 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
4004 STRRET str;
4005 HRESULT hRes;
4007 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
4009 if(!lpsf)
4011 SHGetDesktopFolder(&lpsf);
4012 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
4013 IShellFolder_Release(lpsf);
4014 return hRes;
4017 /* Get the display name of the pidl relative to the folder */
4018 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4020 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4022 return E_FAIL;
4025 /***********************************************************************
4026 * GetShellFolderFromPidl
4028 * pidlRel is the item pidl relative
4029 * Return the IShellFolder of the absolute pidl
4031 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
4033 IShellFolder *psf = NULL,*psfParent;
4035 TRACE("%p\n", pidlAbs);
4037 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4039 psf = psfParent;
4040 if(pidlAbs && pidlAbs->mkid.cb)
4042 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4044 IShellFolder_Release(psfParent);
4045 return psf;
4048 /* return the desktop */
4049 return psfParent;
4051 return NULL;
4054 /***********************************************************************
4055 * GetParentPidl
4057 * Return the LPITEMIDLIST to the parent of the pidl in the list
4059 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
4061 LPITEMIDLIST pidlParent;
4063 TRACE("%p\n", pidl);
4065 pidlParent = ILClone(pidl);
4066 ILRemoveLastID(pidlParent);
4068 return pidlParent;
4071 /***********************************************************************
4072 * GetPidlFromName
4074 * returns the pidl of the file name relative to folder
4075 * NULL if an error occurred
4077 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4079 LPITEMIDLIST pidl = NULL;
4080 ULONG ulEaten;
4082 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4084 if(!lpcstrFileName) return NULL;
4085 if(!*lpcstrFileName) return NULL;
4087 if(!lpsf)
4089 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4090 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4091 IShellFolder_Release(lpsf);
4094 else
4096 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4098 return pidl;
4103 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4105 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4106 HRESULT ret;
4108 TRACE("%p, %p\n", psf, pidl);
4110 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4112 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4113 /* see documentation shell 4.1*/
4114 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4117 /***********************************************************************
4118 * BrowseSelectedFolder
4120 static BOOL BrowseSelectedFolder(HWND hwnd)
4122 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwnd);
4123 BOOL bBrowseSelFolder = FALSE;
4125 TRACE("\n");
4127 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4129 LPITEMIDLIST pidlSelection;
4131 /* get the file selected */
4132 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4133 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4135 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4136 pidlSelection, SBSP_RELATIVE ) ) )
4138 WCHAR buf[64];
4139 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, ARRAY_SIZE(buf));
4140 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4142 bBrowseSelFolder = TRUE;
4143 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4144 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4146 ILFree( pidlSelection );
4149 return bBrowseSelFolder;
4152 static inline BOOL valid_struct_size( DWORD size )
4154 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4155 (size == sizeof( OPENFILENAMEW ));
4158 static inline BOOL is_win16_looks(DWORD flags)
4160 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4161 !(flags & OFN_EXPLORER));
4164 /* ------------------ APIs ---------------------- */
4166 /***********************************************************************
4167 * GetOpenFileNameA (COMDLG32.@)
4169 * Creates a dialog box for the user to select a file to open.
4171 * RETURNS
4172 * TRUE on success: user enters a valid file
4173 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4176 BOOL WINAPI GetOpenFileNameA(OPENFILENAMEA *ofn)
4178 TRACE("flags 0x%08x\n", ofn->Flags);
4180 if (!valid_struct_size( ofn->lStructSize ))
4182 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4183 return FALSE;
4186 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4187 if (ofn->Flags & OFN_FILEMUSTEXIST)
4188 ofn->Flags |= OFN_PATHMUSTEXIST;
4190 if (is_win16_looks(ofn->Flags))
4191 return GetFileName31A(ofn, OPEN_DIALOG);
4192 else
4194 FileOpenDlgInfos info;
4196 init_filedlg_infoA(ofn, &info);
4197 return GetFileDialog95(&info, OPEN_DIALOG);
4201 /***********************************************************************
4202 * GetOpenFileNameW (COMDLG32.@)
4204 * Creates a dialog box for the user to select a file to open.
4206 * RETURNS
4207 * TRUE on success: user enters a valid file
4208 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4211 BOOL WINAPI GetOpenFileNameW(OPENFILENAMEW *ofn)
4213 TRACE("flags 0x%08x\n", ofn->Flags);
4215 if (!valid_struct_size( ofn->lStructSize ))
4217 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4218 return FALSE;
4221 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4222 if (ofn->Flags & OFN_FILEMUSTEXIST)
4223 ofn->Flags |= OFN_PATHMUSTEXIST;
4225 if (is_win16_looks(ofn->Flags))
4226 return GetFileName31W(ofn, OPEN_DIALOG);
4227 else
4229 FileOpenDlgInfos info;
4231 init_filedlg_infoW(ofn, &info);
4232 return GetFileDialog95(&info, OPEN_DIALOG);
4237 /***********************************************************************
4238 * GetSaveFileNameA (COMDLG32.@)
4240 * Creates a dialog box for the user to select a file to save.
4242 * RETURNS
4243 * TRUE on success: user enters a valid file
4244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4247 BOOL WINAPI GetSaveFileNameA(OPENFILENAMEA *ofn)
4249 if (!valid_struct_size( ofn->lStructSize ))
4251 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4252 return FALSE;
4255 if (is_win16_looks(ofn->Flags))
4256 return GetFileName31A(ofn, SAVE_DIALOG);
4257 else
4259 FileOpenDlgInfos info;
4261 init_filedlg_infoA(ofn, &info);
4262 return GetFileDialog95(&info, SAVE_DIALOG);
4266 /***********************************************************************
4267 * GetSaveFileNameW (COMDLG32.@)
4269 * Creates a dialog box for the user to select a file to save.
4271 * RETURNS
4272 * TRUE on success: user enters a valid file
4273 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4276 BOOL WINAPI GetSaveFileNameW(
4277 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4279 if (!valid_struct_size( ofn->lStructSize ))
4281 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4282 return FALSE;
4285 if (is_win16_looks(ofn->Flags))
4286 return GetFileName31W(ofn, SAVE_DIALOG);
4287 else
4289 FileOpenDlgInfos info;
4291 init_filedlg_infoW(ofn, &info);
4292 return GetFileDialog95(&info, SAVE_DIALOG);
4296 /***********************************************************************
4297 * GetFileTitleA (COMDLG32.@)
4299 * See GetFileTitleW.
4301 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4303 int ret;
4304 UNICODE_STRING strWFile;
4305 LPWSTR lpWTitle;
4307 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4308 lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4309 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4310 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4311 RtlFreeUnicodeString( &strWFile );
4312 heap_free( lpWTitle );
4313 return ret;
4317 /***********************************************************************
4318 * GetFileTitleW (COMDLG32.@)
4320 * Get the name of a file.
4322 * PARAMS
4323 * lpFile [I] name and location of file
4324 * lpTitle [O] returned file name
4325 * cbBuf [I] buffer size of lpTitle
4327 * RETURNS
4328 * Success: zero
4329 * Failure: negative number.
4331 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4333 int i, len;
4334 static const WCHAR brkpoint[] = {'*','[',']',0};
4335 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4337 if(lpFile == NULL || lpTitle == NULL)
4338 return -1;
4340 len = lstrlenW(lpFile);
4342 if (len == 0)
4343 return -1;
4345 if(wcspbrk(lpFile, brkpoint))
4346 return -1;
4348 len--;
4350 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4351 return -1;
4353 for(i = len; i >= 0; i--)
4355 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4357 i++;
4358 break;
4362 if(i == -1)
4363 i++;
4365 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4367 len = lstrlenW(lpFile+i)+1;
4368 if(cbBuf < len)
4369 return len;
4371 lstrcpyW(lpTitle, &lpFile[i]);
4372 return 0;