comctl32/tests: Use BOOL type where appropriate.
[wine.git] / dlls / comdlg32 / filedlg.c
blob9dbb69d76f65a921bcde2b6c6252392f1a8e9ad2
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 "cderr.h"
72 #include "shellapi.h"
73 #include "shlobj.h"
74 #include "filedlgbrowser.h"
75 #include "shlwapi.h"
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_DONTADDTORECENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex; /* Index of picture in image list */
95 HIMAGELIST hImgList;
96 int m_iIndent; /* Indentation index */
97 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99 } SFOLDER,*LPSFOLDER;
101 typedef struct tagLookInInfo
103 int iMaxIndentation;
104 UINT uSelectedItem;
105 } LookInInfos;
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define XTEXTOFFSET 3
115 /* AddItem flags*/
116 #define LISTEND -1
118 /* SearchItem methods */
119 #define SEARCH_PIDL 1
120 #define SEARCH_EXP 2
121 #define ITEM_NOTFOUND -1
123 /* Undefined windows message sent by CreateViewObject*/
124 #define WM_GETISHELLBROWSER WM_USER+7
126 /* NOTE
127 * Those macros exist in windowsx.h. However, you can't really use them since
128 * they rely on the UNICODE defines and can't be used inside Wine itself.
131 /* Combo box macros */
132 #define CBAddString(hwnd,str) \
133 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
135 #define CBInsertString(hwnd,str,pos) \
136 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
138 #define CBDeleteString(hwnd,pos) \
139 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
141 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
142 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
144 #define CBGetItemDataPtr(hwnd,iItemId) \
145 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
147 #define CBGetLBText(hwnd,iItemId,str) \
148 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
150 #define CBGetCurSel(hwnd) \
151 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
153 #define CBSetCurSel(hwnd,pos) \
154 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
156 #define CBGetCount(hwnd) \
157 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
158 #define CBShowDropDown(hwnd,show) \
159 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
160 #define CBSetItemHeight(hwnd,index,height) \
161 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
163 #define CBSetExtendedUI(hwnd,flag) \
164 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
166 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
167 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
168 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
170 static const WCHAR LastVisitedMRUW[] =
171 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
172 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
173 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
174 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
175 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
177 /***********************************************************************
178 * Prototypes
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 static BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200 /* Functions used by the filetype combo box */
201 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
202 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
209 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217 /* Functions for dealing with the most-recently-used registry keys */
218 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
219 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
220 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
222 /* Miscellaneous tool functions */
223 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
224 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
225 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
226 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
227 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
228 static UINT GetNumSelected( IDataObject *doSelected );
230 /* Shell memory allocation */
231 static void *MemAlloc(UINT size);
232 static void MemFree(void *mem);
234 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
235 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
236 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
237 static BOOL BrowseSelectedFolder(HWND hwnd);
239 /***********************************************************************
240 * GetFileName95
242 * Creates an Open common dialog box that lets the user select
243 * the drive, directory, and the name of a file or set of files to open.
245 * IN : The FileOpenDlgInfos structure associated with the dialog
246 * OUT : TRUE on success
247 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
249 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
252 LRESULT lRes;
253 LPCVOID origTemplate;
254 DWORD dwSize;
255 LPDLGTEMPLATEW 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 (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
275 !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
276 !(origTemplate = LockResource(hDlgTmpl)))
278 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
279 return FALSE;
281 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
283 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
284 return FALSE;
286 memcpy(template, origTemplate, dwSize);
288 /* msdn: explorer style dialogs permit sizing by default.
289 * The OFN_ENABLESIZING flag is only needed when a hook or
290 * custom tmeplate is provided */
291 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
292 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
293 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
295 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
297 template->style |= WS_SIZEBOX;
298 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
299 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
301 else
302 template->style &= ~WS_SIZEBOX;
305 /* old style hook messages */
306 if (IsHooked(fodInfos))
308 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
309 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
310 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
311 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
314 /* Some shell namespace extensions depend on COM being initialized. */
315 hr = OleInitialize(NULL);
317 if (fodInfos->unicode)
318 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
319 template,
320 fodInfos->ofnInfos->hwndOwner,
321 FileOpenDlgProc95,
322 (LPARAM) fodInfos);
323 else
324 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
325 template,
326 fodInfos->ofnInfos->hwndOwner,
327 FileOpenDlgProc95,
328 (LPARAM) fodInfos);
329 if (SUCCEEDED(hr))
330 OleUninitialize();
332 HeapFree(GetProcessHeap(), 0, template);
334 /* Unable to create the dialog */
335 if( lRes == -1)
336 return FALSE;
338 return lRes;
341 /***********************************************************************
342 * GetFileDialog95A
344 * Call GetFileName95 with this structure and clean the memory.
346 * IN : The OPENFILENAMEA initialisation structure passed to
347 * GetOpenFileNameA win api function (see filedlg.c)
349 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
351 BOOL ret;
352 FileOpenDlgInfos fodInfos;
353 LPSTR lpstrSavDir = NULL;
354 LPWSTR title = NULL;
355 LPWSTR defext = NULL;
356 LPWSTR filter = NULL;
357 LPWSTR customfilter = NULL;
358 INITCOMMONCONTROLSEX icc;
360 /* Initialize ComboBoxEx32 */
361 icc.dwSize = sizeof(icc);
362 icc.dwICC = ICC_USEREX_CLASSES;
363 InitCommonControlsEx(&icc);
365 /* Initialize CommDlgExtendedError() */
366 COMDLG32_SetCommDlgExtendedError(0);
368 /* Initialize FileOpenDlgInfos structure */
369 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
371 /* Pass in the original ofn */
372 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
374 /* save current directory */
375 if (ofn->Flags & OFN_NOCHANGEDIR)
377 lpstrSavDir = MemAlloc(MAX_PATH);
378 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
381 fodInfos.unicode = FALSE;
383 /* convert all the input strings to unicode */
384 if(ofn->lpstrInitialDir)
386 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
387 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
388 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
390 else
391 fodInfos.initdir = NULL;
393 if(ofn->lpstrFile)
395 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
396 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
398 else
399 fodInfos.filename = NULL;
401 if(ofn->lpstrDefExt)
403 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
404 defext = MemAlloc((len+1)*sizeof(WCHAR));
405 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
407 fodInfos.defext = defext;
409 if(ofn->lpstrTitle)
411 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
412 title = MemAlloc((len+1)*sizeof(WCHAR));
413 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
415 fodInfos.title = title;
417 if (ofn->lpstrFilter)
419 LPCSTR s;
420 int n, len;
422 /* filter is a list... title\0ext\0......\0\0 */
423 s = ofn->lpstrFilter;
424 while (*s) s = s+strlen(s)+1;
425 s++;
426 n = s - ofn->lpstrFilter;
427 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
428 filter = MemAlloc(len*sizeof(WCHAR));
429 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
431 fodInfos.filter = filter;
433 /* convert lpstrCustomFilter */
434 if (ofn->lpstrCustomFilter)
436 LPCSTR s;
437 int n, len;
439 /* customfilter contains a pair of strings... title\0ext\0 */
440 s = ofn->lpstrCustomFilter;
441 if (*s) s = s+strlen(s)+1;
442 if (*s) s = s+strlen(s)+1;
443 n = s - ofn->lpstrCustomFilter;
444 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
445 customfilter = MemAlloc(len*sizeof(WCHAR));
446 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
448 fodInfos.customfilter = customfilter;
450 /* Initialize the dialog property */
451 fodInfos.DlgInfos.dwDlgProp = 0;
452 fodInfos.DlgInfos.hwndCustomDlg = NULL;
454 switch(iDlgType)
456 case OPEN_DIALOG :
457 ret = GetFileName95(&fodInfos);
458 break;
459 case SAVE_DIALOG :
460 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
461 ret = GetFileName95(&fodInfos);
462 break;
463 default :
464 ret = FALSE;
467 if (lpstrSavDir)
469 SetCurrentDirectoryA(lpstrSavDir);
470 MemFree(lpstrSavDir);
473 MemFree(title);
474 MemFree(defext);
475 MemFree(filter);
476 MemFree(customfilter);
477 MemFree(fodInfos.initdir);
478 MemFree(fodInfos.filename);
480 TRACE("selected file: %s\n",ofn->lpstrFile);
482 return ret;
485 /***********************************************************************
486 * GetFileDialog95W
488 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
489 * Call GetFileName95 with this structure and clean the memory.
492 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
494 BOOL ret;
495 FileOpenDlgInfos fodInfos;
496 LPWSTR lpstrSavDir = NULL;
497 INITCOMMONCONTROLSEX icc;
499 /* Initialize ComboBoxEx32 */
500 icc.dwSize = sizeof(icc);
501 icc.dwICC = ICC_USEREX_CLASSES;
502 InitCommonControlsEx(&icc);
504 /* Initialize CommDlgExtendedError() */
505 COMDLG32_SetCommDlgExtendedError(0);
507 /* Initialize FileOpenDlgInfos structure */
508 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
510 /* Pass in the original ofn */
511 fodInfos.ofnInfos = ofn;
513 fodInfos.title = ofn->lpstrTitle;
514 fodInfos.defext = ofn->lpstrDefExt;
515 fodInfos.filter = ofn->lpstrFilter;
516 fodInfos.customfilter = ofn->lpstrCustomFilter;
518 /* convert string arguments, save others */
519 if(ofn->lpstrFile)
521 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
522 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
524 else
525 fodInfos.filename = NULL;
527 if(ofn->lpstrInitialDir)
529 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
530 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
531 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
532 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
534 else
535 fodInfos.initdir = NULL;
537 /* save current directory */
538 if (ofn->Flags & OFN_NOCHANGEDIR)
540 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
541 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
544 fodInfos.unicode = TRUE;
546 switch(iDlgType)
548 case OPEN_DIALOG :
549 ret = GetFileName95(&fodInfos);
550 break;
551 case SAVE_DIALOG :
552 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
553 ret = GetFileName95(&fodInfos);
554 break;
555 default :
556 ret = FALSE;
559 if (lpstrSavDir)
561 SetCurrentDirectoryW(lpstrSavDir);
562 MemFree(lpstrSavDir);
565 /* restore saved IN arguments and convert OUT arguments back */
566 MemFree(fodInfos.filename);
567 MemFree(fodInfos.initdir);
568 return ret;
571 /******************************************************************************
572 * COMDLG32_GetDisplayNameOf [internal]
574 * Helper function to get the display name for a pidl.
576 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
577 LPSHELLFOLDER psfDesktop;
578 STRRET strret;
580 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
581 return FALSE;
583 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
584 IShellFolder_Release(psfDesktop);
585 return FALSE;
588 IShellFolder_Release(psfDesktop);
589 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
592 /******************************************************************************
593 * COMDLG32_GetCanonicalPath [internal]
595 * Helper function to get the canonical path.
597 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
598 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
600 WCHAR lpstrTemp[MAX_PATH];
602 /* Get the current directory name */
603 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
605 /* last fallback */
606 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
608 PathAddBackslashW(lpstrPathAndFile);
610 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
612 /* if the user specified a fully qualified path use it */
613 if(PathIsRelativeW(lpstrFile))
615 lstrcatW(lpstrPathAndFile, lpstrFile);
617 else
619 /* does the path have a drive letter? */
620 if (PathGetDriveNumberW(lpstrFile) == -1)
621 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
622 else
623 lstrcpyW(lpstrPathAndFile, lpstrFile);
626 /* resolve "." and ".." */
627 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
628 lstrcpyW(lpstrPathAndFile, lpstrTemp);
629 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
632 /***********************************************************************
633 * COMDLG32_SplitFileNames [internal]
635 * Creates a delimited list of filenames.
637 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
639 UINT nStrCharCount = 0; /* index in src buffer */
640 UINT nFileIndex = 0; /* index in dest buffer */
641 UINT nFileCount = 0; /* number of files */
643 /* we might get single filename without any '"',
644 * so we need nStrLen + terminating \0 + end-of-list \0 */
645 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
646 *sizeUsed = 0;
648 /* build delimited file list from filenames */
649 while ( nStrCharCount <= nStrLen )
651 if ( lpstrEdit[nStrCharCount]=='"' )
653 nStrCharCount++;
654 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
656 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
657 nStrCharCount++;
659 (*lpstrFileList)[nFileIndex++] = 0;
660 nFileCount++;
662 nStrCharCount++;
665 /* single, unquoted string */
666 if ((nStrLen > 0) && (nFileIndex == 0) )
668 lstrcpyW(*lpstrFileList, lpstrEdit);
669 nFileIndex = lstrlenW(lpstrEdit) + 1;
670 nFileCount = 1;
673 /* trailing \0 */
674 (*lpstrFileList)[nFileIndex++] = '\0';
676 *sizeUsed = nFileIndex;
677 return nFileCount;
680 /***********************************************************************
681 * ArrangeCtrlPositions [internal]
683 * NOTE: Make sure to add testcases for any changes made here.
685 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
687 HWND hwndChild, hwndStc32;
688 RECT rectParent, rectChild, rectStc32;
689 INT help_fixup = 0;
690 int chgx, chgy;
692 /* Take into account if open as read only checkbox and help button
693 * are hidden
695 if (hide_help)
697 RECT rectHelp, rectCancel;
698 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
699 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
700 /* subtract the height of the help button plus the space between
701 * the help button and the cancel button to the height of the dialog
703 help_fixup = rectHelp.bottom - rectCancel.bottom;
707 There are two possibilities to add components to the default file dialog box.
709 By default, all the new components are added below the standard dialog box (the else case).
711 However, if there is a static text component with the stc32 id, a special case happens.
712 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
713 in the window and the cx and cy indicate how to size the window.
714 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
715 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
719 GetClientRect(hwndParentDlg, &rectParent);
721 /* when arranging controls we have to use fixed parent size */
722 rectParent.bottom -= help_fixup;
724 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
725 if (hwndStc32)
727 GetWindowRect(hwndStc32, &rectStc32);
728 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
730 /* set the size of the stc32 control according to the size of
731 * client area of the parent dialog
733 SetWindowPos(hwndStc32, 0,
734 0, 0,
735 rectParent.right, rectParent.bottom,
736 SWP_NOMOVE | SWP_NOZORDER);
738 else
739 SetRectEmpty(&rectStc32);
741 /* this part moves controls of the child dialog */
742 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
743 while (hwndChild)
745 if (hwndChild != hwndStc32)
747 GetWindowRect(hwndChild, &rectChild);
748 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
750 /* move only if stc32 exist */
751 if (hwndStc32 && rectChild.left > rectStc32.right)
753 /* move to the right of visible controls of the parent dialog */
754 rectChild.left += rectParent.right;
755 rectChild.left -= rectStc32.right;
757 /* move even if stc32 doesn't exist */
758 if (rectChild.top >= rectStc32.bottom)
760 /* move below visible controls of the parent dialog */
761 rectChild.top += rectParent.bottom;
762 rectChild.top -= rectStc32.bottom - rectStc32.top;
765 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
766 0, 0, SWP_NOSIZE | SWP_NOZORDER);
768 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
771 /* this part moves controls of the parent dialog */
772 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
773 while (hwndChild)
775 if (hwndChild != hwndChildDlg)
777 GetWindowRect(hwndChild, &rectChild);
778 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
780 /* left,top of stc32 marks the position of controls
781 * from the parent dialog
783 rectChild.left += rectStc32.left;
784 rectChild.top += rectStc32.top;
786 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
787 0, 0, SWP_NOSIZE | SWP_NOZORDER);
789 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
792 /* calculate the size of the resulting dialog */
794 /* here we have to use original parent size */
795 GetClientRect(hwndParentDlg, &rectParent);
796 GetClientRect(hwndChildDlg, &rectChild);
797 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
798 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
800 if (hwndStc32)
802 /* width */
803 if (rectParent.right > rectStc32.right - rectStc32.left)
804 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
805 else
806 chgx = rectChild.right - rectParent.right;
807 /* height */
808 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
809 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
810 else
811 /* Unconditionally set new dialog
812 * height to that of the child
814 chgy = rectChild.bottom - rectParent.bottom;
816 else
818 chgx = 0;
819 chgy = rectChild.bottom - help_fixup;
821 /* set the size of the parent dialog */
822 GetWindowRect(hwndParentDlg, &rectParent);
823 SetWindowPos(hwndParentDlg, 0,
824 0, 0,
825 rectParent.right - rectParent.left + chgx,
826 rectParent.bottom - rectParent.top + chgy,
827 SWP_NOMOVE | SWP_NOZORDER);
830 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
832 switch(uMsg) {
833 case WM_INITDIALOG:
834 return TRUE;
836 return FALSE;
839 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
841 LPCVOID template;
842 HRSRC hRes;
843 HANDLE hDlgTmpl = 0;
844 HWND hChildDlg = 0;
846 TRACE("\n");
849 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
850 * structure's hInstance parameter is not a HINSTANCE, but
851 * instead a pointer to a template resource to use.
853 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
855 HINSTANCE hinst;
856 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
858 hinst = COMDLG32_hInstance;
859 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
861 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
862 return NULL;
865 else
867 hinst = fodInfos->ofnInfos->hInstance;
868 if(fodInfos->unicode)
870 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
871 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
873 else
875 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
876 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
878 if (!hRes)
880 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
881 return NULL;
883 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
884 !(template = LockResource( hDlgTmpl )))
886 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
887 return NULL;
890 if (fodInfos->unicode)
891 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
892 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
893 (LPARAM)fodInfos->ofnInfos);
894 else
895 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
896 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
897 (LPARAM)fodInfos->ofnInfos);
898 return hChildDlg;
900 else if( IsHooked(fodInfos))
902 RECT rectHwnd;
903 struct {
904 DLGTEMPLATE tmplate;
905 WORD menu,class,title;
906 } temp;
907 GetClientRect(hwnd,&rectHwnd);
908 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
909 temp.tmplate.dwExtendedStyle = 0;
910 temp.tmplate.cdit = 0;
911 temp.tmplate.x = 0;
912 temp.tmplate.y = 0;
913 temp.tmplate.cx = 0;
914 temp.tmplate.cy = 0;
915 temp.menu = temp.class = temp.title = 0;
917 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
918 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
920 return hChildDlg;
922 return NULL;
925 /***********************************************************************
926 * SendCustomDlgNotificationMessage
928 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
931 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
933 LRESULT hook_result = 0;
934 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
936 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
938 if(!fodInfos) return 0;
940 if(fodInfos->DlgInfos.hwndCustomDlg)
942 TRACE("CALL NOTIFY for %x\n", uCode);
943 if(fodInfos->unicode)
945 OFNOTIFYW ofnNotify;
946 ofnNotify.hdr.hwndFrom=hwndParentDlg;
947 ofnNotify.hdr.idFrom=0;
948 ofnNotify.hdr.code = uCode;
949 ofnNotify.lpOFN = fodInfos->ofnInfos;
950 ofnNotify.pszFile = NULL;
951 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
953 else
955 OFNOTIFYA ofnNotify;
956 ofnNotify.hdr.hwndFrom=hwndParentDlg;
957 ofnNotify.hdr.idFrom=0;
958 ofnNotify.hdr.code = uCode;
959 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
960 ofnNotify.pszFile = NULL;
961 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
963 TRACE("RET NOTIFY\n");
965 TRACE("Retval: 0x%08lx\n", hook_result);
966 return hook_result;
969 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
971 UINT len, total;
972 WCHAR *p, *buffer;
973 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
975 TRACE("CDM_GETFILEPATH:\n");
977 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
978 return -1;
980 /* get path and filenames */
981 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
982 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
983 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
984 if (len)
986 p = buffer + strlenW(buffer);
987 *p++ = '\\';
988 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
990 if (fodInfos->unicode)
992 total = strlenW( buffer) + 1;
993 if (result) lstrcpynW( result, buffer, size );
994 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
996 else
998 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
999 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1000 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1002 HeapFree( GetProcessHeap(), 0, buffer );
1003 return total;
1006 /***********************************************************************
1007 * FILEDLG95_HandleCustomDialogMessages
1009 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1011 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1013 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1014 WCHAR lpstrPath[MAX_PATH];
1015 INT_PTR retval;
1017 if(!fodInfos) return FALSE;
1019 switch(uMsg)
1021 case CDM_GETFILEPATH:
1022 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1023 break;
1025 case CDM_GETFOLDERPATH:
1026 TRACE("CDM_GETFOLDERPATH:\n");
1027 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1028 if (lParam)
1030 if (fodInfos->unicode)
1031 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1032 else
1033 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1034 (LPSTR)lParam, (int)wParam, NULL, NULL);
1036 retval = lstrlenW(lpstrPath) + 1;
1037 break;
1039 case CDM_GETFOLDERIDLIST:
1040 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1041 if (retval <= wParam)
1042 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1043 break;
1045 case CDM_GETSPEC:
1046 TRACE("CDM_GETSPEC:\n");
1047 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1048 if (lParam)
1050 if (fodInfos->unicode)
1051 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1052 else
1053 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1055 break;
1057 case CDM_SETCONTROLTEXT:
1058 TRACE("CDM_SETCONTROLTEXT:\n");
1059 if ( lParam )
1061 if( fodInfos->unicode )
1062 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1063 else
1064 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1066 retval = TRUE;
1067 break;
1069 case CDM_HIDECONTROL:
1070 /* MSDN states that it should fail for not OFN_EXPLORER case */
1071 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1073 HWND control = GetDlgItem( hwnd, wParam );
1074 if (control) ShowWindow( control, SW_HIDE );
1075 retval = TRUE;
1077 else retval = FALSE;
1078 break;
1080 default:
1081 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1082 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1083 return FALSE;
1085 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1086 return TRUE;
1089 /***********************************************************************
1090 * FILEDLG95_OnWMGetMMI
1092 * WM_GETMINMAXINFO message handler for resizable dialogs
1094 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1096 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1097 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1098 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1100 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1102 return TRUE;
1105 /***********************************************************************
1106 * FILEDLG95_OnWMSize
1108 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1110 * FIXME: this could be made more elaborate. Now use a simple scheme
1111 * where the file view is enlarged and the controls are either moved
1112 * vertically or horizontally to get out of the way. Only the "grip"
1113 * is moved in both directions to stay in the corner.
1115 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1117 RECT rc, rcview;
1118 int chgx, chgy;
1119 HWND ctrl;
1120 HDWP hdwp;
1121 FileOpenDlgInfos *fodInfos;
1123 if( wParam != SIZE_RESTORED) return FALSE;
1124 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1125 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1126 /* get the new dialog rectangle */
1127 GetWindowRect( hwnd, &rc);
1128 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1129 rc.right -rc.left, rc.bottom -rc.top);
1130 /* not initialized yet */
1131 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1132 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1133 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1134 return FALSE;
1135 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1136 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1137 fodInfos->sizedlg.cx = rc.right - rc.left;
1138 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1139 /* change the size of the view window */
1140 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1141 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1142 hdwp = BeginDeferWindowPos( 10);
1143 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1144 rcview.right - rcview.left + chgx,
1145 rcview.bottom - rcview.top + chgy,
1146 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1147 /* change position and sizes of the controls */
1148 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1150 int ctrlid = GetDlgCtrlID( ctrl);
1151 GetWindowRect( ctrl, &rc);
1152 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1153 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1155 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1156 0, 0,
1157 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1159 else if( rc.top > rcview.bottom)
1161 /* if it was below the shell view
1162 * move to bottom */
1163 switch( ctrlid)
1165 /* file name (edit or comboboxex) and file types combo change also width */
1166 case edt1:
1167 case cmb13:
1168 case cmb1:
1169 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1170 rc.right - rc.left + chgx, rc.bottom - rc.top,
1171 SWP_NOACTIVATE | SWP_NOZORDER);
1172 break;
1173 /* then these buttons must move out of the way */
1174 case IDOK:
1175 case IDCANCEL:
1176 case pshHelp:
1177 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1178 0, 0,
1179 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1180 break;
1181 default:
1182 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1183 0, 0,
1184 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1187 else if( rc.left > rcview.right)
1189 /* if it was to the right of the shell view
1190 * move to right */
1191 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1192 0, 0,
1193 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1195 else
1196 /* special cases */
1198 switch( ctrlid)
1200 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1201 case IDC_LOOKIN:
1202 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1203 rc.right - rc.left + chgx, rc.bottom - rc.top,
1204 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1205 break;
1206 case IDC_TOOLBARSTATIC:
1207 case IDC_TOOLBAR:
1208 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1209 0, 0,
1210 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1211 break;
1212 #endif
1213 /* not resized in windows. Since wine uses this invisible control
1214 * to size the browser view it needs to be resized */
1215 case IDC_SHELLSTATIC:
1216 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1217 rc.right - rc.left + chgx,
1218 rc.bottom - rc.top + chgy,
1219 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1220 break;
1224 if(fodInfos->DlgInfos.hwndCustomDlg &&
1225 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1227 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1228 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1230 GetWindowRect( ctrl, &rc);
1231 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1232 if( rc.top > rcview.bottom)
1234 /* if it was below the shell view
1235 * move to bottom */
1236 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1237 rc.right - rc.left, rc.bottom - rc.top,
1238 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1240 else if( rc.left > rcview.right)
1242 /* if it was to the right of the shell view
1243 * move to right */
1244 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1245 rc.right - rc.left, rc.bottom - rc.top,
1246 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1249 /* size the custom dialog at the end: some applications do some
1250 * control re-arranging at this point */
1251 GetClientRect(hwnd, &rc);
1252 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1253 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1255 EndDeferWindowPos( hdwp);
1256 /* should not be needed */
1257 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1258 return TRUE;
1261 /***********************************************************************
1262 * FileOpenDlgProc95
1264 * File open dialog procedure
1266 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1268 #if 0
1269 TRACE("%p 0x%04x\n", hwnd, uMsg);
1270 #endif
1272 switch(uMsg)
1274 case WM_INITDIALOG:
1276 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1277 RECT rc, rcstc;
1278 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1279 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1281 /* Adds the FileOpenDlgInfos in the property list of the dialog
1282 so it will be easily accessible through a GetPropA(...) */
1283 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1285 FILEDLG95_InitControls(hwnd);
1287 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1289 GetWindowRect( hwnd, &rc);
1290 fodInfos->DlgInfos.hwndGrip =
1291 CreateWindowExA( 0, "SCROLLBAR", NULL,
1292 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1293 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1294 rc.right - gripx, rc.bottom - gripy,
1295 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1298 fodInfos->DlgInfos.hwndCustomDlg =
1299 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1301 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1302 FILEDLG95_FillControls(hwnd, wParam, lParam);
1304 if( fodInfos->DlgInfos.hwndCustomDlg)
1305 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1307 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1308 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1309 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1312 /* if the app has changed the position of the invisible listbox,
1313 * change that of the listview (browser) as well */
1314 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1315 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1316 if( !EqualRect( &rc, &rcstc))
1318 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1319 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1320 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1321 SWP_NOACTIVATE | SWP_NOZORDER);
1324 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1326 GetWindowRect( hwnd, &rc);
1327 fodInfos->sizedlg.cx = rc.right - rc.left;
1328 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1329 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1330 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1331 GetClientRect( hwnd, &rc);
1332 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1333 rc.right - gripx, rc.bottom - gripy,
1334 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1335 /* resize the dialog to the previous invocation */
1336 if( MemDialogSize.cx && MemDialogSize.cy)
1337 SetWindowPos( hwnd, NULL,
1338 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1339 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1342 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1343 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1345 return 0;
1347 case WM_SIZE:
1348 return FILEDLG95_OnWMSize(hwnd, wParam);
1349 case WM_GETMINMAXINFO:
1350 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1351 case WM_COMMAND:
1352 return FILEDLG95_OnWMCommand(hwnd, wParam);
1353 case WM_DRAWITEM:
1355 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1357 case IDC_LOOKIN:
1358 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1359 return TRUE;
1362 return FALSE;
1364 case WM_GETISHELLBROWSER:
1365 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1367 case WM_DESTROY:
1369 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1370 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1371 MemDialogSize = fodInfos->sizedlg;
1372 RemovePropA(hwnd, FileOpenDlgInfosStr);
1373 return FALSE;
1375 case WM_NOTIFY:
1377 LPNMHDR lpnmh = (LPNMHDR)lParam;
1378 UINT stringId = -1;
1380 /* set up the button tooltips strings */
1381 if(TTN_GETDISPINFOA == lpnmh->code )
1383 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1384 switch(lpnmh->idFrom )
1386 /* Up folder button */
1387 case FCIDM_TB_UPFOLDER:
1388 stringId = IDS_UPFOLDER;
1389 break;
1390 /* New folder button */
1391 case FCIDM_TB_NEWFOLDER:
1392 stringId = IDS_NEWFOLDER;
1393 break;
1394 /* List option button */
1395 case FCIDM_TB_SMALLICON:
1396 stringId = IDS_LISTVIEW;
1397 break;
1398 /* Details option button */
1399 case FCIDM_TB_REPORTVIEW:
1400 stringId = IDS_REPORTVIEW;
1401 break;
1402 /* Desktop button */
1403 case FCIDM_TB_DESKTOP:
1404 stringId = IDS_TODESKTOP;
1405 break;
1406 default:
1407 stringId = 0;
1409 lpdi->hinst = COMDLG32_hInstance;
1410 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1412 return FALSE;
1414 default :
1415 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1416 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1417 return FALSE;
1421 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1423 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1424 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1427 /***********************************************************************
1428 * FILEDLG95_InitControls
1430 * WM_INITDIALOG message handler (before hook notification)
1432 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1434 BOOL win2000plus = FALSE;
1435 BOOL win98plus = FALSE;
1436 BOOL handledPath = FALSE;
1437 OSVERSIONINFOW osVi;
1438 static const WCHAR szwSlash[] = { '\\', 0 };
1439 static const WCHAR szwStar[] = { '*',0 };
1441 static const TBBUTTON tbb[] =
1443 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1444 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1445 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1446 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1447 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1448 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1449 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1450 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1451 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1453 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1455 RECT rectTB;
1456 RECT rectlook;
1458 HIMAGELIST toolbarImageList;
1459 SHFILEINFOA shFileInfo;
1460 ITEMIDLIST *desktopPidl;
1462 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1464 TRACE("%p\n", fodInfos);
1466 /* Get windows version emulating */
1467 osVi.dwOSVersionInfoSize = sizeof(osVi);
1468 GetVersionExW(&osVi);
1469 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1470 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1471 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1472 win2000plus = (osVi.dwMajorVersion > 4);
1473 if (win2000plus) win98plus = TRUE;
1475 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1478 /* Use either the edit or the comboboxex for the filename control */
1479 if (filename_is_edit( fodInfos ))
1481 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1482 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1484 else
1486 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1487 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1490 /* Get the hwnd of the controls */
1491 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1492 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1494 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1495 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1497 /* construct the toolbar */
1498 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1499 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1501 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1502 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1503 rectTB.left = rectlook.right;
1504 rectTB.top = rectlook.top-1;
1506 if (fodInfos->unicode)
1507 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1508 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1509 rectTB.left, rectTB.top,
1510 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1511 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1512 else
1513 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1514 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1515 rectTB.left, rectTB.top,
1516 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1517 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1519 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1521 /* FIXME: use TB_LOADIMAGES when implemented */
1522 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1523 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1524 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1526 /* Retrieve and add desktop icon to the toolbar */
1527 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1528 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1529 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1530 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1531 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1533 DestroyIcon(shFileInfo.hIcon);
1534 CoTaskMemFree(desktopPidl);
1536 /* Finish Toolbar Construction */
1537 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1538 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1540 /* Set the window text with the text specified in the OPENFILENAME structure */
1541 if(fodInfos->title)
1543 SetWindowTextW(hwnd,fodInfos->title);
1545 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1547 WCHAR buf[64];
1548 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1549 SetWindowTextW(hwnd, buf);
1552 /* Initialise the file name edit control */
1553 handledPath = FALSE;
1554 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1556 if(fodInfos->filename)
1558 /* 1. If win2000 or higher and filename contains a path, use it
1559 in preference over the lpstrInitialDir */
1560 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1561 WCHAR tmpBuf[MAX_PATH];
1562 WCHAR *nameBit;
1563 DWORD result;
1565 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1566 if (result) {
1568 /* nameBit is always shorter than the original filename */
1569 lstrcpyW(fodInfos->filename,nameBit);
1571 *nameBit = 0x00;
1572 MemFree(fodInfos->initdir);
1573 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1574 lstrcpyW(fodInfos->initdir, tmpBuf);
1575 handledPath = TRUE;
1576 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1577 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1579 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1581 } else {
1582 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1586 /* 2. (All platforms) If initdir is not null, then use it */
1587 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1589 /* Work out the proper path as supplied one might be relative */
1590 /* (Here because supplying '.' as dir browses to My Computer) */
1591 if (!handledPath) {
1592 WCHAR tmpBuf[MAX_PATH];
1593 WCHAR tmpBuf2[MAX_PATH];
1594 WCHAR *nameBit;
1595 DWORD result;
1597 lstrcpyW(tmpBuf, fodInfos->initdir);
1598 if( PathFileExistsW(tmpBuf) ) {
1599 /* initdir does not have to be a directory. If a file is
1600 * specified, the dir part is taken */
1601 if( PathIsDirectoryW(tmpBuf)) {
1602 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1603 lstrcatW(tmpBuf, szwSlash);
1605 lstrcatW(tmpBuf, szwStar);
1607 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1608 if (result) {
1609 *nameBit = 0x00;
1610 MemFree(fodInfos->initdir);
1611 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1612 lstrcpyW(fodInfos->initdir, tmpBuf2);
1613 handledPath = TRUE;
1614 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1617 else if (fodInfos->initdir)
1619 MemFree(fodInfos->initdir);
1620 fodInfos->initdir = NULL;
1621 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1626 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1628 /* 3. All except w2k+: if filename contains a path use it */
1629 if (!win2000plus && fodInfos->filename &&
1630 *fodInfos->filename &&
1631 strpbrkW(fodInfos->filename, szwSlash)) {
1632 WCHAR tmpBuf[MAX_PATH];
1633 WCHAR *nameBit;
1634 DWORD result;
1636 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1637 tmpBuf, &nameBit);
1638 if (result) {
1639 int len;
1641 /* nameBit is always shorter than the original filename */
1642 lstrcpyW(fodInfos->filename, nameBit);
1643 *nameBit = 0x00;
1645 len = lstrlenW(tmpBuf);
1646 MemFree(fodInfos->initdir);
1647 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1648 lstrcpyW(fodInfos->initdir, tmpBuf);
1650 handledPath = TRUE;
1651 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1652 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1654 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1657 /* 4. Win2000+: Recently used */
1658 if (!handledPath && win2000plus) {
1659 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1660 fodInfos->initdir[0] = '\0';
1662 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1664 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1665 handledPath = TRUE;
1666 }else{
1667 MemFree(fodInfos->initdir);
1668 fodInfos->initdir = NULL;
1672 /* 5. win98+ and win2000+ if any files of specified filter types in
1673 current directory, use it */
1674 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1676 LPCWSTR lpstrPos = fodInfos->filter;
1677 WIN32_FIND_DATAW FindFileData;
1678 HANDLE hFind;
1680 while (1)
1682 /* filter is a list... title\0ext\0......\0\0 */
1684 /* Skip the title */
1685 if(! *lpstrPos) break; /* end */
1686 lpstrPos += lstrlenW(lpstrPos) + 1;
1688 /* See if any files exist in the current dir with this extension */
1689 if(! *lpstrPos) break; /* end */
1691 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1693 if (hFind == INVALID_HANDLE_VALUE) {
1694 /* None found - continue search */
1695 lpstrPos += lstrlenW(lpstrPos) + 1;
1697 } else {
1699 MemFree(fodInfos->initdir);
1700 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1701 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1703 handledPath = TRUE;
1704 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1705 debugstr_w(lpstrPos));
1706 FindClose(hFind);
1707 break;
1712 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1713 if (!handledPath && (win2000plus || win98plus)) {
1714 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1716 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1718 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1720 /* last fallback */
1721 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1722 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1723 } else {
1724 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1726 } else {
1727 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1729 handledPath = TRUE;
1730 } else if (!handledPath) {
1731 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1732 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1733 handledPath = TRUE;
1734 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1737 SetFocus( fodInfos->DlgInfos.hwndFileName );
1738 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1740 /* Must the open as read only check box be checked ?*/
1741 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1743 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1746 /* Must the open as read only check box be hidden? */
1747 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1749 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1750 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1753 /* Must the help button be hidden? */
1754 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1756 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1757 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1760 /* change Open to Save */
1761 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1763 WCHAR buf[16];
1764 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1765 SetDlgItemTextW(hwnd, IDOK, buf);
1766 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1767 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1770 /* Initialize the filter combo box */
1771 FILEDLG95_FILETYPE_Init(hwnd);
1773 return 0;
1776 /***********************************************************************
1777 * FILEDLG95_ResizeControls
1779 * WM_INITDIALOG message handler (after hook notification)
1781 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1783 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1785 if (fodInfos->DlgInfos.hwndCustomDlg)
1787 RECT rc;
1788 UINT flags = SWP_NOACTIVATE;
1790 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1791 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1793 /* resize the custom dialog to the parent size */
1794 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1795 GetClientRect(hwnd, &rc);
1796 else
1798 /* our own fake template is zero sized and doesn't have children, so
1799 * there is no need to resize it. Picasa depends on it.
1801 flags |= SWP_NOSIZE;
1802 SetRectEmpty(&rc);
1804 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1805 0, 0, rc.right, rc.bottom, flags);
1807 else
1809 /* Resize the height, if open as read only checkbox ad help button are
1810 * hidden and we are not using a custom template nor a customDialog
1812 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1813 (!(fodInfos->ofnInfos->Flags &
1814 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1816 RECT rectDlg, rectHelp, rectCancel;
1817 GetWindowRect(hwnd, &rectDlg);
1818 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1819 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1820 /* subtract the height of the help button plus the space between the help
1821 * button and the cancel button to the height of the dialog
1823 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1824 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1825 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1828 return TRUE;
1831 /***********************************************************************
1832 * FILEDLG95_FillControls
1834 * WM_INITDIALOG message handler (after hook notification)
1836 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1838 LPITEMIDLIST pidlItemId = NULL;
1840 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1842 TRACE("dir=%s file=%s\n",
1843 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1845 /* Get the initial directory pidl */
1847 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1849 WCHAR path[MAX_PATH];
1851 GetCurrentDirectoryW(MAX_PATH,path);
1852 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1855 /* Initialise shell objects */
1856 FILEDLG95_SHELL_Init(hwnd);
1858 /* Initialize the Look In combo box */
1859 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1861 /* Browse to the initial directory */
1862 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1864 /* Free pidlItem memory */
1865 COMDLG32_SHFree(pidlItemId);
1867 return TRUE;
1869 /***********************************************************************
1870 * FILEDLG95_Clean
1872 * Regroups all the cleaning functions of the filedlg
1874 void FILEDLG95_Clean(HWND hwnd)
1876 FILEDLG95_FILETYPE_Clean(hwnd);
1877 FILEDLG95_LOOKIN_Clean(hwnd);
1878 FILEDLG95_SHELL_Clean(hwnd);
1880 /***********************************************************************
1881 * FILEDLG95_OnWMCommand
1883 * WM_COMMAND message handler
1885 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1887 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1888 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1889 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1891 switch(wID)
1893 /* OK button */
1894 case IDOK:
1895 FILEDLG95_OnOpen(hwnd);
1896 break;
1897 /* Cancel button */
1898 case IDCANCEL:
1899 FILEDLG95_Clean(hwnd);
1900 EndDialog(hwnd, FALSE);
1901 break;
1902 /* Filetype combo box */
1903 case IDC_FILETYPE:
1904 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1905 break;
1906 /* LookIn combo box */
1907 case IDC_LOOKIN:
1908 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1909 break;
1911 /* --- toolbar --- */
1912 /* Up folder button */
1913 case FCIDM_TB_UPFOLDER:
1914 FILEDLG95_SHELL_UpFolder(hwnd);
1915 break;
1916 /* New folder button */
1917 case FCIDM_TB_NEWFOLDER:
1918 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1919 break;
1920 /* List option button */
1921 case FCIDM_TB_SMALLICON:
1922 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1923 break;
1924 /* Details option button */
1925 case FCIDM_TB_REPORTVIEW:
1926 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1927 break;
1928 /* Details option button */
1929 case FCIDM_TB_DESKTOP:
1930 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1931 break;
1933 case edt1:
1934 case cmb13:
1935 break;
1938 /* Do not use the listview selection anymore */
1939 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1940 return 0;
1943 /***********************************************************************
1944 * FILEDLG95_OnWMGetIShellBrowser
1946 * WM_GETISHELLBROWSER message handler
1948 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1950 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1952 TRACE("\n");
1954 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1956 return TRUE;
1960 /***********************************************************************
1961 * FILEDLG95_SendFileOK
1963 * Sends the CDN_FILEOK notification if required
1965 * RETURNS
1966 * TRUE if the dialog should close
1967 * FALSE if the dialog should not be closed
1969 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1971 /* ask the hook if we can close */
1972 if(IsHooked(fodInfos))
1974 LRESULT retval = 0;
1976 TRACE("---\n");
1977 /* First send CDN_FILEOK as MSDN doc says */
1978 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1979 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1980 if( retval)
1982 TRACE("canceled\n");
1983 return FALSE;
1986 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1987 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1988 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1989 if( retval)
1991 TRACE("canceled\n");
1992 return FALSE;
1995 return TRUE;
1998 /***********************************************************************
1999 * FILEDLG95_OnOpenMultipleFiles
2001 * Handles the opening of multiple files.
2003 * FIXME
2004 * check destination buffer size
2006 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2008 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2009 UINT nCount, nSizePath;
2010 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2012 TRACE("\n");
2014 if(fodInfos->unicode)
2016 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2017 ofn->lpstrFile[0] = '\0';
2019 else
2021 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2022 ofn->lpstrFile[0] = '\0';
2025 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2027 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2028 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2029 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2031 LPWSTR lpstrTemp = lpstrFileList;
2033 for ( nCount = 0; nCount < nFileCount; nCount++ )
2035 LPITEMIDLIST pidl;
2037 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2038 if (!pidl)
2040 WCHAR lpstrNotFound[100];
2041 WCHAR lpstrMsg[100];
2042 WCHAR tmp[400];
2043 static const WCHAR nl[] = {'\n',0};
2045 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2046 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2048 lstrcpyW(tmp, lpstrTemp);
2049 lstrcatW(tmp, nl);
2050 lstrcatW(tmp, lpstrNotFound);
2051 lstrcatW(tmp, nl);
2052 lstrcatW(tmp, lpstrMsg);
2054 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2055 return FALSE;
2058 /* move to the next file in the list of files */
2059 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2060 COMDLG32_SHFree(pidl);
2064 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2065 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2067 /* For "oldstyle" dialog the components have to
2068 be separated by blanks (not '\0'!) and short
2069 filenames have to be used! */
2070 FIXME("Components have to be separated by blanks\n");
2072 if(fodInfos->unicode)
2074 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2075 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2076 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2078 else
2080 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2082 if (ofn->lpstrFile != NULL)
2084 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2085 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2086 if (ofn->nMaxFile > nSizePath)
2088 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2089 ofn->lpstrFile + nSizePath,
2090 ofn->nMaxFile - nSizePath, NULL, NULL);
2095 fodInfos->ofnInfos->nFileOffset = nSizePath;
2096 fodInfos->ofnInfos->nFileExtension = 0;
2098 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2099 return FALSE;
2101 /* clean and exit */
2102 FILEDLG95_Clean(hwnd);
2103 return EndDialog(hwnd,TRUE);
2106 /* Returns the 'slot name' of the given module_name in the registry's
2107 * most-recently-used list. This will be an ASCII value in the
2108 * range ['a','z'). Returns zero on error.
2110 * The slot's value in the registry has the form:
2111 * module_name\0mru_path\0
2113 * If stored_path is given, then stored_path will contain the path name
2114 * stored in the registry's MRU list for the given module_name.
2116 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2117 * MRU list key for the given module_name.
2119 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2121 WCHAR mru_list[32], *cur_mru_slot;
2122 BOOL taken[25] = {0};
2123 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2124 HKEY hkey_tmp, *hkey;
2125 LONG ret;
2127 if(hkey_ret)
2128 hkey = hkey_ret;
2129 else
2130 hkey = &hkey_tmp;
2132 if(stored_path)
2133 *stored_path = '\0';
2135 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2136 if(ret){
2137 WARN("Unable to create MRU key: %d\n", ret);
2138 return 0;
2141 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2142 (LPBYTE)mru_list, &mru_list_size);
2143 if(ret || key_type != REG_SZ){
2144 if(ret == ERROR_FILE_NOT_FOUND)
2145 return 'a';
2147 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2148 RegCloseKey(*hkey);
2149 return 0;
2152 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2153 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2154 DWORD value_data_size = sizeof(value_data);
2156 *value_name = *cur_mru_slot;
2158 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2159 &key_type, (LPBYTE)value_data, &value_data_size);
2160 if(ret || key_type != REG_BINARY){
2161 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2162 continue;
2165 if(!strcmpiW(module_name, value_data)){
2166 if(!hkey_ret)
2167 RegCloseKey(*hkey);
2168 if(stored_path)
2169 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2170 return *value_name;
2174 if(!hkey_ret)
2175 RegCloseKey(*hkey);
2177 /* the module name isn't in the registry, so find the next open slot */
2178 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2179 taken[*cur_mru_slot - 'a'] = TRUE;
2180 for(i = 0; i < 25; ++i){
2181 if(!taken[i])
2182 return i + 'a';
2185 /* all slots are taken, so return the last one in MRUList */
2186 --cur_mru_slot;
2187 return *cur_mru_slot;
2190 /* save the given filename as most-recently-used path for this module */
2191 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2193 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2194 LONG ret;
2195 HKEY hkey;
2197 /* get the current executable's name */
2198 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2199 WARN("GotModuleFileName failed: %d\n", GetLastError());
2200 return;
2202 module_name = strrchrW(module_path, '\\');
2203 if(!module_name)
2204 module_name = module_path;
2205 else
2206 module_name += 1;
2208 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2209 if(!slot)
2210 return;
2211 *slot_name = slot;
2213 { /* update the slot's info */
2214 WCHAR *path_ends, *final;
2215 DWORD path_len, final_len;
2217 /* use only the path segment of `filename' */
2218 path_ends = strrchrW(filename, '\\');
2219 path_len = path_ends - filename;
2221 final_len = path_len + lstrlenW(module_name) + 2;
2223 final = MemAlloc(final_len * sizeof(WCHAR));
2224 if(!final)
2225 return;
2226 lstrcpyW(final, module_name);
2227 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2228 final[final_len-1] = '\0';
2230 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2231 final_len * sizeof(WCHAR));
2232 if(ret){
2233 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2234 MemFree(final);
2235 RegCloseKey(hkey);
2236 return;
2239 MemFree(final);
2242 { /* update MRUList value */
2243 WCHAR old_mru_list[32], new_mru_list[32];
2244 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2245 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2247 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2248 (LPBYTE)old_mru_list, &mru_list_size);
2249 if(ret || key_type != REG_SZ){
2250 if(ret == ERROR_FILE_NOT_FOUND){
2251 new_mru_list[0] = slot;
2252 new_mru_list[1] = '\0';
2253 }else{
2254 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2255 RegCloseKey(hkey);
2256 return;
2258 }else{
2259 /* copy old list data over so that the new slot is at the start
2260 * of the list */
2261 *new_mru_slot++ = slot;
2262 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2263 if(*old_mru_slot != slot)
2264 *new_mru_slot++ = *old_mru_slot;
2266 *new_mru_slot = '\0';
2269 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2270 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2271 if(ret){
2272 WARN("Error saving MRUList data: %d\n", ret);
2273 RegCloseKey(hkey);
2274 return;
2279 /* load the most-recently-used path for this module */
2280 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2282 WCHAR module_path[MAX_PATH], *module_name;
2284 /* get the current executable's name */
2285 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2286 WARN("GotModuleFileName failed: %d\n", GetLastError());
2287 return;
2289 module_name = strrchrW(module_path, '\\');
2290 if(!module_name)
2291 module_name = module_path;
2292 else
2293 module_name += 1;
2295 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2296 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2299 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2301 WCHAR strMsgTitle[MAX_PATH];
2302 WCHAR strMsgText [MAX_PATH];
2303 if (idCaption)
2304 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2305 else
2306 strMsgTitle[0] = '\0';
2307 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2308 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2311 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2312 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2314 int nOpenAction = defAction;
2315 LPWSTR lpszTemp, lpszTemp1;
2316 LPITEMIDLIST pidl = NULL;
2317 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2319 /* check for invalid chars */
2320 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2322 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2323 return FALSE;
2326 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2328 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2329 while (lpszTemp1)
2331 LPSHELLFOLDER lpsfChild;
2332 WCHAR lpwstrTemp[MAX_PATH];
2333 DWORD dwEaten, dwAttributes;
2334 LPWSTR p;
2336 lstrcpyW(lpwstrTemp, lpszTemp);
2337 p = PathFindNextComponentW(lpwstrTemp);
2339 if (!p) break; /* end of path */
2341 *p = 0;
2342 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2344 /* There are no wildcards when OFN_NOVALIDATE is set */
2345 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2347 static const WCHAR wszWild[] = { '*', '?', 0 };
2348 /* if the last element is a wildcard do a search */
2349 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2351 nOpenAction = ONOPEN_SEARCH;
2352 break;
2355 lpszTemp1 = lpszTemp;
2357 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2359 /* append a backslash to drive letters */
2360 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2361 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2362 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2364 PathAddBackslashW(lpwstrTemp);
2367 dwAttributes = SFGAO_FOLDER;
2368 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2370 /* the path component is valid, we have a pidl of the next path component */
2371 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2372 if(dwAttributes & SFGAO_FOLDER)
2374 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2376 ERR("bind to failed\n"); /* should not fail */
2377 break;
2379 IShellFolder_Release(*ppsf);
2380 *ppsf = lpsfChild;
2381 lpsfChild = NULL;
2383 else
2385 TRACE("value\n");
2387 /* end dialog, return value */
2388 nOpenAction = ONOPEN_OPEN;
2389 break;
2391 COMDLG32_SHFree(pidl);
2392 pidl = NULL;
2394 else if (!(flags & OFN_NOVALIDATE))
2396 if(*lpszTemp || /* points to trailing null for last path element */
2397 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2399 if(flags & OFN_PATHMUSTEXIST)
2401 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2402 break;
2405 else
2407 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2409 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2410 break;
2413 /* change to the current folder */
2414 nOpenAction = ONOPEN_OPEN;
2415 break;
2417 else
2419 nOpenAction = ONOPEN_OPEN;
2420 break;
2423 if(pidl) COMDLG32_SHFree(pidl);
2425 return nOpenAction;
2428 /***********************************************************************
2429 * FILEDLG95_OnOpen
2431 * Ok button WM_COMMAND message handler
2433 * If the function succeeds, the return value is nonzero.
2435 BOOL FILEDLG95_OnOpen(HWND hwnd)
2437 LPWSTR lpstrFileList;
2438 UINT nFileCount = 0;
2439 UINT sizeUsed = 0;
2440 BOOL ret = TRUE;
2441 WCHAR lpstrPathAndFile[MAX_PATH];
2442 LPSHELLFOLDER lpsf = NULL;
2443 int nOpenAction;
2444 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2446 TRACE("hwnd=%p\n", hwnd);
2448 /* try to browse the selected item */
2449 if(BrowseSelectedFolder(hwnd))
2450 return FALSE;
2452 /* get the files from the edit control */
2453 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2455 if(nFileCount == 0)
2456 return FALSE;
2458 if(nFileCount > 1)
2460 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2461 goto ret;
2464 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2467 Step 1: Build a complete path name from the current folder and
2468 the filename or path in the edit box.
2469 Special cases:
2470 - the path in the edit box is a root path
2471 (with or without drive letter)
2472 - the edit box contains ".." (or a path with ".." in it)
2475 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2476 MemFree(lpstrFileList);
2479 Step 2: here we have a cleaned up path
2481 We have to parse the path step by step to see if we have to browse
2482 to a folder if the path points to a directory or the last
2483 valid element is a directory.
2485 valid variables:
2486 lpstrPathAndFile: cleaned up path
2489 if (nFileCount &&
2490 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2491 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2492 nOpenAction = ONOPEN_OPEN;
2493 else
2494 nOpenAction = ONOPEN_BROWSE;
2496 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2497 fodInfos->ofnInfos->Flags,
2498 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2499 nOpenAction);
2500 if(!nOpenAction)
2501 goto ret;
2504 Step 3: here we have a cleaned up and validated path
2506 valid variables:
2507 lpsf: ShellFolder bound to the rightmost valid path component
2508 lpstrPathAndFile: cleaned up path
2509 nOpenAction: action to do
2511 TRACE("end validate sf=%p\n", lpsf);
2513 switch(nOpenAction)
2515 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2516 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2518 int iPos;
2519 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2520 DWORD len;
2522 /* replace the current filter */
2523 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2524 len = lstrlenW(lpszTemp)+1;
2525 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2526 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2528 /* set the filter cb to the extension when possible */
2529 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2530 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2532 /* fall through */
2533 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2534 TRACE("ONOPEN_BROWSE\n");
2536 IPersistFolder2 * ppf2;
2537 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2539 LPITEMIDLIST pidlCurrent;
2540 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2541 IPersistFolder2_Release(ppf2);
2542 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2544 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2545 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2547 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2550 else if( nOpenAction == ONOPEN_SEARCH )
2552 if (fodInfos->Shell.FOIShellView)
2553 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2555 COMDLG32_SHFree(pidlCurrent);
2556 if (filename_is_edit( fodInfos ))
2557 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2560 ret = FALSE;
2561 break;
2562 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2563 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2565 WCHAR *ext = NULL;
2567 /* update READONLY check box flag */
2568 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2569 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2570 else
2571 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2573 /* Attach the file extension with file name*/
2574 ext = PathFindExtensionW(lpstrPathAndFile);
2575 if (! *ext && fodInfos->defext)
2577 /* if no extension is specified with file name, then */
2578 /* attach the extension from file filter or default one */
2580 WCHAR *filterExt = NULL;
2581 LPWSTR lpstrFilter = NULL;
2582 static const WCHAR szwDot[] = {'.',0};
2583 int PathLength = lstrlenW(lpstrPathAndFile);
2585 /*Get the file extension from file type filter*/
2586 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2587 fodInfos->ofnInfos->nFilterIndex-1);
2589 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2591 WCHAR* filterSearchIndex;
2592 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2593 strcpyW(filterExt, lpstrFilter);
2595 /* if a semicolon-separated list of file extensions was given, do not include the
2596 semicolon or anything after it in the extension.
2597 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2598 filterSearchIndex = strchrW(filterExt, ';');
2599 if (filterSearchIndex)
2601 filterSearchIndex[0] = '\0';
2604 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2605 /* if the extension is invalid or contains a glob, ignore it */
2606 filterSearchIndex = PathFindExtensionW(filterExt);
2607 if (*filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2609 strcpyW(filterExt, filterSearchIndex);
2611 else
2613 HeapFree(GetProcessHeap(), 0, filterExt);
2614 filterExt = NULL;
2618 if (!filterExt)
2620 /* use the default file extension */
2621 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2622 strcpyW(filterExt, fodInfos->defext);
2625 if (*filterExt) /* ignore filterExt="" */
2627 /* Attach the dot*/
2628 lstrcatW(lpstrPathAndFile, szwDot);
2629 /* Attach the extension */
2630 lstrcatW(lpstrPathAndFile, filterExt);
2633 HeapFree(GetProcessHeap(), 0, filterExt);
2635 /* In Open dialog: if file does not exist try without extension */
2636 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2637 lpstrPathAndFile[PathLength] = '\0';
2639 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2640 if (*ext)
2641 ext++;
2642 if (!lstrcmpiW(fodInfos->defext, ext))
2643 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2644 else
2645 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2648 /* In Save dialog: check if the file already exists */
2649 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2650 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2651 && PathFileExistsW(lpstrPathAndFile))
2653 WCHAR lpstrOverwrite[100];
2654 int answer;
2656 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2657 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2658 MB_YESNO | MB_ICONEXCLAMATION);
2659 if (answer == IDNO || answer == IDCANCEL)
2661 ret = FALSE;
2662 goto ret;
2666 /* In Open dialog: check if it should be created if it doesn't exist */
2667 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2668 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2669 && !PathFileExistsW(lpstrPathAndFile))
2671 WCHAR lpstrCreate[100];
2672 int answer;
2674 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2675 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2676 MB_YESNO | MB_ICONEXCLAMATION);
2677 if (answer == IDNO || answer == IDCANCEL)
2679 ret = FALSE;
2680 goto ret;
2684 /* Check that the size of the file does not exceed buffer size.
2685 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2686 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2687 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2690 /* fill destination buffer */
2691 if (fodInfos->ofnInfos->lpstrFile)
2693 if(fodInfos->unicode)
2695 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2697 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2698 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2699 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2701 else
2703 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2705 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2706 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2707 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2708 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2712 if(fodInfos->unicode)
2714 LPWSTR lpszTemp;
2716 /* set filename offset */
2717 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2718 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2720 /* set extension offset */
2721 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2722 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2724 else
2726 LPSTR lpszTemp;
2727 CHAR tempFileA[MAX_PATH];
2729 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2730 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2731 tempFileA, sizeof(tempFileA), NULL, NULL);
2733 /* set filename offset */
2734 lpszTemp = PathFindFileNameA(tempFileA);
2735 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2737 /* set extension offset */
2738 lpszTemp = PathFindExtensionA(tempFileA);
2739 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2742 /* set the lpstrFileTitle */
2743 if(fodInfos->ofnInfos->lpstrFileTitle)
2745 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2746 if(fodInfos->unicode)
2748 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2749 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2751 else
2753 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2754 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2755 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2759 /* copy currently selected filter to lpstrCustomFilter */
2760 if (fodInfos->ofnInfos->lpstrCustomFilter)
2762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2763 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2764 NULL, 0, NULL, NULL);
2765 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2767 LPSTR s = ofn->lpstrCustomFilter;
2768 s += strlen(ofn->lpstrCustomFilter)+1;
2769 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2770 s, len, NULL, NULL);
2775 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2776 goto ret;
2778 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2780 TRACE("close\n");
2781 FILEDLG95_Clean(hwnd);
2782 ret = EndDialog(hwnd, TRUE);
2784 else
2786 WORD size;
2788 size = lstrlenW(lpstrPathAndFile) + 1;
2789 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2790 size += 1;
2791 /* return needed size in first two bytes of lpstrFile */
2792 if(fodInfos->ofnInfos->lpstrFile)
2793 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2794 FILEDLG95_Clean(hwnd);
2795 ret = EndDialog(hwnd, FALSE);
2796 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2799 break;
2802 ret:
2803 if(lpsf) IShellFolder_Release(lpsf);
2804 return ret;
2807 /***********************************************************************
2808 * FILEDLG95_SHELL_Init
2810 * Initialisation of the shell objects
2812 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2814 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2816 TRACE("\n");
2819 * Initialisation of the FileOpenDialogInfos structure
2822 /* Shell */
2824 /*ShellInfos */
2825 fodInfos->ShellInfos.hwndOwner = hwnd;
2827 /* Disable multi-select if flag not set */
2828 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2830 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2832 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2833 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2835 /* Construct the IShellBrowser interface */
2836 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2838 return NOERROR;
2841 /***********************************************************************
2842 * FILEDLG95_SHELL_ExecuteCommand
2844 * Change the folder option and refresh the view
2845 * If the function succeeds, the return value is nonzero.
2847 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2849 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2850 IContextMenu * pcm;
2852 TRACE("(%p,%p)\n", hwnd, lpVerb);
2854 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2855 SVGIO_BACKGROUND,
2856 &IID_IContextMenu,
2857 (LPVOID*)&pcm)))
2859 CMINVOKECOMMANDINFO ci;
2860 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2861 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2862 ci.lpVerb = lpVerb;
2863 ci.hwnd = hwnd;
2865 IContextMenu_InvokeCommand(pcm, &ci);
2866 IContextMenu_Release(pcm);
2869 return FALSE;
2872 /***********************************************************************
2873 * FILEDLG95_SHELL_UpFolder
2875 * Browse to the specified object
2876 * If the function succeeds, the return value is nonzero.
2878 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2880 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2882 TRACE("\n");
2884 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2885 NULL,
2886 SBSP_PARENT)))
2888 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2889 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2890 return TRUE;
2892 return FALSE;
2895 /***********************************************************************
2896 * FILEDLG95_SHELL_BrowseToDesktop
2898 * Browse to the Desktop
2899 * If the function succeeds, the return value is nonzero.
2901 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2903 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2904 LPITEMIDLIST pidl;
2905 HRESULT hres;
2907 TRACE("\n");
2909 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2910 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2911 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2912 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2913 COMDLG32_SHFree(pidl);
2914 return SUCCEEDED(hres);
2916 /***********************************************************************
2917 * FILEDLG95_SHELL_Clean
2919 * Cleans the memory used by shell objects
2921 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2923 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2925 TRACE("\n");
2927 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2929 /* clean Shell interfaces */
2930 if (fodInfos->Shell.FOIShellView)
2932 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2933 IShellView_Release(fodInfos->Shell.FOIShellView);
2935 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2936 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2937 if (fodInfos->Shell.FOIDataObject)
2938 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2941 /***********************************************************************
2942 * FILEDLG95_FILETYPE_Init
2944 * Initialisation of the file type combo box
2946 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2948 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2949 int nFilters = 0; /* number of filters */
2950 int nFilterIndexCB;
2952 TRACE("\n");
2954 if(fodInfos->customfilter)
2956 /* customfilter has one entry... title\0ext\0
2957 * Set first entry of combo box item with customfilter
2959 LPWSTR lpstrExt;
2960 LPCWSTR lpstrPos = fodInfos->customfilter;
2962 /* Get the title */
2963 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2965 /* Copy the extensions */
2966 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2967 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2968 lstrcpyW(lpstrExt,lpstrPos);
2970 /* Add the item at the end of the combo */
2971 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2972 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2973 nFilters++;
2975 if(fodInfos->filter)
2977 LPCWSTR lpstrPos = fodInfos->filter;
2979 for(;;)
2981 /* filter is a list... title\0ext\0......\0\0
2982 * Set the combo item text to the title and the item data
2983 * to the ext
2985 LPCWSTR lpstrDisplay;
2986 LPWSTR lpstrExt;
2988 /* Get the title */
2989 if(! *lpstrPos) break; /* end */
2990 lpstrDisplay = lpstrPos;
2991 lpstrPos += lstrlenW(lpstrPos) + 1;
2993 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2995 nFilters++;
2997 /* Copy the extensions */
2998 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2999 lstrcpyW(lpstrExt,lpstrPos);
3000 lpstrPos += lstrlenW(lpstrPos) + 1;
3002 /* Add the item at the end of the combo */
3003 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3005 /* malformed filters are added anyway... */
3006 if (!*lpstrExt) break;
3011 * Set the current filter to the one specified
3012 * in the initialisation structure
3014 if (fodInfos->filter || fodInfos->customfilter)
3016 LPWSTR lpstrFilter;
3018 /* Check to make sure our index isn't out of bounds. */
3019 if ( fodInfos->ofnInfos->nFilterIndex >
3020 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3021 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3023 /* set default filter index */
3024 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3025 fodInfos->ofnInfos->nFilterIndex = 1;
3027 /* calculate index of Combo Box item */
3028 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3029 if (fodInfos->customfilter == NULL)
3030 nFilterIndexCB--;
3032 /* Set the current index selection. */
3033 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3035 /* Get the corresponding text string from the combo box. */
3036 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3037 nFilterIndexCB);
3039 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3040 lpstrFilter = NULL;
3042 if(lpstrFilter)
3044 DWORD len;
3045 CharLowerW(lpstrFilter); /* lowercase */
3046 len = lstrlenW(lpstrFilter)+1;
3047 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3048 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3050 } else
3051 fodInfos->ofnInfos->nFilterIndex = 0;
3052 return S_OK;
3055 /***********************************************************************
3056 * FILEDLG95_FILETYPE_OnCommand
3058 * WM_COMMAND of the file type combo box
3059 * If the function succeeds, the return value is nonzero.
3061 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3063 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3065 switch(wNotifyCode)
3067 case CBN_SELENDOK:
3069 LPWSTR lpstrFilter;
3071 /* Get the current item of the filetype combo box */
3072 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3074 /* set the current filter index */
3075 fodInfos->ofnInfos->nFilterIndex = iItem +
3076 (fodInfos->customfilter == NULL ? 1 : 0);
3078 /* Set the current filter with the current selection */
3079 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3081 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3082 iItem);
3083 if((INT_PTR)lpstrFilter != CB_ERR)
3085 DWORD len;
3086 CharLowerW(lpstrFilter); /* lowercase */
3087 len = lstrlenW(lpstrFilter)+1;
3088 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3089 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3090 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3091 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3094 /* Refresh the actual view to display the included items*/
3095 if (fodInfos->Shell.FOIShellView)
3096 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3099 return FALSE;
3101 /***********************************************************************
3102 * FILEDLG95_FILETYPE_SearchExt
3104 * searches for an extension in the filetype box
3106 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3108 int i, iCount = CBGetCount(hwnd);
3110 TRACE("%s\n", debugstr_w(lpstrExt));
3112 if(iCount != CB_ERR)
3114 for(i=0;i<iCount;i++)
3116 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3117 return i;
3120 return -1;
3123 /***********************************************************************
3124 * FILEDLG95_FILETYPE_Clean
3126 * Clean the memory used by the filetype combo box
3128 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3130 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3131 int iPos;
3132 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3134 TRACE("\n");
3136 /* Delete each string of the combo and their associated data */
3137 if(iCount != CB_ERR)
3139 for(iPos = iCount-1;iPos>=0;iPos--)
3141 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3142 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3145 /* Current filter */
3146 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3150 /***********************************************************************
3151 * FILEDLG95_LOOKIN_Init
3153 * Initialisation of the look in combo box
3156 /* Small helper function, to determine if the unixfs shell extension is rooted
3157 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3159 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3160 HKEY hKey;
3161 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3162 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3163 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3164 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3165 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3166 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3167 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3169 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3170 return FALSE;
3172 RegCloseKey(hKey);
3173 return TRUE;
3176 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3178 IShellFolder *psfRoot, *psfDrives;
3179 IEnumIDList *lpeRoot, *lpeDrives;
3180 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3181 HDC hdc;
3182 TEXTMETRICW tm;
3183 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3185 TRACE("\n");
3187 liInfos->iMaxIndentation = 0;
3189 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3191 hdc = GetDC( hwndCombo );
3192 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3193 GetTextMetricsW( hdc, &tm );
3194 ReleaseDC( hwndCombo, hdc );
3196 /* set item height for both text field and listbox */
3197 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3198 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3200 /* Turn on the extended UI for the combo box like Windows does */
3201 CBSetExtendedUI(hwndCombo, TRUE);
3203 /* Initialise data of Desktop folder */
3204 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3205 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3206 COMDLG32_SHFree(pidlTmp);
3208 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3210 SHGetDesktopFolder(&psfRoot);
3212 if (psfRoot)
3214 /* enumerate the contents of the desktop */
3215 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3217 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3219 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3221 /* If the unixfs extension is rooted, we don't expand the drives by default */
3222 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3224 /* special handling for CSIDL_DRIVES */
3225 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3227 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3229 /* enumerate the drives */
3230 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3232 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3234 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3235 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3236 COMDLG32_SHFree(pidlAbsTmp);
3237 COMDLG32_SHFree(pidlTmp1);
3239 IEnumIDList_Release(lpeDrives);
3241 IShellFolder_Release(psfDrives);
3246 COMDLG32_SHFree(pidlTmp);
3248 IEnumIDList_Release(lpeRoot);
3250 IShellFolder_Release(psfRoot);
3253 COMDLG32_SHFree(pidlDrives);
3256 /***********************************************************************
3257 * FILEDLG95_LOOKIN_DrawItem
3259 * WM_DRAWITEM message handler
3261 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3263 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3264 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3265 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3266 RECT rectText;
3267 RECT rectIcon;
3268 SHFILEINFOW sfi;
3269 HIMAGELIST ilItemImage;
3270 int iIndentation;
3271 TEXTMETRICW tm;
3272 LPSFOLDER tmpFolder;
3273 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3274 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3275 UINT icon_width, icon_height;
3277 TRACE("\n");
3279 if(pDIStruct->itemID == -1)
3280 return 0;
3282 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3283 pDIStruct->itemID)))
3284 return 0;
3287 icon_width = GetSystemMetrics(SM_CXICON);
3288 icon_height = GetSystemMetrics(SM_CYICON);
3289 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3291 icon_width = GetSystemMetrics(SM_CXSMICON);
3292 icon_height = GetSystemMetrics(SM_CYSMICON);
3293 shgfi_flags |= SHGFI_SMALLICON;
3296 if(pDIStruct->itemID == liInfos->uSelectedItem)
3298 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3299 0, &sfi, sizeof (sfi), shgfi_flags );
3301 else
3303 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3304 0, &sfi, sizeof (sfi), shgfi_flags );
3307 /* Is this item selected ? */
3308 if(pDIStruct->itemState & ODS_SELECTED)
3310 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3311 SetBkColor(pDIStruct->hDC,crHighLight);
3312 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3314 else
3316 SetTextColor(pDIStruct->hDC,crText);
3317 SetBkColor(pDIStruct->hDC,crWin);
3318 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3321 /* Do not indent item if drawing in the edit of the combo */
3322 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3324 iIndentation = 0;
3325 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3326 0, &sfi, sizeof (sfi), shgfi_flags );
3329 else
3331 iIndentation = tmpFolder->m_iIndent;
3333 /* Draw text and icon */
3335 /* Initialise the icon display area */
3336 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3337 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3338 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3339 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3341 /* Initialise the text display area */
3342 GetTextMetricsW(pDIStruct->hDC, &tm);
3343 rectText.left = rectIcon.right;
3344 rectText.top =
3345 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3346 rectText.right = pDIStruct->rcItem.right;
3347 rectText.bottom =
3348 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3350 /* Draw the icon from the image list */
3351 ImageList_Draw(ilItemImage,
3352 sfi.iIcon,
3353 pDIStruct->hDC,
3354 rectIcon.left,
3355 rectIcon.top,
3356 ILD_TRANSPARENT );
3358 /* Draw the associated text */
3359 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3360 return NOERROR;
3363 /***********************************************************************
3364 * FILEDLG95_LOOKIN_OnCommand
3366 * LookIn combo box WM_COMMAND message handler
3367 * If the function succeeds, the return value is nonzero.
3369 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3371 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3373 TRACE("%p\n", fodInfos);
3375 switch(wNotifyCode)
3377 case CBN_SELENDOK:
3379 LPSFOLDER tmpFolder;
3380 int iItem;
3382 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3384 if( iItem == CB_ERR) return FALSE;
3386 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3387 iItem)))
3388 return FALSE;
3391 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3392 tmpFolder->pidlItem,
3393 SBSP_ABSOLUTE)))
3395 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3396 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3397 return TRUE;
3399 break;
3403 return FALSE;
3406 /***********************************************************************
3407 * FILEDLG95_LOOKIN_AddItem
3409 * Adds an absolute pidl item to the lookin combo box
3410 * returns the index of the inserted item
3412 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3414 LPITEMIDLIST pidlNext;
3415 SHFILEINFOW sfi;
3416 SFOLDER *tmpFolder;
3417 LookInInfos *liInfos;
3419 TRACE("%08x\n", iInsertId);
3421 if(!pidl)
3422 return -1;
3424 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3425 return -1;
3427 tmpFolder = MemAlloc(sizeof(SFOLDER));
3428 tmpFolder->m_iIndent = 0;
3430 /* Calculate the indentation of the item in the lookin*/
3431 pidlNext = pidl;
3432 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3434 tmpFolder->m_iIndent++;
3437 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3439 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3440 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3442 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3443 SHGetFileInfoW((LPCWSTR)pidl,
3445 &sfi,
3446 sizeof(sfi),
3447 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3448 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3450 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3452 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3454 int iItemID;
3456 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3458 /* Add the item at the end of the list */
3459 if(iInsertId < 0)
3461 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3463 /* Insert the item at the iInsertId position*/
3464 else
3466 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3469 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3470 return iItemID;
3473 COMDLG32_SHFree( tmpFolder->pidlItem );
3474 MemFree( tmpFolder );
3475 return -1;
3479 /***********************************************************************
3480 * FILEDLG95_LOOKIN_InsertItemAfterParent
3482 * Insert an item below its parent
3484 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3487 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3488 int iParentPos;
3490 TRACE("\n");
3492 if (pidl == pidlParent)
3493 return -1;
3495 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3497 if(iParentPos < 0)
3499 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3502 /* Free pidlParent memory */
3503 COMDLG32_SHFree(pidlParent);
3505 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3508 /***********************************************************************
3509 * FILEDLG95_LOOKIN_SelectItem
3511 * Adds an absolute pidl item to the lookin combo box
3512 * returns the index of the inserted item
3514 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3516 int iItemPos;
3517 LookInInfos *liInfos;
3519 TRACE("\n");
3521 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3523 liInfos = GetPropA(hwnd,LookInInfosStr);
3525 if(iItemPos < 0)
3527 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3528 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3531 else
3533 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3534 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3536 int iRemovedItem;
3538 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3539 break;
3540 if(iRemovedItem < iItemPos)
3541 iItemPos--;
3545 CBSetCurSel(hwnd,iItemPos);
3546 liInfos->uSelectedItem = iItemPos;
3548 return 0;
3552 /***********************************************************************
3553 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3555 * Remove the item with an expansion level over iExpansionLevel
3557 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3559 int iItemPos;
3560 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3562 TRACE("\n");
3564 if(liInfos->iMaxIndentation <= 2)
3565 return -1;
3567 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3569 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3570 COMDLG32_SHFree(tmpFolder->pidlItem);
3571 MemFree(tmpFolder);
3572 CBDeleteString(hwnd,iItemPos);
3573 liInfos->iMaxIndentation--;
3575 return iItemPos;
3578 return -1;
3581 /***********************************************************************
3582 * FILEDLG95_LOOKIN_SearchItem
3584 * Search for pidl in the lookin combo box
3585 * returns the index of the found item
3587 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3589 int i = 0;
3590 int iCount = CBGetCount(hwnd);
3592 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3594 if (iCount != CB_ERR)
3596 for(;i<iCount;i++)
3598 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3600 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3601 return i;
3602 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3603 return i;
3607 return -1;
3610 /***********************************************************************
3611 * FILEDLG95_LOOKIN_Clean
3613 * Clean the memory used by the lookin combo box
3615 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3617 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3618 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3619 int iPos;
3620 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3622 TRACE("\n");
3624 /* Delete each string of the combo and their associated data */
3625 if (iCount != CB_ERR)
3627 for(iPos = iCount-1;iPos>=0;iPos--)
3629 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3630 COMDLG32_SHFree(tmpFolder->pidlItem);
3631 MemFree(tmpFolder);
3632 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3636 /* LookInInfos structure */
3637 MemFree(liInfos);
3638 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3641 /***********************************************************************
3642 * FILEDLG95_FILENAME_FillFromSelection
3644 * fills the edit box from the cached DataObject
3646 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3648 FileOpenDlgInfos *fodInfos;
3649 LPITEMIDLIST pidl;
3650 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3651 WCHAR lpstrTemp[MAX_PATH];
3652 LPWSTR lpstrAllFile, lpstrCurrFile;
3654 TRACE("\n");
3655 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3657 /* Count how many files we have */
3658 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3660 /* calculate the string length, count files */
3661 if (nFileSelected >= 1)
3663 nLength += 3; /* first and last quotes, trailing \0 */
3664 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3666 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3668 if (pidl)
3670 /* get the total length of the selected file names */
3671 lpstrTemp[0] = '\0';
3672 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3674 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3676 nLength += lstrlenW( lpstrTemp ) + 3;
3677 nFiles++;
3679 COMDLG32_SHFree( pidl );
3684 /* allocate the buffer */
3685 if (nFiles <= 1) nLength = MAX_PATH;
3686 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3688 /* Generate the string for the edit control */
3689 if(nFiles >= 1)
3691 lpstrCurrFile = lpstrAllFile;
3692 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3694 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3696 if (pidl)
3698 /* get the file name */
3699 lpstrTemp[0] = '\0';
3700 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3702 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3704 if ( nFiles > 1)
3706 *lpstrCurrFile++ = '\"';
3707 lstrcpyW( lpstrCurrFile, lpstrTemp );
3708 lpstrCurrFile += lstrlenW( lpstrTemp );
3709 *lpstrCurrFile++ = '\"';
3710 *lpstrCurrFile++ = ' ';
3711 *lpstrCurrFile = 0;
3713 else
3715 lstrcpyW( lpstrAllFile, lpstrTemp );
3718 COMDLG32_SHFree( pidl );
3721 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3723 /* Select the file name like Windows does */
3724 if (filename_is_edit( fodInfos ))
3725 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3727 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3731 /* copied from shell32 to avoid linking to it
3732 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3733 * is dependent on whether emulated OS is unicode or not.
3735 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3737 switch (src->uType)
3739 case STRRET_WSTR:
3740 lstrcpynW(dest, src->u.pOleStr, len);
3741 COMDLG32_SHFree(src->u.pOleStr);
3742 break;
3744 case STRRET_CSTR:
3745 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3746 dest[len-1] = 0;
3747 break;
3749 case STRRET_OFFSET:
3750 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3751 dest[len-1] = 0;
3752 break;
3754 default:
3755 FIXME("unknown type %x!\n", src->uType);
3756 if (len) *dest = '\0';
3757 return E_FAIL;
3759 return S_OK;
3762 /***********************************************************************
3763 * FILEDLG95_FILENAME_GetFileNames
3765 * Copies the filenames to a delimited string list.
3767 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3769 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3770 UINT nFileCount = 0; /* number of files */
3771 UINT nStrLen = 0; /* length of string in edit control */
3772 LPWSTR lpstrEdit; /* buffer for string from edit control */
3774 TRACE("\n");
3776 /* get the filenames from the filename control */
3777 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3778 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3779 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3781 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3783 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3784 MemFree(lpstrEdit);
3785 return nFileCount;
3788 #define SETDefFormatEtc(fe,cf,med) \
3790 (fe).cfFormat = cf;\
3791 (fe).dwAspect = DVASPECT_CONTENT; \
3792 (fe).ptd =NULL;\
3793 (fe).tymed = med;\
3794 (fe).lindex = -1;\
3798 * DATAOBJECT Helper functions
3801 /***********************************************************************
3802 * COMCTL32_ReleaseStgMedium
3804 * like ReleaseStgMedium from ole32
3806 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3808 if(medium.pUnkForRelease)
3810 IUnknown_Release(medium.pUnkForRelease);
3812 else
3814 GlobalUnlock(medium.u.hGlobal);
3815 GlobalFree(medium.u.hGlobal);
3819 /***********************************************************************
3820 * GetPidlFromDataObject
3822 * Return pidl(s) by number from the cached DataObject
3824 * nPidlIndex=0 gets the fully qualified root path
3826 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3829 STGMEDIUM medium;
3830 FORMATETC formatetc;
3831 LPITEMIDLIST pidl = NULL;
3833 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3835 if (!doSelected)
3836 return NULL;
3838 /* Set the FORMATETC structure*/
3839 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3841 /* Get the pidls from IDataObject */
3842 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3844 LPIDA cida = GlobalLock(medium.u.hGlobal);
3845 if(nPidlIndex <= cida->cidl)
3847 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3849 COMCTL32_ReleaseStgMedium(medium);
3851 return pidl;
3854 /***********************************************************************
3855 * GetNumSelected
3857 * Return the number of selected items in the DataObject.
3860 static UINT GetNumSelected( IDataObject *doSelected )
3862 UINT retVal = 0;
3863 STGMEDIUM medium;
3864 FORMATETC formatetc;
3866 TRACE("sv=%p\n", doSelected);
3868 if (!doSelected) return 0;
3870 /* Set the FORMATETC structure*/
3871 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3873 /* Get the pidls from IDataObject */
3874 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3876 LPIDA cida = GlobalLock(medium.u.hGlobal);
3877 retVal = cida->cidl;
3878 COMCTL32_ReleaseStgMedium(medium);
3879 return retVal;
3881 return 0;
3885 * TOOLS
3888 /***********************************************************************
3889 * GetName
3891 * Get the pidl's display name (relative to folder) and
3892 * put it in lpstrFileName.
3894 * Return NOERROR on success,
3895 * E_FAIL otherwise
3898 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3900 STRRET str;
3901 HRESULT hRes;
3903 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3905 if(!lpsf)
3907 SHGetDesktopFolder(&lpsf);
3908 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3909 IShellFolder_Release(lpsf);
3910 return hRes;
3913 /* Get the display name of the pidl relative to the folder */
3914 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3916 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3918 return E_FAIL;
3921 /***********************************************************************
3922 * GetShellFolderFromPidl
3924 * pidlRel is the item pidl relative
3925 * Return the IShellFolder of the absolute pidl
3927 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3929 IShellFolder *psf = NULL,*psfParent;
3931 TRACE("%p\n", pidlAbs);
3933 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3935 psf = psfParent;
3936 if(pidlAbs && pidlAbs->mkid.cb)
3938 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3940 IShellFolder_Release(psfParent);
3941 return psf;
3944 /* return the desktop */
3945 return psfParent;
3947 return NULL;
3950 /***********************************************************************
3951 * GetParentPidl
3953 * Return the LPITEMIDLIST to the parent of the pidl in the list
3955 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3957 LPITEMIDLIST pidlParent;
3959 TRACE("%p\n", pidl);
3961 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3962 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3964 return pidlParent;
3967 /***********************************************************************
3968 * GetPidlFromName
3970 * returns the pidl of the file name relative to folder
3971 * NULL if an error occurred
3973 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3975 LPITEMIDLIST pidl = NULL;
3976 ULONG ulEaten;
3978 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3980 if(!lpcstrFileName) return NULL;
3981 if(!*lpcstrFileName) return NULL;
3983 if(!lpsf)
3985 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3986 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3987 IShellFolder_Release(lpsf);
3990 else
3992 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3994 return pidl;
3999 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4001 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4002 HRESULT ret;
4004 TRACE("%p, %p\n", psf, pidl);
4006 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4008 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4009 /* see documentation shell 4.1*/
4010 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4013 /***********************************************************************
4014 * BrowseSelectedFolder
4016 static BOOL BrowseSelectedFolder(HWND hwnd)
4018 BOOL bBrowseSelFolder = FALSE;
4019 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4021 TRACE("\n");
4023 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4025 LPITEMIDLIST pidlSelection;
4027 /* get the file selected */
4028 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4029 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4031 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4032 pidlSelection, SBSP_RELATIVE ) ) )
4034 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4035 ' ','n','o','t',' ','e','x','i','s','t',0};
4036 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4038 bBrowseSelFolder = TRUE;
4039 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4040 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4042 COMDLG32_SHFree( pidlSelection );
4045 return bBrowseSelFolder;
4049 * Memory allocation methods */
4050 static void *MemAlloc(UINT size)
4052 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4055 static void MemFree(void *mem)
4057 HeapFree(GetProcessHeap(),0,mem);
4060 static inline BOOL valid_struct_size( DWORD size )
4062 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4063 (size == sizeof( OPENFILENAMEW ));
4066 static inline BOOL is_win16_looks(DWORD flags)
4068 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4069 !(flags & OFN_EXPLORER));
4072 /* ------------------ APIs ---------------------- */
4074 /***********************************************************************
4075 * GetOpenFileNameA (COMDLG32.@)
4077 * Creates a dialog box for the user to select a file to open.
4079 * RETURNS
4080 * TRUE on success: user enters a valid file
4081 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4084 BOOL WINAPI GetOpenFileNameA(
4085 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4087 TRACE("flags %08x\n", ofn->Flags);
4089 if (!valid_struct_size( ofn->lStructSize ))
4091 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4092 return FALSE;
4095 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4096 if (ofn->Flags & OFN_FILEMUSTEXIST)
4097 ofn->Flags |= OFN_PATHMUSTEXIST;
4099 if (is_win16_looks(ofn->Flags))
4100 return GetFileName31A(ofn, OPEN_DIALOG);
4101 else
4102 return GetFileDialog95A(ofn, OPEN_DIALOG);
4105 /***********************************************************************
4106 * GetOpenFileNameW (COMDLG32.@)
4108 * Creates a dialog box for the user to select a file to open.
4110 * RETURNS
4111 * TRUE on success: user enters a valid file
4112 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4115 BOOL WINAPI GetOpenFileNameW(
4116 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4118 TRACE("flags %08x\n", ofn->Flags);
4120 if (!valid_struct_size( ofn->lStructSize ))
4122 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4123 return FALSE;
4126 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4127 if (ofn->Flags & OFN_FILEMUSTEXIST)
4128 ofn->Flags |= OFN_PATHMUSTEXIST;
4130 if (is_win16_looks(ofn->Flags))
4131 return GetFileName31W(ofn, OPEN_DIALOG);
4132 else
4133 return GetFileDialog95W(ofn, OPEN_DIALOG);
4137 /***********************************************************************
4138 * GetSaveFileNameA (COMDLG32.@)
4140 * Creates a dialog box for the user to select a file to save.
4142 * RETURNS
4143 * TRUE on success: user enters a valid file
4144 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4147 BOOL WINAPI GetSaveFileNameA(
4148 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4150 if (!valid_struct_size( ofn->lStructSize ))
4152 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4153 return FALSE;
4156 if (is_win16_looks(ofn->Flags))
4157 return GetFileName31A(ofn, SAVE_DIALOG);
4158 else
4159 return GetFileDialog95A(ofn, SAVE_DIALOG);
4162 /***********************************************************************
4163 * GetSaveFileNameW (COMDLG32.@)
4165 * Creates a dialog box for the user to select a file to save.
4167 * RETURNS
4168 * TRUE on success: user enters a valid file
4169 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4172 BOOL WINAPI GetSaveFileNameW(
4173 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4175 if (!valid_struct_size( ofn->lStructSize ))
4177 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4178 return FALSE;
4181 if (is_win16_looks(ofn->Flags))
4182 return GetFileName31W(ofn, SAVE_DIALOG);
4183 else
4184 return GetFileDialog95W(ofn, SAVE_DIALOG);
4187 /***********************************************************************
4188 * GetFileTitleA (COMDLG32.@)
4190 * See GetFileTitleW.
4192 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4194 int ret;
4195 UNICODE_STRING strWFile;
4196 LPWSTR lpWTitle;
4198 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4199 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4200 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4201 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4202 RtlFreeUnicodeString( &strWFile );
4203 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4204 return ret;
4208 /***********************************************************************
4209 * GetFileTitleW (COMDLG32.@)
4211 * Get the name of a file.
4213 * PARAMS
4214 * lpFile [I] name and location of file
4215 * lpTitle [O] returned file name
4216 * cbBuf [I] buffer size of lpTitle
4218 * RETURNS
4219 * Success: zero
4220 * Failure: negative number.
4222 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4224 int i, len;
4225 static const WCHAR brkpoint[] = {'*','[',']',0};
4226 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4228 if(lpFile == NULL || lpTitle == NULL)
4229 return -1;
4231 len = lstrlenW(lpFile);
4233 if (len == 0)
4234 return -1;
4236 if(strpbrkW(lpFile, brkpoint))
4237 return -1;
4239 len--;
4241 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4242 return -1;
4244 for(i = len; i >= 0; i--)
4246 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4248 i++;
4249 break;
4253 if(i == -1)
4254 i++;
4256 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4258 len = lstrlenW(lpFile+i)+1;
4259 if(cbBuf < len)
4260 return len;
4262 lstrcpyW(lpTitle, &lpFile[i]);
4263 return 0;