comdlg32: Use localized "Path does not exist" string.
[wine.git] / dlls / comdlg32 / filedlg.c
blob86575aa394842a478835e53b68976d5a0349babb
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 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2955 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2956 if (fodInfos->Shell.FOIDataObject)
2957 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2960 /***********************************************************************
2961 * FILEDLG95_FILETYPE_Init
2963 * Initialisation of the file type combo box
2965 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2967 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2968 int nFilters = 0; /* number of filters */
2969 int nFilterIndexCB;
2971 TRACE("\n");
2973 if(fodInfos->customfilter)
2975 /* customfilter has one entry... title\0ext\0
2976 * Set first entry of combo box item with customfilter
2978 LPWSTR lpstrExt;
2979 LPCWSTR lpstrPos = fodInfos->customfilter;
2981 /* Get the title */
2982 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2984 /* Copy the extensions */
2985 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2986 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2987 lstrcpyW(lpstrExt,lpstrPos);
2989 /* Add the item at the end of the combo */
2990 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2991 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2992 nFilters++;
2994 if(fodInfos->filter)
2996 LPCWSTR lpstrPos = fodInfos->filter;
2998 for(;;)
3000 /* filter is a list... title\0ext\0......\0\0
3001 * Set the combo item text to the title and the item data
3002 * to the ext
3004 LPCWSTR lpstrDisplay;
3005 LPWSTR lpstrExt;
3007 /* Get the title */
3008 if(! *lpstrPos) break; /* end */
3009 lpstrDisplay = lpstrPos;
3010 lpstrPos += lstrlenW(lpstrPos) + 1;
3012 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
3014 nFilters++;
3016 /* Copy the extensions */
3017 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3018 lstrcpyW(lpstrExt,lpstrPos);
3019 lpstrPos += lstrlenW(lpstrPos) + 1;
3021 /* Add the item at the end of the combo */
3022 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3024 /* malformed filters are added anyway... */
3025 if (!*lpstrExt) break;
3030 * Set the current filter to the one specified
3031 * in the initialisation structure
3033 if (fodInfos->filter || fodInfos->customfilter)
3035 LPWSTR lpstrFilter;
3037 /* Check to make sure our index isn't out of bounds. */
3038 if ( fodInfos->ofnInfos->nFilterIndex >
3039 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3040 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3042 /* set default filter index */
3043 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3044 fodInfos->ofnInfos->nFilterIndex = 1;
3046 /* calculate index of Combo Box item */
3047 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3048 if (fodInfos->customfilter == NULL)
3049 nFilterIndexCB--;
3051 /* Set the current index selection. */
3052 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3054 /* Get the corresponding text string from the combo box. */
3055 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3056 nFilterIndexCB);
3058 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3059 lpstrFilter = NULL;
3061 if(lpstrFilter)
3063 DWORD len;
3064 CharLowerW(lpstrFilter); /* lowercase */
3065 len = lstrlenW(lpstrFilter)+1;
3066 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3067 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3069 } else
3070 fodInfos->ofnInfos->nFilterIndex = 0;
3071 return S_OK;
3074 /***********************************************************************
3075 * FILEDLG95_FILETYPE_OnCommand
3077 * WM_COMMAND of the file type combo box
3078 * If the function succeeds, the return value is nonzero.
3080 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3082 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3084 switch(wNotifyCode)
3086 case CBN_SELENDOK:
3088 LPWSTR lpstrFilter;
3090 /* Get the current item of the filetype combo box */
3091 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3093 /* set the current filter index */
3094 fodInfos->ofnInfos->nFilterIndex = iItem +
3095 (fodInfos->customfilter == NULL ? 1 : 0);
3097 /* Set the current filter with the current selection */
3098 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3100 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3101 iItem);
3102 if((INT_PTR)lpstrFilter != CB_ERR)
3104 DWORD len;
3105 CharLowerW(lpstrFilter); /* lowercase */
3106 len = lstrlenW(lpstrFilter)+1;
3107 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3108 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3109 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3110 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3113 /* Refresh the actual view to display the included items*/
3114 if (fodInfos->Shell.FOIShellView)
3115 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3118 return FALSE;
3120 /***********************************************************************
3121 * FILEDLG95_FILETYPE_SearchExt
3123 * searches for an extension in the filetype box
3125 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3127 int i, iCount = CBGetCount(hwnd);
3129 TRACE("%s\n", debugstr_w(lpstrExt));
3131 if(iCount != CB_ERR)
3133 for(i=0;i<iCount;i++)
3135 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3136 return i;
3139 return -1;
3142 /***********************************************************************
3143 * FILEDLG95_FILETYPE_Clean
3145 * Clean the memory used by the filetype combo box
3147 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3149 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3150 int iPos;
3151 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3153 TRACE("\n");
3155 /* Delete each string of the combo and their associated data */
3156 if(iCount != CB_ERR)
3158 for(iPos = iCount-1;iPos>=0;iPos--)
3160 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3161 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3164 /* Current filter */
3165 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3169 /***********************************************************************
3170 * FILEDLG95_LOOKIN_Init
3172 * Initialisation of the look in combo box
3175 /* Small helper function, to determine if the unixfs shell extension is rooted
3176 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3178 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3179 HKEY hKey;
3180 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3181 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3183 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3184 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3185 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3186 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3188 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3189 return FALSE;
3191 RegCloseKey(hKey);
3192 return TRUE;
3195 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3197 IShellFolder *psfRoot, *psfDrives;
3198 IEnumIDList *lpeRoot, *lpeDrives;
3199 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3200 HDC hdc;
3201 TEXTMETRICW tm;
3202 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3204 TRACE("\n");
3206 liInfos->iMaxIndentation = 0;
3208 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3210 hdc = GetDC( hwndCombo );
3211 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3212 GetTextMetricsW( hdc, &tm );
3213 ReleaseDC( hwndCombo, hdc );
3215 /* set item height for both text field and listbox */
3216 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3217 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3219 /* Turn on the extended UI for the combo box like Windows does */
3220 CBSetExtendedUI(hwndCombo, TRUE);
3222 /* Initialise data of Desktop folder */
3223 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3224 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3225 COMDLG32_SHFree(pidlTmp);
3227 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3229 SHGetDesktopFolder(&psfRoot);
3231 if (psfRoot)
3233 /* enumerate the contents of the desktop */
3234 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3236 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3238 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3240 /* If the unixfs extension is rooted, we don't expand the drives by default */
3241 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3243 /* special handling for CSIDL_DRIVES */
3244 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3246 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3248 /* enumerate the drives */
3249 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3251 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3253 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3254 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3255 COMDLG32_SHFree(pidlAbsTmp);
3256 COMDLG32_SHFree(pidlTmp1);
3258 IEnumIDList_Release(lpeDrives);
3260 IShellFolder_Release(psfDrives);
3265 COMDLG32_SHFree(pidlTmp);
3267 IEnumIDList_Release(lpeRoot);
3269 IShellFolder_Release(psfRoot);
3272 COMDLG32_SHFree(pidlDrives);
3275 /***********************************************************************
3276 * FILEDLG95_LOOKIN_DrawItem
3278 * WM_DRAWITEM message handler
3280 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3282 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3283 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3284 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3285 RECT rectText;
3286 RECT rectIcon;
3287 SHFILEINFOW sfi;
3288 HIMAGELIST ilItemImage;
3289 int iIndentation;
3290 TEXTMETRICW tm;
3291 LPSFOLDER tmpFolder;
3292 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3293 UINT icon_width, icon_height;
3295 TRACE("\n");
3297 if(pDIStruct->itemID == -1)
3298 return 0;
3300 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3301 pDIStruct->itemID)))
3302 return 0;
3305 icon_width = GetSystemMetrics(SM_CXICON);
3306 icon_height = GetSystemMetrics(SM_CYICON);
3307 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3309 icon_width = GetSystemMetrics(SM_CXSMICON);
3310 icon_height = GetSystemMetrics(SM_CYSMICON);
3311 shgfi_flags |= SHGFI_SMALLICON;
3314 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3315 0, &sfi, sizeof (sfi), shgfi_flags );
3317 /* Is this item selected ? */
3318 if(pDIStruct->itemState & ODS_SELECTED)
3320 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3321 SetBkColor(pDIStruct->hDC,crHighLight);
3322 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3324 else
3326 SetTextColor(pDIStruct->hDC,crText);
3327 SetBkColor(pDIStruct->hDC,crWin);
3328 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3331 /* Do not indent item if drawing in the edit of the combo */
3332 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3333 iIndentation = 0;
3334 else
3335 iIndentation = tmpFolder->m_iIndent;
3337 /* Draw text and icon */
3339 /* Initialise the icon display area */
3340 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3341 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3342 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3343 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3345 /* Initialise the text display area */
3346 GetTextMetricsW(pDIStruct->hDC, &tm);
3347 rectText.left = rectIcon.right;
3348 rectText.top =
3349 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3350 rectText.right = pDIStruct->rcItem.right;
3351 rectText.bottom =
3352 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3354 /* Draw the icon from the image list */
3355 ImageList_Draw(ilItemImage,
3356 sfi.iIcon,
3357 pDIStruct->hDC,
3358 rectIcon.left,
3359 rectIcon.top,
3360 ILD_TRANSPARENT );
3362 /* Draw the associated text */
3363 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3364 return NOERROR;
3367 /***********************************************************************
3368 * FILEDLG95_LOOKIN_OnCommand
3370 * LookIn combo box WM_COMMAND message handler
3371 * If the function succeeds, the return value is nonzero.
3373 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3375 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3377 TRACE("%p\n", fodInfos);
3379 switch(wNotifyCode)
3381 case CBN_SELENDOK:
3383 LPSFOLDER tmpFolder;
3384 int iItem;
3386 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3388 if( iItem == CB_ERR) return FALSE;
3390 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3391 iItem)))
3392 return FALSE;
3395 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3396 tmpFolder->pidlItem,
3397 SBSP_ABSOLUTE)))
3399 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3400 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3401 return TRUE;
3403 break;
3407 return FALSE;
3410 /***********************************************************************
3411 * FILEDLG95_LOOKIN_AddItem
3413 * Adds an absolute pidl item to the lookin combo box
3414 * returns the index of the inserted item
3416 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3418 LPITEMIDLIST pidlNext;
3419 SHFILEINFOW sfi;
3420 SFOLDER *tmpFolder;
3421 LookInInfos *liInfos;
3423 TRACE("%08x\n", iInsertId);
3425 if(!pidl)
3426 return -1;
3428 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3429 return -1;
3431 tmpFolder = MemAlloc(sizeof(SFOLDER));
3432 tmpFolder->m_iIndent = 0;
3434 /* Calculate the indentation of the item in the lookin*/
3435 pidlNext = pidl;
3436 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3438 tmpFolder->m_iIndent++;
3441 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3443 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3444 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3446 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3447 SHGetFileInfoW((LPCWSTR)pidl,
3449 &sfi,
3450 sizeof(sfi),
3451 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3452 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3454 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3456 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3458 int iItemID;
3460 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3462 /* Add the item at the end of the list */
3463 if(iInsertId < 0)
3465 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3467 /* Insert the item at the iInsertId position*/
3468 else
3470 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3473 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3474 return iItemID;
3477 COMDLG32_SHFree( tmpFolder->pidlItem );
3478 MemFree( tmpFolder );
3479 return -1;
3483 /***********************************************************************
3484 * FILEDLG95_LOOKIN_InsertItemAfterParent
3486 * Insert an item below its parent
3488 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3491 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3492 int iParentPos;
3494 TRACE("\n");
3496 if (pidl == pidlParent)
3497 return -1;
3499 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3501 if(iParentPos < 0)
3503 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3506 /* Free pidlParent memory */
3507 COMDLG32_SHFree(pidlParent);
3509 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3512 /***********************************************************************
3513 * FILEDLG95_LOOKIN_SelectItem
3515 * Adds an absolute pidl item to the lookin combo box
3516 * returns the index of the inserted item
3518 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3520 int iItemPos;
3521 LookInInfos *liInfos;
3523 TRACE("\n");
3525 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3527 liInfos = GetPropA(hwnd,LookInInfosStr);
3529 if(iItemPos < 0)
3531 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3532 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3535 else
3537 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3538 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3540 int iRemovedItem;
3542 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3543 break;
3544 if(iRemovedItem < iItemPos)
3545 iItemPos--;
3549 CBSetCurSel(hwnd,iItemPos);
3550 liInfos->uSelectedItem = iItemPos;
3552 return 0;
3556 /***********************************************************************
3557 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3559 * Remove the item with an expansion level over iExpansionLevel
3561 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3563 int iItemPos;
3564 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3566 TRACE("\n");
3568 if(liInfos->iMaxIndentation <= 2)
3569 return -1;
3571 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3573 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3574 COMDLG32_SHFree(tmpFolder->pidlItem);
3575 MemFree(tmpFolder);
3576 CBDeleteString(hwnd,iItemPos);
3577 liInfos->iMaxIndentation--;
3579 return iItemPos;
3582 return -1;
3585 /***********************************************************************
3586 * FILEDLG95_LOOKIN_SearchItem
3588 * Search for pidl in the lookin combo box
3589 * returns the index of the found item
3591 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3593 int i = 0;
3594 int iCount = CBGetCount(hwnd);
3596 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3598 if (iCount != CB_ERR)
3600 for(;i<iCount;i++)
3602 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3604 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3605 return i;
3606 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3607 return i;
3611 return -1;
3614 /***********************************************************************
3615 * FILEDLG95_LOOKIN_Clean
3617 * Clean the memory used by the lookin combo box
3619 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3621 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3622 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3623 int iPos;
3624 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3626 TRACE("\n");
3628 /* Delete each string of the combo and their associated data */
3629 if (iCount != CB_ERR)
3631 for(iPos = iCount-1;iPos>=0;iPos--)
3633 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3634 COMDLG32_SHFree(tmpFolder->pidlItem);
3635 MemFree(tmpFolder);
3636 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3640 /* LookInInfos structure */
3641 MemFree(liInfos);
3642 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3645 /***********************************************************************
3646 * get_def_format
3648 * Fill the FORMATETC used in the shell id list
3650 static FORMATETC get_def_format(void)
3652 static CLIPFORMAT cfFormat;
3653 FORMATETC formatetc;
3655 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3656 formatetc.cfFormat = cfFormat;
3657 formatetc.ptd = 0;
3658 formatetc.dwAspect = DVASPECT_CONTENT;
3659 formatetc.lindex = -1;
3660 formatetc.tymed = TYMED_HGLOBAL;
3661 return formatetc;
3664 /***********************************************************************
3665 * FILEDLG95_FILENAME_FillFromSelection
3667 * fills the edit box from the cached DataObject
3669 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3671 FileOpenDlgInfos *fodInfos;
3672 LPITEMIDLIST pidl;
3673 LPWSTR lpstrAllFiles, lpstrTmp;
3674 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3675 STGMEDIUM medium;
3676 LPIDA cida;
3677 FORMATETC formatetc = get_def_format();
3679 TRACE("\n");
3680 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3682 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3683 return;
3685 cida = GlobalLock(medium.u.hGlobal);
3686 nFileSelected = cida->cidl;
3688 /* Allocate a buffer */
3689 nAllFilesMaxLength = MAX_PATH + 3;
3690 lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nAllFilesMaxLength * sizeof(WCHAR));
3691 if (!lpstrAllFiles)
3692 goto ret;
3694 /* Loop through the selection, handle only files (not folders) */
3695 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3697 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3698 if (pidl)
3700 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3702 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3704 nAllFilesMaxLength *= 2;
3705 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3706 if (!lpstrTmp)
3707 goto ret;
3708 lpstrAllFiles = lpstrTmp;
3710 nFiles += 1;
3711 lpstrAllFiles[nAllFilesLength++] = '"';
3712 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3713 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3714 nAllFilesLength += nThisFileLength;
3715 lpstrAllFiles[nAllFilesLength++] = '"';
3716 lpstrAllFiles[nAllFilesLength++] = ' ';
3721 if (nFiles != 0)
3723 /* If there's only one file, use the name as-is without quotes */
3724 lpstrTmp = lpstrAllFiles;
3725 if (nFiles == 1)
3727 lpstrTmp += 1;
3728 lpstrTmp[nThisFileLength] = 0;
3730 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3731 /* Select the file name like Windows does */
3732 if (filename_is_edit(fodInfos))
3733 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3736 ret:
3737 HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
3738 COMCTL32_ReleaseStgMedium(medium);
3742 /* copied from shell32 to avoid linking to it
3743 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3744 * is dependent on whether emulated OS is unicode or not.
3746 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3748 switch (src->uType)
3750 case STRRET_WSTR:
3751 lstrcpynW(dest, src->u.pOleStr, len);
3752 COMDLG32_SHFree(src->u.pOleStr);
3753 break;
3755 case STRRET_CSTR:
3756 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3757 dest[len-1] = 0;
3758 break;
3760 case STRRET_OFFSET:
3761 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3762 dest[len-1] = 0;
3763 break;
3765 default:
3766 FIXME("unknown type %x!\n", src->uType);
3767 if (len) *dest = '\0';
3768 return E_FAIL;
3770 return S_OK;
3773 /***********************************************************************
3774 * FILEDLG95_FILENAME_GetFileNames
3776 * Copies the filenames to a delimited string list.
3778 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3780 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3781 UINT nFileCount = 0; /* number of files */
3782 UINT nStrLen = 0; /* length of string in edit control */
3783 LPWSTR lpstrEdit; /* buffer for string from edit control */
3785 TRACE("\n");
3787 /* get the filenames from the filename control */
3788 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3789 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3790 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3792 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3794 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3795 MemFree(lpstrEdit);
3796 return nFileCount;
3800 * DATAOBJECT Helper functions
3803 /***********************************************************************
3804 * COMCTL32_ReleaseStgMedium
3806 * like ReleaseStgMedium from ole32
3808 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3810 if(medium.pUnkForRelease)
3812 IUnknown_Release(medium.pUnkForRelease);
3814 else
3816 GlobalUnlock(medium.u.hGlobal);
3817 GlobalFree(medium.u.hGlobal);
3821 /***********************************************************************
3822 * GetPidlFromDataObject
3824 * Return pidl(s) by number from the cached DataObject
3826 * nPidlIndex=0 gets the fully qualified root path
3828 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3831 STGMEDIUM medium;
3832 FORMATETC formatetc = get_def_format();
3833 LPITEMIDLIST pidl = NULL;
3835 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3837 if (!doSelected)
3838 return NULL;
3840 /* Get the pidls from IDataObject */
3841 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3843 LPIDA cida = GlobalLock(medium.u.hGlobal);
3844 if(nPidlIndex <= cida->cidl)
3846 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3848 COMCTL32_ReleaseStgMedium(medium);
3850 return pidl;
3853 /***********************************************************************
3854 * GetNumSelected
3856 * Return the number of selected items in the DataObject.
3859 static UINT GetNumSelected( IDataObject *doSelected )
3861 UINT retVal = 0;
3862 STGMEDIUM medium;
3863 FORMATETC formatetc = get_def_format();
3865 TRACE("sv=%p\n", doSelected);
3867 if (!doSelected) return 0;
3869 /* Get the pidls from IDataObject */
3870 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3872 LPIDA cida = GlobalLock(medium.u.hGlobal);
3873 retVal = cida->cidl;
3874 COMCTL32_ReleaseStgMedium(medium);
3875 return retVal;
3877 return 0;
3881 * TOOLS
3884 /***********************************************************************
3885 * GetName
3887 * Get the pidl's display name (relative to folder) and
3888 * put it in lpstrFileName.
3890 * Return NOERROR on success,
3891 * E_FAIL otherwise
3894 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3896 STRRET str;
3897 HRESULT hRes;
3899 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3901 if(!lpsf)
3903 SHGetDesktopFolder(&lpsf);
3904 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3905 IShellFolder_Release(lpsf);
3906 return hRes;
3909 /* Get the display name of the pidl relative to the folder */
3910 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3912 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3914 return E_FAIL;
3917 /***********************************************************************
3918 * GetShellFolderFromPidl
3920 * pidlRel is the item pidl relative
3921 * Return the IShellFolder of the absolute pidl
3923 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3925 IShellFolder *psf = NULL,*psfParent;
3927 TRACE("%p\n", pidlAbs);
3929 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3931 psf = psfParent;
3932 if(pidlAbs && pidlAbs->mkid.cb)
3934 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3936 IShellFolder_Release(psfParent);
3937 return psf;
3940 /* return the desktop */
3941 return psfParent;
3943 return NULL;
3946 /***********************************************************************
3947 * GetParentPidl
3949 * Return the LPITEMIDLIST to the parent of the pidl in the list
3951 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3953 LPITEMIDLIST pidlParent;
3955 TRACE("%p\n", pidl);
3957 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3958 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3960 return pidlParent;
3963 /***********************************************************************
3964 * GetPidlFromName
3966 * returns the pidl of the file name relative to folder
3967 * NULL if an error occurred
3969 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3971 LPITEMIDLIST pidl = NULL;
3972 ULONG ulEaten;
3974 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3976 if(!lpcstrFileName) return NULL;
3977 if(!*lpcstrFileName) return NULL;
3979 if(!lpsf)
3981 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3982 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3983 IShellFolder_Release(lpsf);
3986 else
3988 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3990 return pidl;
3995 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3997 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3998 HRESULT ret;
4000 TRACE("%p, %p\n", psf, pidl);
4002 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4004 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4005 /* see documentation shell 4.1*/
4006 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4009 /***********************************************************************
4010 * BrowseSelectedFolder
4012 static BOOL BrowseSelectedFolder(HWND hwnd)
4014 BOOL bBrowseSelFolder = FALSE;
4015 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4017 TRACE("\n");
4019 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4021 LPITEMIDLIST pidlSelection;
4023 /* get the file selected */
4024 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4025 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4027 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4028 pidlSelection, SBSP_RELATIVE ) ) )
4030 WCHAR buf[64];
4031 LoadStringW( COMDLG32_hInstance, IDS_PATHNOTEXISTING, buf, sizeof(buf)/sizeof(WCHAR) );
4032 MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4034 bBrowseSelFolder = TRUE;
4035 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4036 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4038 COMDLG32_SHFree( pidlSelection );
4041 return bBrowseSelFolder;
4045 * Memory allocation methods */
4046 static void *MemAlloc(UINT size)
4048 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4051 static void MemFree(void *mem)
4053 HeapFree(GetProcessHeap(),0,mem);
4056 static inline BOOL valid_struct_size( DWORD size )
4058 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4059 (size == sizeof( OPENFILENAMEW ));
4062 static inline BOOL is_win16_looks(DWORD flags)
4064 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4065 !(flags & OFN_EXPLORER));
4068 /* ------------------ APIs ---------------------- */
4070 /***********************************************************************
4071 * GetOpenFileNameA (COMDLG32.@)
4073 * Creates a dialog box for the user to select a file to open.
4075 * RETURNS
4076 * TRUE on success: user enters a valid file
4077 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4080 BOOL WINAPI GetOpenFileNameA(
4081 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4083 TRACE("flags %08x\n", ofn->Flags);
4085 if (!valid_struct_size( ofn->lStructSize ))
4087 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4088 return FALSE;
4091 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4092 if (ofn->Flags & OFN_FILEMUSTEXIST)
4093 ofn->Flags |= OFN_PATHMUSTEXIST;
4095 if (is_win16_looks(ofn->Flags))
4096 return GetFileName31A(ofn, OPEN_DIALOG);
4097 else
4098 return GetFileDialog95A(ofn, OPEN_DIALOG);
4101 /***********************************************************************
4102 * GetOpenFileNameW (COMDLG32.@)
4104 * Creates a dialog box for the user to select a file to open.
4106 * RETURNS
4107 * TRUE on success: user enters a valid file
4108 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4111 BOOL WINAPI GetOpenFileNameW(
4112 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4114 TRACE("flags %08x\n", ofn->Flags);
4116 if (!valid_struct_size( ofn->lStructSize ))
4118 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4119 return FALSE;
4122 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4123 if (ofn->Flags & OFN_FILEMUSTEXIST)
4124 ofn->Flags |= OFN_PATHMUSTEXIST;
4126 if (is_win16_looks(ofn->Flags))
4127 return GetFileName31W(ofn, OPEN_DIALOG);
4128 else
4129 return GetFileDialog95W(ofn, OPEN_DIALOG);
4133 /***********************************************************************
4134 * GetSaveFileNameA (COMDLG32.@)
4136 * Creates a dialog box for the user to select a file to save.
4138 * RETURNS
4139 * TRUE on success: user enters a valid file
4140 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4143 BOOL WINAPI GetSaveFileNameA(
4144 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4146 if (!valid_struct_size( ofn->lStructSize ))
4148 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4149 return FALSE;
4152 if (is_win16_looks(ofn->Flags))
4153 return GetFileName31A(ofn, SAVE_DIALOG);
4154 else
4155 return GetFileDialog95A(ofn, SAVE_DIALOG);
4158 /***********************************************************************
4159 * GetSaveFileNameW (COMDLG32.@)
4161 * Creates a dialog box for the user to select a file to save.
4163 * RETURNS
4164 * TRUE on success: user enters a valid file
4165 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4168 BOOL WINAPI GetSaveFileNameW(
4169 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4171 if (!valid_struct_size( ofn->lStructSize ))
4173 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4174 return FALSE;
4177 if (is_win16_looks(ofn->Flags))
4178 return GetFileName31W(ofn, SAVE_DIALOG);
4179 else
4180 return GetFileDialog95W(ofn, SAVE_DIALOG);
4183 /***********************************************************************
4184 * GetFileTitleA (COMDLG32.@)
4186 * See GetFileTitleW.
4188 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4190 int ret;
4191 UNICODE_STRING strWFile;
4192 LPWSTR lpWTitle;
4194 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4195 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4196 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4197 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4198 RtlFreeUnicodeString( &strWFile );
4199 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4200 return ret;
4204 /***********************************************************************
4205 * GetFileTitleW (COMDLG32.@)
4207 * Get the name of a file.
4209 * PARAMS
4210 * lpFile [I] name and location of file
4211 * lpTitle [O] returned file name
4212 * cbBuf [I] buffer size of lpTitle
4214 * RETURNS
4215 * Success: zero
4216 * Failure: negative number.
4218 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4220 int i, len;
4221 static const WCHAR brkpoint[] = {'*','[',']',0};
4222 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4224 if(lpFile == NULL || lpTitle == NULL)
4225 return -1;
4227 len = lstrlenW(lpFile);
4229 if (len == 0)
4230 return -1;
4232 if(strpbrkW(lpFile, brkpoint))
4233 return -1;
4235 len--;
4237 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4238 return -1;
4240 for(i = len; i >= 0; i--)
4242 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4244 i++;
4245 break;
4249 if(i == -1)
4250 i++;
4252 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4254 len = lstrlenW(lpFile+i)+1;
4255 if(cbBuf < len)
4256 return len;
4258 lstrcpyW(lpTitle, &lpFile[i]);
4259 return 0;