mshtml: Removed no longer used attr_name from event_info_t.
[wine.git] / dlls / comdlg32 / filedlg.c
blob8dda4f7712b23fa39871142027a7db25c94b27da
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winternl.h"
63 #include "winnls.h"
64 #include "wingdi.h"
65 #include "winreg.h"
66 #include "winuser.h"
67 #include "commdlg.h"
68 #include "dlgs.h"
69 #include "cdlg.h"
70 #include "cderr.h"
71 #include "shellapi.h"
72 #include "shlobj.h"
73 #include "filedlgbrowser.h"
74 #include "shlwapi.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex; /* Index of picture in image list */
94 HIMAGELIST hImgList;
95 int m_iIndent; /* Indentation index */
96 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
98 } SFOLDER,*LPSFOLDER;
100 typedef struct tagLookInInfo
102 int iMaxIndentation;
103 UINT uSelectedItem;
104 } LookInInfos;
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
114 /* AddItem flags*/
115 #define LISTEND -1
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
119 #define SEARCH_EXP 2
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
125 /* NOTE
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
166 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
167 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
169 static const WCHAR LastVisitedMRUW[] =
170 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
173 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
174 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
176 /***********************************************************************
177 * Prototypes
180 /* Internal functions used by the dialog */
181 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 static BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Functions for dealing with the most-recently-used registry keys */
217 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
218 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
219 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
221 /* Miscellaneous tool functions */
222 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
223 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
224 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
225 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
227 static UINT GetNumSelected( IDataObject *doSelected );
228 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
230 /* Shell memory allocation */
231 static void *MemAlloc(UINT size);
232 static void MemFree(void *mem);
234 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
235 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
236 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
237 static BOOL BrowseSelectedFolder(HWND hwnd);
239 /***********************************************************************
240 * GetFileName95
242 * Creates an Open common dialog box that lets the user select
243 * the drive, directory, and the name of a file or set of files to open.
245 * IN : The FileOpenDlgInfos structure associated with the dialog
246 * OUT : TRUE on success
247 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
249 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
251 LRESULT lRes;
252 void *template;
253 HRSRC hRes;
254 HANDLE hDlgTmpl = 0;
256 /* test for missing functionality */
257 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
259 FIXME("Flags 0x%08x not yet implemented\n",
260 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
263 /* Create the dialog from a template */
265 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
267 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
268 return FALSE;
270 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
271 !(template = LockResource( hDlgTmpl )))
273 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 return FALSE;
277 /* msdn: explorer style dialogs permit sizing by default.
278 * The OFN_ENABLESIZING flag is only needed when a hook or
279 * custom template is provided */
280 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
281 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
282 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
284 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
286 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
287 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
290 /* old style hook messages */
291 if (IsHooked(fodInfos))
293 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
294 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
295 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
296 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
299 if (fodInfos->unicode)
300 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
301 template,
302 fodInfos->ofnInfos->hwndOwner,
303 FileOpenDlgProc95,
304 (LPARAM) fodInfos);
305 else
306 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
307 template,
308 fodInfos->ofnInfos->hwndOwner,
309 FileOpenDlgProc95,
310 (LPARAM) fodInfos);
311 if (fodInfos->ole_initialized)
312 OleUninitialize();
314 /* Unable to create the dialog */
315 if( lRes == -1)
316 return FALSE;
318 return lRes;
321 /***********************************************************************
322 * GetFileDialog95A
324 * Call GetFileName95 with this structure and clean the memory.
326 * IN : The OPENFILENAMEA initialisation structure passed to
327 * GetOpenFileNameA win api function (see filedlg.c)
329 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
331 BOOL ret;
332 FileOpenDlgInfos fodInfos;
333 LPSTR lpstrSavDir = NULL;
334 LPWSTR title = NULL;
335 LPWSTR defext = NULL;
336 LPWSTR filter = NULL;
337 LPWSTR customfilter = NULL;
338 INITCOMMONCONTROLSEX icc;
340 /* Initialize ComboBoxEx32 */
341 icc.dwSize = sizeof(icc);
342 icc.dwICC = ICC_USEREX_CLASSES;
343 InitCommonControlsEx(&icc);
345 /* Initialize CommDlgExtendedError() */
346 COMDLG32_SetCommDlgExtendedError(0);
348 /* Initialize FileOpenDlgInfos structure */
349 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
351 /* Pass in the original ofn */
352 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
354 /* save current directory */
355 if (ofn->Flags & OFN_NOCHANGEDIR)
357 lpstrSavDir = MemAlloc(MAX_PATH);
358 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
361 fodInfos.unicode = FALSE;
363 /* convert all the input strings to unicode */
364 if(ofn->lpstrInitialDir)
366 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
367 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
368 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
370 else
371 fodInfos.initdir = NULL;
373 if(ofn->lpstrFile)
375 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
376 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
378 else
379 fodInfos.filename = NULL;
381 if(ofn->lpstrDefExt)
383 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
384 defext = MemAlloc((len+1)*sizeof(WCHAR));
385 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
387 fodInfos.defext = defext;
389 if(ofn->lpstrTitle)
391 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
392 title = MemAlloc((len+1)*sizeof(WCHAR));
393 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
395 fodInfos.title = title;
397 if (ofn->lpstrFilter)
399 LPCSTR s;
400 int n, len;
402 /* filter is a list... title\0ext\0......\0\0 */
403 s = ofn->lpstrFilter;
404 while (*s) s = s+strlen(s)+1;
405 s++;
406 n = s - ofn->lpstrFilter;
407 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
408 filter = MemAlloc(len*sizeof(WCHAR));
409 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
411 fodInfos.filter = filter;
413 /* convert lpstrCustomFilter */
414 if (ofn->lpstrCustomFilter)
416 LPCSTR s;
417 int n, len;
419 /* customfilter contains a pair of strings... title\0ext\0 */
420 s = ofn->lpstrCustomFilter;
421 if (*s) s = s+strlen(s)+1;
422 if (*s) s = s+strlen(s)+1;
423 n = s - ofn->lpstrCustomFilter;
424 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
425 customfilter = MemAlloc(len*sizeof(WCHAR));
426 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
428 fodInfos.customfilter = customfilter;
430 /* Initialize the dialog property */
431 fodInfos.DlgInfos.dwDlgProp = 0;
432 fodInfos.DlgInfos.hwndCustomDlg = NULL;
434 switch(iDlgType)
436 case OPEN_DIALOG :
437 ret = GetFileName95(&fodInfos);
438 break;
439 case SAVE_DIALOG :
440 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
441 ret = GetFileName95(&fodInfos);
442 break;
443 default :
444 ret = FALSE;
447 if (lpstrSavDir)
449 SetCurrentDirectoryA(lpstrSavDir);
450 MemFree(lpstrSavDir);
453 MemFree(title);
454 MemFree(defext);
455 MemFree(filter);
456 MemFree(customfilter);
457 MemFree(fodInfos.initdir);
458 MemFree(fodInfos.filename);
460 TRACE("selected file: %s\n",ofn->lpstrFile);
462 return ret;
465 /***********************************************************************
466 * GetFileDialog95W
468 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
469 * Call GetFileName95 with this structure and clean the memory.
472 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
474 BOOL ret;
475 FileOpenDlgInfos fodInfos;
476 LPWSTR lpstrSavDir = NULL;
477 INITCOMMONCONTROLSEX icc;
479 /* Initialize ComboBoxEx32 */
480 icc.dwSize = sizeof(icc);
481 icc.dwICC = ICC_USEREX_CLASSES;
482 InitCommonControlsEx(&icc);
484 /* Initialize CommDlgExtendedError() */
485 COMDLG32_SetCommDlgExtendedError(0);
487 /* Initialize FileOpenDlgInfos structure */
488 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
490 /* Pass in the original ofn */
491 fodInfos.ofnInfos = ofn;
493 fodInfos.title = ofn->lpstrTitle;
494 fodInfos.defext = ofn->lpstrDefExt;
495 fodInfos.filter = ofn->lpstrFilter;
496 fodInfos.customfilter = ofn->lpstrCustomFilter;
498 /* convert string arguments, save others */
499 if(ofn->lpstrFile)
501 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
502 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
504 else
505 fodInfos.filename = NULL;
507 if(ofn->lpstrInitialDir)
509 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
510 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
511 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
512 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
514 else
515 fodInfos.initdir = NULL;
517 /* save current directory */
518 if (ofn->Flags & OFN_NOCHANGEDIR)
520 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
521 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
524 fodInfos.unicode = TRUE;
526 switch(iDlgType)
528 case OPEN_DIALOG :
529 ret = GetFileName95(&fodInfos);
530 break;
531 case SAVE_DIALOG :
532 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
533 ret = GetFileName95(&fodInfos);
534 break;
535 default :
536 ret = FALSE;
539 if (lpstrSavDir)
541 SetCurrentDirectoryW(lpstrSavDir);
542 MemFree(lpstrSavDir);
545 /* restore saved IN arguments and convert OUT arguments back */
546 MemFree(fodInfos.filename);
547 MemFree(fodInfos.initdir);
548 return ret;
551 /******************************************************************************
552 * COMDLG32_GetDisplayNameOf [internal]
554 * Helper function to get the display name for a pidl.
556 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
557 LPSHELLFOLDER psfDesktop;
558 STRRET strret;
560 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
561 return FALSE;
563 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
564 IShellFolder_Release(psfDesktop);
565 return FALSE;
568 IShellFolder_Release(psfDesktop);
569 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
572 /******************************************************************************
573 * COMDLG32_GetCanonicalPath [internal]
575 * Helper function to get the canonical path.
577 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
578 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
580 WCHAR lpstrTemp[MAX_PATH];
582 /* Get the current directory name */
583 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
585 /* last fallback */
586 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
588 PathAddBackslashW(lpstrPathAndFile);
590 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
592 /* if the user specified a fully qualified path use it */
593 if(PathIsRelativeW(lpstrFile))
595 lstrcatW(lpstrPathAndFile, lpstrFile);
597 else
599 /* does the path have a drive letter? */
600 if (PathGetDriveNumberW(lpstrFile) == -1)
601 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
602 else
603 lstrcpyW(lpstrPathAndFile, lpstrFile);
606 /* resolve "." and ".." */
607 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
608 lstrcpyW(lpstrPathAndFile, lpstrTemp);
609 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
612 /***********************************************************************
613 * COMDLG32_SplitFileNames [internal]
615 * Creates a delimited list of filenames.
617 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
619 UINT nStrCharCount = 0; /* index in src buffer */
620 UINT nFileIndex = 0; /* index in dest buffer */
621 UINT nFileCount = 0; /* number of files */
623 /* we might get single filename without any '"',
624 * so we need nStrLen + terminating \0 + end-of-list \0 */
625 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
626 *sizeUsed = 0;
628 /* build delimited file list from filenames */
629 while ( nStrCharCount <= nStrLen )
631 if ( lpstrEdit[nStrCharCount]=='"' )
633 nStrCharCount++;
634 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
636 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
637 nStrCharCount++;
639 (*lpstrFileList)[nFileIndex++] = 0;
640 nFileCount++;
642 nStrCharCount++;
645 /* single, unquoted string */
646 if ((nStrLen > 0) && (nFileIndex == 0) )
648 lstrcpyW(*lpstrFileList, lpstrEdit);
649 nFileIndex = lstrlenW(lpstrEdit) + 1;
650 nFileCount = 1;
653 /* trailing \0 */
654 (*lpstrFileList)[nFileIndex++] = '\0';
656 *sizeUsed = nFileIndex;
657 return nFileCount;
660 /***********************************************************************
661 * ArrangeCtrlPositions [internal]
663 * NOTE: Make sure to add testcases for any changes made here.
665 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
667 HWND hwndChild, hwndStc32;
668 RECT rectParent, rectChild, rectStc32;
669 INT help_fixup = 0;
670 int chgx, chgy;
672 /* Take into account if open as read only checkbox and help button
673 * are hidden
675 if (hide_help)
677 RECT rectHelp, rectCancel;
678 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
679 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
680 /* subtract the height of the help button plus the space between
681 * the help button and the cancel button to the height of the dialog
683 help_fixup = rectHelp.bottom - rectCancel.bottom;
687 There are two possibilities to add components to the default file dialog box.
689 By default, all the new components are added below the standard dialog box (the else case).
691 However, if there is a static text component with the stc32 id, a special case happens.
692 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
693 in the window and the cx and cy indicate how to size the window.
694 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
695 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
699 GetClientRect(hwndParentDlg, &rectParent);
701 /* when arranging controls we have to use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
705 if (hwndStc32)
707 GetWindowRect(hwndStc32, &rectStc32);
708 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
710 /* set the size of the stc32 control according to the size of
711 * client area of the parent dialog
713 SetWindowPos(hwndStc32, 0,
714 0, 0,
715 rectParent.right, rectParent.bottom,
716 SWP_NOMOVE | SWP_NOZORDER);
718 else
719 SetRectEmpty(&rectStc32);
721 /* this part moves controls of the child dialog */
722 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
723 while (hwndChild)
725 if (hwndChild != hwndStc32)
727 GetWindowRect(hwndChild, &rectChild);
728 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
730 /* move only if stc32 exist */
731 if (hwndStc32 && rectChild.left > rectStc32.right)
733 /* move to the right of visible controls of the parent dialog */
734 rectChild.left += rectParent.right;
735 rectChild.left -= rectStc32.right;
737 /* move even if stc32 doesn't exist */
738 if (rectChild.top >= rectStc32.bottom)
740 /* move below visible controls of the parent dialog */
741 rectChild.top += rectParent.bottom;
742 rectChild.top -= rectStc32.bottom - rectStc32.top;
745 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
746 0, 0, SWP_NOSIZE | SWP_NOZORDER);
748 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
751 /* this part moves controls of the parent dialog */
752 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
753 while (hwndChild)
755 if (hwndChild != hwndChildDlg)
757 GetWindowRect(hwndChild, &rectChild);
758 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
760 /* left,top of stc32 marks the position of controls
761 * from the parent dialog
763 rectChild.left += rectStc32.left;
764 rectChild.top += rectStc32.top;
766 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
767 0, 0, SWP_NOSIZE | SWP_NOZORDER);
769 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
772 /* calculate the size of the resulting dialog */
774 /* here we have to use original parent size */
775 GetClientRect(hwndParentDlg, &rectParent);
776 GetClientRect(hwndChildDlg, &rectChild);
777 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
778 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
780 if (hwndStc32)
782 /* width */
783 if (rectParent.right > rectStc32.right - rectStc32.left)
784 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
785 else
786 chgx = rectChild.right - rectParent.right;
787 /* height */
788 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
789 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
790 else
791 /* Unconditionally set new dialog
792 * height to that of the child
794 chgy = rectChild.bottom - rectParent.bottom;
796 else
798 chgx = 0;
799 chgy = rectChild.bottom - help_fixup;
801 /* set the size of the parent dialog */
802 GetWindowRect(hwndParentDlg, &rectParent);
803 SetWindowPos(hwndParentDlg, 0,
804 0, 0,
805 rectParent.right - rectParent.left + chgx,
806 rectParent.bottom - rectParent.top + chgy,
807 SWP_NOMOVE | SWP_NOZORDER);
810 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
812 switch(uMsg) {
813 case WM_INITDIALOG:
814 return TRUE;
816 return FALSE;
819 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
821 LPCVOID template;
822 HRSRC hRes;
823 HANDLE hDlgTmpl = 0;
824 HWND hChildDlg = 0;
826 TRACE("\n");
829 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
830 * structure's hInstance parameter is not a HINSTANCE, but
831 * instead a pointer to a template resource to use.
833 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
835 HINSTANCE hinst;
836 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
838 hinst = COMDLG32_hInstance;
839 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
841 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
842 return NULL;
845 else
847 hinst = fodInfos->ofnInfos->hInstance;
848 if(fodInfos->unicode)
850 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
851 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
853 else
855 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
856 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
858 if (!hRes)
860 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
861 return NULL;
863 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
864 !(template = LockResource( hDlgTmpl )))
866 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
867 return NULL;
870 if (fodInfos->unicode)
871 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
872 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
873 (LPARAM)fodInfos->ofnInfos);
874 else
875 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
876 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
877 (LPARAM)fodInfos->ofnInfos);
878 return hChildDlg;
880 else if( IsHooked(fodInfos))
882 RECT rectHwnd;
883 struct {
884 DLGTEMPLATE tmplate;
885 WORD menu,class,title;
886 } temp;
887 GetClientRect(hwnd,&rectHwnd);
888 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
889 temp.tmplate.dwExtendedStyle = 0;
890 temp.tmplate.cdit = 0;
891 temp.tmplate.x = 0;
892 temp.tmplate.y = 0;
893 temp.tmplate.cx = 0;
894 temp.tmplate.cy = 0;
895 temp.menu = temp.class = temp.title = 0;
897 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
898 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
900 return hChildDlg;
902 return NULL;
905 /***********************************************************************
906 * SendCustomDlgNotificationMessage
908 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
911 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
913 LRESULT hook_result = 0;
914 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
916 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
918 if(!fodInfos) return 0;
920 if(fodInfos->DlgInfos.hwndCustomDlg)
922 TRACE("CALL NOTIFY for %x\n", uCode);
923 if(fodInfos->unicode)
925 OFNOTIFYW ofnNotify;
926 ofnNotify.hdr.hwndFrom=hwndParentDlg;
927 ofnNotify.hdr.idFrom=0;
928 ofnNotify.hdr.code = uCode;
929 ofnNotify.lpOFN = fodInfos->ofnInfos;
930 ofnNotify.pszFile = NULL;
931 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
933 else
935 OFNOTIFYA ofnNotify;
936 ofnNotify.hdr.hwndFrom=hwndParentDlg;
937 ofnNotify.hdr.idFrom=0;
938 ofnNotify.hdr.code = uCode;
939 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
940 ofnNotify.pszFile = NULL;
941 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
943 TRACE("RET NOTIFY\n");
945 TRACE("Retval: 0x%08lx\n", hook_result);
946 return hook_result;
949 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
951 UINT len, total;
952 WCHAR *p, *buffer;
953 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
955 TRACE("CDM_GETFILEPATH:\n");
957 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
958 return -1;
960 /* get path and filenames */
961 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
962 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
963 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
964 if (len)
966 p = buffer + strlenW(buffer);
967 *p++ = '\\';
968 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
970 if (fodInfos->unicode)
972 total = strlenW( buffer) + 1;
973 if (result) lstrcpynW( result, buffer, size );
974 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
976 else
978 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
979 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
980 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
982 HeapFree( GetProcessHeap(), 0, buffer );
983 return total;
986 /***********************************************************************
987 * FILEDLG95_HandleCustomDialogMessages
989 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
991 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
993 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
994 WCHAR lpstrPath[MAX_PATH];
995 INT_PTR retval;
997 if(!fodInfos) return FALSE;
999 switch(uMsg)
1001 case CDM_GETFILEPATH:
1002 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1003 break;
1005 case CDM_GETFOLDERPATH:
1006 TRACE("CDM_GETFOLDERPATH:\n");
1007 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1008 if (lParam)
1010 if (fodInfos->unicode)
1011 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1012 else
1013 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1014 (LPSTR)lParam, (int)wParam, NULL, NULL);
1016 retval = lstrlenW(lpstrPath) + 1;
1017 break;
1019 case CDM_GETFOLDERIDLIST:
1020 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1021 if (retval <= wParam)
1022 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1023 break;
1025 case CDM_GETSPEC:
1026 TRACE("CDM_GETSPEC:\n");
1027 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1028 if (lParam)
1030 if (fodInfos->unicode)
1031 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1032 else
1033 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1035 break;
1037 case CDM_SETCONTROLTEXT:
1038 TRACE("CDM_SETCONTROLTEXT:\n");
1039 if ( lParam )
1041 if( fodInfos->unicode )
1042 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1043 else
1044 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1046 retval = TRUE;
1047 break;
1049 case CDM_HIDECONTROL:
1050 /* MSDN states that it should fail for not OFN_EXPLORER case */
1051 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1053 HWND control = GetDlgItem( hwnd, wParam );
1054 if (control) ShowWindow( control, SW_HIDE );
1055 retval = TRUE;
1057 else retval = FALSE;
1058 break;
1060 default:
1061 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1062 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1063 return FALSE;
1065 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1066 return TRUE;
1069 /***********************************************************************
1070 * FILEDLG95_OnWMGetMMI
1072 * WM_GETMINMAXINFO message handler for resizable dialogs
1074 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1076 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1077 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1078 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1080 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1082 return TRUE;
1085 /***********************************************************************
1086 * FILEDLG95_OnWMSize
1088 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1090 * FIXME: this could be made more elaborate. Now use a simple scheme
1091 * where the file view is enlarged and the controls are either moved
1092 * vertically or horizontally to get out of the way. Only the "grip"
1093 * is moved in both directions to stay in the corner.
1095 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1097 RECT rc, rcview;
1098 int chgx, chgy;
1099 HWND ctrl;
1100 HDWP hdwp;
1101 FileOpenDlgInfos *fodInfos;
1103 if( wParam != SIZE_RESTORED) return FALSE;
1104 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1105 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1106 /* get the new dialog rectangle */
1107 GetWindowRect( hwnd, &rc);
1108 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1109 rc.right -rc.left, rc.bottom -rc.top);
1110 /* not initialized yet */
1111 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1112 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1113 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1114 return FALSE;
1115 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1116 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1117 fodInfos->sizedlg.cx = rc.right - rc.left;
1118 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1119 /* change the size of the view window */
1120 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1121 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1122 hdwp = BeginDeferWindowPos( 10);
1123 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1124 rcview.right - rcview.left + chgx,
1125 rcview.bottom - rcview.top + chgy,
1126 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1127 /* change position and sizes of the controls */
1128 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1130 int ctrlid = GetDlgCtrlID( ctrl);
1131 GetWindowRect( ctrl, &rc);
1132 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1133 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1135 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1136 0, 0,
1137 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1139 else if( rc.top > rcview.bottom)
1141 /* if it was below the shell view
1142 * move to bottom */
1143 switch( ctrlid)
1145 /* file name (edit or comboboxex) and file types combo change also width */
1146 case edt1:
1147 case cmb13:
1148 case cmb1:
1149 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1150 rc.right - rc.left + chgx, rc.bottom - rc.top,
1151 SWP_NOACTIVATE | SWP_NOZORDER);
1152 break;
1153 /* then these buttons must move out of the way */
1154 case IDOK:
1155 case IDCANCEL:
1156 case pshHelp:
1157 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1158 0, 0,
1159 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1160 break;
1161 default:
1162 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1163 0, 0,
1164 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1167 else if( rc.left > rcview.right)
1169 /* if it was to the right of the shell view
1170 * move to right */
1171 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1172 0, 0,
1173 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1175 else
1176 /* special cases */
1178 switch( ctrlid)
1180 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1181 case IDC_LOOKIN:
1182 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1183 rc.right - rc.left + chgx, rc.bottom - rc.top,
1184 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1185 break;
1186 case IDC_TOOLBARSTATIC:
1187 case IDC_TOOLBAR:
1188 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1189 0, 0,
1190 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1191 break;
1192 #endif
1193 /* not resized in windows. Since wine uses this invisible control
1194 * to size the browser view it needs to be resized */
1195 case IDC_SHELLSTATIC:
1196 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1197 rc.right - rc.left + chgx,
1198 rc.bottom - rc.top + chgy,
1199 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1200 break;
1204 if(fodInfos->DlgInfos.hwndCustomDlg &&
1205 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1207 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1208 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1210 GetWindowRect( ctrl, &rc);
1211 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1212 if( rc.top > rcview.bottom)
1214 /* if it was below the shell view
1215 * move to bottom */
1216 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1217 rc.right - rc.left, rc.bottom - rc.top,
1218 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1220 else if( rc.left > rcview.right)
1222 /* if it was to the right of the shell view
1223 * move to right */
1224 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1225 rc.right - rc.left, rc.bottom - rc.top,
1226 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1229 /* size the custom dialog at the end: some applications do some
1230 * control re-arranging at this point */
1231 GetClientRect(hwnd, &rc);
1232 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1233 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1235 EndDeferWindowPos( hdwp);
1236 /* should not be needed */
1237 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1238 return TRUE;
1241 /***********************************************************************
1242 * FileOpenDlgProc95
1244 * File open dialog procedure
1246 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1248 #if 0
1249 TRACE("%p 0x%04x\n", hwnd, uMsg);
1250 #endif
1252 switch(uMsg)
1254 case WM_INITDIALOG:
1256 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1257 RECT rc, rcstc;
1258 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1259 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1261 /* Some shell namespace extensions depend on COM being initialized. */
1262 if (SUCCEEDED(OleInitialize(NULL)))
1263 fodInfos->ole_initialized = TRUE;
1265 /* Adds the FileOpenDlgInfos in the property list of the dialog
1266 so it will be easily accessible through a GetPropA(...) */
1267 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1269 FILEDLG95_InitControls(hwnd);
1271 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1273 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1274 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1275 RECT client, client_adjusted;
1277 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1279 style |= WS_SIZEBOX;
1280 ex_style |= WS_EX_WINDOWEDGE;
1282 else
1283 style &= ~WS_SIZEBOX;
1284 SetWindowLongW(hwnd, GWL_STYLE, style);
1285 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1287 GetClientRect( hwnd, &client );
1288 GetClientRect( hwnd, &client_adjusted );
1289 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1291 GetWindowRect( hwnd, &rc );
1292 rc.right += client_adjusted.right - client.right;
1293 rc.bottom += client_adjusted.bottom - client.bottom;
1294 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1295 SWP_NOZORDER | SWP_NOMOVE);
1297 GetWindowRect( hwnd, &rc );
1298 fodInfos->DlgInfos.hwndGrip =
1299 CreateWindowExA( 0, "SCROLLBAR", NULL,
1300 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1301 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1302 rc.right - gripx, rc.bottom - gripy,
1303 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1306 fodInfos->DlgInfos.hwndCustomDlg =
1307 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1309 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1310 FILEDLG95_FillControls(hwnd, wParam, lParam);
1312 if( fodInfos->DlgInfos.hwndCustomDlg)
1313 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1315 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1316 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1317 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1320 /* if the app has changed the position of the invisible listbox,
1321 * change that of the listview (browser) as well */
1322 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1323 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1324 if( !EqualRect( &rc, &rcstc))
1326 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1327 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1328 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1329 SWP_NOACTIVATE | SWP_NOZORDER);
1332 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1334 GetWindowRect( hwnd, &rc);
1335 fodInfos->sizedlg.cx = rc.right - rc.left;
1336 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1337 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1338 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1339 GetClientRect( hwnd, &rc);
1340 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1341 rc.right - gripx, rc.bottom - gripy,
1342 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1343 /* resize the dialog to the previous invocation */
1344 if( MemDialogSize.cx && MemDialogSize.cy)
1345 SetWindowPos( hwnd, NULL,
1346 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1347 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1350 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1351 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1353 return 0;
1355 case WM_SIZE:
1356 return FILEDLG95_OnWMSize(hwnd, wParam);
1357 case WM_GETMINMAXINFO:
1358 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1359 case WM_COMMAND:
1360 return FILEDLG95_OnWMCommand(hwnd, wParam);
1361 case WM_DRAWITEM:
1363 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1365 case IDC_LOOKIN:
1366 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1367 return TRUE;
1370 return FALSE;
1372 case WM_GETISHELLBROWSER:
1373 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1375 case WM_DESTROY:
1377 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1378 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1379 MemDialogSize = fodInfos->sizedlg;
1380 RemovePropA(hwnd, FileOpenDlgInfosStr);
1381 return FALSE;
1383 case WM_NOTIFY:
1385 LPNMHDR lpnmh = (LPNMHDR)lParam;
1386 UINT stringId = -1;
1388 /* set up the button tooltips strings */
1389 if(TTN_GETDISPINFOA == lpnmh->code )
1391 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1392 switch(lpnmh->idFrom )
1394 /* Up folder button */
1395 case FCIDM_TB_UPFOLDER:
1396 stringId = IDS_UPFOLDER;
1397 break;
1398 /* New folder button */
1399 case FCIDM_TB_NEWFOLDER:
1400 stringId = IDS_NEWFOLDER;
1401 break;
1402 /* List option button */
1403 case FCIDM_TB_SMALLICON:
1404 stringId = IDS_LISTVIEW;
1405 break;
1406 /* Details option button */
1407 case FCIDM_TB_REPORTVIEW:
1408 stringId = IDS_REPORTVIEW;
1409 break;
1410 /* Desktop button */
1411 case FCIDM_TB_DESKTOP:
1412 stringId = IDS_TODESKTOP;
1413 break;
1414 default:
1415 stringId = 0;
1417 lpdi->hinst = COMDLG32_hInstance;
1418 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1420 return FALSE;
1422 default :
1423 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1424 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1425 return FALSE;
1429 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1431 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1432 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1435 /***********************************************************************
1436 * FILEDLG95_InitControls
1438 * WM_INITDIALOG message handler (before hook notification)
1440 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1442 BOOL win2000plus = FALSE;
1443 BOOL win98plus = FALSE;
1444 BOOL handledPath = FALSE;
1445 OSVERSIONINFOW osVi;
1446 static const WCHAR szwSlash[] = { '\\', 0 };
1447 static const WCHAR szwStar[] = { '*',0 };
1449 static const TBBUTTON tbb[] =
1451 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1452 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1453 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1454 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1455 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1456 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1457 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1458 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1459 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1461 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1463 RECT rectTB;
1464 RECT rectlook;
1466 HIMAGELIST toolbarImageList;
1467 SHFILEINFOA shFileInfo;
1468 ITEMIDLIST *desktopPidl;
1470 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1472 TRACE("%p\n", fodInfos);
1474 /* Get windows version emulating */
1475 osVi.dwOSVersionInfoSize = sizeof(osVi);
1476 GetVersionExW(&osVi);
1477 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1478 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1479 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1480 win2000plus = (osVi.dwMajorVersion > 4);
1481 if (win2000plus) win98plus = TRUE;
1483 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1486 /* Use either the edit or the comboboxex for the filename control */
1487 if (filename_is_edit( fodInfos ))
1489 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1490 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1492 else
1494 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1495 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1498 /* Get the hwnd of the controls */
1499 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1500 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1502 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1503 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1505 /* construct the toolbar */
1506 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1507 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1509 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1510 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1511 rectTB.left = rectlook.right;
1512 rectTB.top = rectlook.top-1;
1514 if (fodInfos->unicode)
1515 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1516 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1517 rectTB.left, rectTB.top,
1518 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1519 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1520 else
1521 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1522 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1523 rectTB.left, rectTB.top,
1524 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1525 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1527 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1529 /* FIXME: use TB_LOADIMAGES when implemented */
1530 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1531 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1532 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1534 /* Retrieve and add desktop icon to the toolbar */
1535 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1536 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1537 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1538 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1539 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1541 DestroyIcon(shFileInfo.hIcon);
1542 CoTaskMemFree(desktopPidl);
1544 /* Finish Toolbar Construction */
1545 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1546 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1548 /* Set the window text with the text specified in the OPENFILENAME structure */
1549 if(fodInfos->title)
1551 SetWindowTextW(hwnd,fodInfos->title);
1553 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1555 WCHAR buf[64];
1556 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1557 SetWindowTextW(hwnd, buf);
1560 /* Initialise the file name edit control */
1561 handledPath = FALSE;
1562 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1564 if(fodInfos->filename)
1566 /* 1. If win2000 or higher and filename contains a path, use it
1567 in preference over the lpstrInitialDir */
1568 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1569 WCHAR tmpBuf[MAX_PATH];
1570 WCHAR *nameBit;
1571 DWORD result;
1573 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1574 if (result) {
1576 /* nameBit is always shorter than the original filename. It may be NULL
1577 * when the filename contains only a drive name instead of file name */
1578 if (nameBit)
1580 lstrcpyW(fodInfos->filename,nameBit);
1581 *nameBit = 0x00;
1583 else
1584 *fodInfos->filename = '\0';
1586 MemFree(fodInfos->initdir);
1587 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1588 lstrcpyW(fodInfos->initdir, tmpBuf);
1589 handledPath = TRUE;
1590 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1591 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1593 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1595 } else {
1596 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1600 /* 2. (All platforms) If initdir is not null, then use it */
1601 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1603 /* Work out the proper path as supplied one might be relative */
1604 /* (Here because supplying '.' as dir browses to My Computer) */
1605 WCHAR tmpBuf[MAX_PATH];
1606 WCHAR tmpBuf2[MAX_PATH];
1607 WCHAR *nameBit;
1608 DWORD result;
1610 lstrcpyW(tmpBuf, fodInfos->initdir);
1611 if (PathFileExistsW(tmpBuf)) {
1612 /* initdir does not have to be a directory. If a file is
1613 * specified, the dir part is taken */
1614 if (PathIsDirectoryW(tmpBuf)) {
1615 PathAddBackslashW(tmpBuf);
1616 lstrcatW(tmpBuf, szwStar);
1618 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1619 if (result) {
1620 *nameBit = 0x00;
1621 MemFree(fodInfos->initdir);
1622 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1623 lstrcpyW(fodInfos->initdir, tmpBuf2);
1624 handledPath = TRUE;
1625 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1628 else if (fodInfos->initdir)
1630 MemFree(fodInfos->initdir);
1631 fodInfos->initdir = NULL;
1632 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1636 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1638 /* 3. All except w2k+: if filename contains a path use it */
1639 if (!win2000plus && fodInfos->filename &&
1640 *fodInfos->filename &&
1641 strpbrkW(fodInfos->filename, szwSlash)) {
1642 WCHAR tmpBuf[MAX_PATH];
1643 WCHAR *nameBit;
1644 DWORD result;
1646 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1647 tmpBuf, &nameBit);
1648 if (result) {
1649 int len;
1651 /* nameBit is always shorter than the original filename */
1652 lstrcpyW(fodInfos->filename, nameBit);
1653 *nameBit = 0x00;
1655 len = lstrlenW(tmpBuf);
1656 MemFree(fodInfos->initdir);
1657 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1658 lstrcpyW(fodInfos->initdir, tmpBuf);
1660 handledPath = TRUE;
1661 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1662 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1664 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1667 /* 4. Win2000+: Recently used */
1668 if (!handledPath && win2000plus) {
1669 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1670 fodInfos->initdir[0] = '\0';
1672 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1674 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1675 handledPath = TRUE;
1676 }else{
1677 MemFree(fodInfos->initdir);
1678 fodInfos->initdir = NULL;
1682 /* 5. win98+ and win2000+ if any files of specified filter types in
1683 current directory, use it */
1684 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1686 LPCWSTR lpstrPos = fodInfos->filter;
1687 WIN32_FIND_DATAW FindFileData;
1688 HANDLE hFind;
1690 while (1)
1692 /* filter is a list... title\0ext\0......\0\0 */
1694 /* Skip the title */
1695 if(! *lpstrPos) break; /* end */
1696 lpstrPos += lstrlenW(lpstrPos) + 1;
1698 /* See if any files exist in the current dir with this extension */
1699 if(! *lpstrPos) break; /* end */
1701 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1703 if (hFind == INVALID_HANDLE_VALUE) {
1704 /* None found - continue search */
1705 lpstrPos += lstrlenW(lpstrPos) + 1;
1707 } else {
1709 MemFree(fodInfos->initdir);
1710 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1711 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1713 handledPath = TRUE;
1714 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1715 debugstr_w(lpstrPos));
1716 FindClose(hFind);
1717 break;
1722 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1723 if (!handledPath && (win2000plus || win98plus)) {
1724 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1726 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1728 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1730 /* last fallback */
1731 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1732 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1733 } else {
1734 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1736 } else {
1737 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1739 handledPath = TRUE;
1740 } else if (!handledPath) {
1741 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1742 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1743 handledPath = TRUE;
1744 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1747 SetFocus( fodInfos->DlgInfos.hwndFileName );
1748 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1750 /* Must the open as read only check box be checked ?*/
1751 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1753 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1756 /* Must the open as read only check box be hidden? */
1757 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1759 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1760 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1763 /* Must the help button be hidden? */
1764 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1766 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1767 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1770 /* change Open to Save */
1771 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1773 WCHAR buf[16];
1774 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1775 SetDlgItemTextW(hwnd, IDOK, buf);
1776 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1777 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1780 /* Initialize the filter combo box */
1781 FILEDLG95_FILETYPE_Init(hwnd);
1783 return 0;
1786 /***********************************************************************
1787 * FILEDLG95_ResizeControls
1789 * WM_INITDIALOG message handler (after hook notification)
1791 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1793 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1795 if (fodInfos->DlgInfos.hwndCustomDlg)
1797 RECT rc;
1798 UINT flags = SWP_NOACTIVATE;
1800 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1801 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1803 /* resize the custom dialog to the parent size */
1804 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1805 GetClientRect(hwnd, &rc);
1806 else
1808 /* our own fake template is zero sized and doesn't have children, so
1809 * there is no need to resize it. Picasa depends on it.
1811 flags |= SWP_NOSIZE;
1812 SetRectEmpty(&rc);
1814 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1815 0, 0, rc.right, rc.bottom, flags);
1817 else
1819 /* Resize the height; if opened as read-only, checkbox and help button are
1820 * hidden and we are not using a custom template nor a customDialog
1822 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1823 (!(fodInfos->ofnInfos->Flags &
1824 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1826 RECT rectDlg, rectHelp, rectCancel;
1827 GetWindowRect(hwnd, &rectDlg);
1828 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1829 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1830 /* subtract the height of the help button plus the space between the help
1831 * button and the cancel button to the height of the dialog
1833 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1834 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1835 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1838 return TRUE;
1841 /***********************************************************************
1842 * FILEDLG95_FillControls
1844 * WM_INITDIALOG message handler (after hook notification)
1846 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1848 LPITEMIDLIST pidlItemId = NULL;
1850 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1852 TRACE("dir=%s file=%s\n",
1853 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1855 /* Get the initial directory pidl */
1857 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1859 WCHAR path[MAX_PATH];
1861 GetCurrentDirectoryW(MAX_PATH,path);
1862 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1865 /* Initialise shell objects */
1866 FILEDLG95_SHELL_Init(hwnd);
1868 /* Initialize the Look In combo box */
1869 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1871 /* Browse to the initial directory */
1872 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1874 /* Free pidlItem memory */
1875 COMDLG32_SHFree(pidlItemId);
1877 return TRUE;
1879 /***********************************************************************
1880 * FILEDLG95_Clean
1882 * Regroups all the cleaning functions of the filedlg
1884 void FILEDLG95_Clean(HWND hwnd)
1886 FILEDLG95_FILETYPE_Clean(hwnd);
1887 FILEDLG95_LOOKIN_Clean(hwnd);
1888 FILEDLG95_SHELL_Clean(hwnd);
1890 /***********************************************************************
1891 * FILEDLG95_OnWMCommand
1893 * WM_COMMAND message handler
1895 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1897 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1898 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1899 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1901 switch(wID)
1903 /* OK button */
1904 case IDOK:
1905 FILEDLG95_OnOpen(hwnd);
1906 break;
1907 /* Cancel button */
1908 case IDCANCEL:
1909 FILEDLG95_Clean(hwnd);
1910 EndDialog(hwnd, FALSE);
1911 break;
1912 /* Filetype combo box */
1913 case IDC_FILETYPE:
1914 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1915 break;
1916 /* LookIn combo box */
1917 case IDC_LOOKIN:
1918 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1919 break;
1921 /* --- toolbar --- */
1922 /* Up folder button */
1923 case FCIDM_TB_UPFOLDER:
1924 FILEDLG95_SHELL_UpFolder(hwnd);
1925 break;
1926 /* New folder button */
1927 case FCIDM_TB_NEWFOLDER:
1928 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1929 break;
1930 /* List option button */
1931 case FCIDM_TB_SMALLICON:
1932 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1933 break;
1934 /* Details option button */
1935 case FCIDM_TB_REPORTVIEW:
1936 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1937 break;
1938 /* Details option button */
1939 case FCIDM_TB_DESKTOP:
1940 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1941 break;
1943 case edt1:
1944 case cmb13:
1945 break;
1948 /* Do not use the listview selection anymore */
1949 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1950 return 0;
1953 /***********************************************************************
1954 * FILEDLG95_OnWMGetIShellBrowser
1956 * WM_GETISHELLBROWSER message handler
1958 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1960 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1962 TRACE("\n");
1964 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1966 return TRUE;
1970 /***********************************************************************
1971 * FILEDLG95_SendFileOK
1973 * Sends the CDN_FILEOK notification if required
1975 * RETURNS
1976 * TRUE if the dialog should close
1977 * FALSE if the dialog should not be closed
1979 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1981 /* ask the hook if we can close */
1982 if(IsHooked(fodInfos))
1984 LRESULT retval = 0;
1986 TRACE("---\n");
1987 /* First send CDN_FILEOK as MSDN doc says */
1988 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1989 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1990 if( retval)
1992 TRACE("canceled\n");
1993 return FALSE;
1996 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1997 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1998 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1999 if( retval)
2001 TRACE("canceled\n");
2002 return FALSE;
2005 return TRUE;
2008 /***********************************************************************
2009 * FILEDLG95_OnOpenMultipleFiles
2011 * Handles the opening of multiple files.
2013 * FIXME
2014 * check destination buffer size
2016 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2018 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2019 UINT nCount, nSizePath;
2020 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2022 TRACE("\n");
2024 if(fodInfos->unicode)
2026 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2027 ofn->lpstrFile[0] = '\0';
2029 else
2031 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2032 ofn->lpstrFile[0] = '\0';
2035 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2037 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2038 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2039 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2041 LPWSTR lpstrTemp = lpstrFileList;
2043 for ( nCount = 0; nCount < nFileCount; nCount++ )
2045 LPITEMIDLIST pidl;
2047 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2048 if (!pidl)
2050 WCHAR lpstrNotFound[100];
2051 WCHAR lpstrMsg[100];
2052 WCHAR tmp[400];
2053 static const WCHAR nl[] = {'\n',0};
2055 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2056 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2058 lstrcpyW(tmp, lpstrTemp);
2059 lstrcatW(tmp, nl);
2060 lstrcatW(tmp, lpstrNotFound);
2061 lstrcatW(tmp, nl);
2062 lstrcatW(tmp, lpstrMsg);
2064 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2065 return FALSE;
2068 /* move to the next file in the list of files */
2069 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2070 COMDLG32_SHFree(pidl);
2074 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2075 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2077 /* For "oldstyle" dialog the components have to
2078 be separated by blanks (not '\0'!) and short
2079 filenames have to be used! */
2080 FIXME("Components have to be separated by blanks\n");
2082 if(fodInfos->unicode)
2084 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2085 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2086 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2088 else
2090 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2092 if (ofn->lpstrFile != NULL)
2094 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2095 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2096 if (ofn->nMaxFile > nSizePath)
2098 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2099 ofn->lpstrFile + nSizePath,
2100 ofn->nMaxFile - nSizePath, NULL, NULL);
2105 fodInfos->ofnInfos->nFileOffset = nSizePath;
2106 fodInfos->ofnInfos->nFileExtension = 0;
2108 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2109 return FALSE;
2111 /* clean and exit */
2112 FILEDLG95_Clean(hwnd);
2113 return EndDialog(hwnd,TRUE);
2116 /* Returns the 'slot name' of the given module_name in the registry's
2117 * most-recently-used list. This will be an ASCII value in the
2118 * range ['a','z'). Returns zero on error.
2120 * The slot's value in the registry has the form:
2121 * module_name\0mru_path\0
2123 * If stored_path is given, then stored_path will contain the path name
2124 * stored in the registry's MRU list for the given module_name.
2126 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2127 * MRU list key for the given module_name.
2129 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2131 WCHAR mru_list[32], *cur_mru_slot;
2132 BOOL taken[25] = {0};
2133 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2134 HKEY hkey_tmp, *hkey;
2135 LONG ret;
2137 if(hkey_ret)
2138 hkey = hkey_ret;
2139 else
2140 hkey = &hkey_tmp;
2142 if(stored_path)
2143 *stored_path = '\0';
2145 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2146 if(ret){
2147 WARN("Unable to create MRU key: %d\n", ret);
2148 return 0;
2151 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2152 (LPBYTE)mru_list, &mru_list_size);
2153 if(ret || key_type != REG_SZ){
2154 if(ret == ERROR_FILE_NOT_FOUND)
2155 return 'a';
2157 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2158 RegCloseKey(*hkey);
2159 return 0;
2162 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2163 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2164 DWORD value_data_size = sizeof(value_data);
2166 *value_name = *cur_mru_slot;
2168 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2169 &key_type, (LPBYTE)value_data, &value_data_size);
2170 if(ret || key_type != REG_BINARY){
2171 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2172 continue;
2175 if(!strcmpiW(module_name, value_data)){
2176 if(!hkey_ret)
2177 RegCloseKey(*hkey);
2178 if(stored_path)
2179 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2180 return *value_name;
2184 if(!hkey_ret)
2185 RegCloseKey(*hkey);
2187 /* the module name isn't in the registry, so find the next open slot */
2188 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2189 taken[*cur_mru_slot - 'a'] = TRUE;
2190 for(i = 0; i < 25; ++i){
2191 if(!taken[i])
2192 return i + 'a';
2195 /* all slots are taken, so return the last one in MRUList */
2196 --cur_mru_slot;
2197 return *cur_mru_slot;
2200 /* save the given filename as most-recently-used path for this module */
2201 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2203 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2204 LONG ret;
2205 HKEY hkey;
2207 /* get the current executable's name */
2208 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2209 WARN("GotModuleFileName failed: %d\n", GetLastError());
2210 return;
2212 module_name = strrchrW(module_path, '\\');
2213 if(!module_name)
2214 module_name = module_path;
2215 else
2216 module_name += 1;
2218 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2219 if(!slot)
2220 return;
2221 *slot_name = slot;
2223 { /* update the slot's info */
2224 WCHAR *path_ends, *final;
2225 DWORD path_len, final_len;
2227 /* use only the path segment of `filename' */
2228 path_ends = strrchrW(filename, '\\');
2229 path_len = path_ends - filename;
2231 final_len = path_len + lstrlenW(module_name) + 2;
2233 final = MemAlloc(final_len * sizeof(WCHAR));
2234 if(!final)
2235 return;
2236 lstrcpyW(final, module_name);
2237 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2238 final[final_len-1] = '\0';
2240 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2241 final_len * sizeof(WCHAR));
2242 if(ret){
2243 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2244 MemFree(final);
2245 RegCloseKey(hkey);
2246 return;
2249 MemFree(final);
2252 { /* update MRUList value */
2253 WCHAR old_mru_list[32], new_mru_list[32];
2254 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2255 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2257 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2258 (LPBYTE)old_mru_list, &mru_list_size);
2259 if(ret || key_type != REG_SZ){
2260 if(ret == ERROR_FILE_NOT_FOUND){
2261 new_mru_list[0] = slot;
2262 new_mru_list[1] = '\0';
2263 }else{
2264 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2265 RegCloseKey(hkey);
2266 return;
2268 }else{
2269 /* copy old list data over so that the new slot is at the start
2270 * of the list */
2271 *new_mru_slot++ = slot;
2272 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2273 if(*old_mru_slot != slot)
2274 *new_mru_slot++ = *old_mru_slot;
2276 *new_mru_slot = '\0';
2279 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2280 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2281 if(ret){
2282 WARN("Error saving MRUList data: %d\n", ret);
2283 RegCloseKey(hkey);
2284 return;
2289 /* load the most-recently-used path for this module */
2290 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2292 WCHAR module_path[MAX_PATH], *module_name;
2294 /* get the current executable's name */
2295 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2296 WARN("GotModuleFileName failed: %d\n", GetLastError());
2297 return;
2299 module_name = strrchrW(module_path, '\\');
2300 if(!module_name)
2301 module_name = module_path;
2302 else
2303 module_name += 1;
2305 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2306 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2309 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2311 WCHAR strMsgTitle[MAX_PATH];
2312 WCHAR strMsgText [MAX_PATH];
2313 if (idCaption)
2314 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2315 else
2316 strMsgTitle[0] = '\0';
2317 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2318 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2321 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2322 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2324 int nOpenAction = defAction;
2325 LPWSTR lpszTemp, lpszTemp1;
2326 LPITEMIDLIST pidl = NULL;
2327 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2329 /* check for invalid chars */
2330 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2332 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2333 return FALSE;
2336 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2338 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2339 while (lpszTemp1)
2341 LPSHELLFOLDER lpsfChild;
2342 WCHAR lpwstrTemp[MAX_PATH];
2343 DWORD dwEaten, dwAttributes;
2344 LPWSTR p;
2346 lstrcpyW(lpwstrTemp, lpszTemp);
2347 p = PathFindNextComponentW(lpwstrTemp);
2349 if (!p) break; /* end of path */
2351 *p = 0;
2352 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2354 /* There are no wildcards when OFN_NOVALIDATE is set */
2355 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2357 static const WCHAR wszWild[] = { '*', '?', 0 };
2358 /* if the last element is a wildcard do a search */
2359 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2361 nOpenAction = ONOPEN_SEARCH;
2362 break;
2365 lpszTemp1 = lpszTemp;
2367 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2369 /* append a backslash to drive letters */
2370 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2371 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2372 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2374 PathAddBackslashW(lpwstrTemp);
2377 dwAttributes = SFGAO_FOLDER;
2378 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2380 /* the path component is valid, we have a pidl of the next path component */
2381 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2382 if(dwAttributes & SFGAO_FOLDER)
2384 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2386 ERR("bind to failed\n"); /* should not fail */
2387 break;
2389 IShellFolder_Release(*ppsf);
2390 *ppsf = lpsfChild;
2391 lpsfChild = NULL;
2393 else
2395 TRACE("value\n");
2397 /* end dialog, return value */
2398 nOpenAction = ONOPEN_OPEN;
2399 break;
2401 COMDLG32_SHFree(pidl);
2402 pidl = NULL;
2404 else if (!(flags & OFN_NOVALIDATE))
2406 if(*lpszTemp || /* points to trailing null for last path element */
2407 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2409 if(flags & OFN_PATHMUSTEXIST)
2411 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2412 break;
2415 else
2417 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2419 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2420 break;
2423 /* change to the current folder */
2424 nOpenAction = ONOPEN_OPEN;
2425 break;
2427 else
2429 nOpenAction = ONOPEN_OPEN;
2430 break;
2433 if(pidl) COMDLG32_SHFree(pidl);
2435 return nOpenAction;
2438 /***********************************************************************
2439 * FILEDLG95_OnOpen
2441 * Ok button WM_COMMAND message handler
2443 * If the function succeeds, the return value is nonzero.
2445 BOOL FILEDLG95_OnOpen(HWND hwnd)
2447 LPWSTR lpstrFileList;
2448 UINT nFileCount = 0;
2449 UINT sizeUsed = 0;
2450 BOOL ret = TRUE;
2451 WCHAR lpstrPathAndFile[MAX_PATH];
2452 LPSHELLFOLDER lpsf = NULL;
2453 int nOpenAction;
2454 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2456 TRACE("hwnd=%p\n", hwnd);
2458 /* try to browse the selected item */
2459 if(BrowseSelectedFolder(hwnd))
2460 return FALSE;
2462 /* get the files from the edit control */
2463 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2465 if(nFileCount == 0)
2466 return FALSE;
2468 if(nFileCount > 1)
2470 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2471 goto ret;
2474 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2477 Step 1: Build a complete path name from the current folder and
2478 the filename or path in the edit box.
2479 Special cases:
2480 - the path in the edit box is a root path
2481 (with or without drive letter)
2482 - the edit box contains ".." (or a path with ".." in it)
2485 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2486 MemFree(lpstrFileList);
2489 Step 2: here we have a cleaned up path
2491 We have to parse the path step by step to see if we have to browse
2492 to a folder if the path points to a directory or the last
2493 valid element is a directory.
2495 valid variables:
2496 lpstrPathAndFile: cleaned up path
2499 if (nFileCount &&
2500 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2501 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2502 nOpenAction = ONOPEN_OPEN;
2503 else
2504 nOpenAction = ONOPEN_BROWSE;
2506 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2507 fodInfos->ofnInfos->Flags,
2508 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2509 nOpenAction);
2510 if(!nOpenAction)
2511 goto ret;
2514 Step 3: here we have a cleaned up and validated path
2516 valid variables:
2517 lpsf: ShellFolder bound to the rightmost valid path component
2518 lpstrPathAndFile: cleaned up path
2519 nOpenAction: action to do
2521 TRACE("end validate sf=%p\n", lpsf);
2523 switch(nOpenAction)
2525 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2526 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2528 int iPos;
2529 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2530 DWORD len;
2532 /* replace the current filter */
2533 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2534 len = lstrlenW(lpszTemp)+1;
2535 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2536 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2538 /* set the filter cb to the extension when possible */
2539 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2540 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2542 /* fall through */
2543 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2544 TRACE("ONOPEN_BROWSE\n");
2546 IPersistFolder2 * ppf2;
2547 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2549 LPITEMIDLIST pidlCurrent;
2550 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2551 IPersistFolder2_Release(ppf2);
2552 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2554 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2555 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2557 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2558 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2561 else if( nOpenAction == ONOPEN_SEARCH )
2563 if (fodInfos->Shell.FOIShellView)
2564 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2566 COMDLG32_SHFree(pidlCurrent);
2567 if (filename_is_edit( fodInfos ))
2568 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2569 else
2571 HWND hwnd;
2573 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2574 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2578 ret = FALSE;
2579 break;
2580 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2581 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2583 WCHAR *ext = NULL;
2585 /* update READONLY check box flag */
2586 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2587 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2588 else
2589 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2591 /* Attach the file extension with file name*/
2592 ext = PathFindExtensionW(lpstrPathAndFile);
2593 if (! *ext && fodInfos->defext)
2595 /* if no extension is specified with file name, then */
2596 /* attach the extension from file filter or default one */
2598 WCHAR *filterExt = NULL;
2599 LPWSTR lpstrFilter = NULL;
2600 static const WCHAR szwDot[] = {'.',0};
2601 int PathLength = lstrlenW(lpstrPathAndFile);
2603 /*Get the file extension from file type filter*/
2604 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2605 fodInfos->ofnInfos->nFilterIndex-1);
2607 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2609 WCHAR* filterSearchIndex;
2610 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2611 strcpyW(filterExt, lpstrFilter);
2613 /* if a semicolon-separated list of file extensions was given, do not include the
2614 semicolon or anything after it in the extension.
2615 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2616 filterSearchIndex = strchrW(filterExt, ';');
2617 if (filterSearchIndex)
2619 filterSearchIndex[0] = '\0';
2622 /* find the file extension by searching for the first dot in filterExt */
2623 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2624 /* if the extension is invalid or contains a glob, ignore it */
2625 filterSearchIndex = strchrW(filterExt, '.');
2626 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2628 strcpyW(filterExt, filterSearchIndex);
2630 else
2632 HeapFree(GetProcessHeap(), 0, filterExt);
2633 filterExt = NULL;
2637 if (!filterExt)
2639 /* use the default file extension */
2640 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2641 strcpyW(filterExt, fodInfos->defext);
2644 if (*filterExt) /* ignore filterExt="" */
2646 /* Attach the dot*/
2647 lstrcatW(lpstrPathAndFile, szwDot);
2648 /* Attach the extension */
2649 lstrcatW(lpstrPathAndFile, filterExt);
2652 HeapFree(GetProcessHeap(), 0, filterExt);
2654 /* In Open dialog: if file does not exist try without extension */
2655 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2656 lpstrPathAndFile[PathLength] = '\0';
2658 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2659 if (*ext)
2660 ext++;
2661 if (!lstrcmpiW(fodInfos->defext, ext))
2662 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2663 else
2664 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2667 /* In Save dialog: check if the file already exists */
2668 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2669 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2670 && PathFileExistsW(lpstrPathAndFile))
2672 WCHAR lpstrOverwrite[100];
2673 int answer;
2675 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2676 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2677 MB_YESNO | MB_ICONEXCLAMATION);
2678 if (answer == IDNO || answer == IDCANCEL)
2680 ret = FALSE;
2681 goto ret;
2685 /* In Open dialog: check if it should be created if it doesn't exist */
2686 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2687 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2688 && !PathFileExistsW(lpstrPathAndFile))
2690 WCHAR lpstrCreate[100];
2691 int answer;
2693 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2694 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2695 MB_YESNO | MB_ICONEXCLAMATION);
2696 if (answer == IDNO || answer == IDCANCEL)
2698 ret = FALSE;
2699 goto ret;
2703 /* Check that the size of the file does not exceed buffer size.
2704 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2705 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2706 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2709 /* fill destination buffer */
2710 if (fodInfos->ofnInfos->lpstrFile)
2712 if(fodInfos->unicode)
2714 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2716 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2717 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2718 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2720 else
2722 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2724 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2725 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2726 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2727 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2731 if(fodInfos->unicode)
2733 LPWSTR lpszTemp;
2735 /* set filename offset */
2736 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2737 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2739 /* set extension offset */
2740 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2741 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2743 else
2745 LPSTR lpszTemp;
2746 CHAR tempFileA[MAX_PATH];
2748 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2749 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2750 tempFileA, sizeof(tempFileA), NULL, NULL);
2752 /* set filename offset */
2753 lpszTemp = PathFindFileNameA(tempFileA);
2754 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2756 /* set extension offset */
2757 lpszTemp = PathFindExtensionA(tempFileA);
2758 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2761 /* set the lpstrFileTitle */
2762 if(fodInfos->ofnInfos->lpstrFileTitle)
2764 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2765 if(fodInfos->unicode)
2767 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2768 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2770 else
2772 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2773 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2774 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2778 /* copy currently selected filter to lpstrCustomFilter */
2779 if (fodInfos->ofnInfos->lpstrCustomFilter)
2781 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2782 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2783 NULL, 0, NULL, NULL);
2784 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2786 LPSTR s = ofn->lpstrCustomFilter;
2787 s += strlen(ofn->lpstrCustomFilter)+1;
2788 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2789 s, len, NULL, NULL);
2794 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2795 goto ret;
2797 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2799 TRACE("close\n");
2800 FILEDLG95_Clean(hwnd);
2801 ret = EndDialog(hwnd, TRUE);
2803 else
2805 WORD size;
2807 size = lstrlenW(lpstrPathAndFile) + 1;
2808 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2809 size += 1;
2810 /* return needed size in first two bytes of lpstrFile */
2811 if(fodInfos->ofnInfos->lpstrFile)
2812 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2813 FILEDLG95_Clean(hwnd);
2814 ret = EndDialog(hwnd, FALSE);
2815 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2818 break;
2821 ret:
2822 if(lpsf) IShellFolder_Release(lpsf);
2823 return ret;
2826 /***********************************************************************
2827 * FILEDLG95_SHELL_Init
2829 * Initialisation of the shell objects
2831 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2833 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2835 TRACE("\n");
2838 * Initialisation of the FileOpenDialogInfos structure
2841 /* Shell */
2843 /*ShellInfos */
2844 fodInfos->ShellInfos.hwndOwner = hwnd;
2846 /* Disable multi-select if flag not set */
2847 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2849 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2851 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2852 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2854 /* Construct the IShellBrowser interface */
2855 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2857 return NOERROR;
2860 /***********************************************************************
2861 * FILEDLG95_SHELL_ExecuteCommand
2863 * Change the folder option and refresh the view
2864 * If the function succeeds, the return value is nonzero.
2866 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2868 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2869 IContextMenu * pcm;
2871 TRACE("(%p,%p)\n", hwnd, lpVerb);
2873 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2874 SVGIO_BACKGROUND,
2875 &IID_IContextMenu,
2876 (LPVOID*)&pcm)))
2878 CMINVOKECOMMANDINFO ci;
2879 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2880 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2881 ci.lpVerb = lpVerb;
2882 ci.hwnd = hwnd;
2884 IContextMenu_InvokeCommand(pcm, &ci);
2885 IContextMenu_Release(pcm);
2888 return FALSE;
2891 /***********************************************************************
2892 * FILEDLG95_SHELL_UpFolder
2894 * Browse to the specified object
2895 * If the function succeeds, the return value is nonzero.
2897 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2899 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2901 TRACE("\n");
2903 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2904 NULL,
2905 SBSP_PARENT)))
2907 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2908 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2909 return TRUE;
2911 return FALSE;
2914 /***********************************************************************
2915 * FILEDLG95_SHELL_BrowseToDesktop
2917 * Browse to the Desktop
2918 * If the function succeeds, the return value is nonzero.
2920 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2922 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2923 LPITEMIDLIST pidl;
2924 HRESULT hres;
2926 TRACE("\n");
2928 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2929 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2930 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2931 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2932 COMDLG32_SHFree(pidl);
2933 return SUCCEEDED(hres);
2935 /***********************************************************************
2936 * FILEDLG95_SHELL_Clean
2938 * Cleans the memory used by shell objects
2940 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2942 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2944 TRACE("\n");
2946 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2948 /* clean Shell interfaces */
2949 if (fodInfos->Shell.FOIShellView)
2951 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2952 IShellView_Release(fodInfos->Shell.FOIShellView);
2954 if (fodInfos->Shell.FOIShellFolder)
2955 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2956 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2957 if (fodInfos->Shell.FOIDataObject)
2958 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2961 /***********************************************************************
2962 * FILEDLG95_FILETYPE_Init
2964 * Initialisation of the file type combo box
2966 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2968 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2969 int nFilters = 0; /* number of filters */
2970 int nFilterIndexCB;
2972 TRACE("\n");
2974 if(fodInfos->customfilter)
2976 /* customfilter has one entry... title\0ext\0
2977 * Set first entry of combo box item with customfilter
2979 LPWSTR lpstrExt;
2980 LPCWSTR lpstrPos = fodInfos->customfilter;
2982 /* Get the title */
2983 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2985 /* Copy the extensions */
2986 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2987 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2988 lstrcpyW(lpstrExt,lpstrPos);
2990 /* Add the item at the end of the combo */
2991 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2992 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2993 nFilters++;
2995 if(fodInfos->filter)
2997 LPCWSTR lpstrPos = fodInfos->filter;
2999 for(;;)
3001 /* filter is a list... title\0ext\0......\0\0
3002 * Set the combo item text to the title and the item data
3003 * to the ext
3005 LPCWSTR lpstrDisplay;
3006 LPWSTR lpstrExt;
3008 /* Get the title */
3009 if(! *lpstrPos) break; /* end */
3010 lpstrDisplay = lpstrPos;
3011 lpstrPos += lstrlenW(lpstrPos) + 1;
3013 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
3015 nFilters++;
3017 /* Copy the extensions */
3018 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3019 lstrcpyW(lpstrExt,lpstrPos);
3020 lpstrPos += lstrlenW(lpstrPos) + 1;
3022 /* Add the item at the end of the combo */
3023 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3025 /* malformed filters are added anyway... */
3026 if (!*lpstrExt) break;
3031 * Set the current filter to the one specified
3032 * in the initialisation structure
3034 if (fodInfos->filter || fodInfos->customfilter)
3036 LPWSTR lpstrFilter;
3038 /* Check to make sure our index isn't out of bounds. */
3039 if ( fodInfos->ofnInfos->nFilterIndex >
3040 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3041 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3043 /* set default filter index */
3044 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3045 fodInfos->ofnInfos->nFilterIndex = 1;
3047 /* calculate index of Combo Box item */
3048 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3049 if (fodInfos->customfilter == NULL)
3050 nFilterIndexCB--;
3052 /* Set the current index selection. */
3053 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3055 /* Get the corresponding text string from the combo box. */
3056 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3057 nFilterIndexCB);
3059 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3060 lpstrFilter = NULL;
3062 if(lpstrFilter)
3064 DWORD len;
3065 CharLowerW(lpstrFilter); /* lowercase */
3066 len = lstrlenW(lpstrFilter)+1;
3067 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3068 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3070 } else
3071 fodInfos->ofnInfos->nFilterIndex = 0;
3072 return S_OK;
3075 /***********************************************************************
3076 * FILEDLG95_FILETYPE_OnCommand
3078 * WM_COMMAND of the file type combo box
3079 * If the function succeeds, the return value is nonzero.
3081 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3083 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3085 switch(wNotifyCode)
3087 case CBN_SELENDOK:
3089 LPWSTR lpstrFilter;
3091 /* Get the current item of the filetype combo box */
3092 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3094 /* set the current filter index */
3095 fodInfos->ofnInfos->nFilterIndex = iItem +
3096 (fodInfos->customfilter == NULL ? 1 : 0);
3098 /* Set the current filter with the current selection */
3099 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3101 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3102 iItem);
3103 if((INT_PTR)lpstrFilter != CB_ERR)
3105 DWORD len;
3106 CharLowerW(lpstrFilter); /* lowercase */
3107 len = lstrlenW(lpstrFilter)+1;
3108 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3109 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3110 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3111 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3114 /* Refresh the actual view to display the included items*/
3115 if (fodInfos->Shell.FOIShellView)
3116 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3119 return FALSE;
3121 /***********************************************************************
3122 * FILEDLG95_FILETYPE_SearchExt
3124 * searches for an extension in the filetype box
3126 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3128 int i, iCount = CBGetCount(hwnd);
3130 TRACE("%s\n", debugstr_w(lpstrExt));
3132 if(iCount != CB_ERR)
3134 for(i=0;i<iCount;i++)
3136 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3137 return i;
3140 return -1;
3143 /***********************************************************************
3144 * FILEDLG95_FILETYPE_Clean
3146 * Clean the memory used by the filetype combo box
3148 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3150 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3151 int iPos;
3152 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3154 TRACE("\n");
3156 /* Delete each string of the combo and their associated data */
3157 if(iCount != CB_ERR)
3159 for(iPos = iCount-1;iPos>=0;iPos--)
3161 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3162 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3165 /* Current filter */
3166 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3170 /***********************************************************************
3171 * FILEDLG95_LOOKIN_Init
3173 * Initialisation of the look in combo box
3176 /* Small helper function, to determine if the unixfs shell extension is rooted
3177 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3179 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3180 HKEY hKey;
3181 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3182 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3184 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3185 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3186 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3187 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3189 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3190 return FALSE;
3192 RegCloseKey(hKey);
3193 return TRUE;
3196 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3198 IShellFolder *psfRoot, *psfDrives;
3199 IEnumIDList *lpeRoot, *lpeDrives;
3200 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3201 HDC hdc;
3202 TEXTMETRICW tm;
3203 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3205 TRACE("\n");
3207 liInfos->iMaxIndentation = 0;
3209 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3211 hdc = GetDC( hwndCombo );
3212 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3213 GetTextMetricsW( hdc, &tm );
3214 ReleaseDC( hwndCombo, hdc );
3216 /* set item height for both text field and listbox */
3217 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3218 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3220 /* Turn on the extended UI for the combo box like Windows does */
3221 CBSetExtendedUI(hwndCombo, TRUE);
3223 /* Initialise data of Desktop folder */
3224 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3225 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3226 COMDLG32_SHFree(pidlTmp);
3228 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3230 SHGetDesktopFolder(&psfRoot);
3232 if (psfRoot)
3234 /* enumerate the contents of the desktop */
3235 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3237 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3239 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3241 /* If the unixfs extension is rooted, we don't expand the drives by default */
3242 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3244 /* special handling for CSIDL_DRIVES */
3245 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3247 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3249 /* enumerate the drives */
3250 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3252 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3254 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3255 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3256 COMDLG32_SHFree(pidlAbsTmp);
3257 COMDLG32_SHFree(pidlTmp1);
3259 IEnumIDList_Release(lpeDrives);
3261 IShellFolder_Release(psfDrives);
3266 COMDLG32_SHFree(pidlTmp);
3268 IEnumIDList_Release(lpeRoot);
3270 IShellFolder_Release(psfRoot);
3273 COMDLG32_SHFree(pidlDrives);
3276 /***********************************************************************
3277 * FILEDLG95_LOOKIN_DrawItem
3279 * WM_DRAWITEM message handler
3281 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3283 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3284 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3285 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3286 RECT rectText;
3287 RECT rectIcon;
3288 SHFILEINFOW sfi;
3289 HIMAGELIST ilItemImage;
3290 int iIndentation;
3291 TEXTMETRICW tm;
3292 LPSFOLDER tmpFolder;
3293 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3294 UINT icon_width, icon_height;
3296 TRACE("\n");
3298 if(pDIStruct->itemID == -1)
3299 return 0;
3301 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3302 pDIStruct->itemID)))
3303 return 0;
3306 icon_width = GetSystemMetrics(SM_CXICON);
3307 icon_height = GetSystemMetrics(SM_CYICON);
3308 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3310 icon_width = GetSystemMetrics(SM_CXSMICON);
3311 icon_height = GetSystemMetrics(SM_CYSMICON);
3312 shgfi_flags |= SHGFI_SMALLICON;
3315 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3316 0, &sfi, sizeof (sfi), shgfi_flags );
3318 /* Is this item selected ? */
3319 if(pDIStruct->itemState & ODS_SELECTED)
3321 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3322 SetBkColor(pDIStruct->hDC,crHighLight);
3323 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3325 else
3327 SetTextColor(pDIStruct->hDC,crText);
3328 SetBkColor(pDIStruct->hDC,crWin);
3329 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3332 /* Do not indent item if drawing in the edit of the combo */
3333 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3334 iIndentation = 0;
3335 else
3336 iIndentation = tmpFolder->m_iIndent;
3338 /* Draw text and icon */
3340 /* Initialise the icon display area */
3341 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3342 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3343 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3344 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3346 /* Initialise the text display area */
3347 GetTextMetricsW(pDIStruct->hDC, &tm);
3348 rectText.left = rectIcon.right;
3349 rectText.top =
3350 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3351 rectText.right = pDIStruct->rcItem.right;
3352 rectText.bottom =
3353 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3355 /* Draw the icon from the image list */
3356 ImageList_Draw(ilItemImage,
3357 sfi.iIcon,
3358 pDIStruct->hDC,
3359 rectIcon.left,
3360 rectIcon.top,
3361 ILD_TRANSPARENT );
3363 /* Draw the associated text */
3364 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3365 return NOERROR;
3368 /***********************************************************************
3369 * FILEDLG95_LOOKIN_OnCommand
3371 * LookIn combo box WM_COMMAND message handler
3372 * If the function succeeds, the return value is nonzero.
3374 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3376 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3378 TRACE("%p\n", fodInfos);
3380 switch(wNotifyCode)
3382 case CBN_SELENDOK:
3384 LPSFOLDER tmpFolder;
3385 int iItem;
3387 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3389 if( iItem == CB_ERR) return FALSE;
3391 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3392 iItem)))
3393 return FALSE;
3396 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3397 tmpFolder->pidlItem,
3398 SBSP_ABSOLUTE)))
3400 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3401 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3402 return TRUE;
3404 break;
3408 return FALSE;
3411 /***********************************************************************
3412 * FILEDLG95_LOOKIN_AddItem
3414 * Adds an absolute pidl item to the lookin combo box
3415 * returns the index of the inserted item
3417 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3419 LPITEMIDLIST pidlNext;
3420 SHFILEINFOW sfi;
3421 SFOLDER *tmpFolder;
3422 LookInInfos *liInfos;
3424 TRACE("%08x\n", iInsertId);
3426 if(!pidl)
3427 return -1;
3429 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3430 return -1;
3432 tmpFolder = MemAlloc(sizeof(SFOLDER));
3433 tmpFolder->m_iIndent = 0;
3435 /* Calculate the indentation of the item in the lookin*/
3436 pidlNext = pidl;
3437 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3439 tmpFolder->m_iIndent++;
3442 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3444 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3445 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3447 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3448 SHGetFileInfoW((LPCWSTR)pidl,
3450 &sfi,
3451 sizeof(sfi),
3452 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3453 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3455 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3457 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3459 int iItemID;
3461 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3463 /* Add the item at the end of the list */
3464 if(iInsertId < 0)
3466 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3468 /* Insert the item at the iInsertId position*/
3469 else
3471 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3474 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3475 return iItemID;
3478 COMDLG32_SHFree( tmpFolder->pidlItem );
3479 MemFree( tmpFolder );
3480 return -1;
3484 /***********************************************************************
3485 * FILEDLG95_LOOKIN_InsertItemAfterParent
3487 * Insert an item below its parent
3489 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3492 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3493 int iParentPos;
3495 TRACE("\n");
3497 if (pidl == pidlParent)
3498 return -1;
3500 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3502 if(iParentPos < 0)
3504 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3507 /* Free pidlParent memory */
3508 COMDLG32_SHFree(pidlParent);
3510 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3513 /***********************************************************************
3514 * FILEDLG95_LOOKIN_SelectItem
3516 * Adds an absolute pidl item to the lookin combo box
3517 * returns the index of the inserted item
3519 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3521 int iItemPos;
3522 LookInInfos *liInfos;
3524 TRACE("\n");
3526 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3528 liInfos = GetPropA(hwnd,LookInInfosStr);
3530 if(iItemPos < 0)
3532 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3533 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3536 else
3538 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3539 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3541 int iRemovedItem;
3543 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3544 break;
3545 if(iRemovedItem < iItemPos)
3546 iItemPos--;
3550 CBSetCurSel(hwnd,iItemPos);
3551 liInfos->uSelectedItem = iItemPos;
3553 return 0;
3557 /***********************************************************************
3558 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3560 * Remove the item with an expansion level over iExpansionLevel
3562 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3564 int iItemPos;
3565 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3567 TRACE("\n");
3569 if(liInfos->iMaxIndentation <= 2)
3570 return -1;
3572 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3574 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3575 COMDLG32_SHFree(tmpFolder->pidlItem);
3576 MemFree(tmpFolder);
3577 CBDeleteString(hwnd,iItemPos);
3578 liInfos->iMaxIndentation--;
3580 return iItemPos;
3583 return -1;
3586 /***********************************************************************
3587 * FILEDLG95_LOOKIN_SearchItem
3589 * Search for pidl in the lookin combo box
3590 * returns the index of the found item
3592 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3594 int i = 0;
3595 int iCount = CBGetCount(hwnd);
3597 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3599 if (iCount != CB_ERR)
3601 for(;i<iCount;i++)
3603 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3605 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3606 return i;
3607 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3608 return i;
3612 return -1;
3615 /***********************************************************************
3616 * FILEDLG95_LOOKIN_Clean
3618 * Clean the memory used by the lookin combo box
3620 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3622 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3623 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3624 int iPos;
3625 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3627 TRACE("\n");
3629 /* Delete each string of the combo and their associated data */
3630 if (iCount != CB_ERR)
3632 for(iPos = iCount-1;iPos>=0;iPos--)
3634 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3635 COMDLG32_SHFree(tmpFolder->pidlItem);
3636 MemFree(tmpFolder);
3637 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3641 /* LookInInfos structure */
3642 MemFree(liInfos);
3643 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3646 /***********************************************************************
3647 * get_def_format
3649 * Fill the FORMATETC used in the shell id list
3651 static FORMATETC get_def_format(void)
3653 static CLIPFORMAT cfFormat;
3654 FORMATETC formatetc;
3656 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3657 formatetc.cfFormat = cfFormat;
3658 formatetc.ptd = 0;
3659 formatetc.dwAspect = DVASPECT_CONTENT;
3660 formatetc.lindex = -1;
3661 formatetc.tymed = TYMED_HGLOBAL;
3662 return formatetc;
3665 /***********************************************************************
3666 * FILEDLG95_FILENAME_FillFromSelection
3668 * fills the edit box from the cached DataObject
3670 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3672 FileOpenDlgInfos *fodInfos;
3673 LPITEMIDLIST pidl;
3674 LPWSTR lpstrAllFiles, lpstrTmp;
3675 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3676 STGMEDIUM medium;
3677 LPIDA cida;
3678 FORMATETC formatetc = get_def_format();
3680 TRACE("\n");
3681 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3683 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3684 return;
3686 cida = GlobalLock(medium.u.hGlobal);
3687 nFileSelected = cida->cidl;
3689 /* Allocate a buffer */
3690 nAllFilesMaxLength = MAX_PATH + 3;
3691 lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nAllFilesMaxLength * sizeof(WCHAR));
3692 if (!lpstrAllFiles)
3693 goto ret;
3695 /* Loop through the selection, handle only files (not folders) */
3696 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3698 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3699 if (pidl)
3701 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3703 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3705 nAllFilesMaxLength *= 2;
3706 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3707 if (!lpstrTmp)
3708 goto ret;
3709 lpstrAllFiles = lpstrTmp;
3711 nFiles += 1;
3712 lpstrAllFiles[nAllFilesLength++] = '"';
3713 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3714 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3715 nAllFilesLength += nThisFileLength;
3716 lpstrAllFiles[nAllFilesLength++] = '"';
3717 lpstrAllFiles[nAllFilesLength++] = ' ';
3722 if (nFiles != 0)
3724 /* If there's only one file, use the name as-is without quotes */
3725 lpstrTmp = lpstrAllFiles;
3726 if (nFiles == 1)
3728 lpstrTmp += 1;
3729 lpstrTmp[nThisFileLength] = 0;
3731 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3732 /* Select the file name like Windows does */
3733 if (filename_is_edit(fodInfos))
3734 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3737 ret:
3738 HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
3739 COMCTL32_ReleaseStgMedium(medium);
3743 /* copied from shell32 to avoid linking to it
3744 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3745 * is dependent on whether emulated OS is unicode or not.
3747 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3749 switch (src->uType)
3751 case STRRET_WSTR:
3752 lstrcpynW(dest, src->u.pOleStr, len);
3753 COMDLG32_SHFree(src->u.pOleStr);
3754 break;
3756 case STRRET_CSTR:
3757 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3758 dest[len-1] = 0;
3759 break;
3761 case STRRET_OFFSET:
3762 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3763 dest[len-1] = 0;
3764 break;
3766 default:
3767 FIXME("unknown type %x!\n", src->uType);
3768 if (len) *dest = '\0';
3769 return E_FAIL;
3771 return S_OK;
3774 /***********************************************************************
3775 * FILEDLG95_FILENAME_GetFileNames
3777 * Copies the filenames to a delimited string list.
3779 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3781 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3782 UINT nFileCount = 0; /* number of files */
3783 UINT nStrLen = 0; /* length of string in edit control */
3784 LPWSTR lpstrEdit; /* buffer for string from edit control */
3786 TRACE("\n");
3788 /* get the filenames from the filename control */
3789 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3790 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3791 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3793 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3795 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3796 MemFree(lpstrEdit);
3797 return nFileCount;
3801 * DATAOBJECT Helper functions
3804 /***********************************************************************
3805 * COMCTL32_ReleaseStgMedium
3807 * like ReleaseStgMedium from ole32
3809 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3811 if(medium.pUnkForRelease)
3813 IUnknown_Release(medium.pUnkForRelease);
3815 else
3817 GlobalUnlock(medium.u.hGlobal);
3818 GlobalFree(medium.u.hGlobal);
3822 /***********************************************************************
3823 * GetPidlFromDataObject
3825 * Return pidl(s) by number from the cached DataObject
3827 * nPidlIndex=0 gets the fully qualified root path
3829 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3832 STGMEDIUM medium;
3833 FORMATETC formatetc = get_def_format();
3834 LPITEMIDLIST pidl = NULL;
3836 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3838 if (!doSelected)
3839 return NULL;
3841 /* Get the pidls from IDataObject */
3842 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3844 LPIDA cida = GlobalLock(medium.u.hGlobal);
3845 if(nPidlIndex <= cida->cidl)
3847 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3849 COMCTL32_ReleaseStgMedium(medium);
3851 return pidl;
3854 /***********************************************************************
3855 * GetNumSelected
3857 * Return the number of selected items in the DataObject.
3860 static UINT GetNumSelected( IDataObject *doSelected )
3862 UINT retVal = 0;
3863 STGMEDIUM medium;
3864 FORMATETC formatetc = get_def_format();
3866 TRACE("sv=%p\n", doSelected);
3868 if (!doSelected) return 0;
3870 /* Get the pidls from IDataObject */
3871 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3873 LPIDA cida = GlobalLock(medium.u.hGlobal);
3874 retVal = cida->cidl;
3875 COMCTL32_ReleaseStgMedium(medium);
3876 return retVal;
3878 return 0;
3882 * TOOLS
3885 /***********************************************************************
3886 * GetName
3888 * Get the pidl's display name (relative to folder) and
3889 * put it in lpstrFileName.
3891 * Return NOERROR on success,
3892 * E_FAIL otherwise
3895 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3897 STRRET str;
3898 HRESULT hRes;
3900 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3902 if(!lpsf)
3904 SHGetDesktopFolder(&lpsf);
3905 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3906 IShellFolder_Release(lpsf);
3907 return hRes;
3910 /* Get the display name of the pidl relative to the folder */
3911 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3913 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3915 return E_FAIL;
3918 /***********************************************************************
3919 * GetShellFolderFromPidl
3921 * pidlRel is the item pidl relative
3922 * Return the IShellFolder of the absolute pidl
3924 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3926 IShellFolder *psf = NULL,*psfParent;
3928 TRACE("%p\n", pidlAbs);
3930 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3932 psf = psfParent;
3933 if(pidlAbs && pidlAbs->mkid.cb)
3935 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3937 IShellFolder_Release(psfParent);
3938 return psf;
3941 /* return the desktop */
3942 return psfParent;
3944 return NULL;
3947 /***********************************************************************
3948 * GetParentPidl
3950 * Return the LPITEMIDLIST to the parent of the pidl in the list
3952 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3954 LPITEMIDLIST pidlParent;
3956 TRACE("%p\n", pidl);
3958 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3959 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3961 return pidlParent;
3964 /***********************************************************************
3965 * GetPidlFromName
3967 * returns the pidl of the file name relative to folder
3968 * NULL if an error occurred
3970 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3972 LPITEMIDLIST pidl = NULL;
3973 ULONG ulEaten;
3975 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3977 if(!lpcstrFileName) return NULL;
3978 if(!*lpcstrFileName) return NULL;
3980 if(!lpsf)
3982 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3983 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3984 IShellFolder_Release(lpsf);
3987 else
3989 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3991 return pidl;
3996 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3998 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3999 HRESULT ret;
4001 TRACE("%p, %p\n", psf, pidl);
4003 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4005 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4006 /* see documentation shell 4.1*/
4007 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4010 /***********************************************************************
4011 * BrowseSelectedFolder
4013 static BOOL BrowseSelectedFolder(HWND hwnd)
4015 BOOL bBrowseSelFolder = FALSE;
4016 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4018 TRACE("\n");
4020 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4022 LPITEMIDLIST pidlSelection;
4024 /* get the file selected */
4025 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4026 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4028 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4029 pidlSelection, SBSP_RELATIVE ) ) )
4031 WCHAR buf[64];
4032 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, sizeof(buf)/sizeof(WCHAR) );
4033 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4035 bBrowseSelFolder = TRUE;
4036 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4037 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4039 COMDLG32_SHFree( pidlSelection );
4042 return bBrowseSelFolder;
4046 * Memory allocation methods */
4047 static void *MemAlloc(UINT size)
4049 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4052 static void MemFree(void *mem)
4054 HeapFree(GetProcessHeap(),0,mem);
4057 static inline BOOL valid_struct_size( DWORD size )
4059 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4060 (size == sizeof( OPENFILENAMEW ));
4063 static inline BOOL is_win16_looks(DWORD flags)
4065 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4066 !(flags & OFN_EXPLORER));
4069 /* ------------------ APIs ---------------------- */
4071 /***********************************************************************
4072 * GetOpenFileNameA (COMDLG32.@)
4074 * Creates a dialog box for the user to select a file to open.
4076 * RETURNS
4077 * TRUE on success: user enters a valid file
4078 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4081 BOOL WINAPI GetOpenFileNameA(
4082 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4084 TRACE("flags %08x\n", ofn->Flags);
4086 if (!valid_struct_size( ofn->lStructSize ))
4088 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4089 return FALSE;
4092 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4093 if (ofn->Flags & OFN_FILEMUSTEXIST)
4094 ofn->Flags |= OFN_PATHMUSTEXIST;
4096 if (is_win16_looks(ofn->Flags))
4097 return GetFileName31A(ofn, OPEN_DIALOG);
4098 else
4099 return GetFileDialog95A(ofn, OPEN_DIALOG);
4102 /***********************************************************************
4103 * GetOpenFileNameW (COMDLG32.@)
4105 * Creates a dialog box for the user to select a file to open.
4107 * RETURNS
4108 * TRUE on success: user enters a valid file
4109 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4112 BOOL WINAPI GetOpenFileNameW(
4113 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4115 TRACE("flags %08x\n", ofn->Flags);
4117 if (!valid_struct_size( ofn->lStructSize ))
4119 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4120 return FALSE;
4123 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4124 if (ofn->Flags & OFN_FILEMUSTEXIST)
4125 ofn->Flags |= OFN_PATHMUSTEXIST;
4127 if (is_win16_looks(ofn->Flags))
4128 return GetFileName31W(ofn, OPEN_DIALOG);
4129 else
4130 return GetFileDialog95W(ofn, OPEN_DIALOG);
4134 /***********************************************************************
4135 * GetSaveFileNameA (COMDLG32.@)
4137 * Creates a dialog box for the user to select a file to save.
4139 * RETURNS
4140 * TRUE on success: user enters a valid file
4141 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4144 BOOL WINAPI GetSaveFileNameA(
4145 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4147 if (!valid_struct_size( ofn->lStructSize ))
4149 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4150 return FALSE;
4153 if (is_win16_looks(ofn->Flags))
4154 return GetFileName31A(ofn, SAVE_DIALOG);
4155 else
4156 return GetFileDialog95A(ofn, SAVE_DIALOG);
4159 /***********************************************************************
4160 * GetSaveFileNameW (COMDLG32.@)
4162 * Creates a dialog box for the user to select a file to save.
4164 * RETURNS
4165 * TRUE on success: user enters a valid file
4166 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4169 BOOL WINAPI GetSaveFileNameW(
4170 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4172 if (!valid_struct_size( ofn->lStructSize ))
4174 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4175 return FALSE;
4178 if (is_win16_looks(ofn->Flags))
4179 return GetFileName31W(ofn, SAVE_DIALOG);
4180 else
4181 return GetFileDialog95W(ofn, SAVE_DIALOG);
4184 /***********************************************************************
4185 * GetFileTitleA (COMDLG32.@)
4187 * See GetFileTitleW.
4189 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4191 int ret;
4192 UNICODE_STRING strWFile;
4193 LPWSTR lpWTitle;
4195 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4196 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4197 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4198 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4199 RtlFreeUnicodeString( &strWFile );
4200 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4201 return ret;
4205 /***********************************************************************
4206 * GetFileTitleW (COMDLG32.@)
4208 * Get the name of a file.
4210 * PARAMS
4211 * lpFile [I] name and location of file
4212 * lpTitle [O] returned file name
4213 * cbBuf [I] buffer size of lpTitle
4215 * RETURNS
4216 * Success: zero
4217 * Failure: negative number.
4219 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4221 int i, len;
4222 static const WCHAR brkpoint[] = {'*','[',']',0};
4223 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4225 if(lpFile == NULL || lpTitle == NULL)
4226 return -1;
4228 len = lstrlenW(lpFile);
4230 if (len == 0)
4231 return -1;
4233 if(strpbrkW(lpFile, brkpoint))
4234 return -1;
4236 len--;
4238 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4239 return -1;
4241 for(i = len; i >= 0; i--)
4243 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4245 i++;
4246 break;
4250 if(i == -1)
4251 i++;
4253 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4255 len = lstrlenW(lpFile+i)+1;
4256 if(cbBuf < len)
4257 return len;
4259 lstrcpyW(lpTitle, &lpFile[i]);
4260 return 0;