winebus.sys: IOCTL_HID_SET_OUTPUTREPORT for iohid.
[wine.git] / dlls / comdlg32 / filedlg.c
blob67b35665d2755627f73fdafdb32acab083f2699a
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
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winternl.h"
63 #include "winnls.h"
64 #include "wingdi.h"
65 #include "winreg.h"
66 #include "winuser.h"
67 #include "commdlg.h"
68 #include "dlgs.h"
69 #include "cdlg.h"
70 #include "cderr.h"
71 #include "shellapi.h"
72 #include "shlobj.h"
73 #include "filedlgbrowser.h"
74 #include "shlwapi.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex; /* Index of picture in image list */
94 HIMAGELIST hImgList;
95 int m_iIndent; /* Indentation index */
96 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
98 } SFOLDER,*LPSFOLDER;
100 typedef struct tagLookInInfo
102 int iMaxIndentation;
103 UINT uSelectedItem;
104 } LookInInfos;
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
114 /* AddItem flags*/
115 #define LISTEND -1
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
119 #define SEARCH_EXP 2
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
125 /* NOTE
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
166 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
167 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
169 static const WCHAR LastVisitedMRUW[] =
170 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
173 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
174 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
176 /***********************************************************************
177 * Prototypes
180 /* Internal functions used by the dialog */
181 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 static BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Functions for dealing with the most-recently-used registry keys */
217 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
218 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
219 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
221 /* Miscellaneous tool functions */
222 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
223 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
224 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
225 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
227 static UINT GetNumSelected( IDataObject *doSelected );
228 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
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 ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
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. It may be NULL
1569 * when the filename contains only a drive name instead of file name */
1570 if (nameBit)
1572 lstrcpyW(fodInfos->filename,nameBit);
1573 *nameBit = 0x00;
1575 else
1576 *fodInfos->filename = '\0';
1578 MemFree(fodInfos->initdir);
1579 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1580 lstrcpyW(fodInfos->initdir, tmpBuf);
1581 handledPath = TRUE;
1582 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1583 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1585 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1587 } else {
1588 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1592 /* 2. (All platforms) If initdir is not null, then use it */
1593 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1595 /* Work out the proper path as supplied one might be relative */
1596 /* (Here because supplying '.' as dir browses to My Computer) */
1597 WCHAR tmpBuf[MAX_PATH];
1598 WCHAR tmpBuf2[MAX_PATH];
1599 WCHAR *nameBit;
1600 DWORD result;
1602 lstrcpyW(tmpBuf, fodInfos->initdir);
1603 if (PathFileExistsW(tmpBuf)) {
1604 /* initdir does not have to be a directory. If a file is
1605 * specified, the dir part is taken */
1606 if (PathIsDirectoryW(tmpBuf)) {
1607 PathAddBackslashW(tmpBuf);
1608 lstrcatW(tmpBuf, szwStar);
1610 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1611 if (result) {
1612 *nameBit = 0x00;
1613 MemFree(fodInfos->initdir);
1614 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1615 lstrcpyW(fodInfos->initdir, tmpBuf2);
1616 handledPath = TRUE;
1617 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1620 else if (fodInfos->initdir)
1622 MemFree(fodInfos->initdir);
1623 fodInfos->initdir = NULL;
1624 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1628 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1630 /* 3. All except w2k+: if filename contains a path use it */
1631 if (!win2000plus && fodInfos->filename &&
1632 *fodInfos->filename &&
1633 strpbrkW(fodInfos->filename, szwSlash)) {
1634 WCHAR tmpBuf[MAX_PATH];
1635 WCHAR *nameBit;
1636 DWORD result;
1638 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1639 tmpBuf, &nameBit);
1640 if (result) {
1641 int len;
1643 /* nameBit is always shorter than the original filename */
1644 lstrcpyW(fodInfos->filename, nameBit);
1645 *nameBit = 0x00;
1647 len = lstrlenW(tmpBuf);
1648 MemFree(fodInfos->initdir);
1649 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1650 lstrcpyW(fodInfos->initdir, tmpBuf);
1652 handledPath = TRUE;
1653 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1654 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1656 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1659 /* 4. Win2000+: Recently used */
1660 if (!handledPath && win2000plus) {
1661 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1662 fodInfos->initdir[0] = '\0';
1664 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1666 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1667 handledPath = TRUE;
1668 }else{
1669 MemFree(fodInfos->initdir);
1670 fodInfos->initdir = NULL;
1674 /* 5. win98+ and win2000+ if any files of specified filter types in
1675 current directory, use it */
1676 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1678 LPCWSTR lpstrPos = fodInfos->filter;
1679 WIN32_FIND_DATAW FindFileData;
1680 HANDLE hFind;
1682 while (1)
1684 /* filter is a list... title\0ext\0......\0\0 */
1686 /* Skip the title */
1687 if(! *lpstrPos) break; /* end */
1688 lpstrPos += lstrlenW(lpstrPos) + 1;
1690 /* See if any files exist in the current dir with this extension */
1691 if(! *lpstrPos) break; /* end */
1693 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1695 if (hFind == INVALID_HANDLE_VALUE) {
1696 /* None found - continue search */
1697 lpstrPos += lstrlenW(lpstrPos) + 1;
1699 } else {
1701 MemFree(fodInfos->initdir);
1702 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1703 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1705 handledPath = TRUE;
1706 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1707 debugstr_w(lpstrPos));
1708 FindClose(hFind);
1709 break;
1714 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1715 if (!handledPath && (win2000plus || win98plus)) {
1716 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1718 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1720 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1722 /* last fallback */
1723 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1724 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1725 } else {
1726 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1728 } else {
1729 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1731 handledPath = TRUE;
1732 } else if (!handledPath) {
1733 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1734 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1735 handledPath = TRUE;
1736 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1739 SetFocus( fodInfos->DlgInfos.hwndFileName );
1740 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1742 /* Must the open as read only check box be checked ?*/
1743 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1745 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1748 /* Must the open as read only check box be hidden? */
1749 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1751 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1752 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1755 /* Must the help button be hidden? */
1756 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1758 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1759 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1762 /* change Open to Save */
1763 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1765 WCHAR buf[16];
1766 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1767 SetDlgItemTextW(hwnd, IDOK, buf);
1768 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1769 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1772 /* Initialize the filter combo box */
1773 FILEDLG95_FILETYPE_Init(hwnd);
1775 return 0;
1778 /***********************************************************************
1779 * FILEDLG95_ResizeControls
1781 * WM_INITDIALOG message handler (after hook notification)
1783 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1785 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1787 if (fodInfos->DlgInfos.hwndCustomDlg)
1789 RECT rc;
1790 UINT flags = SWP_NOACTIVATE;
1792 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1793 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1795 /* resize the custom dialog to the parent size */
1796 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1797 GetClientRect(hwnd, &rc);
1798 else
1800 /* our own fake template is zero sized and doesn't have children, so
1801 * there is no need to resize it. Picasa depends on it.
1803 flags |= SWP_NOSIZE;
1804 SetRectEmpty(&rc);
1806 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1807 0, 0, rc.right, rc.bottom, flags);
1809 else
1811 /* Resize the height; if opened as read-only, checkbox and help button are
1812 * hidden and we are not using a custom template nor a customDialog
1814 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1815 (!(fodInfos->ofnInfos->Flags &
1816 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1818 RECT rectDlg, rectHelp, rectCancel;
1819 GetWindowRect(hwnd, &rectDlg);
1820 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1821 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1822 /* subtract the height of the help button plus the space between the help
1823 * button and the cancel button to the height of the dialog
1825 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1826 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1827 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1830 return TRUE;
1833 /***********************************************************************
1834 * FILEDLG95_FillControls
1836 * WM_INITDIALOG message handler (after hook notification)
1838 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1840 LPITEMIDLIST pidlItemId = NULL;
1842 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1844 TRACE("dir=%s file=%s\n",
1845 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1847 /* Get the initial directory pidl */
1849 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1851 WCHAR path[MAX_PATH];
1853 GetCurrentDirectoryW(MAX_PATH,path);
1854 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1857 /* Initialise shell objects */
1858 FILEDLG95_SHELL_Init(hwnd);
1860 /* Initialize the Look In combo box */
1861 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1863 /* Browse to the initial directory */
1864 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1866 /* Free pidlItem memory */
1867 COMDLG32_SHFree(pidlItemId);
1869 return TRUE;
1871 /***********************************************************************
1872 * FILEDLG95_Clean
1874 * Regroups all the cleaning functions of the filedlg
1876 void FILEDLG95_Clean(HWND hwnd)
1878 FILEDLG95_FILETYPE_Clean(hwnd);
1879 FILEDLG95_LOOKIN_Clean(hwnd);
1880 FILEDLG95_SHELL_Clean(hwnd);
1882 /***********************************************************************
1883 * FILEDLG95_OnWMCommand
1885 * WM_COMMAND message handler
1887 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1889 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1890 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1891 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1893 switch(wID)
1895 /* OK button */
1896 case IDOK:
1897 FILEDLG95_OnOpen(hwnd);
1898 break;
1899 /* Cancel button */
1900 case IDCANCEL:
1901 FILEDLG95_Clean(hwnd);
1902 EndDialog(hwnd, FALSE);
1903 break;
1904 /* Filetype combo box */
1905 case IDC_FILETYPE:
1906 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1907 break;
1908 /* LookIn combo box */
1909 case IDC_LOOKIN:
1910 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1911 break;
1913 /* --- toolbar --- */
1914 /* Up folder button */
1915 case FCIDM_TB_UPFOLDER:
1916 FILEDLG95_SHELL_UpFolder(hwnd);
1917 break;
1918 /* New folder button */
1919 case FCIDM_TB_NEWFOLDER:
1920 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1921 break;
1922 /* List option button */
1923 case FCIDM_TB_SMALLICON:
1924 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1925 break;
1926 /* Details option button */
1927 case FCIDM_TB_REPORTVIEW:
1928 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1929 break;
1930 /* Details option button */
1931 case FCIDM_TB_DESKTOP:
1932 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1933 break;
1935 case edt1:
1936 case cmb13:
1937 break;
1940 /* Do not use the listview selection anymore */
1941 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1942 return 0;
1945 /***********************************************************************
1946 * FILEDLG95_OnWMGetIShellBrowser
1948 * WM_GETISHELLBROWSER message handler
1950 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1952 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1954 TRACE("\n");
1956 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1958 return TRUE;
1962 /***********************************************************************
1963 * FILEDLG95_SendFileOK
1965 * Sends the CDN_FILEOK notification if required
1967 * RETURNS
1968 * TRUE if the dialog should close
1969 * FALSE if the dialog should not be closed
1971 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1973 /* ask the hook if we can close */
1974 if(IsHooked(fodInfos))
1976 LRESULT retval = 0;
1978 TRACE("---\n");
1979 /* First send CDN_FILEOK as MSDN doc says */
1980 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1981 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1982 if( retval)
1984 TRACE("canceled\n");
1985 return FALSE;
1988 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1989 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1990 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1991 if( retval)
1993 TRACE("canceled\n");
1994 return FALSE;
1997 return TRUE;
2000 /***********************************************************************
2001 * FILEDLG95_OnOpenMultipleFiles
2003 * Handles the opening of multiple files.
2005 * FIXME
2006 * check destination buffer size
2008 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2010 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2011 UINT nCount, nSizePath;
2012 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2014 TRACE("\n");
2016 if(fodInfos->unicode)
2018 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2019 ofn->lpstrFile[0] = '\0';
2021 else
2023 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2024 ofn->lpstrFile[0] = '\0';
2027 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2029 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2030 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2031 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2033 LPWSTR lpstrTemp = lpstrFileList;
2035 for ( nCount = 0; nCount < nFileCount; nCount++ )
2037 LPITEMIDLIST pidl;
2039 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2040 if (!pidl)
2042 WCHAR lpstrNotFound[100];
2043 WCHAR lpstrMsg[100];
2044 WCHAR tmp[400];
2045 static const WCHAR nl[] = {'\n',0};
2047 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2048 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2050 lstrcpyW(tmp, lpstrTemp);
2051 lstrcatW(tmp, nl);
2052 lstrcatW(tmp, lpstrNotFound);
2053 lstrcatW(tmp, nl);
2054 lstrcatW(tmp, lpstrMsg);
2056 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2057 return FALSE;
2060 /* move to the next file in the list of files */
2061 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2062 COMDLG32_SHFree(pidl);
2066 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2067 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2069 /* For "oldstyle" dialog the components have to
2070 be separated by blanks (not '\0'!) and short
2071 filenames have to be used! */
2072 FIXME("Components have to be separated by blanks\n");
2074 if(fodInfos->unicode)
2076 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2077 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2078 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2080 else
2082 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2084 if (ofn->lpstrFile != NULL)
2086 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2087 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2088 if (ofn->nMaxFile > nSizePath)
2090 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2091 ofn->lpstrFile + nSizePath,
2092 ofn->nMaxFile - nSizePath, NULL, NULL);
2097 fodInfos->ofnInfos->nFileOffset = nSizePath;
2098 fodInfos->ofnInfos->nFileExtension = 0;
2100 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2101 return FALSE;
2103 /* clean and exit */
2104 FILEDLG95_Clean(hwnd);
2105 return EndDialog(hwnd,TRUE);
2108 /* Returns the 'slot name' of the given module_name in the registry's
2109 * most-recently-used list. This will be an ASCII value in the
2110 * range ['a','z'). Returns zero on error.
2112 * The slot's value in the registry has the form:
2113 * module_name\0mru_path\0
2115 * If stored_path is given, then stored_path will contain the path name
2116 * stored in the registry's MRU list for the given module_name.
2118 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2119 * MRU list key for the given module_name.
2121 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2123 WCHAR mru_list[32], *cur_mru_slot;
2124 BOOL taken[25] = {0};
2125 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2126 HKEY hkey_tmp, *hkey;
2127 LONG ret;
2129 if(hkey_ret)
2130 hkey = hkey_ret;
2131 else
2132 hkey = &hkey_tmp;
2134 if(stored_path)
2135 *stored_path = '\0';
2137 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2138 if(ret){
2139 WARN("Unable to create MRU key: %d\n", ret);
2140 return 0;
2143 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2144 (LPBYTE)mru_list, &mru_list_size);
2145 if(ret || key_type != REG_SZ){
2146 if(ret == ERROR_FILE_NOT_FOUND)
2147 return 'a';
2149 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2150 RegCloseKey(*hkey);
2151 return 0;
2154 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2155 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2156 DWORD value_data_size = sizeof(value_data);
2158 *value_name = *cur_mru_slot;
2160 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2161 &key_type, (LPBYTE)value_data, &value_data_size);
2162 if(ret || key_type != REG_BINARY){
2163 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2164 continue;
2167 if(!strcmpiW(module_name, value_data)){
2168 if(!hkey_ret)
2169 RegCloseKey(*hkey);
2170 if(stored_path)
2171 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2172 return *value_name;
2176 if(!hkey_ret)
2177 RegCloseKey(*hkey);
2179 /* the module name isn't in the registry, so find the next open slot */
2180 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2181 taken[*cur_mru_slot - 'a'] = TRUE;
2182 for(i = 0; i < 25; ++i){
2183 if(!taken[i])
2184 return i + 'a';
2187 /* all slots are taken, so return the last one in MRUList */
2188 --cur_mru_slot;
2189 return *cur_mru_slot;
2192 /* save the given filename as most-recently-used path for this module */
2193 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2195 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2196 LONG ret;
2197 HKEY hkey;
2199 /* get the current executable's name */
2200 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2201 WARN("GotModuleFileName failed: %d\n", GetLastError());
2202 return;
2204 module_name = strrchrW(module_path, '\\');
2205 if(!module_name)
2206 module_name = module_path;
2207 else
2208 module_name += 1;
2210 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2211 if(!slot)
2212 return;
2213 *slot_name = slot;
2215 { /* update the slot's info */
2216 WCHAR *path_ends, *final;
2217 DWORD path_len, final_len;
2219 /* use only the path segment of `filename' */
2220 path_ends = strrchrW(filename, '\\');
2221 path_len = path_ends - filename;
2223 final_len = path_len + lstrlenW(module_name) + 2;
2225 final = MemAlloc(final_len * sizeof(WCHAR));
2226 if(!final)
2227 return;
2228 lstrcpyW(final, module_name);
2229 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2230 final[final_len-1] = '\0';
2232 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2233 final_len * sizeof(WCHAR));
2234 if(ret){
2235 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2236 MemFree(final);
2237 RegCloseKey(hkey);
2238 return;
2241 MemFree(final);
2244 { /* update MRUList value */
2245 WCHAR old_mru_list[32], new_mru_list[32];
2246 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2247 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2249 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2250 (LPBYTE)old_mru_list, &mru_list_size);
2251 if(ret || key_type != REG_SZ){
2252 if(ret == ERROR_FILE_NOT_FOUND){
2253 new_mru_list[0] = slot;
2254 new_mru_list[1] = '\0';
2255 }else{
2256 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2257 RegCloseKey(hkey);
2258 return;
2260 }else{
2261 /* copy old list data over so that the new slot is at the start
2262 * of the list */
2263 *new_mru_slot++ = slot;
2264 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2265 if(*old_mru_slot != slot)
2266 *new_mru_slot++ = *old_mru_slot;
2268 *new_mru_slot = '\0';
2271 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2272 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2273 if(ret){
2274 WARN("Error saving MRUList data: %d\n", ret);
2275 RegCloseKey(hkey);
2276 return;
2281 /* load the most-recently-used path for this module */
2282 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2284 WCHAR module_path[MAX_PATH], *module_name;
2286 /* get the current executable's name */
2287 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2288 WARN("GotModuleFileName failed: %d\n", GetLastError());
2289 return;
2291 module_name = strrchrW(module_path, '\\');
2292 if(!module_name)
2293 module_name = module_path;
2294 else
2295 module_name += 1;
2297 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2298 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2301 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2303 WCHAR strMsgTitle[MAX_PATH];
2304 WCHAR strMsgText [MAX_PATH];
2305 if (idCaption)
2306 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2307 else
2308 strMsgTitle[0] = '\0';
2309 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2310 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2313 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2314 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2316 int nOpenAction = defAction;
2317 LPWSTR lpszTemp, lpszTemp1;
2318 LPITEMIDLIST pidl = NULL;
2319 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2321 /* check for invalid chars */
2322 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2324 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2325 return FALSE;
2328 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2330 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2331 while (lpszTemp1)
2333 LPSHELLFOLDER lpsfChild;
2334 WCHAR lpwstrTemp[MAX_PATH];
2335 DWORD dwEaten, dwAttributes;
2336 LPWSTR p;
2338 lstrcpyW(lpwstrTemp, lpszTemp);
2339 p = PathFindNextComponentW(lpwstrTemp);
2341 if (!p) break; /* end of path */
2343 *p = 0;
2344 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2346 /* There are no wildcards when OFN_NOVALIDATE is set */
2347 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2349 static const WCHAR wszWild[] = { '*', '?', 0 };
2350 /* if the last element is a wildcard do a search */
2351 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2353 nOpenAction = ONOPEN_SEARCH;
2354 break;
2357 lpszTemp1 = lpszTemp;
2359 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2361 /* append a backslash to drive letters */
2362 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2363 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2364 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2366 PathAddBackslashW(lpwstrTemp);
2369 dwAttributes = SFGAO_FOLDER;
2370 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2372 /* the path component is valid, we have a pidl of the next path component */
2373 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2374 if(dwAttributes & SFGAO_FOLDER)
2376 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2378 ERR("bind to failed\n"); /* should not fail */
2379 break;
2381 IShellFolder_Release(*ppsf);
2382 *ppsf = lpsfChild;
2383 lpsfChild = NULL;
2385 else
2387 TRACE("value\n");
2389 /* end dialog, return value */
2390 nOpenAction = ONOPEN_OPEN;
2391 break;
2393 COMDLG32_SHFree(pidl);
2394 pidl = NULL;
2396 else if (!(flags & OFN_NOVALIDATE))
2398 if(*lpszTemp || /* points to trailing null for last path element */
2399 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2401 if(flags & OFN_PATHMUSTEXIST)
2403 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2404 break;
2407 else
2409 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2411 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2412 break;
2415 /* change to the current folder */
2416 nOpenAction = ONOPEN_OPEN;
2417 break;
2419 else
2421 nOpenAction = ONOPEN_OPEN;
2422 break;
2425 if(pidl) COMDLG32_SHFree(pidl);
2427 return nOpenAction;
2430 /***********************************************************************
2431 * FILEDLG95_OnOpen
2433 * Ok button WM_COMMAND message handler
2435 * If the function succeeds, the return value is nonzero.
2437 BOOL FILEDLG95_OnOpen(HWND hwnd)
2439 LPWSTR lpstrFileList;
2440 UINT nFileCount = 0;
2441 UINT sizeUsed = 0;
2442 BOOL ret = TRUE;
2443 WCHAR lpstrPathAndFile[MAX_PATH];
2444 LPSHELLFOLDER lpsf = NULL;
2445 int nOpenAction;
2446 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2448 TRACE("hwnd=%p\n", hwnd);
2450 /* try to browse the selected item */
2451 if(BrowseSelectedFolder(hwnd))
2452 return FALSE;
2454 /* get the files from the edit control */
2455 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2457 if(nFileCount == 0)
2458 return FALSE;
2460 if(nFileCount > 1)
2462 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2463 goto ret;
2466 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2469 Step 1: Build a complete path name from the current folder and
2470 the filename or path in the edit box.
2471 Special cases:
2472 - the path in the edit box is a root path
2473 (with or without drive letter)
2474 - the edit box contains ".." (or a path with ".." in it)
2477 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2478 MemFree(lpstrFileList);
2481 Step 2: here we have a cleaned up path
2483 We have to parse the path step by step to see if we have to browse
2484 to a folder if the path points to a directory or the last
2485 valid element is a directory.
2487 valid variables:
2488 lpstrPathAndFile: cleaned up path
2491 if (nFileCount &&
2492 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2493 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2494 nOpenAction = ONOPEN_OPEN;
2495 else
2496 nOpenAction = ONOPEN_BROWSE;
2498 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2499 fodInfos->ofnInfos->Flags,
2500 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2501 nOpenAction);
2502 if(!nOpenAction)
2503 goto ret;
2506 Step 3: here we have a cleaned up and validated path
2508 valid variables:
2509 lpsf: ShellFolder bound to the rightmost valid path component
2510 lpstrPathAndFile: cleaned up path
2511 nOpenAction: action to do
2513 TRACE("end validate sf=%p\n", lpsf);
2515 switch(nOpenAction)
2517 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2518 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2520 int iPos;
2521 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2522 DWORD len;
2524 /* replace the current filter */
2525 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2526 len = lstrlenW(lpszTemp)+1;
2527 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2528 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2530 /* set the filter cb to the extension when possible */
2531 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2532 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2534 /* fall through */
2535 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2536 TRACE("ONOPEN_BROWSE\n");
2538 IPersistFolder2 * ppf2;
2539 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2541 LPITEMIDLIST pidlCurrent;
2542 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2543 IPersistFolder2_Release(ppf2);
2544 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2546 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2547 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2549 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2550 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2553 else if( nOpenAction == ONOPEN_SEARCH )
2555 if (fodInfos->Shell.FOIShellView)
2556 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2558 COMDLG32_SHFree(pidlCurrent);
2559 if (filename_is_edit( fodInfos ))
2560 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2561 else
2563 HWND hwnd;
2565 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2566 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2570 ret = FALSE;
2571 break;
2572 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2573 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2575 WCHAR *ext = NULL;
2577 /* update READONLY check box flag */
2578 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2579 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2580 else
2581 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2583 /* Attach the file extension with file name*/
2584 ext = PathFindExtensionW(lpstrPathAndFile);
2585 if (! *ext && fodInfos->defext)
2587 /* if no extension is specified with file name, then */
2588 /* attach the extension from file filter or default one */
2590 WCHAR *filterExt = NULL;
2591 LPWSTR lpstrFilter = NULL;
2592 static const WCHAR szwDot[] = {'.',0};
2593 int PathLength = lstrlenW(lpstrPathAndFile);
2595 /*Get the file extension from file type filter*/
2596 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2597 fodInfos->ofnInfos->nFilterIndex-1);
2599 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2601 WCHAR* filterSearchIndex;
2602 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2603 strcpyW(filterExt, lpstrFilter);
2605 /* if a semicolon-separated list of file extensions was given, do not include the
2606 semicolon or anything after it in the extension.
2607 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2608 filterSearchIndex = strchrW(filterExt, ';');
2609 if (filterSearchIndex)
2611 filterSearchIndex[0] = '\0';
2614 /* find the file extension by searching for the first dot in filterExt */
2615 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2616 /* if the extension is invalid or contains a glob, ignore it */
2617 filterSearchIndex = strchrW(filterExt, '.');
2618 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2620 strcpyW(filterExt, filterSearchIndex);
2622 else
2624 HeapFree(GetProcessHeap(), 0, filterExt);
2625 filterExt = NULL;
2629 if (!filterExt)
2631 /* use the default file extension */
2632 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2633 strcpyW(filterExt, fodInfos->defext);
2636 if (*filterExt) /* ignore filterExt="" */
2638 /* Attach the dot*/
2639 lstrcatW(lpstrPathAndFile, szwDot);
2640 /* Attach the extension */
2641 lstrcatW(lpstrPathAndFile, filterExt);
2644 HeapFree(GetProcessHeap(), 0, filterExt);
2646 /* In Open dialog: if file does not exist try without extension */
2647 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2648 lpstrPathAndFile[PathLength] = '\0';
2650 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2651 if (*ext)
2652 ext++;
2653 if (!lstrcmpiW(fodInfos->defext, ext))
2654 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2655 else
2656 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2659 /* In Save dialog: check if the file already exists */
2660 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2661 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2662 && PathFileExistsW(lpstrPathAndFile))
2664 WCHAR lpstrOverwrite[100];
2665 int answer;
2667 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2668 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2669 MB_YESNO | MB_ICONEXCLAMATION);
2670 if (answer == IDNO || answer == IDCANCEL)
2672 ret = FALSE;
2673 goto ret;
2677 /* In Open dialog: check if it should be created if it doesn't exist */
2678 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2679 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2680 && !PathFileExistsW(lpstrPathAndFile))
2682 WCHAR lpstrCreate[100];
2683 int answer;
2685 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2686 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2687 MB_YESNO | MB_ICONEXCLAMATION);
2688 if (answer == IDNO || answer == IDCANCEL)
2690 ret = FALSE;
2691 goto ret;
2695 /* Check that the size of the file does not exceed buffer size.
2696 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2697 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2698 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2701 /* fill destination buffer */
2702 if (fodInfos->ofnInfos->lpstrFile)
2704 if(fodInfos->unicode)
2706 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2708 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2709 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2710 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2712 else
2714 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2716 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2717 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2718 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2719 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2723 if(fodInfos->unicode)
2725 LPWSTR lpszTemp;
2727 /* set filename offset */
2728 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2729 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2731 /* set extension offset */
2732 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2733 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2735 else
2737 LPSTR lpszTemp;
2738 CHAR tempFileA[MAX_PATH];
2740 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2741 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2742 tempFileA, sizeof(tempFileA), NULL, NULL);
2744 /* set filename offset */
2745 lpszTemp = PathFindFileNameA(tempFileA);
2746 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2748 /* set extension offset */
2749 lpszTemp = PathFindExtensionA(tempFileA);
2750 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2753 /* set the lpstrFileTitle */
2754 if(fodInfos->ofnInfos->lpstrFileTitle)
2756 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2757 if(fodInfos->unicode)
2759 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2760 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2762 else
2764 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2765 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2766 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2770 /* copy currently selected filter to lpstrCustomFilter */
2771 if (fodInfos->ofnInfos->lpstrCustomFilter)
2773 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2774 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2775 NULL, 0, NULL, NULL);
2776 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2778 LPSTR s = ofn->lpstrCustomFilter;
2779 s += strlen(ofn->lpstrCustomFilter)+1;
2780 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2781 s, len, NULL, NULL);
2786 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2787 goto ret;
2789 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2791 TRACE("close\n");
2792 FILEDLG95_Clean(hwnd);
2793 ret = EndDialog(hwnd, TRUE);
2795 else
2797 WORD size;
2799 size = lstrlenW(lpstrPathAndFile) + 1;
2800 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2801 size += 1;
2802 /* return needed size in first two bytes of lpstrFile */
2803 if(fodInfos->ofnInfos->lpstrFile)
2804 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2805 FILEDLG95_Clean(hwnd);
2806 ret = EndDialog(hwnd, FALSE);
2807 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2810 break;
2813 ret:
2814 if(lpsf) IShellFolder_Release(lpsf);
2815 return ret;
2818 /***********************************************************************
2819 * FILEDLG95_SHELL_Init
2821 * Initialisation of the shell objects
2823 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2825 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2827 TRACE("\n");
2830 * Initialisation of the FileOpenDialogInfos structure
2833 /* Shell */
2835 /*ShellInfos */
2836 fodInfos->ShellInfos.hwndOwner = hwnd;
2838 /* Disable multi-select if flag not set */
2839 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2841 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2843 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2844 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2846 /* Construct the IShellBrowser interface */
2847 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2849 return NOERROR;
2852 /***********************************************************************
2853 * FILEDLG95_SHELL_ExecuteCommand
2855 * Change the folder option and refresh the view
2856 * If the function succeeds, the return value is nonzero.
2858 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2860 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2861 IContextMenu * pcm;
2863 TRACE("(%p,%p)\n", hwnd, lpVerb);
2865 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2866 SVGIO_BACKGROUND,
2867 &IID_IContextMenu,
2868 (LPVOID*)&pcm)))
2870 CMINVOKECOMMANDINFO ci;
2871 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2872 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2873 ci.lpVerb = lpVerb;
2874 ci.hwnd = hwnd;
2876 IContextMenu_InvokeCommand(pcm, &ci);
2877 IContextMenu_Release(pcm);
2880 return FALSE;
2883 /***********************************************************************
2884 * FILEDLG95_SHELL_UpFolder
2886 * Browse to the specified object
2887 * If the function succeeds, the return value is nonzero.
2889 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2891 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2893 TRACE("\n");
2895 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2896 NULL,
2897 SBSP_PARENT)))
2899 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2900 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2901 return TRUE;
2903 return FALSE;
2906 /***********************************************************************
2907 * FILEDLG95_SHELL_BrowseToDesktop
2909 * Browse to the Desktop
2910 * If the function succeeds, the return value is nonzero.
2912 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2914 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2915 LPITEMIDLIST pidl;
2916 HRESULT hres;
2918 TRACE("\n");
2920 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2921 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2922 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2923 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2924 COMDLG32_SHFree(pidl);
2925 return SUCCEEDED(hres);
2927 /***********************************************************************
2928 * FILEDLG95_SHELL_Clean
2930 * Cleans the memory used by shell objects
2932 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2934 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2936 TRACE("\n");
2938 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2940 /* clean Shell interfaces */
2941 if (fodInfos->Shell.FOIShellView)
2943 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2944 IShellView_Release(fodInfos->Shell.FOIShellView);
2946 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2947 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2948 if (fodInfos->Shell.FOIDataObject)
2949 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2952 /***********************************************************************
2953 * FILEDLG95_FILETYPE_Init
2955 * Initialisation of the file type combo box
2957 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2959 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2960 int nFilters = 0; /* number of filters */
2961 int nFilterIndexCB;
2963 TRACE("\n");
2965 if(fodInfos->customfilter)
2967 /* customfilter has one entry... title\0ext\0
2968 * Set first entry of combo box item with customfilter
2970 LPWSTR lpstrExt;
2971 LPCWSTR lpstrPos = fodInfos->customfilter;
2973 /* Get the title */
2974 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2976 /* Copy the extensions */
2977 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2978 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2979 lstrcpyW(lpstrExt,lpstrPos);
2981 /* Add the item at the end of the combo */
2982 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2983 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2984 nFilters++;
2986 if(fodInfos->filter)
2988 LPCWSTR lpstrPos = fodInfos->filter;
2990 for(;;)
2992 /* filter is a list... title\0ext\0......\0\0
2993 * Set the combo item text to the title and the item data
2994 * to the ext
2996 LPCWSTR lpstrDisplay;
2997 LPWSTR lpstrExt;
2999 /* Get the title */
3000 if(! *lpstrPos) break; /* end */
3001 lpstrDisplay = lpstrPos;
3002 lpstrPos += lstrlenW(lpstrPos) + 1;
3004 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
3006 nFilters++;
3008 /* Copy the extensions */
3009 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3010 lstrcpyW(lpstrExt,lpstrPos);
3011 lpstrPos += lstrlenW(lpstrPos) + 1;
3013 /* Add the item at the end of the combo */
3014 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3016 /* malformed filters are added anyway... */
3017 if (!*lpstrExt) break;
3022 * Set the current filter to the one specified
3023 * in the initialisation structure
3025 if (fodInfos->filter || fodInfos->customfilter)
3027 LPWSTR lpstrFilter;
3029 /* Check to make sure our index isn't out of bounds. */
3030 if ( fodInfos->ofnInfos->nFilterIndex >
3031 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3032 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3034 /* set default filter index */
3035 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3036 fodInfos->ofnInfos->nFilterIndex = 1;
3038 /* calculate index of Combo Box item */
3039 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3040 if (fodInfos->customfilter == NULL)
3041 nFilterIndexCB--;
3043 /* Set the current index selection. */
3044 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3046 /* Get the corresponding text string from the combo box. */
3047 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3048 nFilterIndexCB);
3050 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3051 lpstrFilter = NULL;
3053 if(lpstrFilter)
3055 DWORD len;
3056 CharLowerW(lpstrFilter); /* lowercase */
3057 len = lstrlenW(lpstrFilter)+1;
3058 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3059 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3061 } else
3062 fodInfos->ofnInfos->nFilterIndex = 0;
3063 return S_OK;
3066 /***********************************************************************
3067 * FILEDLG95_FILETYPE_OnCommand
3069 * WM_COMMAND of the file type combo box
3070 * If the function succeeds, the return value is nonzero.
3072 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3074 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3076 switch(wNotifyCode)
3078 case CBN_SELENDOK:
3080 LPWSTR lpstrFilter;
3082 /* Get the current item of the filetype combo box */
3083 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3085 /* set the current filter index */
3086 fodInfos->ofnInfos->nFilterIndex = iItem +
3087 (fodInfos->customfilter == NULL ? 1 : 0);
3089 /* Set the current filter with the current selection */
3090 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3092 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3093 iItem);
3094 if((INT_PTR)lpstrFilter != CB_ERR)
3096 DWORD len;
3097 CharLowerW(lpstrFilter); /* lowercase */
3098 len = lstrlenW(lpstrFilter)+1;
3099 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3100 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3101 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3102 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3105 /* Refresh the actual view to display the included items*/
3106 if (fodInfos->Shell.FOIShellView)
3107 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3110 return FALSE;
3112 /***********************************************************************
3113 * FILEDLG95_FILETYPE_SearchExt
3115 * searches for an extension in the filetype box
3117 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3119 int i, iCount = CBGetCount(hwnd);
3121 TRACE("%s\n", debugstr_w(lpstrExt));
3123 if(iCount != CB_ERR)
3125 for(i=0;i<iCount;i++)
3127 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3128 return i;
3131 return -1;
3134 /***********************************************************************
3135 * FILEDLG95_FILETYPE_Clean
3137 * Clean the memory used by the filetype combo box
3139 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3141 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3142 int iPos;
3143 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3145 TRACE("\n");
3147 /* Delete each string of the combo and their associated data */
3148 if(iCount != CB_ERR)
3150 for(iPos = iCount-1;iPos>=0;iPos--)
3152 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3153 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3156 /* Current filter */
3157 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3161 /***********************************************************************
3162 * FILEDLG95_LOOKIN_Init
3164 * Initialisation of the look in combo box
3167 /* Small helper function, to determine if the unixfs shell extension is rooted
3168 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3170 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3171 HKEY hKey;
3172 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3173 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3175 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3176 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3177 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3178 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3180 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3181 return FALSE;
3183 RegCloseKey(hKey);
3184 return TRUE;
3187 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3189 IShellFolder *psfRoot, *psfDrives;
3190 IEnumIDList *lpeRoot, *lpeDrives;
3191 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3192 HDC hdc;
3193 TEXTMETRICW tm;
3194 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3196 TRACE("\n");
3198 liInfos->iMaxIndentation = 0;
3200 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3202 hdc = GetDC( hwndCombo );
3203 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3204 GetTextMetricsW( hdc, &tm );
3205 ReleaseDC( hwndCombo, hdc );
3207 /* set item height for both text field and listbox */
3208 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3209 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3211 /* Turn on the extended UI for the combo box like Windows does */
3212 CBSetExtendedUI(hwndCombo, TRUE);
3214 /* Initialise data of Desktop folder */
3215 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3216 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3217 COMDLG32_SHFree(pidlTmp);
3219 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3221 SHGetDesktopFolder(&psfRoot);
3223 if (psfRoot)
3225 /* enumerate the contents of the desktop */
3226 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3228 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3230 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3232 /* If the unixfs extension is rooted, we don't expand the drives by default */
3233 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3235 /* special handling for CSIDL_DRIVES */
3236 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3238 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3240 /* enumerate the drives */
3241 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3243 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3245 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3246 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3247 COMDLG32_SHFree(pidlAbsTmp);
3248 COMDLG32_SHFree(pidlTmp1);
3250 IEnumIDList_Release(lpeDrives);
3252 IShellFolder_Release(psfDrives);
3257 COMDLG32_SHFree(pidlTmp);
3259 IEnumIDList_Release(lpeRoot);
3261 IShellFolder_Release(psfRoot);
3264 COMDLG32_SHFree(pidlDrives);
3267 /***********************************************************************
3268 * FILEDLG95_LOOKIN_DrawItem
3270 * WM_DRAWITEM message handler
3272 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3274 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3275 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3276 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3277 RECT rectText;
3278 RECT rectIcon;
3279 SHFILEINFOW sfi;
3280 HIMAGELIST ilItemImage;
3281 int iIndentation;
3282 TEXTMETRICW tm;
3283 LPSFOLDER tmpFolder;
3284 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3285 UINT icon_width, icon_height;
3287 TRACE("\n");
3289 if(pDIStruct->itemID == -1)
3290 return 0;
3292 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3293 pDIStruct->itemID)))
3294 return 0;
3297 icon_width = GetSystemMetrics(SM_CXICON);
3298 icon_height = GetSystemMetrics(SM_CYICON);
3299 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3301 icon_width = GetSystemMetrics(SM_CXSMICON);
3302 icon_height = GetSystemMetrics(SM_CYSMICON);
3303 shgfi_flags |= SHGFI_SMALLICON;
3306 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3307 0, &sfi, sizeof (sfi), shgfi_flags );
3309 /* Is this item selected ? */
3310 if(pDIStruct->itemState & ODS_SELECTED)
3312 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3313 SetBkColor(pDIStruct->hDC,crHighLight);
3314 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3316 else
3318 SetTextColor(pDIStruct->hDC,crText);
3319 SetBkColor(pDIStruct->hDC,crWin);
3320 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3323 /* Do not indent item if drawing in the edit of the combo */
3324 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3325 iIndentation = 0;
3326 else
3327 iIndentation = tmpFolder->m_iIndent;
3329 /* Draw text and icon */
3331 /* Initialise the icon display area */
3332 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3333 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3334 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3335 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3337 /* Initialise the text display area */
3338 GetTextMetricsW(pDIStruct->hDC, &tm);
3339 rectText.left = rectIcon.right;
3340 rectText.top =
3341 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3342 rectText.right = pDIStruct->rcItem.right;
3343 rectText.bottom =
3344 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3346 /* Draw the icon from the image list */
3347 ImageList_Draw(ilItemImage,
3348 sfi.iIcon,
3349 pDIStruct->hDC,
3350 rectIcon.left,
3351 rectIcon.top,
3352 ILD_TRANSPARENT );
3354 /* Draw the associated text */
3355 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3356 return NOERROR;
3359 /***********************************************************************
3360 * FILEDLG95_LOOKIN_OnCommand
3362 * LookIn combo box WM_COMMAND message handler
3363 * If the function succeeds, the return value is nonzero.
3365 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3367 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3369 TRACE("%p\n", fodInfos);
3371 switch(wNotifyCode)
3373 case CBN_SELENDOK:
3375 LPSFOLDER tmpFolder;
3376 int iItem;
3378 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3380 if( iItem == CB_ERR) return FALSE;
3382 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3383 iItem)))
3384 return FALSE;
3387 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3388 tmpFolder->pidlItem,
3389 SBSP_ABSOLUTE)))
3391 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3392 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3393 return TRUE;
3395 break;
3399 return FALSE;
3402 /***********************************************************************
3403 * FILEDLG95_LOOKIN_AddItem
3405 * Adds an absolute pidl item to the lookin combo box
3406 * returns the index of the inserted item
3408 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3410 LPITEMIDLIST pidlNext;
3411 SHFILEINFOW sfi;
3412 SFOLDER *tmpFolder;
3413 LookInInfos *liInfos;
3415 TRACE("%08x\n", iInsertId);
3417 if(!pidl)
3418 return -1;
3420 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3421 return -1;
3423 tmpFolder = MemAlloc(sizeof(SFOLDER));
3424 tmpFolder->m_iIndent = 0;
3426 /* Calculate the indentation of the item in the lookin*/
3427 pidlNext = pidl;
3428 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3430 tmpFolder->m_iIndent++;
3433 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3435 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3436 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3438 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3439 SHGetFileInfoW((LPCWSTR)pidl,
3441 &sfi,
3442 sizeof(sfi),
3443 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3444 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3446 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3448 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3450 int iItemID;
3452 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3454 /* Add the item at the end of the list */
3455 if(iInsertId < 0)
3457 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3459 /* Insert the item at the iInsertId position*/
3460 else
3462 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3465 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3466 return iItemID;
3469 COMDLG32_SHFree( tmpFolder->pidlItem );
3470 MemFree( tmpFolder );
3471 return -1;
3475 /***********************************************************************
3476 * FILEDLG95_LOOKIN_InsertItemAfterParent
3478 * Insert an item below its parent
3480 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3483 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3484 int iParentPos;
3486 TRACE("\n");
3488 if (pidl == pidlParent)
3489 return -1;
3491 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3493 if(iParentPos < 0)
3495 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3498 /* Free pidlParent memory */
3499 COMDLG32_SHFree(pidlParent);
3501 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3504 /***********************************************************************
3505 * FILEDLG95_LOOKIN_SelectItem
3507 * Adds an absolute pidl item to the lookin combo box
3508 * returns the index of the inserted item
3510 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3512 int iItemPos;
3513 LookInInfos *liInfos;
3515 TRACE("\n");
3517 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3519 liInfos = GetPropA(hwnd,LookInInfosStr);
3521 if(iItemPos < 0)
3523 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3524 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3527 else
3529 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3530 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3532 int iRemovedItem;
3534 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3535 break;
3536 if(iRemovedItem < iItemPos)
3537 iItemPos--;
3541 CBSetCurSel(hwnd,iItemPos);
3542 liInfos->uSelectedItem = iItemPos;
3544 return 0;
3548 /***********************************************************************
3549 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3551 * Remove the item with an expansion level over iExpansionLevel
3553 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3555 int iItemPos;
3556 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3558 TRACE("\n");
3560 if(liInfos->iMaxIndentation <= 2)
3561 return -1;
3563 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3565 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3566 COMDLG32_SHFree(tmpFolder->pidlItem);
3567 MemFree(tmpFolder);
3568 CBDeleteString(hwnd,iItemPos);
3569 liInfos->iMaxIndentation--;
3571 return iItemPos;
3574 return -1;
3577 /***********************************************************************
3578 * FILEDLG95_LOOKIN_SearchItem
3580 * Search for pidl in the lookin combo box
3581 * returns the index of the found item
3583 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3585 int i = 0;
3586 int iCount = CBGetCount(hwnd);
3588 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3590 if (iCount != CB_ERR)
3592 for(;i<iCount;i++)
3594 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3596 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3597 return i;
3598 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3599 return i;
3603 return -1;
3606 /***********************************************************************
3607 * FILEDLG95_LOOKIN_Clean
3609 * Clean the memory used by the lookin combo box
3611 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3613 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3614 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3615 int iPos;
3616 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3618 TRACE("\n");
3620 /* Delete each string of the combo and their associated data */
3621 if (iCount != CB_ERR)
3623 for(iPos = iCount-1;iPos>=0;iPos--)
3625 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3626 COMDLG32_SHFree(tmpFolder->pidlItem);
3627 MemFree(tmpFolder);
3628 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3632 /* LookInInfos structure */
3633 MemFree(liInfos);
3634 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3637 /***********************************************************************
3638 * get_def_format
3640 * Fill the FORMATETC used in the shell id list
3642 static FORMATETC get_def_format(void)
3644 static CLIPFORMAT cfFormat;
3645 FORMATETC formatetc;
3647 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3648 formatetc.cfFormat = cfFormat;
3649 formatetc.ptd = 0;
3650 formatetc.dwAspect = DVASPECT_CONTENT;
3651 formatetc.lindex = -1;
3652 formatetc.tymed = TYMED_HGLOBAL;
3653 return formatetc;
3656 /***********************************************************************
3657 * FILEDLG95_FILENAME_FillFromSelection
3659 * fills the edit box from the cached DataObject
3661 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3663 FileOpenDlgInfos *fodInfos;
3664 LPITEMIDLIST pidl;
3665 LPWSTR lpstrAllFiles, lpstrTmp;
3666 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3667 STGMEDIUM medium;
3668 LPIDA cida;
3669 FORMATETC formatetc = get_def_format();
3671 TRACE("\n");
3672 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3674 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3675 return;
3677 cida = GlobalLock(medium.u.hGlobal);
3678 nFileSelected = cida->cidl;
3680 /* Allocate a buffer */
3681 nAllFilesMaxLength = MAX_PATH + 3;
3682 lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nAllFilesMaxLength * sizeof(WCHAR));
3683 if (!lpstrAllFiles)
3684 goto ret;
3686 /* Loop through the selection, handle only files (not folders) */
3687 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3689 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3690 if (pidl)
3692 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3694 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3696 nAllFilesMaxLength *= 2;
3697 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3698 if (!lpstrTmp)
3699 goto ret;
3700 lpstrAllFiles = lpstrTmp;
3702 nFiles += 1;
3703 lpstrAllFiles[nAllFilesLength++] = '"';
3704 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3705 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3706 nAllFilesLength += nThisFileLength;
3707 lpstrAllFiles[nAllFilesLength++] = '"';
3708 lpstrAllFiles[nAllFilesLength++] = ' ';
3713 if (nFiles != 0)
3715 /* If there's only one file, use the name as-is without quotes */
3716 lpstrTmp = lpstrAllFiles;
3717 if (nFiles == 1)
3719 lpstrTmp += 1;
3720 lpstrTmp[nThisFileLength] = 0;
3722 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3723 /* Select the file name like Windows does */
3724 if (filename_is_edit(fodInfos))
3725 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3728 ret:
3729 HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
3730 COMCTL32_ReleaseStgMedium(medium);
3734 /* copied from shell32 to avoid linking to it
3735 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3736 * is dependent on whether emulated OS is unicode or not.
3738 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3740 switch (src->uType)
3742 case STRRET_WSTR:
3743 lstrcpynW(dest, src->u.pOleStr, len);
3744 COMDLG32_SHFree(src->u.pOleStr);
3745 break;
3747 case STRRET_CSTR:
3748 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3749 dest[len-1] = 0;
3750 break;
3752 case STRRET_OFFSET:
3753 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3754 dest[len-1] = 0;
3755 break;
3757 default:
3758 FIXME("unknown type %x!\n", src->uType);
3759 if (len) *dest = '\0';
3760 return E_FAIL;
3762 return S_OK;
3765 /***********************************************************************
3766 * FILEDLG95_FILENAME_GetFileNames
3768 * Copies the filenames to a delimited string list.
3770 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3772 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3773 UINT nFileCount = 0; /* number of files */
3774 UINT nStrLen = 0; /* length of string in edit control */
3775 LPWSTR lpstrEdit; /* buffer for string from edit control */
3777 TRACE("\n");
3779 /* get the filenames from the filename control */
3780 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3781 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3782 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3784 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3786 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3787 MemFree(lpstrEdit);
3788 return nFileCount;
3792 * DATAOBJECT Helper functions
3795 /***********************************************************************
3796 * COMCTL32_ReleaseStgMedium
3798 * like ReleaseStgMedium from ole32
3800 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3802 if(medium.pUnkForRelease)
3804 IUnknown_Release(medium.pUnkForRelease);
3806 else
3808 GlobalUnlock(medium.u.hGlobal);
3809 GlobalFree(medium.u.hGlobal);
3813 /***********************************************************************
3814 * GetPidlFromDataObject
3816 * Return pidl(s) by number from the cached DataObject
3818 * nPidlIndex=0 gets the fully qualified root path
3820 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3823 STGMEDIUM medium;
3824 FORMATETC formatetc = get_def_format();
3825 LPITEMIDLIST pidl = NULL;
3827 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3829 if (!doSelected)
3830 return NULL;
3832 /* Get the pidls from IDataObject */
3833 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3835 LPIDA cida = GlobalLock(medium.u.hGlobal);
3836 if(nPidlIndex <= cida->cidl)
3838 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3840 COMCTL32_ReleaseStgMedium(medium);
3842 return pidl;
3845 /***********************************************************************
3846 * GetNumSelected
3848 * Return the number of selected items in the DataObject.
3851 static UINT GetNumSelected( IDataObject *doSelected )
3853 UINT retVal = 0;
3854 STGMEDIUM medium;
3855 FORMATETC formatetc = get_def_format();
3857 TRACE("sv=%p\n", doSelected);
3859 if (!doSelected) return 0;
3861 /* Get the pidls from IDataObject */
3862 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3864 LPIDA cida = GlobalLock(medium.u.hGlobal);
3865 retVal = cida->cidl;
3866 COMCTL32_ReleaseStgMedium(medium);
3867 return retVal;
3869 return 0;
3873 * TOOLS
3876 /***********************************************************************
3877 * GetName
3879 * Get the pidl's display name (relative to folder) and
3880 * put it in lpstrFileName.
3882 * Return NOERROR on success,
3883 * E_FAIL otherwise
3886 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3888 STRRET str;
3889 HRESULT hRes;
3891 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3893 if(!lpsf)
3895 SHGetDesktopFolder(&lpsf);
3896 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3897 IShellFolder_Release(lpsf);
3898 return hRes;
3901 /* Get the display name of the pidl relative to the folder */
3902 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3904 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3906 return E_FAIL;
3909 /***********************************************************************
3910 * GetShellFolderFromPidl
3912 * pidlRel is the item pidl relative
3913 * Return the IShellFolder of the absolute pidl
3915 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3917 IShellFolder *psf = NULL,*psfParent;
3919 TRACE("%p\n", pidlAbs);
3921 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3923 psf = psfParent;
3924 if(pidlAbs && pidlAbs->mkid.cb)
3926 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3928 IShellFolder_Release(psfParent);
3929 return psf;
3932 /* return the desktop */
3933 return psfParent;
3935 return NULL;
3938 /***********************************************************************
3939 * GetParentPidl
3941 * Return the LPITEMIDLIST to the parent of the pidl in the list
3943 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3945 LPITEMIDLIST pidlParent;
3947 TRACE("%p\n", pidl);
3949 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3950 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3952 return pidlParent;
3955 /***********************************************************************
3956 * GetPidlFromName
3958 * returns the pidl of the file name relative to folder
3959 * NULL if an error occurred
3961 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3963 LPITEMIDLIST pidl = NULL;
3964 ULONG ulEaten;
3966 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3968 if(!lpcstrFileName) return NULL;
3969 if(!*lpcstrFileName) return NULL;
3971 if(!lpsf)
3973 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3974 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3975 IShellFolder_Release(lpsf);
3978 else
3980 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3982 return pidl;
3987 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3989 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3990 HRESULT ret;
3992 TRACE("%p, %p\n", psf, pidl);
3994 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3996 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3997 /* see documentation shell 4.1*/
3998 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4001 /***********************************************************************
4002 * BrowseSelectedFolder
4004 static BOOL BrowseSelectedFolder(HWND hwnd)
4006 BOOL bBrowseSelFolder = FALSE;
4007 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4009 TRACE("\n");
4011 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4013 LPITEMIDLIST pidlSelection;
4015 /* get the file selected */
4016 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4017 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4019 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4020 pidlSelection, SBSP_RELATIVE ) ) )
4022 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4023 ' ','n','o','t',' ','e','x','i','s','t',0};
4024 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4026 bBrowseSelFolder = TRUE;
4027 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4028 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4030 COMDLG32_SHFree( pidlSelection );
4033 return bBrowseSelFolder;
4037 * Memory allocation methods */
4038 static void *MemAlloc(UINT size)
4040 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4043 static void MemFree(void *mem)
4045 HeapFree(GetProcessHeap(),0,mem);
4048 static inline BOOL valid_struct_size( DWORD size )
4050 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4051 (size == sizeof( OPENFILENAMEW ));
4054 static inline BOOL is_win16_looks(DWORD flags)
4056 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4057 !(flags & OFN_EXPLORER));
4060 /* ------------------ APIs ---------------------- */
4062 /***********************************************************************
4063 * GetOpenFileNameA (COMDLG32.@)
4065 * Creates a dialog box for the user to select a file to open.
4067 * RETURNS
4068 * TRUE on success: user enters a valid file
4069 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4072 BOOL WINAPI GetOpenFileNameA(
4073 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4075 TRACE("flags %08x\n", ofn->Flags);
4077 if (!valid_struct_size( ofn->lStructSize ))
4079 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4080 return FALSE;
4083 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4084 if (ofn->Flags & OFN_FILEMUSTEXIST)
4085 ofn->Flags |= OFN_PATHMUSTEXIST;
4087 if (is_win16_looks(ofn->Flags))
4088 return GetFileName31A(ofn, OPEN_DIALOG);
4089 else
4090 return GetFileDialog95A(ofn, OPEN_DIALOG);
4093 /***********************************************************************
4094 * GetOpenFileNameW (COMDLG32.@)
4096 * Creates a dialog box for the user to select a file to open.
4098 * RETURNS
4099 * TRUE on success: user enters a valid file
4100 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4103 BOOL WINAPI GetOpenFileNameW(
4104 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4106 TRACE("flags %08x\n", ofn->Flags);
4108 if (!valid_struct_size( ofn->lStructSize ))
4110 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4111 return FALSE;
4114 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4115 if (ofn->Flags & OFN_FILEMUSTEXIST)
4116 ofn->Flags |= OFN_PATHMUSTEXIST;
4118 if (is_win16_looks(ofn->Flags))
4119 return GetFileName31W(ofn, OPEN_DIALOG);
4120 else
4121 return GetFileDialog95W(ofn, OPEN_DIALOG);
4125 /***********************************************************************
4126 * GetSaveFileNameA (COMDLG32.@)
4128 * Creates a dialog box for the user to select a file to save.
4130 * RETURNS
4131 * TRUE on success: user enters a valid file
4132 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4135 BOOL WINAPI GetSaveFileNameA(
4136 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4138 if (!valid_struct_size( ofn->lStructSize ))
4140 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4141 return FALSE;
4144 if (is_win16_looks(ofn->Flags))
4145 return GetFileName31A(ofn, SAVE_DIALOG);
4146 else
4147 return GetFileDialog95A(ofn, SAVE_DIALOG);
4150 /***********************************************************************
4151 * GetSaveFileNameW (COMDLG32.@)
4153 * Creates a dialog box for the user to select a file to save.
4155 * RETURNS
4156 * TRUE on success: user enters a valid file
4157 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4160 BOOL WINAPI GetSaveFileNameW(
4161 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4163 if (!valid_struct_size( ofn->lStructSize ))
4165 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4166 return FALSE;
4169 if (is_win16_looks(ofn->Flags))
4170 return GetFileName31W(ofn, SAVE_DIALOG);
4171 else
4172 return GetFileDialog95W(ofn, SAVE_DIALOG);
4175 /***********************************************************************
4176 * GetFileTitleA (COMDLG32.@)
4178 * See GetFileTitleW.
4180 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4182 int ret;
4183 UNICODE_STRING strWFile;
4184 LPWSTR lpWTitle;
4186 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4187 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4188 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4189 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4190 RtlFreeUnicodeString( &strWFile );
4191 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4192 return ret;
4196 /***********************************************************************
4197 * GetFileTitleW (COMDLG32.@)
4199 * Get the name of a file.
4201 * PARAMS
4202 * lpFile [I] name and location of file
4203 * lpTitle [O] returned file name
4204 * cbBuf [I] buffer size of lpTitle
4206 * RETURNS
4207 * Success: zero
4208 * Failure: negative number.
4210 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4212 int i, len;
4213 static const WCHAR brkpoint[] = {'*','[',']',0};
4214 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4216 if(lpFile == NULL || lpTitle == NULL)
4217 return -1;
4219 len = lstrlenW(lpFile);
4221 if (len == 0)
4222 return -1;
4224 if(strpbrkW(lpFile, brkpoint))
4225 return -1;
4227 len--;
4229 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4230 return -1;
4232 for(i = len; i >= 0; i--)
4234 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4236 i++;
4237 break;
4241 if(i == -1)
4242 i++;
4244 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4246 len = lstrlenW(lpFile+i)+1;
4247 if(cbBuf < len)
4248 return len;
4250 lstrcpyW(lpTitle, &lpFile[i]);
4251 return 0;