comdlg32: Factor out some path building code from FILEDLG95_OnOpen.
[wine.git] / dlls / comdlg32 / filedlg.c
blob84b4eebf6c0e4d9e974d90793588a9f7da3bf822
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlobj.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
109 /***********************************************************************
110 * Defines and global variables
113 /* Draw item constant */
114 #define ICONWIDTH 18
115 #define XTEXTOFFSET 3
117 /* AddItem flags*/
118 #define LISTEND -1
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
122 #define SEARCH_EXP 2
123 #define ITEM_NOTFOUND -1
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
128 /* NOTE
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
172 static const WCHAR LastVisitedMRUW[] =
173 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
176 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
177 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
179 /***********************************************************************
180 * Prototypes
183 /* Internal functions used by the dialog */
184 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 static BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Functions for dealing with the most-recently-used registry keys */
220 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
221 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
222 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
224 /* Miscellaneous tool functions */
225 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
226 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
227 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
228 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
229 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
230 static UINT GetNumSelected( IDataObject *doSelected );
232 /* Shell memory allocation */
233 static void *MemAlloc(UINT size);
234 static void MemFree(void *mem);
236 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
237 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
238 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
239 static BOOL BrowseSelectedFolder(HWND hwnd);
241 /***********************************************************************
242 * GetFileName95
244 * Creates an Open common dialog box that lets the user select
245 * the drive, directory, and the name of a file or set of files to open.
247 * IN : The FileOpenDlgInfos structure associated with the dialog
248 * OUT : TRUE on success
249 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
251 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
254 LRESULT lRes;
255 LPVOID template;
256 HRSRC hRes;
257 HANDLE hDlgTmpl = 0;
258 HRESULT hr;
260 /* test for missing functionality */
261 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
263 FIXME("Flags 0x%08x not yet implemented\n",
264 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
267 /* Create the dialog from a template */
269 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
271 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
272 return FALSE;
274 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
275 !(template = LockResource( hDlgTmpl )))
277 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
278 return FALSE;
281 /* msdn: explorer style dialogs permit sizing by default.
282 * The OFN_ENABLESIZING flag is only needed when a hook or
283 * custom tmeplate is provided */
284 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
285 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
286 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
288 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
290 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
291 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
292 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
294 else
295 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
298 /* old style hook messages */
299 if (IsHooked(fodInfos))
301 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
302 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
303 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
304 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
307 /* Some shell namespace extensions depend on COM being initialized. */
308 hr = OleInitialize(NULL);
310 if (fodInfos->unicode)
311 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
312 template,
313 fodInfos->ofnInfos->hwndOwner,
314 FileOpenDlgProc95,
315 (LPARAM) fodInfos);
316 else
317 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
318 template,
319 fodInfos->ofnInfos->hwndOwner,
320 FileOpenDlgProc95,
321 (LPARAM) fodInfos);
322 if (SUCCEEDED(hr))
323 OleUninitialize();
325 /* Unable to create the dialog */
326 if( lRes == -1)
327 return FALSE;
329 return lRes;
332 /***********************************************************************
333 * GetFileDialog95A
335 * Call GetFileName95 with this structure and clean the memory.
337 * IN : The OPENFILENAMEA initialisation structure passed to
338 * GetOpenFileNameA win api function (see filedlg.c)
340 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
342 BOOL ret;
343 FileOpenDlgInfos fodInfos;
344 LPSTR lpstrSavDir = NULL;
345 LPWSTR title = NULL;
346 LPWSTR defext = NULL;
347 LPWSTR filter = NULL;
348 LPWSTR customfilter = NULL;
350 /* Initialize CommDlgExtendedError() */
351 COMDLG32_SetCommDlgExtendedError(0);
353 /* Initialize FileOpenDlgInfos structure */
354 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
356 /* Pass in the original ofn */
357 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
359 /* save current directory */
360 if (ofn->Flags & OFN_NOCHANGEDIR)
362 lpstrSavDir = MemAlloc(MAX_PATH);
363 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
366 fodInfos.unicode = FALSE;
368 /* convert all the input strings to unicode */
369 if(ofn->lpstrInitialDir)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
372 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
375 else
376 fodInfos.initdir = NULL;
378 if(ofn->lpstrFile)
380 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
383 else
384 fodInfos.filename = NULL;
386 if(ofn->lpstrDefExt)
388 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
389 defext = MemAlloc((len+1)*sizeof(WCHAR));
390 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
392 fodInfos.defext = defext;
394 if(ofn->lpstrTitle)
396 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
397 title = MemAlloc((len+1)*sizeof(WCHAR));
398 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
400 fodInfos.title = title;
402 if (ofn->lpstrFilter)
404 LPCSTR s;
405 int n, len;
407 /* filter is a list... title\0ext\0......\0\0 */
408 s = ofn->lpstrFilter;
409 while (*s) s = s+strlen(s)+1;
410 s++;
411 n = s - ofn->lpstrFilter;
412 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
413 filter = MemAlloc(len*sizeof(WCHAR));
414 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
416 fodInfos.filter = filter;
418 /* convert lpstrCustomFilter */
419 if (ofn->lpstrCustomFilter)
421 LPCSTR s;
422 int n, len;
424 /* customfilter contains a pair of strings... title\0ext\0 */
425 s = ofn->lpstrCustomFilter;
426 if (*s) s = s+strlen(s)+1;
427 if (*s) s = s+strlen(s)+1;
428 n = s - ofn->lpstrCustomFilter;
429 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
430 customfilter = MemAlloc(len*sizeof(WCHAR));
431 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
433 fodInfos.customfilter = customfilter;
435 /* Initialize the dialog property */
436 fodInfos.DlgInfos.dwDlgProp = 0;
437 fodInfos.DlgInfos.hwndCustomDlg = NULL;
439 switch(iDlgType)
441 case OPEN_DIALOG :
442 ret = GetFileName95(&fodInfos);
443 break;
444 case SAVE_DIALOG :
445 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
446 ret = GetFileName95(&fodInfos);
447 break;
448 default :
449 ret = 0;
452 if (lpstrSavDir)
454 SetCurrentDirectoryA(lpstrSavDir);
455 MemFree(lpstrSavDir);
458 MemFree(title);
459 MemFree(defext);
460 MemFree(filter);
461 MemFree(customfilter);
462 MemFree(fodInfos.initdir);
463 MemFree(fodInfos.filename);
465 TRACE("selected file: %s\n",ofn->lpstrFile);
467 return ret;
470 /***********************************************************************
471 * GetFileDialog95W
473 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
474 * Call GetFileName95 with this structure and clean the memory.
477 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
479 BOOL ret;
480 FileOpenDlgInfos fodInfos;
481 LPWSTR lpstrSavDir = NULL;
483 /* Initialize CommDlgExtendedError() */
484 COMDLG32_SetCommDlgExtendedError(0);
486 /* Initialize FileOpenDlgInfos structure */
487 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
489 /* Pass in the original ofn */
490 fodInfos.ofnInfos = ofn;
492 fodInfos.title = ofn->lpstrTitle;
493 fodInfos.defext = ofn->lpstrDefExt;
494 fodInfos.filter = ofn->lpstrFilter;
495 fodInfos.customfilter = ofn->lpstrCustomFilter;
497 /* convert string arguments, save others */
498 if(ofn->lpstrFile)
500 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
501 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
503 else
504 fodInfos.filename = NULL;
506 if(ofn->lpstrInitialDir)
508 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
509 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
510 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
511 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
513 else
514 fodInfos.initdir = NULL;
516 /* save current directory */
517 if (ofn->Flags & OFN_NOCHANGEDIR)
519 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
520 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
523 fodInfos.unicode = TRUE;
525 switch(iDlgType)
527 case OPEN_DIALOG :
528 ret = GetFileName95(&fodInfos);
529 break;
530 case SAVE_DIALOG :
531 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
532 ret = GetFileName95(&fodInfos);
533 break;
534 default :
535 ret = 0;
538 if (lpstrSavDir)
540 SetCurrentDirectoryW(lpstrSavDir);
541 MemFree(lpstrSavDir);
544 /* restore saved IN arguments and convert OUT arguments back */
545 MemFree(fodInfos.filename);
546 MemFree(fodInfos.initdir);
547 return ret;
550 /******************************************************************************
551 * COMDLG32_GetDisplayNameOf [internal]
553 * Helper function to get the display name for a pidl.
555 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
556 LPSHELLFOLDER psfDesktop;
557 STRRET strret;
559 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
560 return FALSE;
562 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
563 IShellFolder_Release(psfDesktop);
564 return FALSE;
567 IShellFolder_Release(psfDesktop);
568 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
571 /******************************************************************************
572 * COMDLG32_GetCanonicalPath [internal]
574 * Helper function to get the canonical path.
576 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
577 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
579 WCHAR lpstrTemp[MAX_PATH];
581 /* Get the current directory name */
582 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
584 /* last fallback */
585 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
587 PathAddBackslashW(lpstrPathAndFile);
589 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
591 /* if the user specified a fully qualified path use it */
592 if(PathIsRelativeW(lpstrFile))
594 lstrcatW(lpstrPathAndFile, lpstrFile);
596 else
598 /* does the path have a drive letter? */
599 if (PathGetDriveNumberW(lpstrFile) == -1)
600 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
601 else
602 lstrcpyW(lpstrPathAndFile, lpstrFile);
605 /* resolve "." and ".." */
606 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
607 lstrcpyW(lpstrPathAndFile, lpstrTemp);
608 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
611 /***********************************************************************
612 * ArrangeCtrlPositions [internal]
614 * NOTE: Make sure to add testcases for any changes made here.
616 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
618 HWND hwndChild, hwndStc32;
619 RECT rectParent, rectChild, rectStc32;
620 INT help_fixup = 0;
621 int chgx, chgy;
623 /* Take into account if open as read only checkbox and help button
624 * are hidden
626 if (hide_help)
628 RECT rectHelp, rectCancel;
629 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
630 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
631 /* subtract the height of the help button plus the space between
632 * the help button and the cancel button to the height of the dialog
634 help_fixup = rectHelp.bottom - rectCancel.bottom;
638 There are two possibilities to add components to the default file dialog box.
640 By default, all the new components are added below the standard dialog box (the else case).
642 However, if there is a static text component with the stc32 id, a special case happens.
643 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
644 in the window and the cx and cy indicate how to size the window.
645 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
646 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
650 GetClientRect(hwndParentDlg, &rectParent);
652 /* when arranging controls we have to use fixed parent size */
653 rectParent.bottom -= help_fixup;
655 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
656 if (hwndStc32)
658 GetWindowRect(hwndStc32, &rectStc32);
659 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
661 /* set the size of the stc32 control according to the size of
662 * client area of the parent dialog
664 SetWindowPos(hwndStc32, 0,
665 0, 0,
666 rectParent.right, rectParent.bottom,
667 SWP_NOMOVE | SWP_NOZORDER);
669 else
670 SetRectEmpty(&rectStc32);
672 /* this part moves controls of the child dialog */
673 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
674 while (hwndChild)
676 if (hwndChild != hwndStc32)
678 GetWindowRect(hwndChild, &rectChild);
679 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
681 /* move only if stc32 exist */
682 if (hwndStc32 && rectChild.left > rectStc32.right)
684 /* move to the right of visible controls of the parent dialog */
685 rectChild.left += rectParent.right;
686 rectChild.left -= rectStc32.right;
688 /* move even if stc32 doesn't exist */
689 if (rectChild.top >= rectStc32.bottom)
691 /* move below visible controls of the parent dialog */
692 rectChild.top += rectParent.bottom;
693 rectChild.top -= rectStc32.bottom - rectStc32.top;
696 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
697 0, 0, SWP_NOSIZE | SWP_NOZORDER);
699 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
702 /* this part moves controls of the parent dialog */
703 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
704 while (hwndChild)
706 if (hwndChild != hwndChildDlg)
708 GetWindowRect(hwndChild, &rectChild);
709 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
711 /* left,top of stc32 marks the position of controls
712 * from the parent dialog
714 rectChild.left += rectStc32.left;
715 rectChild.top += rectStc32.top;
717 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
718 0, 0, SWP_NOSIZE | SWP_NOZORDER);
720 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
723 /* calculate the size of the resulting dialog */
725 /* here we have to use original parent size */
726 GetClientRect(hwndParentDlg, &rectParent);
727 GetClientRect(hwndChildDlg, &rectChild);
728 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
729 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
731 if (hwndStc32)
733 /* width */
734 if (rectParent.right > rectStc32.right - rectStc32.left)
735 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
736 else
737 chgx = rectChild.right - rectParent.right;
738 /* height */
739 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
740 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
741 else
742 /* Unconditionally set new dialog
743 * height to that of the child
745 chgy = rectChild.bottom - rectParent.bottom;
747 else
749 chgx = 0;
750 chgy = rectChild.bottom - help_fixup;
752 /* set the size of the parent dialog */
753 GetWindowRect(hwndParentDlg, &rectParent);
754 SetWindowPos(hwndParentDlg, 0,
755 0, 0,
756 rectParent.right - rectParent.left + chgx,
757 rectParent.bottom - rectParent.top + chgy,
758 SWP_NOMOVE | SWP_NOZORDER);
761 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
763 switch(uMsg) {
764 case WM_INITDIALOG:
765 return TRUE;
767 return FALSE;
770 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
772 LPCVOID template;
773 HRSRC hRes;
774 HANDLE hDlgTmpl = 0;
775 HWND hChildDlg = 0;
777 TRACE("\n");
780 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
781 * structure's hInstance parameter is not a HINSTANCE, but
782 * instead a pointer to a template resource to use.
784 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
786 HINSTANCE hinst;
787 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
789 hinst = COMDLG32_hInstance;
790 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
792 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
793 return NULL;
796 else
798 hinst = fodInfos->ofnInfos->hInstance;
799 if(fodInfos->unicode)
801 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
802 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
804 else
806 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
807 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
809 if (!hRes)
811 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
812 return NULL;
814 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
815 !(template = LockResource( hDlgTmpl )))
817 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
818 return NULL;
821 if (fodInfos->unicode)
822 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
823 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
824 (LPARAM)fodInfos->ofnInfos);
825 else
826 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
827 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
828 (LPARAM)fodInfos->ofnInfos);
829 return hChildDlg;
831 else if( IsHooked(fodInfos))
833 RECT rectHwnd;
834 struct {
835 DLGTEMPLATE tmplate;
836 WORD menu,class,title;
837 } temp;
838 GetClientRect(hwnd,&rectHwnd);
839 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
840 temp.tmplate.dwExtendedStyle = 0;
841 temp.tmplate.cdit = 0;
842 temp.tmplate.x = 0;
843 temp.tmplate.y = 0;
844 temp.tmplate.cx = 0;
845 temp.tmplate.cy = 0;
846 temp.menu = temp.class = temp.title = 0;
848 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
849 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
851 return hChildDlg;
853 return NULL;
856 /***********************************************************************
857 * SendCustomDlgNotificationMessage
859 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
862 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
864 LRESULT hook_result = 0;
865 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
867 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
869 if(!fodInfos) return 0;
871 if(fodInfos->DlgInfos.hwndCustomDlg)
873 TRACE("CALL NOTIFY for %x\n", uCode);
874 if(fodInfos->unicode)
876 OFNOTIFYW ofnNotify;
877 ofnNotify.hdr.hwndFrom=hwndParentDlg;
878 ofnNotify.hdr.idFrom=0;
879 ofnNotify.hdr.code = uCode;
880 ofnNotify.lpOFN = fodInfos->ofnInfos;
881 ofnNotify.pszFile = NULL;
882 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
884 else
886 OFNOTIFYA ofnNotify;
887 ofnNotify.hdr.hwndFrom=hwndParentDlg;
888 ofnNotify.hdr.idFrom=0;
889 ofnNotify.hdr.code = uCode;
890 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
891 ofnNotify.pszFile = NULL;
892 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
894 TRACE("RET NOTIFY\n");
896 TRACE("Retval: 0x%08lx\n", hook_result);
897 return hook_result;
900 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
902 UINT len, total;
903 WCHAR *p, *buffer;
904 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
906 TRACE("CDM_GETFILEPATH:\n");
908 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
909 return -1;
911 /* get path and filenames */
912 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
913 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
914 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
915 if (len)
917 p = buffer + strlenW(buffer);
918 *p++ = '\\';
919 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
921 if (fodInfos->unicode)
923 total = strlenW( buffer) + 1;
924 if (result) lstrcpynW( result, buffer, size );
925 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
927 else
929 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
930 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
931 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
933 HeapFree( GetProcessHeap(), 0, buffer );
934 return total;
937 /***********************************************************************
938 * FILEDLG95_HandleCustomDialogMessages
940 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
942 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
944 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
945 WCHAR lpstrPath[MAX_PATH];
946 INT_PTR retval;
948 if(!fodInfos) return FALSE;
950 switch(uMsg)
952 case CDM_GETFILEPATH:
953 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
954 break;
956 case CDM_GETFOLDERPATH:
957 TRACE("CDM_GETFOLDERPATH:\n");
958 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
959 if (lParam)
961 if (fodInfos->unicode)
962 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
963 else
964 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
965 (LPSTR)lParam, (int)wParam, NULL, NULL);
967 retval = lstrlenW(lpstrPath) + 1;
968 break;
970 case CDM_GETFOLDERIDLIST:
971 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
972 if (retval <= wParam)
973 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
974 break;
976 case CDM_GETSPEC:
977 TRACE("CDM_GETSPEC:\n");
978 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
979 if (lParam)
981 if (fodInfos->unicode)
982 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
983 else
984 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
986 break;
988 case CDM_SETCONTROLTEXT:
989 TRACE("CDM_SETCONTROLTEXT:\n");
990 if ( lParam )
992 if( fodInfos->unicode )
993 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
994 else
995 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
997 retval = TRUE;
998 break;
1000 case CDM_HIDECONTROL:
1001 /* MSDN states that it should fail for not OFN_EXPLORER case */
1002 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1004 HWND control = GetDlgItem( hwnd, wParam );
1005 if (control) ShowWindow( control, SW_HIDE );
1006 retval = TRUE;
1008 else retval = FALSE;
1009 break;
1011 default:
1012 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1013 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1014 return FALSE;
1016 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1017 return TRUE;
1020 /***********************************************************************
1021 * FILEDLG95_OnWMGetMMI
1023 * WM_GETMINMAXINFO message handler for resizable dialogs
1025 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1027 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1028 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1029 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1031 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1033 return TRUE;
1036 /***********************************************************************
1037 * FILEDLG95_OnWMSize
1039 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1041 * FIXME: this could be made more elaborate. Now use a simple scheme
1042 * where the file view is enlarged and the controls are either moved
1043 * vertically or horizontally to get out of the way. Only the "grip"
1044 * is moved in both directions to stay in the corner.
1046 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1048 RECT rc, rcview;
1049 int chgx, chgy;
1050 HWND ctrl;
1051 HDWP hdwp;
1052 FileOpenDlgInfos *fodInfos;
1054 if( wParam != SIZE_RESTORED) return FALSE;
1055 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1056 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1057 /* get the new dialog rectangle */
1058 GetWindowRect( hwnd, &rc);
1059 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1060 rc.right -rc.left, rc.bottom -rc.top);
1061 /* not initialized yet */
1062 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1063 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1064 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1065 return FALSE;
1066 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1067 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1068 fodInfos->sizedlg.cx = rc.right - rc.left;
1069 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1070 /* change the size of the view window */
1071 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1072 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1073 hdwp = BeginDeferWindowPos( 10);
1074 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1075 rcview.right - rcview.left + chgx,
1076 rcview.bottom - rcview.top + chgy,
1077 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1078 /* change position and sizes of the controls */
1079 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1081 int ctrlid = GetDlgCtrlID( ctrl);
1082 GetWindowRect( ctrl, &rc);
1083 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1084 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1086 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1087 0, 0,
1088 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1090 else if( rc.top > rcview.bottom)
1092 /* if it was below the shell view
1093 * move to bottom */
1094 switch( ctrlid)
1096 /* file name box and file types combo change also width */
1097 case edt1:
1098 case cmb1:
1099 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1100 rc.right - rc.left + chgx, rc.bottom - rc.top,
1101 SWP_NOACTIVATE | SWP_NOZORDER);
1102 break;
1103 /* then these buttons must move out of the way */
1104 case IDOK:
1105 case IDCANCEL:
1106 case pshHelp:
1107 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1108 0, 0,
1109 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1110 break;
1111 default:
1112 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1113 0, 0,
1114 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1117 else if( rc.left > rcview.right)
1119 /* if it was to the right of the shell view
1120 * move to right */
1121 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1122 0, 0,
1123 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1125 else
1126 /* special cases */
1128 switch( ctrlid)
1130 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1131 case IDC_LOOKIN:
1132 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1133 rc.right - rc.left + chgx, rc.bottom - rc.top,
1134 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1135 break;
1136 case IDC_TOOLBARSTATIC:
1137 case IDC_TOOLBAR:
1138 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1139 0, 0,
1140 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1141 break;
1142 #endif
1143 /* not resized in windows. Since wine uses this invisible control
1144 * to size the browser view it needs to be resized */
1145 case IDC_SHELLSTATIC:
1146 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1147 rc.right - rc.left + chgx,
1148 rc.bottom - rc.top + chgy,
1149 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1150 break;
1154 if(fodInfos->DlgInfos.hwndCustomDlg &&
1155 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1157 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1158 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1160 GetWindowRect( ctrl, &rc);
1161 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1162 if( rc.top > rcview.bottom)
1164 /* if it was below the shell view
1165 * move to bottom */
1166 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1167 rc.right - rc.left, rc.bottom - rc.top,
1168 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1170 else if( rc.left > rcview.right)
1172 /* if it was to the right of the shell view
1173 * move to right */
1174 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1175 rc.right - rc.left, rc.bottom - rc.top,
1176 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1179 /* size the custom dialog at the end: some applications do some
1180 * control re-arranging at this point */
1181 GetClientRect(hwnd, &rc);
1182 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1183 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1185 EndDeferWindowPos( hdwp);
1186 /* should not be needed */
1187 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1188 return TRUE;
1191 /***********************************************************************
1192 * FileOpenDlgProc95
1194 * File open dialog procedure
1196 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1198 #if 0
1199 TRACE("%p 0x%04x\n", hwnd, uMsg);
1200 #endif
1202 switch(uMsg)
1204 case WM_INITDIALOG:
1206 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1207 RECT rc, rcstc;
1208 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1209 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1211 /* Adds the FileOpenDlgInfos in the property list of the dialog
1212 so it will be easily accessible through a GetPropA(...) */
1213 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1215 FILEDLG95_InitControls(hwnd);
1217 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1219 GetWindowRect( hwnd, &rc);
1220 fodInfos->DlgInfos.hwndGrip =
1221 CreateWindowExA( 0, "SCROLLBAR", NULL,
1222 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1223 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1224 rc.right - gripx, rc.bottom - gripy,
1225 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1228 fodInfos->DlgInfos.hwndCustomDlg =
1229 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1231 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1232 FILEDLG95_FillControls(hwnd, wParam, lParam);
1234 if( fodInfos->DlgInfos.hwndCustomDlg)
1235 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1237 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1238 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1239 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1242 /* if the app has changed the position of the invisible listbox,
1243 * change that of the listview (browser) as well */
1244 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1245 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1246 if( !EqualRect( &rc, &rcstc))
1248 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1249 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1250 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1251 SWP_NOACTIVATE | SWP_NOZORDER);
1254 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1256 GetWindowRect( hwnd, &rc);
1257 fodInfos->sizedlg.cx = rc.right - rc.left;
1258 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1259 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1260 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1261 GetClientRect( hwnd, &rc);
1262 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1263 rc.right - gripx, rc.bottom - gripy,
1264 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1265 /* resize the dialog to the previous invocation */
1266 if( MemDialogSize.cx && MemDialogSize.cy)
1267 SetWindowPos( hwnd, NULL,
1268 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1269 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1272 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1273 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1275 return 0;
1277 case WM_SIZE:
1278 return FILEDLG95_OnWMSize(hwnd, wParam);
1279 case WM_GETMINMAXINFO:
1280 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1281 case WM_COMMAND:
1282 return FILEDLG95_OnWMCommand(hwnd, wParam);
1283 case WM_DRAWITEM:
1285 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1287 case IDC_LOOKIN:
1288 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1289 return TRUE;
1292 return FALSE;
1294 case WM_GETISHELLBROWSER:
1295 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1297 case WM_DESTROY:
1299 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1300 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1301 MemDialogSize = fodInfos->sizedlg;
1302 RemovePropA(hwnd, FileOpenDlgInfosStr);
1303 return FALSE;
1305 case WM_NOTIFY:
1307 LPNMHDR lpnmh = (LPNMHDR)lParam;
1308 UINT stringId = -1;
1310 /* set up the button tooltips strings */
1311 if(TTN_GETDISPINFOA == lpnmh->code )
1313 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1314 switch(lpnmh->idFrom )
1316 /* Up folder button */
1317 case FCIDM_TB_UPFOLDER:
1318 stringId = IDS_UPFOLDER;
1319 break;
1320 /* New folder button */
1321 case FCIDM_TB_NEWFOLDER:
1322 stringId = IDS_NEWFOLDER;
1323 break;
1324 /* List option button */
1325 case FCIDM_TB_SMALLICON:
1326 stringId = IDS_LISTVIEW;
1327 break;
1328 /* Details option button */
1329 case FCIDM_TB_REPORTVIEW:
1330 stringId = IDS_REPORTVIEW;
1331 break;
1332 /* Desktop button */
1333 case FCIDM_TB_DESKTOP:
1334 stringId = IDS_TODESKTOP;
1335 break;
1336 default:
1337 stringId = 0;
1339 lpdi->hinst = COMDLG32_hInstance;
1340 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1342 return FALSE;
1344 default :
1345 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1346 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1347 return FALSE;
1351 /***********************************************************************
1352 * FILEDLG95_InitControls
1354 * WM_INITDIALOG message handler (before hook notification)
1356 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1358 int win2000plus = 0;
1359 int win98plus = 0;
1360 int handledPath = FALSE;
1361 OSVERSIONINFOW osVi;
1362 static const WCHAR szwSlash[] = { '\\', 0 };
1363 static const WCHAR szwStar[] = { '*',0 };
1365 static const TBBUTTON tbb[] =
1367 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1368 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1369 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1370 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1371 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1372 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1373 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1374 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1375 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1377 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1379 RECT rectTB;
1380 RECT rectlook;
1382 HIMAGELIST toolbarImageList;
1383 SHFILEINFOA shFileInfo;
1384 ITEMIDLIST *desktopPidl;
1386 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1388 TRACE("%p\n", fodInfos);
1390 /* Get windows version emulating */
1391 osVi.dwOSVersionInfoSize = sizeof(osVi);
1392 GetVersionExW(&osVi);
1393 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1394 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1395 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1396 win2000plus = (osVi.dwMajorVersion > 4);
1397 if (win2000plus) win98plus = TRUE;
1399 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1401 /* Get the hwnd of the controls */
1402 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1403 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1404 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1406 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1407 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1409 /* construct the toolbar */
1410 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1411 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1413 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1414 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1415 rectTB.left = rectlook.right;
1416 rectTB.top = rectlook.top-1;
1418 if (fodInfos->unicode)
1419 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1420 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1421 rectTB.left, rectTB.top,
1422 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1423 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1424 else
1425 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1426 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1427 rectTB.left, rectTB.top,
1428 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1429 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1431 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1433 /* FIXME: use TB_LOADIMAGES when implemented */
1434 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1435 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1436 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1438 /* Retrieve and add desktop icon to the toolbar */
1439 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1440 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1441 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1442 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1443 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1445 DestroyIcon(shFileInfo.hIcon);
1446 CoTaskMemFree(desktopPidl);
1448 /* Finish Toolbar Construction */
1449 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1450 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1452 /* Set the window text with the text specified in the OPENFILENAME structure */
1453 if(fodInfos->title)
1455 SetWindowTextW(hwnd,fodInfos->title);
1457 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1459 WCHAR buf[16];
1460 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1461 SetWindowTextW(hwnd, buf);
1464 /* Initialise the file name edit control */
1465 handledPath = FALSE;
1466 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1468 if(fodInfos->filename)
1470 /* 1. If win2000 or higher and filename contains a path, use it
1471 in preference over the lpstrInitialDir */
1472 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1473 WCHAR tmpBuf[MAX_PATH];
1474 WCHAR *nameBit;
1475 DWORD result;
1477 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1478 if (result) {
1480 /* nameBit is always shorter than the original filename */
1481 lstrcpyW(fodInfos->filename,nameBit);
1483 *nameBit = 0x00;
1484 if (fodInfos->initdir == NULL)
1485 MemFree(fodInfos->initdir);
1486 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1487 lstrcpyW(fodInfos->initdir, tmpBuf);
1488 handledPath = TRUE;
1489 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1490 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1492 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1494 } else {
1495 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1499 /* 2. (All platforms) If initdir is not null, then use it */
1500 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1501 (*fodInfos->initdir!=0x00))
1503 /* Work out the proper path as supplied one might be relative */
1504 /* (Here because supplying '.' as dir browses to My Computer) */
1505 if (handledPath==FALSE) {
1506 WCHAR tmpBuf[MAX_PATH];
1507 WCHAR tmpBuf2[MAX_PATH];
1508 WCHAR *nameBit;
1509 DWORD result;
1511 lstrcpyW(tmpBuf, fodInfos->initdir);
1512 if( PathFileExistsW(tmpBuf) ) {
1513 /* initdir does not have to be a directory. If a file is
1514 * specified, the dir part is taken */
1515 if( PathIsDirectoryW(tmpBuf)) {
1516 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1517 lstrcatW(tmpBuf, szwSlash);
1519 lstrcatW(tmpBuf, szwStar);
1521 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1522 if (result) {
1523 *nameBit = 0x00;
1524 MemFree(fodInfos->initdir);
1525 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1526 lstrcpyW(fodInfos->initdir, tmpBuf2);
1527 handledPath = TRUE;
1528 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1531 else if (fodInfos->initdir)
1533 MemFree(fodInfos->initdir);
1534 fodInfos->initdir = NULL;
1535 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1540 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1541 (*fodInfos->initdir==0x00)))
1543 /* 3. All except w2k+: if filename contains a path use it */
1544 if (!win2000plus && fodInfos->filename &&
1545 *fodInfos->filename &&
1546 strpbrkW(fodInfos->filename, szwSlash)) {
1547 WCHAR tmpBuf[MAX_PATH];
1548 WCHAR *nameBit;
1549 DWORD result;
1551 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1552 tmpBuf, &nameBit);
1553 if (result) {
1554 int len;
1556 /* nameBit is always shorter than the original filename */
1557 lstrcpyW(fodInfos->filename, nameBit);
1558 *nameBit = 0x00;
1560 len = lstrlenW(tmpBuf);
1561 MemFree(fodInfos->initdir);
1562 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1563 lstrcpyW(fodInfos->initdir, tmpBuf);
1565 handledPath = TRUE;
1566 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1567 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1569 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1572 /* 4. Win2000+: Recently used */
1573 if (handledPath == FALSE && win2000plus) {
1574 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1575 fodInfos->initdir[0] = '\0';
1577 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1579 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1580 handledPath = TRUE;
1581 }else{
1582 MemFree(fodInfos->initdir);
1583 fodInfos->initdir = NULL;
1587 /* 5. win98+ and win2000+ if any files of specified filter types in
1588 current directory, use it */
1589 if ( win98plus && handledPath == FALSE &&
1590 fodInfos->filter && *fodInfos->filter) {
1592 LPCWSTR lpstrPos = fodInfos->filter;
1593 WIN32_FIND_DATAW FindFileData;
1594 HANDLE hFind;
1596 while (1)
1598 /* filter is a list... title\0ext\0......\0\0 */
1600 /* Skip the title */
1601 if(! *lpstrPos) break; /* end */
1602 lpstrPos += lstrlenW(lpstrPos) + 1;
1604 /* See if any files exist in the current dir with this extension */
1605 if(! *lpstrPos) break; /* end */
1607 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1609 if (hFind == INVALID_HANDLE_VALUE) {
1610 /* None found - continue search */
1611 lpstrPos += lstrlenW(lpstrPos) + 1;
1613 } else {
1615 MemFree(fodInfos->initdir);
1616 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1617 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1619 handledPath = TRUE;
1620 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1621 debugstr_w(lpstrPos));
1622 FindClose(hFind);
1623 break;
1628 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1629 if (handledPath == FALSE && (win2000plus || win98plus)) {
1630 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1632 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1634 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1636 /* last fallback */
1637 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1638 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1639 } else {
1640 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1642 } else {
1643 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1645 handledPath = TRUE;
1646 } else if (handledPath==FALSE) {
1647 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1648 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1649 handledPath = TRUE;
1650 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1653 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1654 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1656 /* Must the open as read only check box be checked ?*/
1657 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1659 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1662 /* Must the open as read only check box be hidden? */
1663 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1665 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1666 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1669 /* Must the help button be hidden? */
1670 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1672 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1673 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1676 /* change Open to Save */
1677 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1679 WCHAR buf[16];
1680 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1681 SetDlgItemTextW(hwnd, IDOK, buf);
1682 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1683 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1686 /* Initialize the filter combo box */
1687 FILEDLG95_FILETYPE_Init(hwnd);
1689 return 0;
1692 /***********************************************************************
1693 * FILEDLG95_ResizeControls
1695 * WM_INITDIALOG message handler (after hook notification)
1697 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1699 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1701 if (fodInfos->DlgInfos.hwndCustomDlg)
1703 RECT rc;
1704 UINT flags = SWP_NOACTIVATE;
1706 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1707 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1709 /* resize the custom dialog to the parent size */
1710 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1711 GetClientRect(hwnd, &rc);
1712 else
1714 /* our own fake template is zero sized and doesn't have children, so
1715 * there is no need to resize it. Picasa depends on it.
1717 flags |= SWP_NOSIZE;
1718 SetRectEmpty(&rc);
1720 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1721 0, 0, rc.right, rc.bottom, flags);
1723 else
1725 /* Resize the height, if open as read only checkbox ad help button are
1726 * hidden and we are not using a custom template nor a customDialog
1728 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1729 (!(fodInfos->ofnInfos->Flags &
1730 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1732 RECT rectDlg, rectHelp, rectCancel;
1733 GetWindowRect(hwnd, &rectDlg);
1734 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1735 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1736 /* subtract the height of the help button plus the space between the help
1737 * button and the cancel button to the height of the dialog
1739 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1740 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1741 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1744 return TRUE;
1747 /***********************************************************************
1748 * FILEDLG95_FillControls
1750 * WM_INITDIALOG message handler (after hook notification)
1752 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1754 LPITEMIDLIST pidlItemId = NULL;
1756 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1758 TRACE("dir=%s file=%s\n",
1759 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1761 /* Get the initial directory pidl */
1763 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1765 WCHAR path[MAX_PATH];
1767 GetCurrentDirectoryW(MAX_PATH,path);
1768 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1771 /* Initialise shell objects */
1772 FILEDLG95_SHELL_Init(hwnd);
1774 /* Initialize the Look In combo box */
1775 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1777 /* Browse to the initial directory */
1778 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1780 /* Free pidlItem memory */
1781 COMDLG32_SHFree(pidlItemId);
1783 return TRUE;
1785 /***********************************************************************
1786 * FILEDLG95_Clean
1788 * Regroups all the cleaning functions of the filedlg
1790 void FILEDLG95_Clean(HWND hwnd)
1792 FILEDLG95_FILETYPE_Clean(hwnd);
1793 FILEDLG95_LOOKIN_Clean(hwnd);
1794 FILEDLG95_SHELL_Clean(hwnd);
1796 /***********************************************************************
1797 * FILEDLG95_OnWMCommand
1799 * WM_COMMAND message handler
1801 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1803 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1804 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1805 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1807 switch(wID)
1809 /* OK button */
1810 case IDOK:
1811 FILEDLG95_OnOpen(hwnd);
1812 break;
1813 /* Cancel button */
1814 case IDCANCEL:
1815 FILEDLG95_Clean(hwnd);
1816 EndDialog(hwnd, FALSE);
1817 break;
1818 /* Filetype combo box */
1819 case IDC_FILETYPE:
1820 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1821 break;
1822 /* LookIn combo box */
1823 case IDC_LOOKIN:
1824 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1825 break;
1827 /* --- toolbar --- */
1828 /* Up folder button */
1829 case FCIDM_TB_UPFOLDER:
1830 FILEDLG95_SHELL_UpFolder(hwnd);
1831 break;
1832 /* New folder button */
1833 case FCIDM_TB_NEWFOLDER:
1834 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1835 break;
1836 /* List option button */
1837 case FCIDM_TB_SMALLICON:
1838 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1839 break;
1840 /* Details option button */
1841 case FCIDM_TB_REPORTVIEW:
1842 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1843 break;
1844 /* Details option button */
1845 case FCIDM_TB_DESKTOP:
1846 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1847 break;
1849 case IDC_FILENAME:
1850 break;
1853 /* Do not use the listview selection anymore */
1854 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1855 return 0;
1858 /***********************************************************************
1859 * FILEDLG95_OnWMGetIShellBrowser
1861 * WM_GETISHELLBROWSER message handler
1863 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1865 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1867 TRACE("\n");
1869 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1871 return TRUE;
1875 /***********************************************************************
1876 * FILEDLG95_SendFileOK
1878 * Sends the CDN_FILEOK notification if required
1880 * RETURNS
1881 * TRUE if the dialog should close
1882 * FALSE if the dialog should not be closed
1884 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1886 /* ask the hook if we can close */
1887 if(IsHooked(fodInfos))
1889 LRESULT retval = 0;
1891 TRACE("---\n");
1892 /* First send CDN_FILEOK as MSDN doc says */
1893 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1894 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1895 if( retval)
1897 TRACE("canceled\n");
1898 return FALSE;
1901 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1902 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1903 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1904 if( retval)
1906 TRACE("canceled\n");
1907 return FALSE;
1910 return TRUE;
1913 /***********************************************************************
1914 * FILEDLG95_OnOpenMultipleFiles
1916 * Handles the opening of multiple files.
1918 * FIXME
1919 * check destination buffer size
1921 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1923 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1924 UINT nCount, nSizePath;
1925 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1927 TRACE("\n");
1929 if(fodInfos->unicode)
1931 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1932 ofn->lpstrFile[0] = '\0';
1934 else
1936 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1937 ofn->lpstrFile[0] = '\0';
1940 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1942 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1943 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1944 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1946 LPWSTR lpstrTemp = lpstrFileList;
1948 for ( nCount = 0; nCount < nFileCount; nCount++ )
1950 LPITEMIDLIST pidl;
1952 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1953 if (!pidl)
1955 WCHAR lpstrNotFound[100];
1956 WCHAR lpstrMsg[100];
1957 WCHAR tmp[400];
1958 static const WCHAR nl[] = {'\n',0};
1960 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1961 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1963 lstrcpyW(tmp, lpstrTemp);
1964 lstrcatW(tmp, nl);
1965 lstrcatW(tmp, lpstrNotFound);
1966 lstrcatW(tmp, nl);
1967 lstrcatW(tmp, lpstrMsg);
1969 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1970 return FALSE;
1973 /* move to the next file in the list of files */
1974 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1975 COMDLG32_SHFree(pidl);
1979 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1980 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1982 /* For "oldstyle" dialog the components have to
1983 be separated by blanks (not '\0'!) and short
1984 filenames have to be used! */
1985 FIXME("Components have to be separated by blanks\n");
1987 if(fodInfos->unicode)
1989 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1990 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1991 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1993 else
1995 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1997 if (ofn->lpstrFile != NULL)
1999 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2000 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2001 if (ofn->nMaxFile > nSizePath)
2003 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2004 ofn->lpstrFile + nSizePath,
2005 ofn->nMaxFile - nSizePath, NULL, NULL);
2010 fodInfos->ofnInfos->nFileOffset = nSizePath;
2011 fodInfos->ofnInfos->nFileExtension = 0;
2013 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2014 return FALSE;
2016 /* clean and exit */
2017 FILEDLG95_Clean(hwnd);
2018 return EndDialog(hwnd,TRUE);
2021 /* Returns the 'slot name' of the given module_name in the registry's
2022 * most-recently-used list. This will be an ASCII value in the
2023 * range ['a','z'). Returns zero on error.
2025 * The slot's value in the registry has the form:
2026 * module_name\0mru_path\0
2028 * If stored_path is given, then stored_path will contain the path name
2029 * stored in the registry's MRU list for the given module_name.
2031 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2032 * MRU list key for the given module_name.
2034 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2036 WCHAR mru_list[32], *cur_mru_slot;
2037 BOOL taken[25] = {0};
2038 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2039 HKEY hkey_tmp, *hkey;
2040 LONG ret;
2042 if(hkey_ret)
2043 hkey = hkey_ret;
2044 else
2045 hkey = &hkey_tmp;
2047 if(stored_path)
2048 *stored_path = '\0';
2050 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2051 if(ret){
2052 WARN("Unable to create MRU key: %d\n", ret);
2053 return 0;
2056 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2057 (LPBYTE)mru_list, &mru_list_size);
2058 if(ret || key_type != REG_SZ){
2059 if(ret == ERROR_FILE_NOT_FOUND)
2060 return 'a';
2062 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2063 RegCloseKey(*hkey);
2064 return 0;
2067 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2068 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2069 DWORD value_data_size = sizeof(value_data);
2071 *value_name = *cur_mru_slot;
2073 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2074 &key_type, (LPBYTE)value_data, &value_data_size);
2075 if(ret || key_type != REG_BINARY){
2076 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2077 continue;
2080 if(!strcmpiW(module_name, value_data)){
2081 if(!hkey_ret)
2082 RegCloseKey(*hkey);
2083 if(stored_path)
2084 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2085 return *value_name;
2089 if(!hkey_ret)
2090 RegCloseKey(*hkey);
2092 /* the module name isn't in the registry, so find the next open slot */
2093 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2094 taken[*cur_mru_slot - 'a'] = TRUE;
2095 for(i = 0; i < 25; ++i){
2096 if(!taken[i])
2097 return i + 'a';
2100 /* all slots are taken, so return the last one in MRUList */
2101 --cur_mru_slot;
2102 return *cur_mru_slot;
2105 /* save the given filename as most-recently-used path for this module */
2106 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2108 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2109 LONG ret;
2110 HKEY hkey;
2112 /* get the current executable's name */
2113 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2114 WARN("GotModuleFileName failed: %d\n", GetLastError());
2115 return;
2117 module_name = strrchrW(module_path, '\\');
2118 if(!module_name)
2119 module_name = module_path;
2120 else
2121 module_name += 1;
2123 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2124 if(!slot)
2125 return;
2126 *slot_name = slot;
2128 { /* update the slot's info */
2129 WCHAR *path_ends, *final;
2130 DWORD path_len, final_len;
2132 /* use only the path segment of `filename' */
2133 path_ends = strrchrW(filename, '\\');
2134 path_len = path_ends - filename;
2136 final_len = path_len + lstrlenW(module_name) + 2;
2138 final = MemAlloc(final_len * sizeof(WCHAR));
2139 if(!final)
2140 return;
2141 lstrcpyW(final, module_name);
2142 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2143 final[final_len-1] = '\0';
2145 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2146 final_len * sizeof(WCHAR));
2147 if(ret){
2148 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2149 MemFree(final);
2150 RegCloseKey(hkey);
2151 return;
2154 MemFree(final);
2157 { /* update MRUList value */
2158 WCHAR old_mru_list[32], new_mru_list[32];
2159 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2160 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2162 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2163 (LPBYTE)old_mru_list, &mru_list_size);
2164 if(ret || key_type != REG_SZ){
2165 if(ret == ERROR_FILE_NOT_FOUND){
2166 new_mru_list[0] = slot;
2167 new_mru_list[1] = '\0';
2168 }else{
2169 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2170 RegCloseKey(hkey);
2171 return;
2173 }else{
2174 /* copy old list data over so that the new slot is at the start
2175 * of the list */
2176 *new_mru_slot++ = slot;
2177 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2178 if(*old_mru_slot != slot)
2179 *new_mru_slot++ = *old_mru_slot;
2181 *new_mru_slot = '\0';
2184 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2185 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2186 if(ret){
2187 WARN("Error saving MRUList data: %d\n", ret);
2188 RegCloseKey(hkey);
2189 return;
2194 /* load the most-recently-used path for this module */
2195 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2197 WCHAR module_path[MAX_PATH], *module_name;
2199 /* get the current executable's name */
2200 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2201 WARN("GotModuleFileName failed: %d\n", GetLastError());
2202 return;
2204 module_name = strrchrW(module_path, '\\');
2205 if(!module_name)
2206 module_name = module_path;
2207 else
2208 module_name += 1;
2210 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2211 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2214 /***********************************************************************
2215 * FILEDLG95_OnOpen
2217 * Ok button WM_COMMAND message handler
2219 * If the function succeeds, the return value is nonzero.
2221 #define ONOPEN_BROWSE 1
2222 #define ONOPEN_OPEN 2
2223 #define ONOPEN_SEARCH 3
2224 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2226 WCHAR strMsgTitle[MAX_PATH];
2227 WCHAR strMsgText [MAX_PATH];
2228 if (idCaption)
2229 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2230 else
2231 strMsgTitle[0] = '\0';
2232 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2233 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2236 BOOL FILEDLG95_OnOpen(HWND hwnd)
2238 LPWSTR lpstrFileList;
2239 UINT nFileCount = 0;
2240 UINT sizeUsed = 0;
2241 BOOL ret = TRUE;
2242 WCHAR lpstrPathAndFile[MAX_PATH];
2243 LPSHELLFOLDER lpsf = NULL;
2244 int nOpenAction;
2245 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2247 TRACE("hwnd=%p\n", hwnd);
2249 /* try to browse the selected item */
2250 if(BrowseSelectedFolder(hwnd))
2251 return FALSE;
2253 /* get the files from the edit control */
2254 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2256 if(nFileCount == 0)
2257 return FALSE;
2259 if(nFileCount > 1)
2261 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2262 goto ret;
2265 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2268 Step 1: Build a complete path name from the current folder and
2269 the filename or path in the edit box.
2270 Special cases:
2271 - the path in the edit box is a root path
2272 (with or without drive letter)
2273 - the edit box contains ".." (or a path with ".." in it)
2276 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2277 MemFree(lpstrFileList);
2280 Step 2: here we have a cleaned up path
2282 We have to parse the path step by step to see if we have to browse
2283 to a folder if the path points to a directory or the last
2284 valid element is a directory.
2286 valid variables:
2287 lpstrPathAndFile: cleaned up path
2290 if (nFileCount &&
2291 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2292 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2293 nOpenAction = ONOPEN_OPEN;
2294 else
2295 nOpenAction = ONOPEN_BROWSE;
2297 /* don't apply any checks with OFN_NOVALIDATE */
2299 LPWSTR lpszTemp, lpszTemp1;
2300 LPITEMIDLIST pidl = NULL;
2301 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2303 /* check for invalid chars */
2304 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2306 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2307 ret = FALSE;
2308 goto ret;
2311 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2313 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2314 while (lpszTemp1)
2316 LPSHELLFOLDER lpsfChild;
2317 WCHAR lpwstrTemp[MAX_PATH];
2318 DWORD dwEaten, dwAttributes;
2319 LPWSTR p;
2321 lstrcpyW(lpwstrTemp, lpszTemp);
2322 p = PathFindNextComponentW(lpwstrTemp);
2324 if (!p) break; /* end of path */
2326 *p = 0;
2327 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2329 /* There are no wildcards when OFN_NOVALIDATE is set */
2330 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2332 static const WCHAR wszWild[] = { '*', '?', 0 };
2333 /* if the last element is a wildcard do a search */
2334 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2336 nOpenAction = ONOPEN_SEARCH;
2337 break;
2340 lpszTemp1 = lpszTemp;
2342 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2344 /* append a backslash to drive letters */
2345 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2346 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2347 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2349 PathAddBackslashW(lpwstrTemp);
2352 dwAttributes = SFGAO_FOLDER;
2353 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2355 /* the path component is valid, we have a pidl of the next path component */
2356 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2357 if(dwAttributes & SFGAO_FOLDER)
2359 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2361 ERR("bind to failed\n"); /* should not fail */
2362 break;
2364 IShellFolder_Release(lpsf);
2365 lpsf = lpsfChild;
2366 lpsfChild = NULL;
2368 else
2370 TRACE("value\n");
2372 /* end dialog, return value */
2373 nOpenAction = ONOPEN_OPEN;
2374 break;
2376 COMDLG32_SHFree(pidl);
2377 pidl = NULL;
2379 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2381 if(*lpszTemp || /* points to trailing null for last path element */
2382 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2384 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2386 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2387 break;
2390 else
2392 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2393 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2395 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2396 break;
2399 /* change to the current folder */
2400 nOpenAction = ONOPEN_OPEN;
2401 break;
2403 else
2405 nOpenAction = ONOPEN_OPEN;
2406 break;
2409 if(pidl) COMDLG32_SHFree(pidl);
2413 Step 3: here we have a cleaned up and validated path
2415 valid variables:
2416 lpsf: ShellFolder bound to the rightmost valid path component
2417 lpstrPathAndFile: cleaned up path
2418 nOpenAction: action to do
2420 TRACE("end validate sf=%p\n", lpsf);
2422 switch(nOpenAction)
2424 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2425 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2427 int iPos;
2428 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2429 DWORD len;
2431 /* replace the current filter */
2432 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2433 len = lstrlenW(lpszTemp)+1;
2434 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2435 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2437 /* set the filter cb to the extension when possible */
2438 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2439 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2441 /* fall through */
2442 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2443 TRACE("ONOPEN_BROWSE\n");
2445 IPersistFolder2 * ppf2;
2446 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2448 LPITEMIDLIST pidlCurrent;
2449 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2450 IPersistFolder2_Release(ppf2);
2451 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2453 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2454 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2456 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2459 else if( nOpenAction == ONOPEN_SEARCH )
2461 if (fodInfos->Shell.FOIShellView)
2462 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2464 COMDLG32_SHFree(pidlCurrent);
2465 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2468 ret = FALSE;
2469 break;
2470 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2471 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2473 WCHAR *ext = NULL;
2475 /* update READONLY check box flag */
2476 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2477 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2478 else
2479 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2481 /* Attach the file extension with file name*/
2482 ext = PathFindExtensionW(lpstrPathAndFile);
2483 if (! *ext)
2485 /* if no extension is specified with file name, then */
2486 /* attach the extension from file filter or default one */
2488 const WCHAR *filterExt = NULL;
2489 LPWSTR lpstrFilter = NULL;
2490 static const WCHAR szwDot[] = {'.',0};
2491 int PathLength = lstrlenW(lpstrPathAndFile);
2493 /*Get the file extension from file type filter*/
2494 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2495 fodInfos->ofnInfos->nFilterIndex-1);
2497 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2498 filterExt = PathFindExtensionW(lpstrFilter);
2500 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2501 filterExt = filterExt + 1;
2502 else if ( fodInfos->defext ) /* attach the default file extension*/
2503 filterExt = fodInfos->defext;
2505 /* If extension contains a glob, ignore it */
2506 if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
2508 /* Attach the dot*/
2509 lstrcatW(lpstrPathAndFile, szwDot);
2510 /* Attach the extension */
2511 lstrcatW(lpstrPathAndFile, filterExt );
2514 /* In Open dialog: if file does not exist try without extension */
2515 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2516 lpstrPathAndFile[PathLength] = '\0';
2519 if (fodInfos->defext) /* add default extension */
2521 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2522 if (*ext)
2523 ext++;
2524 if (!lstrcmpiW(fodInfos->defext, ext))
2525 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2526 else
2527 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2530 /* In Save dialog: check if the file already exists */
2531 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2532 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2533 && PathFileExistsW(lpstrPathAndFile))
2535 WCHAR lpstrOverwrite[100];
2536 int answer;
2538 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2539 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2540 MB_YESNO | MB_ICONEXCLAMATION);
2541 if (answer == IDNO || answer == IDCANCEL)
2543 ret = FALSE;
2544 goto ret;
2548 /* In Open dialog: check if it should be created if it doesn't exist */
2549 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2550 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2551 && !PathFileExistsW(lpstrPathAndFile))
2553 WCHAR lpstrCreate[100];
2554 int answer;
2556 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2557 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2558 MB_YESNO | MB_ICONEXCLAMATION);
2559 if (answer == IDNO || answer == IDCANCEL)
2561 ret = FALSE;
2562 goto ret;
2566 /* Check that the size of the file does not exceed buffer size.
2567 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2568 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2569 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2572 /* fill destination buffer */
2573 if (fodInfos->ofnInfos->lpstrFile)
2575 if(fodInfos->unicode)
2577 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2579 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2580 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2581 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2583 else
2585 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2587 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2588 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2589 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2590 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2594 if(fodInfos->unicode)
2596 LPWSTR lpszTemp;
2598 /* set filename offset */
2599 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2600 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2602 /* set extension offset */
2603 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2604 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2606 else
2608 LPSTR lpszTemp;
2609 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2611 /* set filename offset */
2612 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2613 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2615 /* set extension offset */
2616 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2617 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2620 /* set the lpstrFileTitle */
2621 if(fodInfos->ofnInfos->lpstrFileTitle)
2623 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2624 if(fodInfos->unicode)
2626 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2627 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2629 else
2631 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2632 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2633 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2637 /* copy currently selected filter to lpstrCustomFilter */
2638 if (fodInfos->ofnInfos->lpstrCustomFilter)
2640 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2641 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2642 NULL, 0, NULL, NULL);
2643 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2645 LPSTR s = ofn->lpstrCustomFilter;
2646 s += strlen(ofn->lpstrCustomFilter)+1;
2647 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2648 s, len, NULL, NULL);
2653 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2654 goto ret;
2656 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2658 TRACE("close\n");
2659 FILEDLG95_Clean(hwnd);
2660 ret = EndDialog(hwnd, TRUE);
2662 else
2664 WORD size;
2666 size = lstrlenW(lpstrPathAndFile) + 1;
2667 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2668 size += 1;
2669 /* return needed size in first two bytes of lpstrFile */
2670 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2671 FILEDLG95_Clean(hwnd);
2672 ret = EndDialog(hwnd, FALSE);
2673 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2676 break;
2679 ret:
2680 if(lpsf) IShellFolder_Release(lpsf);
2681 return ret;
2684 /***********************************************************************
2685 * FILEDLG95_SHELL_Init
2687 * Initialisation of the shell objects
2689 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2691 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2693 TRACE("\n");
2696 * Initialisation of the FileOpenDialogInfos structure
2699 /* Shell */
2701 /*ShellInfos */
2702 fodInfos->ShellInfos.hwndOwner = hwnd;
2704 /* Disable multi-select if flag not set */
2705 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2707 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2709 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2710 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2712 /* Construct the IShellBrowser interface */
2713 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2715 return NOERROR;
2718 /***********************************************************************
2719 * FILEDLG95_SHELL_ExecuteCommand
2721 * Change the folder option and refresh the view
2722 * If the function succeeds, the return value is nonzero.
2724 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2726 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2727 IContextMenu * pcm;
2729 TRACE("(%p,%p)\n", hwnd, lpVerb);
2731 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2732 SVGIO_BACKGROUND,
2733 &IID_IContextMenu,
2734 (LPVOID*)&pcm)))
2736 CMINVOKECOMMANDINFO ci;
2737 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2738 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2739 ci.lpVerb = lpVerb;
2740 ci.hwnd = hwnd;
2742 IContextMenu_InvokeCommand(pcm, &ci);
2743 IContextMenu_Release(pcm);
2746 return FALSE;
2749 /***********************************************************************
2750 * FILEDLG95_SHELL_UpFolder
2752 * Browse to the specified object
2753 * If the function succeeds, the return value is nonzero.
2755 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2757 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2759 TRACE("\n");
2761 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2762 NULL,
2763 SBSP_PARENT)))
2765 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2766 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2767 return TRUE;
2769 return FALSE;
2772 /***********************************************************************
2773 * FILEDLG95_SHELL_BrowseToDesktop
2775 * Browse to the Desktop
2776 * If the function succeeds, the return value is nonzero.
2778 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2780 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2781 LPITEMIDLIST pidl;
2782 HRESULT hres;
2784 TRACE("\n");
2786 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2787 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2788 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2789 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2790 COMDLG32_SHFree(pidl);
2791 return SUCCEEDED(hres);
2793 /***********************************************************************
2794 * FILEDLG95_SHELL_Clean
2796 * Cleans the memory used by shell objects
2798 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2800 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2802 TRACE("\n");
2804 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2806 /* clean Shell interfaces */
2807 if (fodInfos->Shell.FOIShellView)
2809 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2810 IShellView_Release(fodInfos->Shell.FOIShellView);
2812 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2813 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2814 if (fodInfos->Shell.FOIDataObject)
2815 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2818 /***********************************************************************
2819 * FILEDLG95_FILETYPE_Init
2821 * Initialisation of the file type combo box
2823 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2825 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2826 int nFilters = 0; /* number of filters */
2827 int nFilterIndexCB;
2829 TRACE("\n");
2831 if(fodInfos->customfilter)
2833 /* customfilter has one entry... title\0ext\0
2834 * Set first entry of combo box item with customfilter
2836 LPWSTR lpstrExt;
2837 LPCWSTR lpstrPos = fodInfos->customfilter;
2839 /* Get the title */
2840 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2842 /* Copy the extensions */
2843 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2844 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2845 lstrcpyW(lpstrExt,lpstrPos);
2847 /* Add the item at the end of the combo */
2848 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2849 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2850 nFilters++;
2852 if(fodInfos->filter)
2854 LPCWSTR lpstrPos = fodInfos->filter;
2856 for(;;)
2858 /* filter is a list... title\0ext\0......\0\0
2859 * Set the combo item text to the title and the item data
2860 * to the ext
2862 LPCWSTR lpstrDisplay;
2863 LPWSTR lpstrExt;
2865 /* Get the title */
2866 if(! *lpstrPos) break; /* end */
2867 lpstrDisplay = lpstrPos;
2868 lpstrPos += lstrlenW(lpstrPos) + 1;
2870 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2872 nFilters++;
2874 /* Copy the extensions */
2875 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2876 lstrcpyW(lpstrExt,lpstrPos);
2877 lpstrPos += lstrlenW(lpstrPos) + 1;
2879 /* Add the item at the end of the combo */
2880 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2882 /* malformed filters are added anyway... */
2883 if (!*lpstrExt) break;
2888 * Set the current filter to the one specified
2889 * in the initialisation structure
2891 if (fodInfos->filter || fodInfos->customfilter)
2893 LPWSTR lpstrFilter;
2895 /* Check to make sure our index isn't out of bounds. */
2896 if ( fodInfos->ofnInfos->nFilterIndex >
2897 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2898 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2900 /* set default filter index */
2901 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2902 fodInfos->ofnInfos->nFilterIndex = 1;
2904 /* calculate index of Combo Box item */
2905 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2906 if (fodInfos->customfilter == NULL)
2907 nFilterIndexCB--;
2909 /* Set the current index selection. */
2910 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2912 /* Get the corresponding text string from the combo box. */
2913 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2914 nFilterIndexCB);
2916 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2917 lpstrFilter = NULL;
2919 if(lpstrFilter)
2921 DWORD len;
2922 CharLowerW(lpstrFilter); /* lowercase */
2923 len = lstrlenW(lpstrFilter)+1;
2924 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2925 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2927 } else
2928 fodInfos->ofnInfos->nFilterIndex = 0;
2929 return S_OK;
2932 /***********************************************************************
2933 * FILEDLG95_FILETYPE_OnCommand
2935 * WM_COMMAND of the file type combo box
2936 * If the function succeeds, the return value is nonzero.
2938 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2940 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2942 switch(wNotifyCode)
2944 case CBN_SELENDOK:
2946 LPWSTR lpstrFilter;
2948 /* Get the current item of the filetype combo box */
2949 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2951 /* set the current filter index */
2952 fodInfos->ofnInfos->nFilterIndex = iItem +
2953 (fodInfos->customfilter == NULL ? 1 : 0);
2955 /* Set the current filter with the current selection */
2956 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2958 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2959 iItem);
2960 if((INT_PTR)lpstrFilter != CB_ERR)
2962 DWORD len;
2963 CharLowerW(lpstrFilter); /* lowercase */
2964 len = lstrlenW(lpstrFilter)+1;
2965 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2966 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2967 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2968 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2971 /* Refresh the actual view to display the included items*/
2972 if (fodInfos->Shell.FOIShellView)
2973 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2976 return FALSE;
2978 /***********************************************************************
2979 * FILEDLG95_FILETYPE_SearchExt
2981 * searches for an extension in the filetype box
2983 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2985 int i, iCount = CBGetCount(hwnd);
2987 TRACE("%s\n", debugstr_w(lpstrExt));
2989 if(iCount != CB_ERR)
2991 for(i=0;i<iCount;i++)
2993 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2994 return i;
2997 return -1;
3000 /***********************************************************************
3001 * FILEDLG95_FILETYPE_Clean
3003 * Clean the memory used by the filetype combo box
3005 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3007 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3008 int iPos;
3009 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3011 TRACE("\n");
3013 /* Delete each string of the combo and their associated data */
3014 if(iCount != CB_ERR)
3016 for(iPos = iCount-1;iPos>=0;iPos--)
3018 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3019 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3022 /* Current filter */
3023 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3027 /***********************************************************************
3028 * FILEDLG95_LOOKIN_Init
3030 * Initialisation of the look in combo box
3033 /* Small helper function, to determine if the unixfs shell extension is rooted
3034 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3036 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3037 HKEY hKey;
3038 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3039 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3040 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3041 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3042 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3043 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3044 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3046 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3047 return FALSE;
3049 RegCloseKey(hKey);
3050 return TRUE;
3053 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3055 IShellFolder *psfRoot, *psfDrives;
3056 IEnumIDList *lpeRoot, *lpeDrives;
3057 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3059 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3061 TRACE("\n");
3063 liInfos->iMaxIndentation = 0;
3065 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3067 /* set item height for both text field and listbox */
3068 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3069 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3071 /* Turn on the extended UI for the combo box like Windows does */
3072 CBSetExtendedUI(hwndCombo, TRUE);
3074 /* Initialise data of Desktop folder */
3075 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3076 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3077 COMDLG32_SHFree(pidlTmp);
3079 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3081 SHGetDesktopFolder(&psfRoot);
3083 if (psfRoot)
3085 /* enumerate the contents of the desktop */
3086 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3088 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3090 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3092 /* If the unixfs extension is rooted, we don't expand the drives by default */
3093 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3095 /* special handling for CSIDL_DRIVES */
3096 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3098 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3100 /* enumerate the drives */
3101 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3103 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3105 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3106 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3107 COMDLG32_SHFree(pidlAbsTmp);
3108 COMDLG32_SHFree(pidlTmp1);
3110 IEnumIDList_Release(lpeDrives);
3112 IShellFolder_Release(psfDrives);
3117 COMDLG32_SHFree(pidlTmp);
3119 IEnumIDList_Release(lpeRoot);
3121 IShellFolder_Release(psfRoot);
3124 COMDLG32_SHFree(pidlDrives);
3127 /***********************************************************************
3128 * FILEDLG95_LOOKIN_DrawItem
3130 * WM_DRAWITEM message handler
3132 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3134 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3135 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3136 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3137 RECT rectText;
3138 RECT rectIcon;
3139 SHFILEINFOW sfi;
3140 HIMAGELIST ilItemImage;
3141 int iIndentation;
3142 TEXTMETRICW tm;
3143 LPSFOLDER tmpFolder;
3144 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3146 TRACE("\n");
3148 if(pDIStruct->itemID == -1)
3149 return 0;
3151 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3152 pDIStruct->itemID)))
3153 return 0;
3156 if(pDIStruct->itemID == liInfos->uSelectedItem)
3158 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3160 &sfi,
3161 sizeof (sfi),
3162 SHGFI_PIDL | SHGFI_SMALLICON |
3163 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3164 SHGFI_DISPLAYNAME );
3166 else
3168 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3170 &sfi,
3171 sizeof (sfi),
3172 SHGFI_PIDL | SHGFI_SMALLICON |
3173 SHGFI_SYSICONINDEX |
3174 SHGFI_DISPLAYNAME);
3177 /* Is this item selected ? */
3178 if(pDIStruct->itemState & ODS_SELECTED)
3180 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3181 SetBkColor(pDIStruct->hDC,crHighLight);
3182 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3184 else
3186 SetTextColor(pDIStruct->hDC,crText);
3187 SetBkColor(pDIStruct->hDC,crWin);
3188 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3191 /* Do not indent item if drawing in the edit of the combo */
3192 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3194 iIndentation = 0;
3195 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3197 &sfi,
3198 sizeof (sfi),
3199 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3200 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3203 else
3205 iIndentation = tmpFolder->m_iIndent;
3207 /* Draw text and icon */
3209 /* Initialise the icon display area */
3210 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3211 rectIcon.top = pDIStruct->rcItem.top;
3212 rectIcon.right = rectIcon.left + ICONWIDTH;
3213 rectIcon.bottom = pDIStruct->rcItem.bottom;
3215 /* Initialise the text display area */
3216 GetTextMetricsW(pDIStruct->hDC, &tm);
3217 rectText.left = rectIcon.right;
3218 rectText.top =
3219 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3220 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3221 rectText.bottom =
3222 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3224 /* Draw the icon from the image list */
3225 ImageList_Draw(ilItemImage,
3226 sfi.iIcon,
3227 pDIStruct->hDC,
3228 rectIcon.left,
3229 rectIcon.top,
3230 ILD_TRANSPARENT );
3232 /* Draw the associated text */
3233 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3234 return NOERROR;
3237 /***********************************************************************
3238 * FILEDLG95_LOOKIN_OnCommand
3240 * LookIn combo box WM_COMMAND message handler
3241 * If the function succeeds, the return value is nonzero.
3243 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3245 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3247 TRACE("%p\n", fodInfos);
3249 switch(wNotifyCode)
3251 case CBN_SELENDOK:
3253 LPSFOLDER tmpFolder;
3254 int iItem;
3256 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3258 if( iItem == CB_ERR) return FALSE;
3260 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3261 iItem)))
3262 return FALSE;
3265 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3266 tmpFolder->pidlItem,
3267 SBSP_ABSOLUTE)))
3269 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3270 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3271 return TRUE;
3273 break;
3277 return FALSE;
3280 /***********************************************************************
3281 * FILEDLG95_LOOKIN_AddItem
3283 * Adds an absolute pidl item to the lookin combo box
3284 * returns the index of the inserted item
3286 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3288 LPITEMIDLIST pidlNext;
3289 SHFILEINFOW sfi;
3290 SFOLDER *tmpFolder;
3291 LookInInfos *liInfos;
3293 TRACE("%08x\n", iInsertId);
3295 if(!pidl)
3296 return -1;
3298 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3299 return -1;
3301 tmpFolder = MemAlloc(sizeof(SFOLDER));
3302 tmpFolder->m_iIndent = 0;
3304 /* Calculate the indentation of the item in the lookin*/
3305 pidlNext = pidl;
3306 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3308 tmpFolder->m_iIndent++;
3311 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3313 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3314 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3316 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3317 SHGetFileInfoW((LPCWSTR)pidl,
3319 &sfi,
3320 sizeof(sfi),
3321 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3322 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3324 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3326 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3328 int iItemID;
3330 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3332 /* Add the item at the end of the list */
3333 if(iInsertId < 0)
3335 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3337 /* Insert the item at the iInsertId position*/
3338 else
3340 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3343 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3344 return iItemID;
3347 COMDLG32_SHFree( tmpFolder->pidlItem );
3348 MemFree( tmpFolder );
3349 return -1;
3353 /***********************************************************************
3354 * FILEDLG95_LOOKIN_InsertItemAfterParent
3356 * Insert an item below its parent
3358 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3361 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3362 int iParentPos;
3364 TRACE("\n");
3366 if (pidl == pidlParent)
3367 return -1;
3369 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3371 if(iParentPos < 0)
3373 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3376 /* Free pidlParent memory */
3377 COMDLG32_SHFree(pidlParent);
3379 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3382 /***********************************************************************
3383 * FILEDLG95_LOOKIN_SelectItem
3385 * Adds an absolute pidl item to the lookin combo box
3386 * returns the index of the inserted item
3388 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3390 int iItemPos;
3391 LookInInfos *liInfos;
3393 TRACE("\n");
3395 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3397 liInfos = GetPropA(hwnd,LookInInfosStr);
3399 if(iItemPos < 0)
3401 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3402 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3405 else
3407 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3408 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3410 int iRemovedItem;
3412 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3413 break;
3414 if(iRemovedItem < iItemPos)
3415 iItemPos--;
3419 CBSetCurSel(hwnd,iItemPos);
3420 liInfos->uSelectedItem = iItemPos;
3422 return 0;
3426 /***********************************************************************
3427 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3429 * Remove the item with an expansion level over iExpansionLevel
3431 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3433 int iItemPos;
3434 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3436 TRACE("\n");
3438 if(liInfos->iMaxIndentation <= 2)
3439 return -1;
3441 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3443 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3444 COMDLG32_SHFree(tmpFolder->pidlItem);
3445 MemFree(tmpFolder);
3446 CBDeleteString(hwnd,iItemPos);
3447 liInfos->iMaxIndentation--;
3449 return iItemPos;
3452 return -1;
3455 /***********************************************************************
3456 * FILEDLG95_LOOKIN_SearchItem
3458 * Search for pidl in the lookin combo box
3459 * returns the index of the found item
3461 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3463 int i = 0;
3464 int iCount = CBGetCount(hwnd);
3466 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3468 if (iCount != CB_ERR)
3470 for(;i<iCount;i++)
3472 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3474 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3475 return i;
3476 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3477 return i;
3481 return -1;
3484 /***********************************************************************
3485 * FILEDLG95_LOOKIN_Clean
3487 * Clean the memory used by the lookin combo box
3489 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3491 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3492 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3493 int iPos;
3494 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3496 TRACE("\n");
3498 /* Delete each string of the combo and their associated data */
3499 if (iCount != CB_ERR)
3501 for(iPos = iCount-1;iPos>=0;iPos--)
3503 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3504 COMDLG32_SHFree(tmpFolder->pidlItem);
3505 MemFree(tmpFolder);
3506 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3510 /* LookInInfos structure */
3511 MemFree(liInfos);
3512 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3515 /***********************************************************************
3516 * FILEDLG95_FILENAME_FillFromSelection
3518 * fills the edit box from the cached DataObject
3520 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3522 FileOpenDlgInfos *fodInfos;
3523 LPITEMIDLIST pidl;
3524 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3525 WCHAR lpstrTemp[MAX_PATH];
3526 LPWSTR lpstrAllFile, lpstrCurrFile;
3528 TRACE("\n");
3529 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3531 /* Count how many files we have */
3532 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3534 /* calculate the string length, count files */
3535 if (nFileSelected >= 1)
3537 nLength += 3; /* first and last quotes, trailing \0 */
3538 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3540 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3542 if (pidl)
3544 /* get the total length of the selected file names */
3545 lpstrTemp[0] = '\0';
3546 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3548 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3550 nLength += lstrlenW( lpstrTemp ) + 3;
3551 nFiles++;
3553 COMDLG32_SHFree( pidl );
3558 /* allocate the buffer */
3559 if (nFiles <= 1) nLength = MAX_PATH;
3560 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3562 /* Generate the string for the edit control */
3563 if(nFiles >= 1)
3565 lpstrCurrFile = lpstrAllFile;
3566 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3568 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3570 if (pidl)
3572 /* get the file name */
3573 lpstrTemp[0] = '\0';
3574 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3576 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3578 if ( nFiles > 1)
3580 *lpstrCurrFile++ = '\"';
3581 lstrcpyW( lpstrCurrFile, lpstrTemp );
3582 lpstrCurrFile += lstrlenW( lpstrTemp );
3583 *lpstrCurrFile++ = '\"';
3584 *lpstrCurrFile++ = ' ';
3585 *lpstrCurrFile = 0;
3587 else
3589 lstrcpyW( lpstrAllFile, lpstrTemp );
3592 COMDLG32_SHFree( pidl );
3595 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3597 /* Select the file name like Windows does */
3598 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3600 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3604 /* copied from shell32 to avoid linking to it
3605 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3606 * is dependent on whether emulated OS is unicode or not.
3608 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3610 switch (src->uType)
3612 case STRRET_WSTR:
3613 lstrcpynW(dest, src->u.pOleStr, len);
3614 COMDLG32_SHFree(src->u.pOleStr);
3615 break;
3617 case STRRET_CSTR:
3618 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3619 dest[len-1] = 0;
3620 break;
3622 case STRRET_OFFSET:
3623 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3624 dest[len-1] = 0;
3625 break;
3627 default:
3628 FIXME("unknown type %x!\n", src->uType);
3629 if (len) *dest = '\0';
3630 return E_FAIL;
3632 return S_OK;
3635 /***********************************************************************
3636 * FILEDLG95_FILENAME_GetFileNames
3638 * Copies the filenames to a delimited string list.
3639 * The delimiter is specified by the parameter 'separator',
3640 * usually either a space or a nul
3642 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3644 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3645 UINT nStrCharCount = 0; /* index in src buffer */
3646 UINT nFileIndex = 0; /* index in dest buffer */
3647 UINT nFileCount = 0; /* number of files */
3648 UINT nStrLen = 0; /* length of string in edit control */
3649 LPWSTR lpstrEdit; /* buffer for string from edit control */
3651 TRACE("\n");
3653 /* get the filenames from the edit control */
3654 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3655 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3656 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3658 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3660 /* we might get single filename without any '"',
3661 * so we need nStrLen + terminating \0 + end-of-list \0 */
3662 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3663 *sizeUsed = 0;
3665 /* build delimited file list from filenames */
3666 while ( nStrCharCount <= nStrLen )
3668 if ( lpstrEdit[nStrCharCount]=='"' )
3670 nStrCharCount++;
3671 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3673 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3674 nStrCharCount++;
3676 (*lpstrFileList)[nFileIndex++] = 0;
3677 nFileCount++;
3679 nStrCharCount++;
3682 /* single, unquoted string */
3683 if ((nStrLen > 0) && (nFileIndex == 0) )
3685 lstrcpyW(*lpstrFileList, lpstrEdit);
3686 nFileIndex = lstrlenW(lpstrEdit) + 1;
3687 nFileCount = 1;
3690 /* trailing \0 */
3691 (*lpstrFileList)[nFileIndex++] = '\0';
3693 *sizeUsed = nFileIndex;
3694 MemFree(lpstrEdit);
3695 return nFileCount;
3698 #define SETDefFormatEtc(fe,cf,med) \
3700 (fe).cfFormat = cf;\
3701 (fe).dwAspect = DVASPECT_CONTENT; \
3702 (fe).ptd =NULL;\
3703 (fe).tymed = med;\
3704 (fe).lindex = -1;\
3708 * DATAOBJECT Helper functions
3711 /***********************************************************************
3712 * COMCTL32_ReleaseStgMedium
3714 * like ReleaseStgMedium from ole32
3716 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3718 if(medium.pUnkForRelease)
3720 IUnknown_Release(medium.pUnkForRelease);
3722 else
3724 GlobalUnlock(medium.u.hGlobal);
3725 GlobalFree(medium.u.hGlobal);
3729 /***********************************************************************
3730 * GetPidlFromDataObject
3732 * Return pidl(s) by number from the cached DataObject
3734 * nPidlIndex=0 gets the fully qualified root path
3736 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3739 STGMEDIUM medium;
3740 FORMATETC formatetc;
3741 LPITEMIDLIST pidl = NULL;
3743 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3745 if (!doSelected)
3746 return NULL;
3748 /* Set the FORMATETC structure*/
3749 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3751 /* Get the pidls from IDataObject */
3752 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3754 LPIDA cida = GlobalLock(medium.u.hGlobal);
3755 if(nPidlIndex <= cida->cidl)
3757 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3759 COMCTL32_ReleaseStgMedium(medium);
3761 return pidl;
3764 /***********************************************************************
3765 * GetNumSelected
3767 * Return the number of selected items in the DataObject.
3770 static UINT GetNumSelected( IDataObject *doSelected )
3772 UINT retVal = 0;
3773 STGMEDIUM medium;
3774 FORMATETC formatetc;
3776 TRACE("sv=%p\n", doSelected);
3778 if (!doSelected) return 0;
3780 /* Set the FORMATETC structure*/
3781 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3783 /* Get the pidls from IDataObject */
3784 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3786 LPIDA cida = GlobalLock(medium.u.hGlobal);
3787 retVal = cida->cidl;
3788 COMCTL32_ReleaseStgMedium(medium);
3789 return retVal;
3791 return 0;
3795 * TOOLS
3798 /***********************************************************************
3799 * GetName
3801 * Get the pidl's display name (relative to folder) and
3802 * put it in lpstrFileName.
3804 * Return NOERROR on success,
3805 * E_FAIL otherwise
3808 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3810 STRRET str;
3811 HRESULT hRes;
3813 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3815 if(!lpsf)
3817 SHGetDesktopFolder(&lpsf);
3818 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3819 IShellFolder_Release(lpsf);
3820 return hRes;
3823 /* Get the display name of the pidl relative to the folder */
3824 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3826 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3828 return E_FAIL;
3831 /***********************************************************************
3832 * GetShellFolderFromPidl
3834 * pidlRel is the item pidl relative
3835 * Return the IShellFolder of the absolute pidl
3837 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3839 IShellFolder *psf = NULL,*psfParent;
3841 TRACE("%p\n", pidlAbs);
3843 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3845 psf = psfParent;
3846 if(pidlAbs && pidlAbs->mkid.cb)
3848 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3850 IShellFolder_Release(psfParent);
3851 return psf;
3854 /* return the desktop */
3855 return psfParent;
3857 return NULL;
3860 /***********************************************************************
3861 * GetParentPidl
3863 * Return the LPITEMIDLIST to the parent of the pidl in the list
3865 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3867 LPITEMIDLIST pidlParent;
3869 TRACE("%p\n", pidl);
3871 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3872 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3874 return pidlParent;
3877 /***********************************************************************
3878 * GetPidlFromName
3880 * returns the pidl of the file name relative to folder
3881 * NULL if an error occurred
3883 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3885 LPITEMIDLIST pidl = NULL;
3886 ULONG ulEaten;
3888 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3890 if(!lpcstrFileName) return NULL;
3891 if(!*lpcstrFileName) return NULL;
3893 if(!lpsf)
3895 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3896 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3897 IShellFolder_Release(lpsf);
3900 else
3902 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3904 return pidl;
3909 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3911 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3912 HRESULT ret;
3914 TRACE("%p, %p\n", psf, pidl);
3916 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3918 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3919 /* see documentation shell 4.1*/
3920 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3923 /***********************************************************************
3924 * BrowseSelectedFolder
3926 static BOOL BrowseSelectedFolder(HWND hwnd)
3928 BOOL bBrowseSelFolder = FALSE;
3929 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3931 TRACE("\n");
3933 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3935 LPITEMIDLIST pidlSelection;
3937 /* get the file selected */
3938 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3939 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3941 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3942 pidlSelection, SBSP_RELATIVE ) ) )
3944 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3945 ' ','n','o','t',' ','e','x','i','s','t',0};
3946 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3948 bBrowseSelFolder = TRUE;
3949 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3950 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3952 COMDLG32_SHFree( pidlSelection );
3955 return bBrowseSelFolder;
3959 * Memory allocation methods */
3960 static void *MemAlloc(UINT size)
3962 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3965 static void MemFree(void *mem)
3967 HeapFree(GetProcessHeap(),0,mem);
3971 * Old-style (win3.1) dialogs */
3973 /***********************************************************************
3974 * FD32_GetTemplate [internal]
3976 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3977 * by a 32 bits application
3980 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3982 LPOPENFILENAMEW ofnW = lfs->ofnW;
3983 LPOPENFILENAMEA ofnA = lfs->ofnA;
3984 HANDLE hDlgTmpl;
3986 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3988 if (!(lfs->template = LockResource( ofnW->hInstance )))
3990 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3991 return FALSE;
3994 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3996 HRSRC hResInfo;
3997 if (ofnA)
3998 hResInfo = FindResourceA(ofnA->hInstance,
3999 ofnA->lpTemplateName,
4000 (LPSTR)RT_DIALOG);
4001 else
4002 hResInfo = FindResourceW(ofnW->hInstance,
4003 ofnW->lpTemplateName,
4004 (LPWSTR)RT_DIALOG);
4005 if (!hResInfo)
4007 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4008 return FALSE;
4010 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4011 hResInfo)) ||
4012 !(lfs->template = LockResource(hDlgTmpl)))
4014 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4015 return FALSE;
4017 } else { /* get it from internal Wine resource */
4018 HRSRC hResInfo;
4019 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4020 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4022 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4023 return FALSE;
4025 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4026 !(lfs->template = LockResource( hDlgTmpl )))
4028 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4029 return FALSE;
4032 return TRUE;
4036 /***********************************************************************
4037 * FD32_WMMeasureItem [internal]
4039 static LONG FD32_WMMeasureItem(LPARAM lParam)
4041 LPMEASUREITEMSTRUCT lpmeasure;
4043 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4044 lpmeasure->itemHeight = FD31_GetFldrHeight();
4045 return TRUE;
4049 /***********************************************************************
4050 * FileOpenDlgProc [internal]
4051 * Used for open and save, in fact.
4053 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4054 WPARAM wParam, LPARAM lParam)
4056 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4058 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4059 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4061 INT_PTR lRet;
4062 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4063 if (lRet)
4064 return lRet; /* else continue message processing */
4066 switch (wMsg)
4068 case WM_INITDIALOG:
4069 return FD31_WMInitDialog(hWnd, wParam, lParam);
4071 case WM_MEASUREITEM:
4072 return FD32_WMMeasureItem(lParam);
4074 case WM_DRAWITEM:
4075 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4077 case WM_COMMAND:
4078 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4079 #if 0
4080 case WM_CTLCOLOR:
4081 SetBkColor((HDC16)wParam, 0x00C0C0C0);
4082 switch (HIWORD(lParam))
4084 case CTLCOLOR_BTN:
4085 SetTextColor((HDC16)wParam, 0x00000000);
4086 return hGRAYBrush;
4087 case CTLCOLOR_STATIC:
4088 SetTextColor((HDC16)wParam, 0x00000000);
4089 return hGRAYBrush;
4091 break;
4092 #endif
4094 return FALSE;
4098 /***********************************************************************
4099 * GetFileName31A [internal]
4101 * Creates a win31 style dialog box for the user to select a file to open/save.
4103 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4104 UINT dlgType /* type dialogue : open/save */
4107 BOOL bRet = FALSE;
4108 PFD31_DATA lfs;
4110 if (!lpofn || !FD31_Init()) return FALSE;
4112 TRACE("ofn flags %08x\n", lpofn->Flags);
4113 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4114 if (lfs)
4116 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4117 FD32_FileOpenDlgProc, (LPARAM)lfs);
4118 FD31_DestroyPrivate(lfs);
4121 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4122 return bRet;
4125 /***********************************************************************
4126 * GetFileName31W [internal]
4128 * Creates a win31 style dialog box for the user to select a file to open/save
4130 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4131 UINT dlgType /* type dialogue : open/save */
4134 BOOL bRet = FALSE;
4135 PFD31_DATA lfs;
4137 if (!lpofn || !FD31_Init()) return FALSE;
4139 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4140 if (lfs)
4142 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4143 FD32_FileOpenDlgProc, (LPARAM)lfs);
4144 FD31_DestroyPrivate(lfs);
4147 TRACE("file %s, file offset %d, ext offset %d\n",
4148 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4149 return bRet;
4152 /* ------------------ APIs ---------------------- */
4154 /***********************************************************************
4155 * GetOpenFileNameA (COMDLG32.@)
4157 * Creates a dialog box for the user to select a file to open.
4159 * RETURNS
4160 * TRUE on success: user enters a valid file
4161 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4164 BOOL WINAPI GetOpenFileNameA(
4165 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4167 BOOL win16look = FALSE;
4169 TRACE("flags %08x\n", ofn->Flags);
4171 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4172 if (ofn->Flags & OFN_FILEMUSTEXIST)
4173 ofn->Flags |= OFN_PATHMUSTEXIST;
4175 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4176 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4178 if (win16look)
4179 return GetFileName31A(ofn, OPEN_DIALOG);
4180 else
4181 return GetFileDialog95A(ofn, OPEN_DIALOG);
4184 /***********************************************************************
4185 * GetOpenFileNameW (COMDLG32.@)
4187 * Creates a dialog box for the user to select a file to open.
4189 * RETURNS
4190 * TRUE on success: user enters a valid file
4191 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4194 BOOL WINAPI GetOpenFileNameW(
4195 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4197 BOOL win16look = FALSE;
4199 TRACE("flags %08x\n", ofn->Flags);
4201 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4202 if (ofn->Flags & OFN_FILEMUSTEXIST)
4203 ofn->Flags |= OFN_PATHMUSTEXIST;
4205 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4206 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4208 if (win16look)
4209 return GetFileName31W(ofn, OPEN_DIALOG);
4210 else
4211 return GetFileDialog95W(ofn, OPEN_DIALOG);
4215 /***********************************************************************
4216 * GetSaveFileNameA (COMDLG32.@)
4218 * Creates a dialog box for the user to select a file to save.
4220 * RETURNS
4221 * TRUE on success: user enters a valid file
4222 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4225 BOOL WINAPI GetSaveFileNameA(
4226 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4228 BOOL win16look = FALSE;
4230 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4231 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4233 if (win16look)
4234 return GetFileName31A(ofn, SAVE_DIALOG);
4235 else
4236 return GetFileDialog95A(ofn, SAVE_DIALOG);
4239 /***********************************************************************
4240 * GetSaveFileNameW (COMDLG32.@)
4242 * Creates a dialog box for the user to select a file to save.
4244 * RETURNS
4245 * TRUE on success: user enters a valid file
4246 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4249 BOOL WINAPI GetSaveFileNameW(
4250 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4252 BOOL win16look = FALSE;
4254 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4255 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4257 if (win16look)
4258 return GetFileName31W(ofn, SAVE_DIALOG);
4259 else
4260 return GetFileDialog95W(ofn, SAVE_DIALOG);
4263 /***********************************************************************
4264 * GetFileTitleA (COMDLG32.@)
4266 * See GetFileTitleW.
4268 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4270 int ret;
4271 UNICODE_STRING strWFile;
4272 LPWSTR lpWTitle;
4274 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4275 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4276 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4277 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4278 RtlFreeUnicodeString( &strWFile );
4279 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4280 return ret;
4284 /***********************************************************************
4285 * GetFileTitleW (COMDLG32.@)
4287 * Get the name of a file.
4289 * PARAMS
4290 * lpFile [I] name and location of file
4291 * lpTitle [O] returned file name
4292 * cbBuf [I] buffer size of lpTitle
4294 * RETURNS
4295 * Success: zero
4296 * Failure: negative number.
4298 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4300 int i, len;
4301 static const WCHAR brkpoint[] = {'*','[',']',0};
4302 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4304 if(lpFile == NULL || lpTitle == NULL)
4305 return -1;
4307 len = lstrlenW(lpFile);
4309 if (len == 0)
4310 return -1;
4312 if(strpbrkW(lpFile, brkpoint))
4313 return -1;
4315 len--;
4317 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4318 return -1;
4320 for(i = len; i >= 0; i--)
4322 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4324 i++;
4325 break;
4329 if(i == -1)
4330 i++;
4332 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4334 len = lstrlenW(lpFile+i)+1;
4335 if(cbBuf < len)
4336 return len;
4338 lstrcpyW(lpTitle, &lpFile[i]);
4339 return 0;