comctl32: Improve mouse wheel scrolling in treeview control.
[wine.git] / dlls / comdlg32 / filedlg.c
blobeeac384fdf7905df9ed21e15453fae9490a75216
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "cderr.h"
72 #include "shellapi.h"
73 #include "shlobj.h"
74 #include "filedlgbrowser.h"
75 #include "shlwapi.h"
77 #include "wine/unicode.h"
78 #include "wine/debug.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_DONTADDTORECENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex; /* Index of picture in image list */
95 HIMAGELIST hImgList;
96 int m_iIndent; /* Indentation index */
97 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99 } SFOLDER,*LPSFOLDER;
101 typedef struct tagLookInInfo
103 int iMaxIndentation;
104 UINT uSelectedItem;
105 } LookInInfos;
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define ICONWIDTH 18
114 #define XTEXTOFFSET 3
116 /* AddItem flags*/
117 #define LISTEND -1
119 /* SearchItem methods */
120 #define SEARCH_PIDL 1
121 #define SEARCH_EXP 2
122 #define ITEM_NOTFOUND -1
124 /* Undefined windows message sent by CreateViewObject*/
125 #define WM_GETISHELLBROWSER WM_USER+7
127 /* NOTE
128 * Those macros exist in windowsx.h. However, you can't really use them since
129 * they rely on the UNICODE defines and can't be used inside Wine itself.
132 /* Combo box macros */
133 #define CBAddString(hwnd,str) \
134 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
136 #define CBInsertString(hwnd,str,pos) \
137 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
139 #define CBDeleteString(hwnd,pos) \
140 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
142 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
143 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
145 #define CBGetItemDataPtr(hwnd,iItemId) \
146 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
148 #define CBGetLBText(hwnd,iItemId,str) \
149 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
151 #define CBGetCurSel(hwnd) \
152 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
154 #define CBSetCurSel(hwnd,pos) \
155 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
157 #define CBGetCount(hwnd) \
158 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
159 #define CBShowDropDown(hwnd,show) \
160 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
161 #define CBSetItemHeight(hwnd,index,height) \
162 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
164 #define CBSetExtendedUI(hwnd,flag) \
165 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
167 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
168 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
169 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
171 static const WCHAR LastVisitedMRUW[] =
172 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
174 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
175 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
176 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Functions for dealing with the most-recently-used registry keys */
219 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
220 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
221 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
223 /* Miscellaneous tool functions */
224 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
225 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
226 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
227 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
228 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
229 static UINT GetNumSelected( IDataObject *doSelected );
231 /* Shell memory allocation */
232 static void *MemAlloc(UINT size);
233 static void MemFree(void *mem);
235 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
236 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
237 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
238 static BOOL BrowseSelectedFolder(HWND hwnd);
240 /***********************************************************************
241 * GetFileName95
243 * Creates an Open common dialog box that lets the user select
244 * the drive, directory, and the name of a file or set of files to open.
246 * IN : The FileOpenDlgInfos structure associated with the dialog
247 * OUT : TRUE on success
248 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
250 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
253 LRESULT lRes;
254 LPCVOID origTemplate;
255 DWORD dwSize;
256 LPDLGTEMPLATEW template;
257 HRSRC hRes;
258 HANDLE hDlgTmpl = 0;
259 HRESULT hr;
261 /* test for missing functionality */
262 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
264 FIXME("Flags 0x%08x not yet implemented\n",
265 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
268 /* Create the dialog from a template */
270 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
272 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
273 return FALSE;
275 if (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
276 !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
277 !(origTemplate = LockResource(hDlgTmpl)))
279 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
280 return FALSE;
282 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
284 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
285 return FALSE;
287 memcpy(template, origTemplate, dwSize);
289 /* msdn: explorer style dialogs permit sizing by default.
290 * The OFN_ENABLESIZING flag is only needed when a hook or
291 * custom tmeplate is provided */
292 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
293 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
294 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
296 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
298 template->style |= WS_SIZEBOX;
299 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
300 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
302 else
303 template->style &= ~WS_SIZEBOX;
306 /* old style hook messages */
307 if (IsHooked(fodInfos))
309 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
310 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
311 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
312 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
315 /* Some shell namespace extensions depend on COM being initialized. */
316 hr = OleInitialize(NULL);
318 if (fodInfos->unicode)
319 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
320 template,
321 fodInfos->ofnInfos->hwndOwner,
322 FileOpenDlgProc95,
323 (LPARAM) fodInfos);
324 else
325 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
326 template,
327 fodInfos->ofnInfos->hwndOwner,
328 FileOpenDlgProc95,
329 (LPARAM) fodInfos);
330 if (SUCCEEDED(hr))
331 OleUninitialize();
333 HeapFree(GetProcessHeap(), 0, template);
335 /* Unable to create the dialog */
336 if( lRes == -1)
337 return FALSE;
339 return lRes;
342 /***********************************************************************
343 * GetFileDialog95A
345 * Call GetFileName95 with this structure and clean the memory.
347 * IN : The OPENFILENAMEA initialisation structure passed to
348 * GetOpenFileNameA win api function (see filedlg.c)
350 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
352 BOOL ret;
353 FileOpenDlgInfos fodInfos;
354 LPSTR lpstrSavDir = NULL;
355 LPWSTR title = NULL;
356 LPWSTR defext = NULL;
357 LPWSTR filter = NULL;
358 LPWSTR customfilter = NULL;
360 /* Initialize CommDlgExtendedError() */
361 COMDLG32_SetCommDlgExtendedError(0);
363 /* Initialize FileOpenDlgInfos structure */
364 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
366 /* Pass in the original ofn */
367 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
369 /* save current directory */
370 if (ofn->Flags & OFN_NOCHANGEDIR)
372 lpstrSavDir = MemAlloc(MAX_PATH);
373 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
376 fodInfos.unicode = FALSE;
378 /* convert all the input strings to unicode */
379 if(ofn->lpstrInitialDir)
381 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
382 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
383 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
385 else
386 fodInfos.initdir = NULL;
388 if(ofn->lpstrFile)
390 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
393 else
394 fodInfos.filename = NULL;
396 if(ofn->lpstrDefExt)
398 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
399 defext = MemAlloc((len+1)*sizeof(WCHAR));
400 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
402 fodInfos.defext = defext;
404 if(ofn->lpstrTitle)
406 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
407 title = MemAlloc((len+1)*sizeof(WCHAR));
408 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
410 fodInfos.title = title;
412 if (ofn->lpstrFilter)
414 LPCSTR s;
415 int n, len;
417 /* filter is a list... title\0ext\0......\0\0 */
418 s = ofn->lpstrFilter;
419 while (*s) s = s+strlen(s)+1;
420 s++;
421 n = s - ofn->lpstrFilter;
422 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
423 filter = MemAlloc(len*sizeof(WCHAR));
424 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
426 fodInfos.filter = filter;
428 /* convert lpstrCustomFilter */
429 if (ofn->lpstrCustomFilter)
431 LPCSTR s;
432 int n, len;
434 /* customfilter contains a pair of strings... title\0ext\0 */
435 s = ofn->lpstrCustomFilter;
436 if (*s) s = s+strlen(s)+1;
437 if (*s) s = s+strlen(s)+1;
438 n = s - ofn->lpstrCustomFilter;
439 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
440 customfilter = MemAlloc(len*sizeof(WCHAR));
441 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
443 fodInfos.customfilter = customfilter;
445 /* Initialize the dialog property */
446 fodInfos.DlgInfos.dwDlgProp = 0;
447 fodInfos.DlgInfos.hwndCustomDlg = NULL;
449 switch(iDlgType)
451 case OPEN_DIALOG :
452 ret = GetFileName95(&fodInfos);
453 break;
454 case SAVE_DIALOG :
455 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
456 ret = GetFileName95(&fodInfos);
457 break;
458 default :
459 ret = 0;
462 if (lpstrSavDir)
464 SetCurrentDirectoryA(lpstrSavDir);
465 MemFree(lpstrSavDir);
468 MemFree(title);
469 MemFree(defext);
470 MemFree(filter);
471 MemFree(customfilter);
472 MemFree(fodInfos.initdir);
473 MemFree(fodInfos.filename);
475 TRACE("selected file: %s\n",ofn->lpstrFile);
477 return ret;
480 /***********************************************************************
481 * GetFileDialog95W
483 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
484 * Call GetFileName95 with this structure and clean the memory.
487 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
489 BOOL ret;
490 FileOpenDlgInfos fodInfos;
491 LPWSTR lpstrSavDir = NULL;
493 /* Initialize CommDlgExtendedError() */
494 COMDLG32_SetCommDlgExtendedError(0);
496 /* Initialize FileOpenDlgInfos structure */
497 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
499 /* Pass in the original ofn */
500 fodInfos.ofnInfos = ofn;
502 fodInfos.title = ofn->lpstrTitle;
503 fodInfos.defext = ofn->lpstrDefExt;
504 fodInfos.filter = ofn->lpstrFilter;
505 fodInfos.customfilter = ofn->lpstrCustomFilter;
507 /* convert string arguments, save others */
508 if(ofn->lpstrFile)
510 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
511 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
513 else
514 fodInfos.filename = NULL;
516 if(ofn->lpstrInitialDir)
518 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
519 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
520 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
521 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
523 else
524 fodInfos.initdir = NULL;
526 /* save current directory */
527 if (ofn->Flags & OFN_NOCHANGEDIR)
529 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
530 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
533 fodInfos.unicode = TRUE;
535 switch(iDlgType)
537 case OPEN_DIALOG :
538 ret = GetFileName95(&fodInfos);
539 break;
540 case SAVE_DIALOG :
541 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
542 ret = GetFileName95(&fodInfos);
543 break;
544 default :
545 ret = 0;
548 if (lpstrSavDir)
550 SetCurrentDirectoryW(lpstrSavDir);
551 MemFree(lpstrSavDir);
554 /* restore saved IN arguments and convert OUT arguments back */
555 MemFree(fodInfos.filename);
556 MemFree(fodInfos.initdir);
557 return ret;
560 /******************************************************************************
561 * COMDLG32_GetDisplayNameOf [internal]
563 * Helper function to get the display name for a pidl.
565 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
566 LPSHELLFOLDER psfDesktop;
567 STRRET strret;
569 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
570 return FALSE;
572 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
573 IShellFolder_Release(psfDesktop);
574 return FALSE;
577 IShellFolder_Release(psfDesktop);
578 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
581 /******************************************************************************
582 * COMDLG32_GetCanonicalPath [internal]
584 * Helper function to get the canonical path.
586 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
587 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
589 WCHAR lpstrTemp[MAX_PATH];
591 /* Get the current directory name */
592 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
594 /* last fallback */
595 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
597 PathAddBackslashW(lpstrPathAndFile);
599 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
601 /* if the user specified a fully qualified path use it */
602 if(PathIsRelativeW(lpstrFile))
604 lstrcatW(lpstrPathAndFile, lpstrFile);
606 else
608 /* does the path have a drive letter? */
609 if (PathGetDriveNumberW(lpstrFile) == -1)
610 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
611 else
612 lstrcpyW(lpstrPathAndFile, lpstrFile);
615 /* resolve "." and ".." */
616 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
617 lstrcpyW(lpstrPathAndFile, lpstrTemp);
618 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
621 /***********************************************************************
622 * COMDLG32_SplitFileNames [internal]
624 * Creates a delimited list of filenames.
626 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
628 UINT nStrCharCount = 0; /* index in src buffer */
629 UINT nFileIndex = 0; /* index in dest buffer */
630 UINT nFileCount = 0; /* number of files */
632 /* we might get single filename without any '"',
633 * so we need nStrLen + terminating \0 + end-of-list \0 */
634 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
635 *sizeUsed = 0;
637 /* build delimited file list from filenames */
638 while ( nStrCharCount <= nStrLen )
640 if ( lpstrEdit[nStrCharCount]=='"' )
642 nStrCharCount++;
643 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
645 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
646 nStrCharCount++;
648 (*lpstrFileList)[nFileIndex++] = 0;
649 nFileCount++;
651 nStrCharCount++;
654 /* single, unquoted string */
655 if ((nStrLen > 0) && (nFileIndex == 0) )
657 lstrcpyW(*lpstrFileList, lpstrEdit);
658 nFileIndex = lstrlenW(lpstrEdit) + 1;
659 nFileCount = 1;
662 /* trailing \0 */
663 (*lpstrFileList)[nFileIndex++] = '\0';
665 *sizeUsed = nFileIndex;
666 return nFileCount;
669 /***********************************************************************
670 * ArrangeCtrlPositions [internal]
672 * NOTE: Make sure to add testcases for any changes made here.
674 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
676 HWND hwndChild, hwndStc32;
677 RECT rectParent, rectChild, rectStc32;
678 INT help_fixup = 0;
679 int chgx, chgy;
681 /* Take into account if open as read only checkbox and help button
682 * are hidden
684 if (hide_help)
686 RECT rectHelp, rectCancel;
687 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
688 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
689 /* subtract the height of the help button plus the space between
690 * the help button and the cancel button to the height of the dialog
692 help_fixup = rectHelp.bottom - rectCancel.bottom;
696 There are two possibilities to add components to the default file dialog box.
698 By default, all the new components are added below the standard dialog box (the else case).
700 However, if there is a static text component with the stc32 id, a special case happens.
701 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
702 in the window and the cx and cy indicate how to size the window.
703 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
704 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
708 GetClientRect(hwndParentDlg, &rectParent);
710 /* when arranging controls we have to use fixed parent size */
711 rectParent.bottom -= help_fixup;
713 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
714 if (hwndStc32)
716 GetWindowRect(hwndStc32, &rectStc32);
717 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
719 /* set the size of the stc32 control according to the size of
720 * client area of the parent dialog
722 SetWindowPos(hwndStc32, 0,
723 0, 0,
724 rectParent.right, rectParent.bottom,
725 SWP_NOMOVE | SWP_NOZORDER);
727 else
728 SetRectEmpty(&rectStc32);
730 /* this part moves controls of the child dialog */
731 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
732 while (hwndChild)
734 if (hwndChild != hwndStc32)
736 GetWindowRect(hwndChild, &rectChild);
737 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
739 /* move only if stc32 exist */
740 if (hwndStc32 && rectChild.left > rectStc32.right)
742 /* move to the right of visible controls of the parent dialog */
743 rectChild.left += rectParent.right;
744 rectChild.left -= rectStc32.right;
746 /* move even if stc32 doesn't exist */
747 if (rectChild.top >= rectStc32.bottom)
749 /* move below visible controls of the parent dialog */
750 rectChild.top += rectParent.bottom;
751 rectChild.top -= rectStc32.bottom - rectStc32.top;
754 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
755 0, 0, SWP_NOSIZE | SWP_NOZORDER);
757 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
760 /* this part moves controls of the parent dialog */
761 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
762 while (hwndChild)
764 if (hwndChild != hwndChildDlg)
766 GetWindowRect(hwndChild, &rectChild);
767 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
769 /* left,top of stc32 marks the position of controls
770 * from the parent dialog
772 rectChild.left += rectStc32.left;
773 rectChild.top += rectStc32.top;
775 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
776 0, 0, SWP_NOSIZE | SWP_NOZORDER);
778 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
781 /* calculate the size of the resulting dialog */
783 /* here we have to use original parent size */
784 GetClientRect(hwndParentDlg, &rectParent);
785 GetClientRect(hwndChildDlg, &rectChild);
786 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
787 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
789 if (hwndStc32)
791 /* width */
792 if (rectParent.right > rectStc32.right - rectStc32.left)
793 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
794 else
795 chgx = rectChild.right - rectParent.right;
796 /* height */
797 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
798 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
799 else
800 /* Unconditionally set new dialog
801 * height to that of the child
803 chgy = rectChild.bottom - rectParent.bottom;
805 else
807 chgx = 0;
808 chgy = rectChild.bottom - help_fixup;
810 /* set the size of the parent dialog */
811 GetWindowRect(hwndParentDlg, &rectParent);
812 SetWindowPos(hwndParentDlg, 0,
813 0, 0,
814 rectParent.right - rectParent.left + chgx,
815 rectParent.bottom - rectParent.top + chgy,
816 SWP_NOMOVE | SWP_NOZORDER);
819 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
821 switch(uMsg) {
822 case WM_INITDIALOG:
823 return TRUE;
825 return FALSE;
828 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
830 LPCVOID template;
831 HRSRC hRes;
832 HANDLE hDlgTmpl = 0;
833 HWND hChildDlg = 0;
835 TRACE("\n");
838 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
839 * structure's hInstance parameter is not a HINSTANCE, but
840 * instead a pointer to a template resource to use.
842 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
844 HINSTANCE hinst;
845 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
847 hinst = COMDLG32_hInstance;
848 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
850 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
851 return NULL;
854 else
856 hinst = fodInfos->ofnInfos->hInstance;
857 if(fodInfos->unicode)
859 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
860 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
862 else
864 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
865 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
867 if (!hRes)
869 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
870 return NULL;
872 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
873 !(template = LockResource( hDlgTmpl )))
875 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
876 return NULL;
879 if (fodInfos->unicode)
880 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
881 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
882 (LPARAM)fodInfos->ofnInfos);
883 else
884 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
885 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
886 (LPARAM)fodInfos->ofnInfos);
887 return hChildDlg;
889 else if( IsHooked(fodInfos))
891 RECT rectHwnd;
892 struct {
893 DLGTEMPLATE tmplate;
894 WORD menu,class,title;
895 } temp;
896 GetClientRect(hwnd,&rectHwnd);
897 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
898 temp.tmplate.dwExtendedStyle = 0;
899 temp.tmplate.cdit = 0;
900 temp.tmplate.x = 0;
901 temp.tmplate.y = 0;
902 temp.tmplate.cx = 0;
903 temp.tmplate.cy = 0;
904 temp.menu = temp.class = temp.title = 0;
906 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
907 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
909 return hChildDlg;
911 return NULL;
914 /***********************************************************************
915 * SendCustomDlgNotificationMessage
917 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
920 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
922 LRESULT hook_result = 0;
923 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
925 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
927 if(!fodInfos) return 0;
929 if(fodInfos->DlgInfos.hwndCustomDlg)
931 TRACE("CALL NOTIFY for %x\n", uCode);
932 if(fodInfos->unicode)
934 OFNOTIFYW ofnNotify;
935 ofnNotify.hdr.hwndFrom=hwndParentDlg;
936 ofnNotify.hdr.idFrom=0;
937 ofnNotify.hdr.code = uCode;
938 ofnNotify.lpOFN = fodInfos->ofnInfos;
939 ofnNotify.pszFile = NULL;
940 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
942 else
944 OFNOTIFYA ofnNotify;
945 ofnNotify.hdr.hwndFrom=hwndParentDlg;
946 ofnNotify.hdr.idFrom=0;
947 ofnNotify.hdr.code = uCode;
948 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
949 ofnNotify.pszFile = NULL;
950 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
952 TRACE("RET NOTIFY\n");
954 TRACE("Retval: 0x%08lx\n", hook_result);
955 return hook_result;
958 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
960 UINT len, total;
961 WCHAR *p, *buffer;
962 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
964 TRACE("CDM_GETFILEPATH:\n");
966 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
967 return -1;
969 /* get path and filenames */
970 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
971 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
972 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
973 if (len)
975 p = buffer + strlenW(buffer);
976 *p++ = '\\';
977 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
979 if (fodInfos->unicode)
981 total = strlenW( buffer) + 1;
982 if (result) lstrcpynW( result, buffer, size );
983 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
985 else
987 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
988 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
989 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
991 HeapFree( GetProcessHeap(), 0, buffer );
992 return total;
995 /***********************************************************************
996 * FILEDLG95_HandleCustomDialogMessages
998 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1000 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1002 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1003 WCHAR lpstrPath[MAX_PATH];
1004 INT_PTR retval;
1006 if(!fodInfos) return FALSE;
1008 switch(uMsg)
1010 case CDM_GETFILEPATH:
1011 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1012 break;
1014 case CDM_GETFOLDERPATH:
1015 TRACE("CDM_GETFOLDERPATH:\n");
1016 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1017 if (lParam)
1019 if (fodInfos->unicode)
1020 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1021 else
1022 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1023 (LPSTR)lParam, (int)wParam, NULL, NULL);
1025 retval = lstrlenW(lpstrPath) + 1;
1026 break;
1028 case CDM_GETFOLDERIDLIST:
1029 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1030 if (retval <= wParam)
1031 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1032 break;
1034 case CDM_GETSPEC:
1035 TRACE("CDM_GETSPEC:\n");
1036 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1037 if (lParam)
1039 if (fodInfos->unicode)
1040 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1041 else
1042 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1044 break;
1046 case CDM_SETCONTROLTEXT:
1047 TRACE("CDM_SETCONTROLTEXT:\n");
1048 if ( lParam )
1050 if( fodInfos->unicode )
1051 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1052 else
1053 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1055 retval = TRUE;
1056 break;
1058 case CDM_HIDECONTROL:
1059 /* MSDN states that it should fail for not OFN_EXPLORER case */
1060 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1062 HWND control = GetDlgItem( hwnd, wParam );
1063 if (control) ShowWindow( control, SW_HIDE );
1064 retval = TRUE;
1066 else retval = FALSE;
1067 break;
1069 default:
1070 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1071 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1072 return FALSE;
1074 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1075 return TRUE;
1078 /***********************************************************************
1079 * FILEDLG95_OnWMGetMMI
1081 * WM_GETMINMAXINFO message handler for resizable dialogs
1083 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1085 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1086 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1087 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1089 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1091 return TRUE;
1094 /***********************************************************************
1095 * FILEDLG95_OnWMSize
1097 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1099 * FIXME: this could be made more elaborate. Now use a simple scheme
1100 * where the file view is enlarged and the controls are either moved
1101 * vertically or horizontally to get out of the way. Only the "grip"
1102 * is moved in both directions to stay in the corner.
1104 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1106 RECT rc, rcview;
1107 int chgx, chgy;
1108 HWND ctrl;
1109 HDWP hdwp;
1110 FileOpenDlgInfos *fodInfos;
1112 if( wParam != SIZE_RESTORED) return FALSE;
1113 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1114 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1115 /* get the new dialog rectangle */
1116 GetWindowRect( hwnd, &rc);
1117 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1118 rc.right -rc.left, rc.bottom -rc.top);
1119 /* not initialized yet */
1120 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1121 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1122 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1123 return FALSE;
1124 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1125 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1126 fodInfos->sizedlg.cx = rc.right - rc.left;
1127 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1128 /* change the size of the view window */
1129 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1130 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1131 hdwp = BeginDeferWindowPos( 10);
1132 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1133 rcview.right - rcview.left + chgx,
1134 rcview.bottom - rcview.top + chgy,
1135 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1136 /* change position and sizes of the controls */
1137 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1139 int ctrlid = GetDlgCtrlID( ctrl);
1140 GetWindowRect( ctrl, &rc);
1141 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1142 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1144 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1145 0, 0,
1146 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1148 else if( rc.top > rcview.bottom)
1150 /* if it was below the shell view
1151 * move to bottom */
1152 switch( ctrlid)
1154 /* file name (edit or comboboxex) and file types combo change also width */
1155 case edt1:
1156 case cmb13:
1157 case cmb1:
1158 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1159 rc.right - rc.left + chgx, rc.bottom - rc.top,
1160 SWP_NOACTIVATE | SWP_NOZORDER);
1161 break;
1162 /* then these buttons must move out of the way */
1163 case IDOK:
1164 case IDCANCEL:
1165 case pshHelp:
1166 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1167 0, 0,
1168 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1169 break;
1170 default:
1171 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1172 0, 0,
1173 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1176 else if( rc.left > rcview.right)
1178 /* if it was to the right of the shell view
1179 * move to right */
1180 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1181 0, 0,
1182 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1184 else
1185 /* special cases */
1187 switch( ctrlid)
1189 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1190 case IDC_LOOKIN:
1191 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1192 rc.right - rc.left + chgx, rc.bottom - rc.top,
1193 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1194 break;
1195 case IDC_TOOLBARSTATIC:
1196 case IDC_TOOLBAR:
1197 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1198 0, 0,
1199 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1200 break;
1201 #endif
1202 /* not resized in windows. Since wine uses this invisible control
1203 * to size the browser view it needs to be resized */
1204 case IDC_SHELLSTATIC:
1205 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1206 rc.right - rc.left + chgx,
1207 rc.bottom - rc.top + chgy,
1208 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1209 break;
1213 if(fodInfos->DlgInfos.hwndCustomDlg &&
1214 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1216 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1217 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1219 GetWindowRect( ctrl, &rc);
1220 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1221 if( rc.top > rcview.bottom)
1223 /* if it was below the shell view
1224 * move to bottom */
1225 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1226 rc.right - rc.left, rc.bottom - rc.top,
1227 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1229 else if( rc.left > rcview.right)
1231 /* if it was to the right of the shell view
1232 * move to right */
1233 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1234 rc.right - rc.left, rc.bottom - rc.top,
1235 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1238 /* size the custom dialog at the end: some applications do some
1239 * control re-arranging at this point */
1240 GetClientRect(hwnd, &rc);
1241 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1242 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1244 EndDeferWindowPos( hdwp);
1245 /* should not be needed */
1246 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1247 return TRUE;
1250 /***********************************************************************
1251 * FileOpenDlgProc95
1253 * File open dialog procedure
1255 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1257 #if 0
1258 TRACE("%p 0x%04x\n", hwnd, uMsg);
1259 #endif
1261 switch(uMsg)
1263 case WM_INITDIALOG:
1265 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1266 RECT rc, rcstc;
1267 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1268 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1270 /* Adds the FileOpenDlgInfos in the property list of the dialog
1271 so it will be easily accessible through a GetPropA(...) */
1272 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1274 FILEDLG95_InitControls(hwnd);
1276 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1278 GetWindowRect( hwnd, &rc);
1279 fodInfos->DlgInfos.hwndGrip =
1280 CreateWindowExA( 0, "SCROLLBAR", NULL,
1281 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1282 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1283 rc.right - gripx, rc.bottom - gripy,
1284 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1287 fodInfos->DlgInfos.hwndCustomDlg =
1288 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1290 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1291 FILEDLG95_FillControls(hwnd, wParam, lParam);
1293 if( fodInfos->DlgInfos.hwndCustomDlg)
1294 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1296 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1297 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1298 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1301 /* if the app has changed the position of the invisible listbox,
1302 * change that of the listview (browser) as well */
1303 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1304 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1305 if( !EqualRect( &rc, &rcstc))
1307 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1308 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1309 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1310 SWP_NOACTIVATE | SWP_NOZORDER);
1313 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1315 GetWindowRect( hwnd, &rc);
1316 fodInfos->sizedlg.cx = rc.right - rc.left;
1317 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1318 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1319 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1320 GetClientRect( hwnd, &rc);
1321 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1322 rc.right - gripx, rc.bottom - gripy,
1323 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1324 /* resize the dialog to the previous invocation */
1325 if( MemDialogSize.cx && MemDialogSize.cy)
1326 SetWindowPos( hwnd, NULL,
1327 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1328 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1331 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1332 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1334 return 0;
1336 case WM_SIZE:
1337 return FILEDLG95_OnWMSize(hwnd, wParam);
1338 case WM_GETMINMAXINFO:
1339 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1340 case WM_COMMAND:
1341 return FILEDLG95_OnWMCommand(hwnd, wParam);
1342 case WM_DRAWITEM:
1344 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1346 case IDC_LOOKIN:
1347 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1348 return TRUE;
1351 return FALSE;
1353 case WM_GETISHELLBROWSER:
1354 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1356 case WM_DESTROY:
1358 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1359 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1360 MemDialogSize = fodInfos->sizedlg;
1361 RemovePropA(hwnd, FileOpenDlgInfosStr);
1362 return FALSE;
1364 case WM_NOTIFY:
1366 LPNMHDR lpnmh = (LPNMHDR)lParam;
1367 UINT stringId = -1;
1369 /* set up the button tooltips strings */
1370 if(TTN_GETDISPINFOA == lpnmh->code )
1372 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1373 switch(lpnmh->idFrom )
1375 /* Up folder button */
1376 case FCIDM_TB_UPFOLDER:
1377 stringId = IDS_UPFOLDER;
1378 break;
1379 /* New folder button */
1380 case FCIDM_TB_NEWFOLDER:
1381 stringId = IDS_NEWFOLDER;
1382 break;
1383 /* List option button */
1384 case FCIDM_TB_SMALLICON:
1385 stringId = IDS_LISTVIEW;
1386 break;
1387 /* Details option button */
1388 case FCIDM_TB_REPORTVIEW:
1389 stringId = IDS_REPORTVIEW;
1390 break;
1391 /* Desktop button */
1392 case FCIDM_TB_DESKTOP:
1393 stringId = IDS_TODESKTOP;
1394 break;
1395 default:
1396 stringId = 0;
1398 lpdi->hinst = COMDLG32_hInstance;
1399 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1401 return FALSE;
1403 default :
1404 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1405 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1406 return FALSE;
1410 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1412 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1413 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1416 /***********************************************************************
1417 * FILEDLG95_InitControls
1419 * WM_INITDIALOG message handler (before hook notification)
1421 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1423 int win2000plus = 0;
1424 int win98plus = 0;
1425 int handledPath = FALSE;
1426 OSVERSIONINFOW osVi;
1427 static const WCHAR szwSlash[] = { '\\', 0 };
1428 static const WCHAR szwStar[] = { '*',0 };
1430 static const TBBUTTON tbb[] =
1432 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1433 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1434 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1435 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1436 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1437 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1438 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1439 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1440 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1442 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1444 RECT rectTB;
1445 RECT rectlook;
1447 HIMAGELIST toolbarImageList;
1448 SHFILEINFOA shFileInfo;
1449 ITEMIDLIST *desktopPidl;
1451 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1453 TRACE("%p\n", fodInfos);
1455 /* Get windows version emulating */
1456 osVi.dwOSVersionInfoSize = sizeof(osVi);
1457 GetVersionExW(&osVi);
1458 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1459 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1460 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1461 win2000plus = (osVi.dwMajorVersion > 4);
1462 if (win2000plus) win98plus = TRUE;
1464 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1467 /* Use either the edit or the comboboxex for the filename control */
1468 if (filename_is_edit( fodInfos ))
1470 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1471 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1473 else
1475 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1476 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1479 /* Get the hwnd of the controls */
1480 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1481 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1483 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1484 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1486 /* construct the toolbar */
1487 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1488 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1490 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1491 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1492 rectTB.left = rectlook.right;
1493 rectTB.top = rectlook.top-1;
1495 if (fodInfos->unicode)
1496 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1497 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1498 rectTB.left, rectTB.top,
1499 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1500 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1501 else
1502 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1503 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1504 rectTB.left, rectTB.top,
1505 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1506 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1508 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1510 /* FIXME: use TB_LOADIMAGES when implemented */
1511 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1512 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1513 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1515 /* Retrieve and add desktop icon to the toolbar */
1516 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1517 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1518 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1519 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1520 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1522 DestroyIcon(shFileInfo.hIcon);
1523 CoTaskMemFree(desktopPidl);
1525 /* Finish Toolbar Construction */
1526 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1527 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1529 /* Set the window text with the text specified in the OPENFILENAME structure */
1530 if(fodInfos->title)
1532 SetWindowTextW(hwnd,fodInfos->title);
1534 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1536 WCHAR buf[64];
1537 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1538 SetWindowTextW(hwnd, buf);
1541 /* Initialise the file name edit control */
1542 handledPath = FALSE;
1543 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1545 if(fodInfos->filename)
1547 /* 1. If win2000 or higher and filename contains a path, use it
1548 in preference over the lpstrInitialDir */
1549 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1550 WCHAR tmpBuf[MAX_PATH];
1551 WCHAR *nameBit;
1552 DWORD result;
1554 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1555 if (result) {
1557 /* nameBit is always shorter than the original filename */
1558 lstrcpyW(fodInfos->filename,nameBit);
1560 *nameBit = 0x00;
1561 MemFree(fodInfos->initdir);
1562 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1563 lstrcpyW(fodInfos->initdir, tmpBuf);
1564 handledPath = TRUE;
1565 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1566 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1568 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1570 } else {
1571 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1575 /* 2. (All platforms) If initdir is not null, then use it */
1576 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1577 (*fodInfos->initdir!=0x00))
1579 /* Work out the proper path as supplied one might be relative */
1580 /* (Here because supplying '.' as dir browses to My Computer) */
1581 if (handledPath==FALSE) {
1582 WCHAR tmpBuf[MAX_PATH];
1583 WCHAR tmpBuf2[MAX_PATH];
1584 WCHAR *nameBit;
1585 DWORD result;
1587 lstrcpyW(tmpBuf, fodInfos->initdir);
1588 if( PathFileExistsW(tmpBuf) ) {
1589 /* initdir does not have to be a directory. If a file is
1590 * specified, the dir part is taken */
1591 if( PathIsDirectoryW(tmpBuf)) {
1592 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1593 lstrcatW(tmpBuf, szwSlash);
1595 lstrcatW(tmpBuf, szwStar);
1597 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1598 if (result) {
1599 *nameBit = 0x00;
1600 MemFree(fodInfos->initdir);
1601 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1602 lstrcpyW(fodInfos->initdir, tmpBuf2);
1603 handledPath = TRUE;
1604 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1607 else if (fodInfos->initdir)
1609 MemFree(fodInfos->initdir);
1610 fodInfos->initdir = NULL;
1611 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1616 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1617 (*fodInfos->initdir==0x00)))
1619 /* 3. All except w2k+: if filename contains a path use it */
1620 if (!win2000plus && fodInfos->filename &&
1621 *fodInfos->filename &&
1622 strpbrkW(fodInfos->filename, szwSlash)) {
1623 WCHAR tmpBuf[MAX_PATH];
1624 WCHAR *nameBit;
1625 DWORD result;
1627 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1628 tmpBuf, &nameBit);
1629 if (result) {
1630 int len;
1632 /* nameBit is always shorter than the original filename */
1633 lstrcpyW(fodInfos->filename, nameBit);
1634 *nameBit = 0x00;
1636 len = lstrlenW(tmpBuf);
1637 MemFree(fodInfos->initdir);
1638 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1639 lstrcpyW(fodInfos->initdir, tmpBuf);
1641 handledPath = TRUE;
1642 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1643 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1645 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1648 /* 4. Win2000+: Recently used */
1649 if (handledPath == FALSE && win2000plus) {
1650 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1651 fodInfos->initdir[0] = '\0';
1653 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1655 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1656 handledPath = TRUE;
1657 }else{
1658 MemFree(fodInfos->initdir);
1659 fodInfos->initdir = NULL;
1663 /* 5. win98+ and win2000+ if any files of specified filter types in
1664 current directory, use it */
1665 if ( win98plus && handledPath == FALSE &&
1666 fodInfos->filter && *fodInfos->filter) {
1668 LPCWSTR lpstrPos = fodInfos->filter;
1669 WIN32_FIND_DATAW FindFileData;
1670 HANDLE hFind;
1672 while (1)
1674 /* filter is a list... title\0ext\0......\0\0 */
1676 /* Skip the title */
1677 if(! *lpstrPos) break; /* end */
1678 lpstrPos += lstrlenW(lpstrPos) + 1;
1680 /* See if any files exist in the current dir with this extension */
1681 if(! *lpstrPos) break; /* end */
1683 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1685 if (hFind == INVALID_HANDLE_VALUE) {
1686 /* None found - continue search */
1687 lpstrPos += lstrlenW(lpstrPos) + 1;
1689 } else {
1691 MemFree(fodInfos->initdir);
1692 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1693 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1695 handledPath = TRUE;
1696 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1697 debugstr_w(lpstrPos));
1698 FindClose(hFind);
1699 break;
1704 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1705 if (handledPath == FALSE && (win2000plus || win98plus)) {
1706 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1708 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1710 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1712 /* last fallback */
1713 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1714 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1715 } else {
1716 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1718 } else {
1719 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1721 handledPath = TRUE;
1722 } else if (handledPath==FALSE) {
1723 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1724 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1725 handledPath = TRUE;
1726 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1729 SetFocus( fodInfos->DlgInfos.hwndFileName );
1730 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1732 /* Must the open as read only check box be checked ?*/
1733 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1735 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1738 /* Must the open as read only check box be hidden? */
1739 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1741 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1742 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1745 /* Must the help button be hidden? */
1746 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1748 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1749 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1752 /* change Open to Save */
1753 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1755 WCHAR buf[16];
1756 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1757 SetDlgItemTextW(hwnd, IDOK, buf);
1758 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1759 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1762 /* Initialize the filter combo box */
1763 FILEDLG95_FILETYPE_Init(hwnd);
1765 return 0;
1768 /***********************************************************************
1769 * FILEDLG95_ResizeControls
1771 * WM_INITDIALOG message handler (after hook notification)
1773 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1775 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1777 if (fodInfos->DlgInfos.hwndCustomDlg)
1779 RECT rc;
1780 UINT flags = SWP_NOACTIVATE;
1782 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1783 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1785 /* resize the custom dialog to the parent size */
1786 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1787 GetClientRect(hwnd, &rc);
1788 else
1790 /* our own fake template is zero sized and doesn't have children, so
1791 * there is no need to resize it. Picasa depends on it.
1793 flags |= SWP_NOSIZE;
1794 SetRectEmpty(&rc);
1796 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1797 0, 0, rc.right, rc.bottom, flags);
1799 else
1801 /* Resize the height, if open as read only checkbox ad help button are
1802 * hidden and we are not using a custom template nor a customDialog
1804 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1805 (!(fodInfos->ofnInfos->Flags &
1806 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1808 RECT rectDlg, rectHelp, rectCancel;
1809 GetWindowRect(hwnd, &rectDlg);
1810 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1811 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1812 /* subtract the height of the help button plus the space between the help
1813 * button and the cancel button to the height of the dialog
1815 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1816 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1817 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1820 return TRUE;
1823 /***********************************************************************
1824 * FILEDLG95_FillControls
1826 * WM_INITDIALOG message handler (after hook notification)
1828 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1830 LPITEMIDLIST pidlItemId = NULL;
1832 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1834 TRACE("dir=%s file=%s\n",
1835 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1837 /* Get the initial directory pidl */
1839 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1841 WCHAR path[MAX_PATH];
1843 GetCurrentDirectoryW(MAX_PATH,path);
1844 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1847 /* Initialise shell objects */
1848 FILEDLG95_SHELL_Init(hwnd);
1850 /* Initialize the Look In combo box */
1851 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1853 /* Browse to the initial directory */
1854 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1856 /* Free pidlItem memory */
1857 COMDLG32_SHFree(pidlItemId);
1859 return TRUE;
1861 /***********************************************************************
1862 * FILEDLG95_Clean
1864 * Regroups all the cleaning functions of the filedlg
1866 void FILEDLG95_Clean(HWND hwnd)
1868 FILEDLG95_FILETYPE_Clean(hwnd);
1869 FILEDLG95_LOOKIN_Clean(hwnd);
1870 FILEDLG95_SHELL_Clean(hwnd);
1872 /***********************************************************************
1873 * FILEDLG95_OnWMCommand
1875 * WM_COMMAND message handler
1877 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1879 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1880 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1881 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1883 switch(wID)
1885 /* OK button */
1886 case IDOK:
1887 FILEDLG95_OnOpen(hwnd);
1888 break;
1889 /* Cancel button */
1890 case IDCANCEL:
1891 FILEDLG95_Clean(hwnd);
1892 EndDialog(hwnd, FALSE);
1893 break;
1894 /* Filetype combo box */
1895 case IDC_FILETYPE:
1896 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1897 break;
1898 /* LookIn combo box */
1899 case IDC_LOOKIN:
1900 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1901 break;
1903 /* --- toolbar --- */
1904 /* Up folder button */
1905 case FCIDM_TB_UPFOLDER:
1906 FILEDLG95_SHELL_UpFolder(hwnd);
1907 break;
1908 /* New folder button */
1909 case FCIDM_TB_NEWFOLDER:
1910 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1911 break;
1912 /* List option button */
1913 case FCIDM_TB_SMALLICON:
1914 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1915 break;
1916 /* Details option button */
1917 case FCIDM_TB_REPORTVIEW:
1918 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1919 break;
1920 /* Details option button */
1921 case FCIDM_TB_DESKTOP:
1922 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1923 break;
1925 case edt1:
1926 case cmb13:
1927 break;
1930 /* Do not use the listview selection anymore */
1931 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1932 return 0;
1935 /***********************************************************************
1936 * FILEDLG95_OnWMGetIShellBrowser
1938 * WM_GETISHELLBROWSER message handler
1940 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1942 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1944 TRACE("\n");
1946 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1948 return TRUE;
1952 /***********************************************************************
1953 * FILEDLG95_SendFileOK
1955 * Sends the CDN_FILEOK notification if required
1957 * RETURNS
1958 * TRUE if the dialog should close
1959 * FALSE if the dialog should not be closed
1961 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1963 /* ask the hook if we can close */
1964 if(IsHooked(fodInfos))
1966 LRESULT retval = 0;
1968 TRACE("---\n");
1969 /* First send CDN_FILEOK as MSDN doc says */
1970 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1971 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1972 if( retval)
1974 TRACE("canceled\n");
1975 return FALSE;
1978 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1979 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1980 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1981 if( retval)
1983 TRACE("canceled\n");
1984 return FALSE;
1987 return TRUE;
1990 /***********************************************************************
1991 * FILEDLG95_OnOpenMultipleFiles
1993 * Handles the opening of multiple files.
1995 * FIXME
1996 * check destination buffer size
1998 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2000 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2001 UINT nCount, nSizePath;
2002 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2004 TRACE("\n");
2006 if(fodInfos->unicode)
2008 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2009 ofn->lpstrFile[0] = '\0';
2011 else
2013 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2014 ofn->lpstrFile[0] = '\0';
2017 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2019 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2020 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2021 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2023 LPWSTR lpstrTemp = lpstrFileList;
2025 for ( nCount = 0; nCount < nFileCount; nCount++ )
2027 LPITEMIDLIST pidl;
2029 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2030 if (!pidl)
2032 WCHAR lpstrNotFound[100];
2033 WCHAR lpstrMsg[100];
2034 WCHAR tmp[400];
2035 static const WCHAR nl[] = {'\n',0};
2037 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2038 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2040 lstrcpyW(tmp, lpstrTemp);
2041 lstrcatW(tmp, nl);
2042 lstrcatW(tmp, lpstrNotFound);
2043 lstrcatW(tmp, nl);
2044 lstrcatW(tmp, lpstrMsg);
2046 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2047 return FALSE;
2050 /* move to the next file in the list of files */
2051 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2052 COMDLG32_SHFree(pidl);
2056 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2057 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2059 /* For "oldstyle" dialog the components have to
2060 be separated by blanks (not '\0'!) and short
2061 filenames have to be used! */
2062 FIXME("Components have to be separated by blanks\n");
2064 if(fodInfos->unicode)
2066 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2067 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2068 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2070 else
2072 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2074 if (ofn->lpstrFile != NULL)
2076 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2077 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2078 if (ofn->nMaxFile > nSizePath)
2080 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2081 ofn->lpstrFile + nSizePath,
2082 ofn->nMaxFile - nSizePath, NULL, NULL);
2087 fodInfos->ofnInfos->nFileOffset = nSizePath;
2088 fodInfos->ofnInfos->nFileExtension = 0;
2090 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2091 return FALSE;
2093 /* clean and exit */
2094 FILEDLG95_Clean(hwnd);
2095 return EndDialog(hwnd,TRUE);
2098 /* Returns the 'slot name' of the given module_name in the registry's
2099 * most-recently-used list. This will be an ASCII value in the
2100 * range ['a','z'). Returns zero on error.
2102 * The slot's value in the registry has the form:
2103 * module_name\0mru_path\0
2105 * If stored_path is given, then stored_path will contain the path name
2106 * stored in the registry's MRU list for the given module_name.
2108 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2109 * MRU list key for the given module_name.
2111 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2113 WCHAR mru_list[32], *cur_mru_slot;
2114 BOOL taken[25] = {0};
2115 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2116 HKEY hkey_tmp, *hkey;
2117 LONG ret;
2119 if(hkey_ret)
2120 hkey = hkey_ret;
2121 else
2122 hkey = &hkey_tmp;
2124 if(stored_path)
2125 *stored_path = '\0';
2127 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2128 if(ret){
2129 WARN("Unable to create MRU key: %d\n", ret);
2130 return 0;
2133 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2134 (LPBYTE)mru_list, &mru_list_size);
2135 if(ret || key_type != REG_SZ){
2136 if(ret == ERROR_FILE_NOT_FOUND)
2137 return 'a';
2139 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2140 RegCloseKey(*hkey);
2141 return 0;
2144 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2145 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2146 DWORD value_data_size = sizeof(value_data);
2148 *value_name = *cur_mru_slot;
2150 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2151 &key_type, (LPBYTE)value_data, &value_data_size);
2152 if(ret || key_type != REG_BINARY){
2153 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2154 continue;
2157 if(!strcmpiW(module_name, value_data)){
2158 if(!hkey_ret)
2159 RegCloseKey(*hkey);
2160 if(stored_path)
2161 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2162 return *value_name;
2166 if(!hkey_ret)
2167 RegCloseKey(*hkey);
2169 /* the module name isn't in the registry, so find the next open slot */
2170 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2171 taken[*cur_mru_slot - 'a'] = TRUE;
2172 for(i = 0; i < 25; ++i){
2173 if(!taken[i])
2174 return i + 'a';
2177 /* all slots are taken, so return the last one in MRUList */
2178 --cur_mru_slot;
2179 return *cur_mru_slot;
2182 /* save the given filename as most-recently-used path for this module */
2183 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2185 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2186 LONG ret;
2187 HKEY hkey;
2189 /* get the current executable's name */
2190 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2191 WARN("GotModuleFileName failed: %d\n", GetLastError());
2192 return;
2194 module_name = strrchrW(module_path, '\\');
2195 if(!module_name)
2196 module_name = module_path;
2197 else
2198 module_name += 1;
2200 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2201 if(!slot)
2202 return;
2203 *slot_name = slot;
2205 { /* update the slot's info */
2206 WCHAR *path_ends, *final;
2207 DWORD path_len, final_len;
2209 /* use only the path segment of `filename' */
2210 path_ends = strrchrW(filename, '\\');
2211 path_len = path_ends - filename;
2213 final_len = path_len + lstrlenW(module_name) + 2;
2215 final = MemAlloc(final_len * sizeof(WCHAR));
2216 if(!final)
2217 return;
2218 lstrcpyW(final, module_name);
2219 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2220 final[final_len-1] = '\0';
2222 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2223 final_len * sizeof(WCHAR));
2224 if(ret){
2225 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2226 MemFree(final);
2227 RegCloseKey(hkey);
2228 return;
2231 MemFree(final);
2234 { /* update MRUList value */
2235 WCHAR old_mru_list[32], new_mru_list[32];
2236 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2237 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2239 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2240 (LPBYTE)old_mru_list, &mru_list_size);
2241 if(ret || key_type != REG_SZ){
2242 if(ret == ERROR_FILE_NOT_FOUND){
2243 new_mru_list[0] = slot;
2244 new_mru_list[1] = '\0';
2245 }else{
2246 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2247 RegCloseKey(hkey);
2248 return;
2250 }else{
2251 /* copy old list data over so that the new slot is at the start
2252 * of the list */
2253 *new_mru_slot++ = slot;
2254 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2255 if(*old_mru_slot != slot)
2256 *new_mru_slot++ = *old_mru_slot;
2258 *new_mru_slot = '\0';
2261 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2262 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2263 if(ret){
2264 WARN("Error saving MRUList data: %d\n", ret);
2265 RegCloseKey(hkey);
2266 return;
2271 /* load the most-recently-used path for this module */
2272 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2274 WCHAR module_path[MAX_PATH], *module_name;
2276 /* get the current executable's name */
2277 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2278 WARN("GotModuleFileName failed: %d\n", GetLastError());
2279 return;
2281 module_name = strrchrW(module_path, '\\');
2282 if(!module_name)
2283 module_name = module_path;
2284 else
2285 module_name += 1;
2287 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2288 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2291 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2293 WCHAR strMsgTitle[MAX_PATH];
2294 WCHAR strMsgText [MAX_PATH];
2295 if (idCaption)
2296 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2297 else
2298 strMsgTitle[0] = '\0';
2299 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2300 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2303 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2304 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2306 int nOpenAction = defAction;
2307 LPWSTR lpszTemp, lpszTemp1;
2308 LPITEMIDLIST pidl = NULL;
2309 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2311 /* check for invalid chars */
2312 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2314 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2315 return FALSE;
2318 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2320 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2321 while (lpszTemp1)
2323 LPSHELLFOLDER lpsfChild;
2324 WCHAR lpwstrTemp[MAX_PATH];
2325 DWORD dwEaten, dwAttributes;
2326 LPWSTR p;
2328 lstrcpyW(lpwstrTemp, lpszTemp);
2329 p = PathFindNextComponentW(lpwstrTemp);
2331 if (!p) break; /* end of path */
2333 *p = 0;
2334 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2336 /* There are no wildcards when OFN_NOVALIDATE is set */
2337 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2339 static const WCHAR wszWild[] = { '*', '?', 0 };
2340 /* if the last element is a wildcard do a search */
2341 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2343 nOpenAction = ONOPEN_SEARCH;
2344 break;
2347 lpszTemp1 = lpszTemp;
2349 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2351 /* append a backslash to drive letters */
2352 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2353 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2354 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2356 PathAddBackslashW(lpwstrTemp);
2359 dwAttributes = SFGAO_FOLDER;
2360 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2362 /* the path component is valid, we have a pidl of the next path component */
2363 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2364 if(dwAttributes & SFGAO_FOLDER)
2366 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2368 ERR("bind to failed\n"); /* should not fail */
2369 break;
2371 IShellFolder_Release(*ppsf);
2372 *ppsf = lpsfChild;
2373 lpsfChild = NULL;
2375 else
2377 TRACE("value\n");
2379 /* end dialog, return value */
2380 nOpenAction = ONOPEN_OPEN;
2381 break;
2383 COMDLG32_SHFree(pidl);
2384 pidl = NULL;
2386 else if (!(flags & OFN_NOVALIDATE))
2388 if(*lpszTemp || /* points to trailing null for last path element */
2389 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2391 if(flags & OFN_PATHMUSTEXIST)
2393 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2394 break;
2397 else
2399 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2401 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2402 break;
2405 /* change to the current folder */
2406 nOpenAction = ONOPEN_OPEN;
2407 break;
2409 else
2411 nOpenAction = ONOPEN_OPEN;
2412 break;
2415 if(pidl) COMDLG32_SHFree(pidl);
2417 return nOpenAction;
2420 /***********************************************************************
2421 * FILEDLG95_OnOpen
2423 * Ok button WM_COMMAND message handler
2425 * If the function succeeds, the return value is nonzero.
2427 BOOL FILEDLG95_OnOpen(HWND hwnd)
2429 LPWSTR lpstrFileList;
2430 UINT nFileCount = 0;
2431 UINT sizeUsed = 0;
2432 BOOL ret = TRUE;
2433 WCHAR lpstrPathAndFile[MAX_PATH];
2434 LPSHELLFOLDER lpsf = NULL;
2435 int nOpenAction;
2436 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2438 TRACE("hwnd=%p\n", hwnd);
2440 /* try to browse the selected item */
2441 if(BrowseSelectedFolder(hwnd))
2442 return FALSE;
2444 /* get the files from the edit control */
2445 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2447 if(nFileCount == 0)
2448 return FALSE;
2450 if(nFileCount > 1)
2452 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2453 goto ret;
2456 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2459 Step 1: Build a complete path name from the current folder and
2460 the filename or path in the edit box.
2461 Special cases:
2462 - the path in the edit box is a root path
2463 (with or without drive letter)
2464 - the edit box contains ".." (or a path with ".." in it)
2467 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2468 MemFree(lpstrFileList);
2471 Step 2: here we have a cleaned up path
2473 We have to parse the path step by step to see if we have to browse
2474 to a folder if the path points to a directory or the last
2475 valid element is a directory.
2477 valid variables:
2478 lpstrPathAndFile: cleaned up path
2481 if (nFileCount &&
2482 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2483 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2484 nOpenAction = ONOPEN_OPEN;
2485 else
2486 nOpenAction = ONOPEN_BROWSE;
2488 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2489 fodInfos->ofnInfos->Flags,
2490 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2491 nOpenAction);
2492 if(!nOpenAction)
2493 goto ret;
2496 Step 3: here we have a cleaned up and validated path
2498 valid variables:
2499 lpsf: ShellFolder bound to the rightmost valid path component
2500 lpstrPathAndFile: cleaned up path
2501 nOpenAction: action to do
2503 TRACE("end validate sf=%p\n", lpsf);
2505 switch(nOpenAction)
2507 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2508 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2510 int iPos;
2511 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2512 DWORD len;
2514 /* replace the current filter */
2515 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2516 len = lstrlenW(lpszTemp)+1;
2517 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2518 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2520 /* set the filter cb to the extension when possible */
2521 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2522 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2524 /* fall through */
2525 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2526 TRACE("ONOPEN_BROWSE\n");
2528 IPersistFolder2 * ppf2;
2529 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2531 LPITEMIDLIST pidlCurrent;
2532 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2533 IPersistFolder2_Release(ppf2);
2534 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2536 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2537 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2539 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2542 else if( nOpenAction == ONOPEN_SEARCH )
2544 if (fodInfos->Shell.FOIShellView)
2545 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2547 COMDLG32_SHFree(pidlCurrent);
2548 if (filename_is_edit( fodInfos ))
2549 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2552 ret = FALSE;
2553 break;
2554 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2555 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2557 WCHAR *ext = NULL;
2559 /* update READONLY check box flag */
2560 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2561 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2562 else
2563 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2565 /* Attach the file extension with file name*/
2566 ext = PathFindExtensionW(lpstrPathAndFile);
2567 if (! *ext && fodInfos->defext)
2569 /* if no extension is specified with file name, then */
2570 /* attach the extension from file filter or default one */
2572 WCHAR *filterExt = NULL;
2573 LPWSTR lpstrFilter = NULL;
2574 static const WCHAR szwDot[] = {'.',0};
2575 int PathLength = lstrlenW(lpstrPathAndFile);
2577 /*Get the file extension from file type filter*/
2578 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2579 fodInfos->ofnInfos->nFilterIndex-1);
2581 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2583 WCHAR* filterSearchIndex;
2584 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2585 strcpyW(filterExt, lpstrFilter);
2587 /* if a semicolon-separated list of file extensions was given, do not include the
2588 semicolon or anything after it in the extension.
2589 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2590 filterSearchIndex = strchrW(filterExt, ';');
2591 if (filterSearchIndex)
2593 filterSearchIndex[0] = '\0';
2596 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2597 /* if the extension is invalid or contains a glob, ignore it */
2598 filterSearchIndex = PathFindExtensionW(filterExt);
2599 if (*filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2601 strcpyW(filterExt, filterSearchIndex);
2603 else
2605 HeapFree(GetProcessHeap(), 0, filterExt);
2606 filterExt = NULL;
2610 if (!filterExt)
2612 /* use the default file extension */
2613 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2614 strcpyW(filterExt, fodInfos->defext);
2617 if (*filterExt) /* ignore filterExt="" */
2619 /* Attach the dot*/
2620 lstrcatW(lpstrPathAndFile, szwDot);
2621 /* Attach the extension */
2622 lstrcatW(lpstrPathAndFile, filterExt);
2625 HeapFree(GetProcessHeap(), 0, filterExt);
2627 /* In Open dialog: if file does not exist try without extension */
2628 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2629 lpstrPathAndFile[PathLength] = '\0';
2631 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2632 if (*ext)
2633 ext++;
2634 if (!lstrcmpiW(fodInfos->defext, ext))
2635 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2636 else
2637 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2640 /* In Save dialog: check if the file already exists */
2641 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2642 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2643 && PathFileExistsW(lpstrPathAndFile))
2645 WCHAR lpstrOverwrite[100];
2646 int answer;
2648 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2649 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2650 MB_YESNO | MB_ICONEXCLAMATION);
2651 if (answer == IDNO || answer == IDCANCEL)
2653 ret = FALSE;
2654 goto ret;
2658 /* In Open dialog: check if it should be created if it doesn't exist */
2659 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2660 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2661 && !PathFileExistsW(lpstrPathAndFile))
2663 WCHAR lpstrCreate[100];
2664 int answer;
2666 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2667 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2668 MB_YESNO | MB_ICONEXCLAMATION);
2669 if (answer == IDNO || answer == IDCANCEL)
2671 ret = FALSE;
2672 goto ret;
2676 /* Check that the size of the file does not exceed buffer size.
2677 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2678 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2679 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2682 /* fill destination buffer */
2683 if (fodInfos->ofnInfos->lpstrFile)
2685 if(fodInfos->unicode)
2687 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2689 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2690 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2691 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2693 else
2695 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2697 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2698 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2699 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2700 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2704 if(fodInfos->unicode)
2706 LPWSTR lpszTemp;
2708 /* set filename offset */
2709 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2710 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2712 /* set extension offset */
2713 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2714 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2716 else
2718 LPSTR lpszTemp;
2719 CHAR tempFileA[MAX_PATH];
2721 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2722 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2723 tempFileA, sizeof(tempFileA), NULL, NULL);
2725 /* set filename offset */
2726 lpszTemp = PathFindFileNameA(tempFileA);
2727 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2729 /* set extension offset */
2730 lpszTemp = PathFindExtensionA(tempFileA);
2731 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2734 /* set the lpstrFileTitle */
2735 if(fodInfos->ofnInfos->lpstrFileTitle)
2737 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2738 if(fodInfos->unicode)
2740 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2741 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2743 else
2745 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2746 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2747 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2751 /* copy currently selected filter to lpstrCustomFilter */
2752 if (fodInfos->ofnInfos->lpstrCustomFilter)
2754 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2755 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2756 NULL, 0, NULL, NULL);
2757 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2759 LPSTR s = ofn->lpstrCustomFilter;
2760 s += strlen(ofn->lpstrCustomFilter)+1;
2761 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2762 s, len, NULL, NULL);
2767 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2768 goto ret;
2770 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2772 TRACE("close\n");
2773 FILEDLG95_Clean(hwnd);
2774 ret = EndDialog(hwnd, TRUE);
2776 else
2778 WORD size;
2780 size = lstrlenW(lpstrPathAndFile) + 1;
2781 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2782 size += 1;
2783 /* return needed size in first two bytes of lpstrFile */
2784 if(fodInfos->ofnInfos->lpstrFile)
2785 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2786 FILEDLG95_Clean(hwnd);
2787 ret = EndDialog(hwnd, FALSE);
2788 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2791 break;
2794 ret:
2795 if(lpsf) IShellFolder_Release(lpsf);
2796 return ret;
2799 /***********************************************************************
2800 * FILEDLG95_SHELL_Init
2802 * Initialisation of the shell objects
2804 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2806 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2808 TRACE("\n");
2811 * Initialisation of the FileOpenDialogInfos structure
2814 /* Shell */
2816 /*ShellInfos */
2817 fodInfos->ShellInfos.hwndOwner = hwnd;
2819 /* Disable multi-select if flag not set */
2820 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2822 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2824 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2825 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2827 /* Construct the IShellBrowser interface */
2828 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2830 return NOERROR;
2833 /***********************************************************************
2834 * FILEDLG95_SHELL_ExecuteCommand
2836 * Change the folder option and refresh the view
2837 * If the function succeeds, the return value is nonzero.
2839 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2841 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2842 IContextMenu * pcm;
2844 TRACE("(%p,%p)\n", hwnd, lpVerb);
2846 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2847 SVGIO_BACKGROUND,
2848 &IID_IContextMenu,
2849 (LPVOID*)&pcm)))
2851 CMINVOKECOMMANDINFO ci;
2852 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2853 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2854 ci.lpVerb = lpVerb;
2855 ci.hwnd = hwnd;
2857 IContextMenu_InvokeCommand(pcm, &ci);
2858 IContextMenu_Release(pcm);
2861 return FALSE;
2864 /***********************************************************************
2865 * FILEDLG95_SHELL_UpFolder
2867 * Browse to the specified object
2868 * If the function succeeds, the return value is nonzero.
2870 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2872 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2874 TRACE("\n");
2876 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2877 NULL,
2878 SBSP_PARENT)))
2880 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2881 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2882 return TRUE;
2884 return FALSE;
2887 /***********************************************************************
2888 * FILEDLG95_SHELL_BrowseToDesktop
2890 * Browse to the Desktop
2891 * If the function succeeds, the return value is nonzero.
2893 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2895 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2896 LPITEMIDLIST pidl;
2897 HRESULT hres;
2899 TRACE("\n");
2901 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2902 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2903 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2904 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2905 COMDLG32_SHFree(pidl);
2906 return SUCCEEDED(hres);
2908 /***********************************************************************
2909 * FILEDLG95_SHELL_Clean
2911 * Cleans the memory used by shell objects
2913 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2915 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2917 TRACE("\n");
2919 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2921 /* clean Shell interfaces */
2922 if (fodInfos->Shell.FOIShellView)
2924 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2925 IShellView_Release(fodInfos->Shell.FOIShellView);
2927 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2928 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2929 if (fodInfos->Shell.FOIDataObject)
2930 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2933 /***********************************************************************
2934 * FILEDLG95_FILETYPE_Init
2936 * Initialisation of the file type combo box
2938 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2940 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2941 int nFilters = 0; /* number of filters */
2942 int nFilterIndexCB;
2944 TRACE("\n");
2946 if(fodInfos->customfilter)
2948 /* customfilter has one entry... title\0ext\0
2949 * Set first entry of combo box item with customfilter
2951 LPWSTR lpstrExt;
2952 LPCWSTR lpstrPos = fodInfos->customfilter;
2954 /* Get the title */
2955 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2957 /* Copy the extensions */
2958 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2959 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2960 lstrcpyW(lpstrExt,lpstrPos);
2962 /* Add the item at the end of the combo */
2963 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2964 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2965 nFilters++;
2967 if(fodInfos->filter)
2969 LPCWSTR lpstrPos = fodInfos->filter;
2971 for(;;)
2973 /* filter is a list... title\0ext\0......\0\0
2974 * Set the combo item text to the title and the item data
2975 * to the ext
2977 LPCWSTR lpstrDisplay;
2978 LPWSTR lpstrExt;
2980 /* Get the title */
2981 if(! *lpstrPos) break; /* end */
2982 lpstrDisplay = lpstrPos;
2983 lpstrPos += lstrlenW(lpstrPos) + 1;
2985 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2987 nFilters++;
2989 /* Copy the extensions */
2990 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2991 lstrcpyW(lpstrExt,lpstrPos);
2992 lpstrPos += lstrlenW(lpstrPos) + 1;
2994 /* Add the item at the end of the combo */
2995 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2997 /* malformed filters are added anyway... */
2998 if (!*lpstrExt) break;
3003 * Set the current filter to the one specified
3004 * in the initialisation structure
3006 if (fodInfos->filter || fodInfos->customfilter)
3008 LPWSTR lpstrFilter;
3010 /* Check to make sure our index isn't out of bounds. */
3011 if ( fodInfos->ofnInfos->nFilterIndex >
3012 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3013 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3015 /* set default filter index */
3016 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3017 fodInfos->ofnInfos->nFilterIndex = 1;
3019 /* calculate index of Combo Box item */
3020 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3021 if (fodInfos->customfilter == NULL)
3022 nFilterIndexCB--;
3024 /* Set the current index selection. */
3025 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3027 /* Get the corresponding text string from the combo box. */
3028 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3029 nFilterIndexCB);
3031 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3032 lpstrFilter = NULL;
3034 if(lpstrFilter)
3036 DWORD len;
3037 CharLowerW(lpstrFilter); /* lowercase */
3038 len = lstrlenW(lpstrFilter)+1;
3039 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3040 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3042 } else
3043 fodInfos->ofnInfos->nFilterIndex = 0;
3044 return S_OK;
3047 /***********************************************************************
3048 * FILEDLG95_FILETYPE_OnCommand
3050 * WM_COMMAND of the file type combo box
3051 * If the function succeeds, the return value is nonzero.
3053 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3055 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3057 switch(wNotifyCode)
3059 case CBN_SELENDOK:
3061 LPWSTR lpstrFilter;
3063 /* Get the current item of the filetype combo box */
3064 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3066 /* set the current filter index */
3067 fodInfos->ofnInfos->nFilterIndex = iItem +
3068 (fodInfos->customfilter == NULL ? 1 : 0);
3070 /* Set the current filter with the current selection */
3071 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3073 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3074 iItem);
3075 if((INT_PTR)lpstrFilter != CB_ERR)
3077 DWORD len;
3078 CharLowerW(lpstrFilter); /* lowercase */
3079 len = lstrlenW(lpstrFilter)+1;
3080 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3081 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3082 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3083 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3086 /* Refresh the actual view to display the included items*/
3087 if (fodInfos->Shell.FOIShellView)
3088 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3091 return FALSE;
3093 /***********************************************************************
3094 * FILEDLG95_FILETYPE_SearchExt
3096 * searches for an extension in the filetype box
3098 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3100 int i, iCount = CBGetCount(hwnd);
3102 TRACE("%s\n", debugstr_w(lpstrExt));
3104 if(iCount != CB_ERR)
3106 for(i=0;i<iCount;i++)
3108 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3109 return i;
3112 return -1;
3115 /***********************************************************************
3116 * FILEDLG95_FILETYPE_Clean
3118 * Clean the memory used by the filetype combo box
3120 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3122 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3123 int iPos;
3124 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3126 TRACE("\n");
3128 /* Delete each string of the combo and their associated data */
3129 if(iCount != CB_ERR)
3131 for(iPos = iCount-1;iPos>=0;iPos--)
3133 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3134 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3137 /* Current filter */
3138 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3142 /***********************************************************************
3143 * FILEDLG95_LOOKIN_Init
3145 * Initialisation of the look in combo box
3148 /* Small helper function, to determine if the unixfs shell extension is rooted
3149 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3151 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3152 HKEY hKey;
3153 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3154 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3156 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3157 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3158 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3159 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3161 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3162 return FALSE;
3164 RegCloseKey(hKey);
3165 return TRUE;
3168 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3170 IShellFolder *psfRoot, *psfDrives;
3171 IEnumIDList *lpeRoot, *lpeDrives;
3172 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3174 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3176 TRACE("\n");
3178 liInfos->iMaxIndentation = 0;
3180 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3182 /* set item height for both text field and listbox */
3183 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3184 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3186 /* Turn on the extended UI for the combo box like Windows does */
3187 CBSetExtendedUI(hwndCombo, TRUE);
3189 /* Initialise data of Desktop folder */
3190 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3191 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3192 COMDLG32_SHFree(pidlTmp);
3194 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3196 SHGetDesktopFolder(&psfRoot);
3198 if (psfRoot)
3200 /* enumerate the contents of the desktop */
3201 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3203 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3205 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3207 /* If the unixfs extension is rooted, we don't expand the drives by default */
3208 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3210 /* special handling for CSIDL_DRIVES */
3211 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3213 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3215 /* enumerate the drives */
3216 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3218 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3220 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3221 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3222 COMDLG32_SHFree(pidlAbsTmp);
3223 COMDLG32_SHFree(pidlTmp1);
3225 IEnumIDList_Release(lpeDrives);
3227 IShellFolder_Release(psfDrives);
3232 COMDLG32_SHFree(pidlTmp);
3234 IEnumIDList_Release(lpeRoot);
3236 IShellFolder_Release(psfRoot);
3239 COMDLG32_SHFree(pidlDrives);
3242 /***********************************************************************
3243 * FILEDLG95_LOOKIN_DrawItem
3245 * WM_DRAWITEM message handler
3247 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3249 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3250 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3251 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3252 RECT rectText;
3253 RECT rectIcon;
3254 SHFILEINFOW sfi;
3255 HIMAGELIST ilItemImage;
3256 int iIndentation;
3257 TEXTMETRICW tm;
3258 LPSFOLDER tmpFolder;
3259 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3261 TRACE("\n");
3263 if(pDIStruct->itemID == -1)
3264 return 0;
3266 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3267 pDIStruct->itemID)))
3268 return 0;
3271 if(pDIStruct->itemID == liInfos->uSelectedItem)
3273 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3275 &sfi,
3276 sizeof (sfi),
3277 SHGFI_PIDL | SHGFI_SMALLICON |
3278 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3279 SHGFI_DISPLAYNAME );
3281 else
3283 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3285 &sfi,
3286 sizeof (sfi),
3287 SHGFI_PIDL | SHGFI_SMALLICON |
3288 SHGFI_SYSICONINDEX |
3289 SHGFI_DISPLAYNAME);
3292 /* Is this item selected ? */
3293 if(pDIStruct->itemState & ODS_SELECTED)
3295 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3296 SetBkColor(pDIStruct->hDC,crHighLight);
3297 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3299 else
3301 SetTextColor(pDIStruct->hDC,crText);
3302 SetBkColor(pDIStruct->hDC,crWin);
3303 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3306 /* Do not indent item if drawing in the edit of the combo */
3307 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3309 iIndentation = 0;
3310 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3312 &sfi,
3313 sizeof (sfi),
3314 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3315 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3318 else
3320 iIndentation = tmpFolder->m_iIndent;
3322 /* Draw text and icon */
3324 /* Initialise the icon display area */
3325 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3326 rectIcon.top = pDIStruct->rcItem.top;
3327 rectIcon.right = rectIcon.left + ICONWIDTH;
3328 rectIcon.bottom = pDIStruct->rcItem.bottom;
3330 /* Initialise the text display area */
3331 GetTextMetricsW(pDIStruct->hDC, &tm);
3332 rectText.left = rectIcon.right;
3333 rectText.top =
3334 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3335 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3336 rectText.bottom =
3337 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3339 /* Draw the icon from the image list */
3340 ImageList_Draw(ilItemImage,
3341 sfi.iIcon,
3342 pDIStruct->hDC,
3343 rectIcon.left,
3344 rectIcon.top,
3345 ILD_TRANSPARENT );
3347 /* Draw the associated text */
3348 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3349 return NOERROR;
3352 /***********************************************************************
3353 * FILEDLG95_LOOKIN_OnCommand
3355 * LookIn combo box WM_COMMAND message handler
3356 * If the function succeeds, the return value is nonzero.
3358 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3360 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3362 TRACE("%p\n", fodInfos);
3364 switch(wNotifyCode)
3366 case CBN_SELENDOK:
3368 LPSFOLDER tmpFolder;
3369 int iItem;
3371 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3373 if( iItem == CB_ERR) return FALSE;
3375 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3376 iItem)))
3377 return FALSE;
3380 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3381 tmpFolder->pidlItem,
3382 SBSP_ABSOLUTE)))
3384 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3385 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3386 return TRUE;
3388 break;
3392 return FALSE;
3395 /***********************************************************************
3396 * FILEDLG95_LOOKIN_AddItem
3398 * Adds an absolute pidl item to the lookin combo box
3399 * returns the index of the inserted item
3401 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3403 LPITEMIDLIST pidlNext;
3404 SHFILEINFOW sfi;
3405 SFOLDER *tmpFolder;
3406 LookInInfos *liInfos;
3408 TRACE("%08x\n", iInsertId);
3410 if(!pidl)
3411 return -1;
3413 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3414 return -1;
3416 tmpFolder = MemAlloc(sizeof(SFOLDER));
3417 tmpFolder->m_iIndent = 0;
3419 /* Calculate the indentation of the item in the lookin*/
3420 pidlNext = pidl;
3421 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3423 tmpFolder->m_iIndent++;
3426 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3428 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3429 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3431 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3432 SHGetFileInfoW((LPCWSTR)pidl,
3434 &sfi,
3435 sizeof(sfi),
3436 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3437 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3439 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3441 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3443 int iItemID;
3445 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3447 /* Add the item at the end of the list */
3448 if(iInsertId < 0)
3450 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3452 /* Insert the item at the iInsertId position*/
3453 else
3455 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3458 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3459 return iItemID;
3462 COMDLG32_SHFree( tmpFolder->pidlItem );
3463 MemFree( tmpFolder );
3464 return -1;
3468 /***********************************************************************
3469 * FILEDLG95_LOOKIN_InsertItemAfterParent
3471 * Insert an item below its parent
3473 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3476 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3477 int iParentPos;
3479 TRACE("\n");
3481 if (pidl == pidlParent)
3482 return -1;
3484 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3486 if(iParentPos < 0)
3488 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3491 /* Free pidlParent memory */
3492 COMDLG32_SHFree(pidlParent);
3494 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3497 /***********************************************************************
3498 * FILEDLG95_LOOKIN_SelectItem
3500 * Adds an absolute pidl item to the lookin combo box
3501 * returns the index of the inserted item
3503 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3505 int iItemPos;
3506 LookInInfos *liInfos;
3508 TRACE("\n");
3510 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3512 liInfos = GetPropA(hwnd,LookInInfosStr);
3514 if(iItemPos < 0)
3516 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3517 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3520 else
3522 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3523 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3525 int iRemovedItem;
3527 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3528 break;
3529 if(iRemovedItem < iItemPos)
3530 iItemPos--;
3534 CBSetCurSel(hwnd,iItemPos);
3535 liInfos->uSelectedItem = iItemPos;
3537 return 0;
3541 /***********************************************************************
3542 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3544 * Remove the item with an expansion level over iExpansionLevel
3546 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3548 int iItemPos;
3549 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3551 TRACE("\n");
3553 if(liInfos->iMaxIndentation <= 2)
3554 return -1;
3556 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3558 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3559 COMDLG32_SHFree(tmpFolder->pidlItem);
3560 MemFree(tmpFolder);
3561 CBDeleteString(hwnd,iItemPos);
3562 liInfos->iMaxIndentation--;
3564 return iItemPos;
3567 return -1;
3570 /***********************************************************************
3571 * FILEDLG95_LOOKIN_SearchItem
3573 * Search for pidl in the lookin combo box
3574 * returns the index of the found item
3576 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3578 int i = 0;
3579 int iCount = CBGetCount(hwnd);
3581 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3583 if (iCount != CB_ERR)
3585 for(;i<iCount;i++)
3587 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3589 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3590 return i;
3591 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3592 return i;
3596 return -1;
3599 /***********************************************************************
3600 * FILEDLG95_LOOKIN_Clean
3602 * Clean the memory used by the lookin combo box
3604 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3606 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3607 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3608 int iPos;
3609 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3611 TRACE("\n");
3613 /* Delete each string of the combo and their associated data */
3614 if (iCount != CB_ERR)
3616 for(iPos = iCount-1;iPos>=0;iPos--)
3618 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3619 COMDLG32_SHFree(tmpFolder->pidlItem);
3620 MemFree(tmpFolder);
3621 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3625 /* LookInInfos structure */
3626 MemFree(liInfos);
3627 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3630 /***********************************************************************
3631 * FILEDLG95_FILENAME_FillFromSelection
3633 * fills the edit box from the cached DataObject
3635 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3637 FileOpenDlgInfos *fodInfos;
3638 LPITEMIDLIST pidl;
3639 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3640 WCHAR lpstrTemp[MAX_PATH];
3641 LPWSTR lpstrAllFile, lpstrCurrFile;
3643 TRACE("\n");
3644 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3646 /* Count how many files we have */
3647 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3649 /* calculate the string length, count files */
3650 if (nFileSelected >= 1)
3652 nLength += 3; /* first and last quotes, trailing \0 */
3653 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3655 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3657 if (pidl)
3659 /* get the total length of the selected file names */
3660 lpstrTemp[0] = '\0';
3661 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3663 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3665 nLength += lstrlenW( lpstrTemp ) + 3;
3666 nFiles++;
3668 COMDLG32_SHFree( pidl );
3673 /* allocate the buffer */
3674 if (nFiles <= 1) nLength = MAX_PATH;
3675 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3677 /* Generate the string for the edit control */
3678 if(nFiles >= 1)
3680 lpstrCurrFile = lpstrAllFile;
3681 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3683 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3685 if (pidl)
3687 /* get the file name */
3688 lpstrTemp[0] = '\0';
3689 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3691 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3693 if ( nFiles > 1)
3695 *lpstrCurrFile++ = '\"';
3696 lstrcpyW( lpstrCurrFile, lpstrTemp );
3697 lpstrCurrFile += lstrlenW( lpstrTemp );
3698 *lpstrCurrFile++ = '\"';
3699 *lpstrCurrFile++ = ' ';
3700 *lpstrCurrFile = 0;
3702 else
3704 lstrcpyW( lpstrAllFile, lpstrTemp );
3707 COMDLG32_SHFree( pidl );
3710 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3712 /* Select the file name like Windows does */
3713 if (filename_is_edit( fodInfos ))
3714 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3716 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3720 /* copied from shell32 to avoid linking to it
3721 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3722 * is dependent on whether emulated OS is unicode or not.
3724 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3726 switch (src->uType)
3728 case STRRET_WSTR:
3729 lstrcpynW(dest, src->u.pOleStr, len);
3730 COMDLG32_SHFree(src->u.pOleStr);
3731 break;
3733 case STRRET_CSTR:
3734 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3735 dest[len-1] = 0;
3736 break;
3738 case STRRET_OFFSET:
3739 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3740 dest[len-1] = 0;
3741 break;
3743 default:
3744 FIXME("unknown type %x!\n", src->uType);
3745 if (len) *dest = '\0';
3746 return E_FAIL;
3748 return S_OK;
3751 /***********************************************************************
3752 * FILEDLG95_FILENAME_GetFileNames
3754 * Copies the filenames to a delimited string list.
3756 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3758 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3759 UINT nFileCount = 0; /* number of files */
3760 UINT nStrLen = 0; /* length of string in edit control */
3761 LPWSTR lpstrEdit; /* buffer for string from edit control */
3763 TRACE("\n");
3765 /* get the filenames from the filename control */
3766 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3767 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3768 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3770 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3772 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3773 MemFree(lpstrEdit);
3774 return nFileCount;
3777 #define SETDefFormatEtc(fe,cf,med) \
3779 (fe).cfFormat = cf;\
3780 (fe).dwAspect = DVASPECT_CONTENT; \
3781 (fe).ptd =NULL;\
3782 (fe).tymed = med;\
3783 (fe).lindex = -1;\
3787 * DATAOBJECT Helper functions
3790 /***********************************************************************
3791 * COMCTL32_ReleaseStgMedium
3793 * like ReleaseStgMedium from ole32
3795 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3797 if(medium.pUnkForRelease)
3799 IUnknown_Release(medium.pUnkForRelease);
3801 else
3803 GlobalUnlock(medium.u.hGlobal);
3804 GlobalFree(medium.u.hGlobal);
3808 /***********************************************************************
3809 * GetPidlFromDataObject
3811 * Return pidl(s) by number from the cached DataObject
3813 * nPidlIndex=0 gets the fully qualified root path
3815 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3818 STGMEDIUM medium;
3819 FORMATETC formatetc;
3820 LPITEMIDLIST pidl = NULL;
3822 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3824 if (!doSelected)
3825 return NULL;
3827 /* Set the FORMATETC structure*/
3828 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3830 /* Get the pidls from IDataObject */
3831 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3833 LPIDA cida = GlobalLock(medium.u.hGlobal);
3834 if(nPidlIndex <= cida->cidl)
3836 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3838 COMCTL32_ReleaseStgMedium(medium);
3840 return pidl;
3843 /***********************************************************************
3844 * GetNumSelected
3846 * Return the number of selected items in the DataObject.
3849 static UINT GetNumSelected( IDataObject *doSelected )
3851 UINT retVal = 0;
3852 STGMEDIUM medium;
3853 FORMATETC formatetc;
3855 TRACE("sv=%p\n", doSelected);
3857 if (!doSelected) return 0;
3859 /* Set the FORMATETC structure*/
3860 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3862 /* Get the pidls from IDataObject */
3863 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3865 LPIDA cida = GlobalLock(medium.u.hGlobal);
3866 retVal = cida->cidl;
3867 COMCTL32_ReleaseStgMedium(medium);
3868 return retVal;
3870 return 0;
3874 * TOOLS
3877 /***********************************************************************
3878 * GetName
3880 * Get the pidl's display name (relative to folder) and
3881 * put it in lpstrFileName.
3883 * Return NOERROR on success,
3884 * E_FAIL otherwise
3887 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3889 STRRET str;
3890 HRESULT hRes;
3892 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3894 if(!lpsf)
3896 SHGetDesktopFolder(&lpsf);
3897 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3898 IShellFolder_Release(lpsf);
3899 return hRes;
3902 /* Get the display name of the pidl relative to the folder */
3903 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3905 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3907 return E_FAIL;
3910 /***********************************************************************
3911 * GetShellFolderFromPidl
3913 * pidlRel is the item pidl relative
3914 * Return the IShellFolder of the absolute pidl
3916 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3918 IShellFolder *psf = NULL,*psfParent;
3920 TRACE("%p\n", pidlAbs);
3922 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3924 psf = psfParent;
3925 if(pidlAbs && pidlAbs->mkid.cb)
3927 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3929 IShellFolder_Release(psfParent);
3930 return psf;
3933 /* return the desktop */
3934 return psfParent;
3936 return NULL;
3939 /***********************************************************************
3940 * GetParentPidl
3942 * Return the LPITEMIDLIST to the parent of the pidl in the list
3944 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3946 LPITEMIDLIST pidlParent;
3948 TRACE("%p\n", pidl);
3950 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3951 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3953 return pidlParent;
3956 /***********************************************************************
3957 * GetPidlFromName
3959 * returns the pidl of the file name relative to folder
3960 * NULL if an error occurred
3962 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3964 LPITEMIDLIST pidl = NULL;
3965 ULONG ulEaten;
3967 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3969 if(!lpcstrFileName) return NULL;
3970 if(!*lpcstrFileName) return NULL;
3972 if(!lpsf)
3974 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3975 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3976 IShellFolder_Release(lpsf);
3979 else
3981 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3983 return pidl;
3988 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3990 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3991 HRESULT ret;
3993 TRACE("%p, %p\n", psf, pidl);
3995 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3997 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3998 /* see documentation shell 4.1*/
3999 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4002 /***********************************************************************
4003 * BrowseSelectedFolder
4005 static BOOL BrowseSelectedFolder(HWND hwnd)
4007 BOOL bBrowseSelFolder = FALSE;
4008 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4010 TRACE("\n");
4012 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4014 LPITEMIDLIST pidlSelection;
4016 /* get the file selected */
4017 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4018 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4020 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4021 pidlSelection, SBSP_RELATIVE ) ) )
4023 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4024 ' ','n','o','t',' ','e','x','i','s','t',0};
4025 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4027 bBrowseSelFolder = TRUE;
4028 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4029 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4031 COMDLG32_SHFree( pidlSelection );
4034 return bBrowseSelFolder;
4038 * Memory allocation methods */
4039 static void *MemAlloc(UINT size)
4041 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4044 static void MemFree(void *mem)
4046 HeapFree(GetProcessHeap(),0,mem);
4049 static inline BOOL valid_struct_size( DWORD size )
4051 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4052 (size == sizeof( OPENFILENAMEW ));
4055 static inline BOOL is_win16_looks(DWORD flags)
4057 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4058 !(flags & OFN_EXPLORER));
4061 /* ------------------ APIs ---------------------- */
4063 /***********************************************************************
4064 * GetOpenFileNameA (COMDLG32.@)
4066 * Creates a dialog box for the user to select a file to open.
4068 * RETURNS
4069 * TRUE on success: user enters a valid file
4070 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4073 BOOL WINAPI GetOpenFileNameA(
4074 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4076 TRACE("flags %08x\n", ofn->Flags);
4078 if (!valid_struct_size( ofn->lStructSize ))
4080 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4081 return FALSE;
4084 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4085 if (ofn->Flags & OFN_FILEMUSTEXIST)
4086 ofn->Flags |= OFN_PATHMUSTEXIST;
4088 if (is_win16_looks(ofn->Flags))
4089 return GetFileName31A(ofn, OPEN_DIALOG);
4090 else
4091 return GetFileDialog95A(ofn, OPEN_DIALOG);
4094 /***********************************************************************
4095 * GetOpenFileNameW (COMDLG32.@)
4097 * Creates a dialog box for the user to select a file to open.
4099 * RETURNS
4100 * TRUE on success: user enters a valid file
4101 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4104 BOOL WINAPI GetOpenFileNameW(
4105 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4107 TRACE("flags %08x\n", ofn->Flags);
4109 if (!valid_struct_size( ofn->lStructSize ))
4111 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4112 return FALSE;
4115 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4116 if (ofn->Flags & OFN_FILEMUSTEXIST)
4117 ofn->Flags |= OFN_PATHMUSTEXIST;
4119 if (is_win16_looks(ofn->Flags))
4120 return GetFileName31W(ofn, OPEN_DIALOG);
4121 else
4122 return GetFileDialog95W(ofn, OPEN_DIALOG);
4126 /***********************************************************************
4127 * GetSaveFileNameA (COMDLG32.@)
4129 * Creates a dialog box for the user to select a file to save.
4131 * RETURNS
4132 * TRUE on success: user enters a valid file
4133 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4136 BOOL WINAPI GetSaveFileNameA(
4137 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4139 if (!valid_struct_size( ofn->lStructSize ))
4141 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4142 return FALSE;
4145 if (is_win16_looks(ofn->Flags))
4146 return GetFileName31A(ofn, SAVE_DIALOG);
4147 else
4148 return GetFileDialog95A(ofn, SAVE_DIALOG);
4151 /***********************************************************************
4152 * GetSaveFileNameW (COMDLG32.@)
4154 * Creates a dialog box for the user to select a file to save.
4156 * RETURNS
4157 * TRUE on success: user enters a valid file
4158 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4161 BOOL WINAPI GetSaveFileNameW(
4162 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4164 if (!valid_struct_size( ofn->lStructSize ))
4166 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4167 return FALSE;
4170 if (is_win16_looks(ofn->Flags))
4171 return GetFileName31W(ofn, SAVE_DIALOG);
4172 else
4173 return GetFileDialog95W(ofn, SAVE_DIALOG);
4176 /***********************************************************************
4177 * GetFileTitleA (COMDLG32.@)
4179 * See GetFileTitleW.
4181 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4183 int ret;
4184 UNICODE_STRING strWFile;
4185 LPWSTR lpWTitle;
4187 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4188 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4189 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4190 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4191 RtlFreeUnicodeString( &strWFile );
4192 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4193 return ret;
4197 /***********************************************************************
4198 * GetFileTitleW (COMDLG32.@)
4200 * Get the name of a file.
4202 * PARAMS
4203 * lpFile [I] name and location of file
4204 * lpTitle [O] returned file name
4205 * cbBuf [I] buffer size of lpTitle
4207 * RETURNS
4208 * Success: zero
4209 * Failure: negative number.
4211 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4213 int i, len;
4214 static const WCHAR brkpoint[] = {'*','[',']',0};
4215 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4217 if(lpFile == NULL || lpTitle == NULL)
4218 return -1;
4220 len = lstrlenW(lpFile);
4222 if (len == 0)
4223 return -1;
4225 if(strpbrkW(lpFile, brkpoint))
4226 return -1;
4228 len--;
4230 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4231 return -1;
4233 for(i = len; i >= 0; i--)
4235 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4237 i++;
4238 break;
4242 if(i == -1)
4243 i++;
4245 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4247 len = lstrlenW(lpFile+i)+1;
4248 if(cbBuf < len)
4249 return len;
4251 lstrcpyW(lpTitle, &lpFile[i]);
4252 return 0;