winmm: Add support for MEVT_LONGMSG.
[wine/multimedia.git] / dlls / comdlg32 / filedlg.c
blob1e39d192c85a24ae4aa79cffc2134b3e209d9857
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlobj.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
109 /***********************************************************************
110 * Defines and global variables
113 /* Draw item constant */
114 #define ICONWIDTH 18
115 #define XTEXTOFFSET 3
117 /* AddItem flags*/
118 #define LISTEND -1
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
122 #define SEARCH_EXP 2
123 #define ITEM_NOTFOUND -1
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
128 /* NOTE
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
172 static const WCHAR LastVisitedMRUW[] =
173 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
176 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
177 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
179 /***********************************************************************
180 * Prototypes
183 /* Internal functions used by the dialog */
184 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 static BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Functions for dealing with the most-recently-used registry keys */
220 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
221 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
222 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
224 /* Miscellaneous tool functions */
225 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
226 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
227 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
228 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
229 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
230 static UINT GetNumSelected( IDataObject *doSelected );
232 /* Shell memory allocation */
233 static void *MemAlloc(UINT size);
234 static void MemFree(void *mem);
236 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
237 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
238 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
239 static BOOL BrowseSelectedFolder(HWND hwnd);
241 /***********************************************************************
242 * GetFileName95
244 * Creates an Open common dialog box that lets the user select
245 * the drive, directory, and the name of a file or set of files to open.
247 * IN : The FileOpenDlgInfos structure associated with the dialog
248 * OUT : TRUE on success
249 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
251 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
254 LRESULT lRes;
255 LPVOID template;
256 HRSRC hRes;
257 HANDLE hDlgTmpl = 0;
258 HRESULT hr;
260 /* test for missing functionality */
261 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
263 FIXME("Flags 0x%08x not yet implemented\n",
264 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
267 /* Create the dialog from a template */
269 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
271 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
272 return FALSE;
274 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
275 !(template = LockResource( hDlgTmpl )))
277 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
278 return FALSE;
281 /* msdn: explorer style dialogs permit sizing by default.
282 * The OFN_ENABLESIZING flag is only needed when a hook or
283 * custom tmeplate is provided */
284 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
285 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
286 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
288 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
290 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
291 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
292 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
294 else
295 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
298 /* old style hook messages */
299 if (IsHooked(fodInfos))
301 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
302 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
303 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
304 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
307 /* Some shell namespace extensions depend on COM being initialized. */
308 hr = OleInitialize(NULL);
310 if (fodInfos->unicode)
311 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
312 template,
313 fodInfos->ofnInfos->hwndOwner,
314 FileOpenDlgProc95,
315 (LPARAM) fodInfos);
316 else
317 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
318 template,
319 fodInfos->ofnInfos->hwndOwner,
320 FileOpenDlgProc95,
321 (LPARAM) fodInfos);
322 if (SUCCEEDED(hr))
323 OleUninitialize();
325 /* Unable to create the dialog */
326 if( lRes == -1)
327 return FALSE;
329 return lRes;
332 /***********************************************************************
333 * GetFileDialog95A
335 * Call GetFileName95 with this structure and clean the memory.
337 * IN : The OPENFILENAMEA initialisation structure passed to
338 * GetOpenFileNameA win api function (see filedlg.c)
340 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
342 BOOL ret;
343 FileOpenDlgInfos fodInfos;
344 LPSTR lpstrSavDir = NULL;
345 LPWSTR title = NULL;
346 LPWSTR defext = NULL;
347 LPWSTR filter = NULL;
348 LPWSTR customfilter = NULL;
350 /* Initialize CommDlgExtendedError() */
351 COMDLG32_SetCommDlgExtendedError(0);
353 /* Initialize FileOpenDlgInfos structure */
354 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
356 /* Pass in the original ofn */
357 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
359 /* save current directory */
360 if (ofn->Flags & OFN_NOCHANGEDIR)
362 lpstrSavDir = MemAlloc(MAX_PATH);
363 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
366 fodInfos.unicode = FALSE;
368 /* convert all the input strings to unicode */
369 if(ofn->lpstrInitialDir)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
372 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
375 else
376 fodInfos.initdir = NULL;
378 if(ofn->lpstrFile)
380 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
383 else
384 fodInfos.filename = NULL;
386 if(ofn->lpstrDefExt)
388 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
389 defext = MemAlloc((len+1)*sizeof(WCHAR));
390 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
392 fodInfos.defext = defext;
394 if(ofn->lpstrTitle)
396 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
397 title = MemAlloc((len+1)*sizeof(WCHAR));
398 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
400 fodInfos.title = title;
402 if (ofn->lpstrFilter)
404 LPCSTR s;
405 int n, len;
407 /* filter is a list... title\0ext\0......\0\0 */
408 s = ofn->lpstrFilter;
409 while (*s) s = s+strlen(s)+1;
410 s++;
411 n = s - ofn->lpstrFilter;
412 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
413 filter = MemAlloc(len*sizeof(WCHAR));
414 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
416 fodInfos.filter = filter;
418 /* convert lpstrCustomFilter */
419 if (ofn->lpstrCustomFilter)
421 LPCSTR s;
422 int n, len;
424 /* customfilter contains a pair of strings... title\0ext\0 */
425 s = ofn->lpstrCustomFilter;
426 if (*s) s = s+strlen(s)+1;
427 if (*s) s = s+strlen(s)+1;
428 n = s - ofn->lpstrCustomFilter;
429 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
430 customfilter = MemAlloc(len*sizeof(WCHAR));
431 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
433 fodInfos.customfilter = customfilter;
435 /* Initialize the dialog property */
436 fodInfos.DlgInfos.dwDlgProp = 0;
437 fodInfos.DlgInfos.hwndCustomDlg = NULL;
439 switch(iDlgType)
441 case OPEN_DIALOG :
442 ret = GetFileName95(&fodInfos);
443 break;
444 case SAVE_DIALOG :
445 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
446 ret = GetFileName95(&fodInfos);
447 break;
448 default :
449 ret = 0;
452 if (lpstrSavDir)
454 SetCurrentDirectoryA(lpstrSavDir);
455 MemFree(lpstrSavDir);
458 MemFree(title);
459 MemFree(defext);
460 MemFree(filter);
461 MemFree(customfilter);
462 MemFree(fodInfos.initdir);
463 MemFree(fodInfos.filename);
465 TRACE("selected file: %s\n",ofn->lpstrFile);
467 return ret;
470 /***********************************************************************
471 * GetFileDialog95W
473 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
474 * Call GetFileName95 with this structure and clean the memory.
477 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
479 BOOL ret;
480 FileOpenDlgInfos fodInfos;
481 LPWSTR lpstrSavDir = NULL;
483 /* Initialize CommDlgExtendedError() */
484 COMDLG32_SetCommDlgExtendedError(0);
486 /* Initialize FileOpenDlgInfos structure */
487 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
489 /* Pass in the original ofn */
490 fodInfos.ofnInfos = ofn;
492 fodInfos.title = ofn->lpstrTitle;
493 fodInfos.defext = ofn->lpstrDefExt;
494 fodInfos.filter = ofn->lpstrFilter;
495 fodInfos.customfilter = ofn->lpstrCustomFilter;
497 /* convert string arguments, save others */
498 if(ofn->lpstrFile)
500 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
501 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
503 else
504 fodInfos.filename = NULL;
506 if(ofn->lpstrInitialDir)
508 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
509 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
510 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
511 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
513 else
514 fodInfos.initdir = NULL;
516 /* save current directory */
517 if (ofn->Flags & OFN_NOCHANGEDIR)
519 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
520 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
523 fodInfos.unicode = TRUE;
525 switch(iDlgType)
527 case OPEN_DIALOG :
528 ret = GetFileName95(&fodInfos);
529 break;
530 case SAVE_DIALOG :
531 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
532 ret = GetFileName95(&fodInfos);
533 break;
534 default :
535 ret = 0;
538 if (lpstrSavDir)
540 SetCurrentDirectoryW(lpstrSavDir);
541 MemFree(lpstrSavDir);
544 /* restore saved IN arguments and convert OUT arguments back */
545 MemFree(fodInfos.filename);
546 MemFree(fodInfos.initdir);
547 return ret;
550 /******************************************************************************
551 * COMDLG32_GetDisplayNameOf [internal]
553 * Helper function to get the display name for a pidl.
555 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
556 LPSHELLFOLDER psfDesktop;
557 STRRET strret;
559 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
560 return FALSE;
562 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
563 IShellFolder_Release(psfDesktop);
564 return FALSE;
567 IShellFolder_Release(psfDesktop);
568 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
571 /******************************************************************************
572 * COMDLG32_GetCanonicalPath [internal]
574 * Helper function to get the canonical path.
576 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
577 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
579 WCHAR lpstrTemp[MAX_PATH];
581 /* Get the current directory name */
582 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
584 /* last fallback */
585 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
587 PathAddBackslashW(lpstrPathAndFile);
589 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
591 /* if the user specified a fully qualified path use it */
592 if(PathIsRelativeW(lpstrFile))
594 lstrcatW(lpstrPathAndFile, lpstrFile);
596 else
598 /* does the path have a drive letter? */
599 if (PathGetDriveNumberW(lpstrFile) == -1)
600 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
601 else
602 lstrcpyW(lpstrPathAndFile, lpstrFile);
605 /* resolve "." and ".." */
606 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
607 lstrcpyW(lpstrPathAndFile, lpstrTemp);
608 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
611 /***********************************************************************
612 * COMDLG32_SplitFileNames [internal]
614 * Creates a delimited list of filenames.
616 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
618 UINT nStrCharCount = 0; /* index in src buffer */
619 UINT nFileIndex = 0; /* index in dest buffer */
620 UINT nFileCount = 0; /* number of files */
622 /* we might get single filename without any '"',
623 * so we need nStrLen + terminating \0 + end-of-list \0 */
624 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
625 *sizeUsed = 0;
627 /* build delimited file list from filenames */
628 while ( nStrCharCount <= nStrLen )
630 if ( lpstrEdit[nStrCharCount]=='"' )
632 nStrCharCount++;
633 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
635 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
636 nStrCharCount++;
638 (*lpstrFileList)[nFileIndex++] = 0;
639 nFileCount++;
641 nStrCharCount++;
644 /* single, unquoted string */
645 if ((nStrLen > 0) && (nFileIndex == 0) )
647 lstrcpyW(*lpstrFileList, lpstrEdit);
648 nFileIndex = lstrlenW(lpstrEdit) + 1;
649 nFileCount = 1;
652 /* trailing \0 */
653 (*lpstrFileList)[nFileIndex++] = '\0';
655 *sizeUsed = nFileIndex;
656 return nFileCount;
659 /***********************************************************************
660 * ArrangeCtrlPositions [internal]
662 * NOTE: Make sure to add testcases for any changes made here.
664 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
666 HWND hwndChild, hwndStc32;
667 RECT rectParent, rectChild, rectStc32;
668 INT help_fixup = 0;
669 int chgx, chgy;
671 /* Take into account if open as read only checkbox and help button
672 * are hidden
674 if (hide_help)
676 RECT rectHelp, rectCancel;
677 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
678 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
679 /* subtract the height of the help button plus the space between
680 * the help button and the cancel button to the height of the dialog
682 help_fixup = rectHelp.bottom - rectCancel.bottom;
686 There are two possibilities to add components to the default file dialog box.
688 By default, all the new components are added below the standard dialog box (the else case).
690 However, if there is a static text component with the stc32 id, a special case happens.
691 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
692 in the window and the cx and cy indicate how to size the window.
693 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
694 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
698 GetClientRect(hwndParentDlg, &rectParent);
700 /* when arranging controls we have to use fixed parent size */
701 rectParent.bottom -= help_fixup;
703 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
704 if (hwndStc32)
706 GetWindowRect(hwndStc32, &rectStc32);
707 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
709 /* set the size of the stc32 control according to the size of
710 * client area of the parent dialog
712 SetWindowPos(hwndStc32, 0,
713 0, 0,
714 rectParent.right, rectParent.bottom,
715 SWP_NOMOVE | SWP_NOZORDER);
717 else
718 SetRectEmpty(&rectStc32);
720 /* this part moves controls of the child dialog */
721 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
722 while (hwndChild)
724 if (hwndChild != hwndStc32)
726 GetWindowRect(hwndChild, &rectChild);
727 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
729 /* move only if stc32 exist */
730 if (hwndStc32 && rectChild.left > rectStc32.right)
732 /* move to the right of visible controls of the parent dialog */
733 rectChild.left += rectParent.right;
734 rectChild.left -= rectStc32.right;
736 /* move even if stc32 doesn't exist */
737 if (rectChild.top >= rectStc32.bottom)
739 /* move below visible controls of the parent dialog */
740 rectChild.top += rectParent.bottom;
741 rectChild.top -= rectStc32.bottom - rectStc32.top;
744 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
745 0, 0, SWP_NOSIZE | SWP_NOZORDER);
747 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
750 /* this part moves controls of the parent dialog */
751 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
752 while (hwndChild)
754 if (hwndChild != hwndChildDlg)
756 GetWindowRect(hwndChild, &rectChild);
757 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
759 /* left,top of stc32 marks the position of controls
760 * from the parent dialog
762 rectChild.left += rectStc32.left;
763 rectChild.top += rectStc32.top;
765 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
766 0, 0, SWP_NOSIZE | SWP_NOZORDER);
768 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
771 /* calculate the size of the resulting dialog */
773 /* here we have to use original parent size */
774 GetClientRect(hwndParentDlg, &rectParent);
775 GetClientRect(hwndChildDlg, &rectChild);
776 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
777 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
779 if (hwndStc32)
781 /* width */
782 if (rectParent.right > rectStc32.right - rectStc32.left)
783 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
784 else
785 chgx = rectChild.right - rectParent.right;
786 /* height */
787 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
788 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
789 else
790 /* Unconditionally set new dialog
791 * height to that of the child
793 chgy = rectChild.bottom - rectParent.bottom;
795 else
797 chgx = 0;
798 chgy = rectChild.bottom - help_fixup;
800 /* set the size of the parent dialog */
801 GetWindowRect(hwndParentDlg, &rectParent);
802 SetWindowPos(hwndParentDlg, 0,
803 0, 0,
804 rectParent.right - rectParent.left + chgx,
805 rectParent.bottom - rectParent.top + chgy,
806 SWP_NOMOVE | SWP_NOZORDER);
809 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
811 switch(uMsg) {
812 case WM_INITDIALOG:
813 return TRUE;
815 return FALSE;
818 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
820 LPCVOID template;
821 HRSRC hRes;
822 HANDLE hDlgTmpl = 0;
823 HWND hChildDlg = 0;
825 TRACE("\n");
828 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
829 * structure's hInstance parameter is not a HINSTANCE, but
830 * instead a pointer to a template resource to use.
832 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
834 HINSTANCE hinst;
835 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
837 hinst = COMDLG32_hInstance;
838 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
840 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
841 return NULL;
844 else
846 hinst = fodInfos->ofnInfos->hInstance;
847 if(fodInfos->unicode)
849 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
850 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
852 else
854 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
855 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
857 if (!hRes)
859 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
860 return NULL;
862 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
863 !(template = LockResource( hDlgTmpl )))
865 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
866 return NULL;
869 if (fodInfos->unicode)
870 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
871 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
872 (LPARAM)fodInfos->ofnInfos);
873 else
874 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
875 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
876 (LPARAM)fodInfos->ofnInfos);
877 return hChildDlg;
879 else if( IsHooked(fodInfos))
881 RECT rectHwnd;
882 struct {
883 DLGTEMPLATE tmplate;
884 WORD menu,class,title;
885 } temp;
886 GetClientRect(hwnd,&rectHwnd);
887 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
888 temp.tmplate.dwExtendedStyle = 0;
889 temp.tmplate.cdit = 0;
890 temp.tmplate.x = 0;
891 temp.tmplate.y = 0;
892 temp.tmplate.cx = 0;
893 temp.tmplate.cy = 0;
894 temp.menu = temp.class = temp.title = 0;
896 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
897 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
899 return hChildDlg;
901 return NULL;
904 /***********************************************************************
905 * SendCustomDlgNotificationMessage
907 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
910 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
912 LRESULT hook_result = 0;
913 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
915 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
917 if(!fodInfos) return 0;
919 if(fodInfos->DlgInfos.hwndCustomDlg)
921 TRACE("CALL NOTIFY for %x\n", uCode);
922 if(fodInfos->unicode)
924 OFNOTIFYW ofnNotify;
925 ofnNotify.hdr.hwndFrom=hwndParentDlg;
926 ofnNotify.hdr.idFrom=0;
927 ofnNotify.hdr.code = uCode;
928 ofnNotify.lpOFN = fodInfos->ofnInfos;
929 ofnNotify.pszFile = NULL;
930 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
932 else
934 OFNOTIFYA ofnNotify;
935 ofnNotify.hdr.hwndFrom=hwndParentDlg;
936 ofnNotify.hdr.idFrom=0;
937 ofnNotify.hdr.code = uCode;
938 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
939 ofnNotify.pszFile = NULL;
940 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
942 TRACE("RET NOTIFY\n");
944 TRACE("Retval: 0x%08lx\n", hook_result);
945 return hook_result;
948 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
950 UINT len, total;
951 WCHAR *p, *buffer;
952 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
954 TRACE("CDM_GETFILEPATH:\n");
956 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
957 return -1;
959 /* get path and filenames */
960 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
961 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
962 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
963 if (len)
965 p = buffer + strlenW(buffer);
966 *p++ = '\\';
967 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
969 if (fodInfos->unicode)
971 total = strlenW( buffer) + 1;
972 if (result) lstrcpynW( result, buffer, size );
973 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
975 else
977 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
978 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
979 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
981 HeapFree( GetProcessHeap(), 0, buffer );
982 return total;
985 /***********************************************************************
986 * FILEDLG95_HandleCustomDialogMessages
988 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
990 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
992 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
993 WCHAR lpstrPath[MAX_PATH];
994 INT_PTR retval;
996 if(!fodInfos) return FALSE;
998 switch(uMsg)
1000 case CDM_GETFILEPATH:
1001 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1002 break;
1004 case CDM_GETFOLDERPATH:
1005 TRACE("CDM_GETFOLDERPATH:\n");
1006 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1007 if (lParam)
1009 if (fodInfos->unicode)
1010 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1011 else
1012 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1013 (LPSTR)lParam, (int)wParam, NULL, NULL);
1015 retval = lstrlenW(lpstrPath) + 1;
1016 break;
1018 case CDM_GETFOLDERIDLIST:
1019 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1020 if (retval <= wParam)
1021 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1022 break;
1024 case CDM_GETSPEC:
1025 TRACE("CDM_GETSPEC:\n");
1026 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1027 if (lParam)
1029 if (fodInfos->unicode)
1030 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1031 else
1032 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1034 break;
1036 case CDM_SETCONTROLTEXT:
1037 TRACE("CDM_SETCONTROLTEXT:\n");
1038 if ( lParam )
1040 if( fodInfos->unicode )
1041 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1042 else
1043 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1045 retval = TRUE;
1046 break;
1048 case CDM_HIDECONTROL:
1049 /* MSDN states that it should fail for not OFN_EXPLORER case */
1050 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1052 HWND control = GetDlgItem( hwnd, wParam );
1053 if (control) ShowWindow( control, SW_HIDE );
1054 retval = TRUE;
1056 else retval = FALSE;
1057 break;
1059 default:
1060 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1061 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1062 return FALSE;
1064 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1065 return TRUE;
1068 /***********************************************************************
1069 * FILEDLG95_OnWMGetMMI
1071 * WM_GETMINMAXINFO message handler for resizable dialogs
1073 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1075 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1076 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1077 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1079 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1081 return TRUE;
1084 /***********************************************************************
1085 * FILEDLG95_OnWMSize
1087 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1089 * FIXME: this could be made more elaborate. Now use a simple scheme
1090 * where the file view is enlarged and the controls are either moved
1091 * vertically or horizontally to get out of the way. Only the "grip"
1092 * is moved in both directions to stay in the corner.
1094 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1096 RECT rc, rcview;
1097 int chgx, chgy;
1098 HWND ctrl;
1099 HDWP hdwp;
1100 FileOpenDlgInfos *fodInfos;
1102 if( wParam != SIZE_RESTORED) return FALSE;
1103 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1104 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1105 /* get the new dialog rectangle */
1106 GetWindowRect( hwnd, &rc);
1107 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1108 rc.right -rc.left, rc.bottom -rc.top);
1109 /* not initialized yet */
1110 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1111 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1112 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1113 return FALSE;
1114 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1115 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1116 fodInfos->sizedlg.cx = rc.right - rc.left;
1117 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1118 /* change the size of the view window */
1119 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1120 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1121 hdwp = BeginDeferWindowPos( 10);
1122 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1123 rcview.right - rcview.left + chgx,
1124 rcview.bottom - rcview.top + chgy,
1125 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1126 /* change position and sizes of the controls */
1127 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1129 int ctrlid = GetDlgCtrlID( ctrl);
1130 GetWindowRect( ctrl, &rc);
1131 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1132 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1134 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1135 0, 0,
1136 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1138 else if( rc.top > rcview.bottom)
1140 /* if it was below the shell view
1141 * move to bottom */
1142 switch( ctrlid)
1144 /* file name box and file types combo change also width */
1145 case edt1:
1146 case cmb1:
1147 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1148 rc.right - rc.left + chgx, rc.bottom - rc.top,
1149 SWP_NOACTIVATE | SWP_NOZORDER);
1150 break;
1151 /* then these buttons must move out of the way */
1152 case IDOK:
1153 case IDCANCEL:
1154 case pshHelp:
1155 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1156 0, 0,
1157 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1158 break;
1159 default:
1160 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1161 0, 0,
1162 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1165 else if( rc.left > rcview.right)
1167 /* if it was to the right of the shell view
1168 * move to right */
1169 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1170 0, 0,
1171 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1173 else
1174 /* special cases */
1176 switch( ctrlid)
1178 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1179 case IDC_LOOKIN:
1180 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1181 rc.right - rc.left + chgx, rc.bottom - rc.top,
1182 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1183 break;
1184 case IDC_TOOLBARSTATIC:
1185 case IDC_TOOLBAR:
1186 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1187 0, 0,
1188 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1189 break;
1190 #endif
1191 /* not resized in windows. Since wine uses this invisible control
1192 * to size the browser view it needs to be resized */
1193 case IDC_SHELLSTATIC:
1194 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1195 rc.right - rc.left + chgx,
1196 rc.bottom - rc.top + chgy,
1197 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1198 break;
1202 if(fodInfos->DlgInfos.hwndCustomDlg &&
1203 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1205 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1206 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1208 GetWindowRect( ctrl, &rc);
1209 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1210 if( rc.top > rcview.bottom)
1212 /* if it was below the shell view
1213 * move to bottom */
1214 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1215 rc.right - rc.left, rc.bottom - rc.top,
1216 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 else if( rc.left > rcview.right)
1220 /* if it was to the right of the shell view
1221 * move to right */
1222 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1223 rc.right - rc.left, rc.bottom - rc.top,
1224 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1227 /* size the custom dialog at the end: some applications do some
1228 * control re-arranging at this point */
1229 GetClientRect(hwnd, &rc);
1230 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1231 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1233 EndDeferWindowPos( hdwp);
1234 /* should not be needed */
1235 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1236 return TRUE;
1239 /***********************************************************************
1240 * FileOpenDlgProc95
1242 * File open dialog procedure
1244 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1246 #if 0
1247 TRACE("%p 0x%04x\n", hwnd, uMsg);
1248 #endif
1250 switch(uMsg)
1252 case WM_INITDIALOG:
1254 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1255 RECT rc, rcstc;
1256 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1257 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1259 /* Adds the FileOpenDlgInfos in the property list of the dialog
1260 so it will be easily accessible through a GetPropA(...) */
1261 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1263 FILEDLG95_InitControls(hwnd);
1265 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1267 GetWindowRect( hwnd, &rc);
1268 fodInfos->DlgInfos.hwndGrip =
1269 CreateWindowExA( 0, "SCROLLBAR", NULL,
1270 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1271 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1272 rc.right - gripx, rc.bottom - gripy,
1273 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1276 fodInfos->DlgInfos.hwndCustomDlg =
1277 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1279 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1280 FILEDLG95_FillControls(hwnd, wParam, lParam);
1282 if( fodInfos->DlgInfos.hwndCustomDlg)
1283 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1285 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1286 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1287 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1290 /* if the app has changed the position of the invisible listbox,
1291 * change that of the listview (browser) as well */
1292 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1293 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1294 if( !EqualRect( &rc, &rcstc))
1296 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1297 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1298 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1299 SWP_NOACTIVATE | SWP_NOZORDER);
1302 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1304 GetWindowRect( hwnd, &rc);
1305 fodInfos->sizedlg.cx = rc.right - rc.left;
1306 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1307 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1308 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1309 GetClientRect( hwnd, &rc);
1310 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1311 rc.right - gripx, rc.bottom - gripy,
1312 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1313 /* resize the dialog to the previous invocation */
1314 if( MemDialogSize.cx && MemDialogSize.cy)
1315 SetWindowPos( hwnd, NULL,
1316 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1317 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1320 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1321 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1323 return 0;
1325 case WM_SIZE:
1326 return FILEDLG95_OnWMSize(hwnd, wParam);
1327 case WM_GETMINMAXINFO:
1328 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1329 case WM_COMMAND:
1330 return FILEDLG95_OnWMCommand(hwnd, wParam);
1331 case WM_DRAWITEM:
1333 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1335 case IDC_LOOKIN:
1336 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1337 return TRUE;
1340 return FALSE;
1342 case WM_GETISHELLBROWSER:
1343 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1345 case WM_DESTROY:
1347 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1348 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1349 MemDialogSize = fodInfos->sizedlg;
1350 RemovePropA(hwnd, FileOpenDlgInfosStr);
1351 return FALSE;
1353 case WM_NOTIFY:
1355 LPNMHDR lpnmh = (LPNMHDR)lParam;
1356 UINT stringId = -1;
1358 /* set up the button tooltips strings */
1359 if(TTN_GETDISPINFOA == lpnmh->code )
1361 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1362 switch(lpnmh->idFrom )
1364 /* Up folder button */
1365 case FCIDM_TB_UPFOLDER:
1366 stringId = IDS_UPFOLDER;
1367 break;
1368 /* New folder button */
1369 case FCIDM_TB_NEWFOLDER:
1370 stringId = IDS_NEWFOLDER;
1371 break;
1372 /* List option button */
1373 case FCIDM_TB_SMALLICON:
1374 stringId = IDS_LISTVIEW;
1375 break;
1376 /* Details option button */
1377 case FCIDM_TB_REPORTVIEW:
1378 stringId = IDS_REPORTVIEW;
1379 break;
1380 /* Desktop button */
1381 case FCIDM_TB_DESKTOP:
1382 stringId = IDS_TODESKTOP;
1383 break;
1384 default:
1385 stringId = 0;
1387 lpdi->hinst = COMDLG32_hInstance;
1388 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1390 return FALSE;
1392 default :
1393 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1394 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1395 return FALSE;
1399 /***********************************************************************
1400 * FILEDLG95_InitControls
1402 * WM_INITDIALOG message handler (before hook notification)
1404 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1406 int win2000plus = 0;
1407 int win98plus = 0;
1408 int handledPath = FALSE;
1409 OSVERSIONINFOW osVi;
1410 static const WCHAR szwSlash[] = { '\\', 0 };
1411 static const WCHAR szwStar[] = { '*',0 };
1413 static const TBBUTTON tbb[] =
1415 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1416 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1417 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1418 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1419 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1420 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1421 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1422 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1423 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1425 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1427 RECT rectTB;
1428 RECT rectlook;
1430 HIMAGELIST toolbarImageList;
1431 SHFILEINFOA shFileInfo;
1432 ITEMIDLIST *desktopPidl;
1434 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1436 TRACE("%p\n", fodInfos);
1438 /* Get windows version emulating */
1439 osVi.dwOSVersionInfoSize = sizeof(osVi);
1440 GetVersionExW(&osVi);
1441 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1442 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1443 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1444 win2000plus = (osVi.dwMajorVersion > 4);
1445 if (win2000plus) win98plus = TRUE;
1447 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1449 /* Get the hwnd of the controls */
1450 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1451 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1452 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1454 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1455 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1457 /* construct the toolbar */
1458 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1459 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1461 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1462 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1463 rectTB.left = rectlook.right;
1464 rectTB.top = rectlook.top-1;
1466 if (fodInfos->unicode)
1467 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1468 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1469 rectTB.left, rectTB.top,
1470 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1471 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1472 else
1473 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1474 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1475 rectTB.left, rectTB.top,
1476 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1477 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1479 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1481 /* FIXME: use TB_LOADIMAGES when implemented */
1482 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1483 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1484 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1486 /* Retrieve and add desktop icon to the toolbar */
1487 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1488 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1489 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1490 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1491 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1493 DestroyIcon(shFileInfo.hIcon);
1494 CoTaskMemFree(desktopPidl);
1496 /* Finish Toolbar Construction */
1497 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1498 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1500 /* Set the window text with the text specified in the OPENFILENAME structure */
1501 if(fodInfos->title)
1503 SetWindowTextW(hwnd,fodInfos->title);
1505 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1507 WCHAR buf[16];
1508 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1509 SetWindowTextW(hwnd, buf);
1512 /* Initialise the file name edit control */
1513 handledPath = FALSE;
1514 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1516 if(fodInfos->filename)
1518 /* 1. If win2000 or higher and filename contains a path, use it
1519 in preference over the lpstrInitialDir */
1520 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1521 WCHAR tmpBuf[MAX_PATH];
1522 WCHAR *nameBit;
1523 DWORD result;
1525 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1526 if (result) {
1528 /* nameBit is always shorter than the original filename */
1529 lstrcpyW(fodInfos->filename,nameBit);
1531 *nameBit = 0x00;
1532 if (fodInfos->initdir == NULL)
1533 MemFree(fodInfos->initdir);
1534 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1535 lstrcpyW(fodInfos->initdir, tmpBuf);
1536 handledPath = TRUE;
1537 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1538 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1540 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1542 } else {
1543 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1547 /* 2. (All platforms) If initdir is not null, then use it */
1548 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1549 (*fodInfos->initdir!=0x00))
1551 /* Work out the proper path as supplied one might be relative */
1552 /* (Here because supplying '.' as dir browses to My Computer) */
1553 if (handledPath==FALSE) {
1554 WCHAR tmpBuf[MAX_PATH];
1555 WCHAR tmpBuf2[MAX_PATH];
1556 WCHAR *nameBit;
1557 DWORD result;
1559 lstrcpyW(tmpBuf, fodInfos->initdir);
1560 if( PathFileExistsW(tmpBuf) ) {
1561 /* initdir does not have to be a directory. If a file is
1562 * specified, the dir part is taken */
1563 if( PathIsDirectoryW(tmpBuf)) {
1564 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1565 lstrcatW(tmpBuf, szwSlash);
1567 lstrcatW(tmpBuf, szwStar);
1569 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1570 if (result) {
1571 *nameBit = 0x00;
1572 MemFree(fodInfos->initdir);
1573 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1574 lstrcpyW(fodInfos->initdir, tmpBuf2);
1575 handledPath = TRUE;
1576 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1579 else if (fodInfos->initdir)
1581 MemFree(fodInfos->initdir);
1582 fodInfos->initdir = NULL;
1583 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1588 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1589 (*fodInfos->initdir==0x00)))
1591 /* 3. All except w2k+: if filename contains a path use it */
1592 if (!win2000plus && fodInfos->filename &&
1593 *fodInfos->filename &&
1594 strpbrkW(fodInfos->filename, szwSlash)) {
1595 WCHAR tmpBuf[MAX_PATH];
1596 WCHAR *nameBit;
1597 DWORD result;
1599 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1600 tmpBuf, &nameBit);
1601 if (result) {
1602 int len;
1604 /* nameBit is always shorter than the original filename */
1605 lstrcpyW(fodInfos->filename, nameBit);
1606 *nameBit = 0x00;
1608 len = lstrlenW(tmpBuf);
1609 MemFree(fodInfos->initdir);
1610 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1611 lstrcpyW(fodInfos->initdir, tmpBuf);
1613 handledPath = TRUE;
1614 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1615 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1617 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1620 /* 4. Win2000+: Recently used */
1621 if (handledPath == FALSE && win2000plus) {
1622 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1623 fodInfos->initdir[0] = '\0';
1625 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1627 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1628 handledPath = TRUE;
1629 }else{
1630 MemFree(fodInfos->initdir);
1631 fodInfos->initdir = NULL;
1635 /* 5. win98+ and win2000+ if any files of specified filter types in
1636 current directory, use it */
1637 if ( win98plus && handledPath == FALSE &&
1638 fodInfos->filter && *fodInfos->filter) {
1640 LPCWSTR lpstrPos = fodInfos->filter;
1641 WIN32_FIND_DATAW FindFileData;
1642 HANDLE hFind;
1644 while (1)
1646 /* filter is a list... title\0ext\0......\0\0 */
1648 /* Skip the title */
1649 if(! *lpstrPos) break; /* end */
1650 lpstrPos += lstrlenW(lpstrPos) + 1;
1652 /* See if any files exist in the current dir with this extension */
1653 if(! *lpstrPos) break; /* end */
1655 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1657 if (hFind == INVALID_HANDLE_VALUE) {
1658 /* None found - continue search */
1659 lpstrPos += lstrlenW(lpstrPos) + 1;
1661 } else {
1663 MemFree(fodInfos->initdir);
1664 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1665 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1667 handledPath = TRUE;
1668 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1669 debugstr_w(lpstrPos));
1670 FindClose(hFind);
1671 break;
1676 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1677 if (handledPath == FALSE && (win2000plus || win98plus)) {
1678 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1680 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1682 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1684 /* last fallback */
1685 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1686 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1687 } else {
1688 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1690 } else {
1691 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1693 handledPath = TRUE;
1694 } else if (handledPath==FALSE) {
1695 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1696 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1697 handledPath = TRUE;
1698 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1701 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1702 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1704 /* Must the open as read only check box be checked ?*/
1705 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1707 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1710 /* Must the open as read only check box be hidden? */
1711 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1713 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1714 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1717 /* Must the help button be hidden? */
1718 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1720 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1721 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1724 /* change Open to Save */
1725 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1727 WCHAR buf[16];
1728 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1729 SetDlgItemTextW(hwnd, IDOK, buf);
1730 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1731 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1734 /* Initialize the filter combo box */
1735 FILEDLG95_FILETYPE_Init(hwnd);
1737 return 0;
1740 /***********************************************************************
1741 * FILEDLG95_ResizeControls
1743 * WM_INITDIALOG message handler (after hook notification)
1745 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1747 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1749 if (fodInfos->DlgInfos.hwndCustomDlg)
1751 RECT rc;
1752 UINT flags = SWP_NOACTIVATE;
1754 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1755 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1757 /* resize the custom dialog to the parent size */
1758 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1759 GetClientRect(hwnd, &rc);
1760 else
1762 /* our own fake template is zero sized and doesn't have children, so
1763 * there is no need to resize it. Picasa depends on it.
1765 flags |= SWP_NOSIZE;
1766 SetRectEmpty(&rc);
1768 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1769 0, 0, rc.right, rc.bottom, flags);
1771 else
1773 /* Resize the height, if open as read only checkbox ad help button are
1774 * hidden and we are not using a custom template nor a customDialog
1776 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1777 (!(fodInfos->ofnInfos->Flags &
1778 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1780 RECT rectDlg, rectHelp, rectCancel;
1781 GetWindowRect(hwnd, &rectDlg);
1782 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1783 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1784 /* subtract the height of the help button plus the space between the help
1785 * button and the cancel button to the height of the dialog
1787 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1788 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1789 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1792 return TRUE;
1795 /***********************************************************************
1796 * FILEDLG95_FillControls
1798 * WM_INITDIALOG message handler (after hook notification)
1800 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1802 LPITEMIDLIST pidlItemId = NULL;
1804 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1806 TRACE("dir=%s file=%s\n",
1807 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1809 /* Get the initial directory pidl */
1811 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1813 WCHAR path[MAX_PATH];
1815 GetCurrentDirectoryW(MAX_PATH,path);
1816 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1819 /* Initialise shell objects */
1820 FILEDLG95_SHELL_Init(hwnd);
1822 /* Initialize the Look In combo box */
1823 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1825 /* Browse to the initial directory */
1826 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1828 /* Free pidlItem memory */
1829 COMDLG32_SHFree(pidlItemId);
1831 return TRUE;
1833 /***********************************************************************
1834 * FILEDLG95_Clean
1836 * Regroups all the cleaning functions of the filedlg
1838 void FILEDLG95_Clean(HWND hwnd)
1840 FILEDLG95_FILETYPE_Clean(hwnd);
1841 FILEDLG95_LOOKIN_Clean(hwnd);
1842 FILEDLG95_SHELL_Clean(hwnd);
1844 /***********************************************************************
1845 * FILEDLG95_OnWMCommand
1847 * WM_COMMAND message handler
1849 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1851 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1852 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1853 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1855 switch(wID)
1857 /* OK button */
1858 case IDOK:
1859 FILEDLG95_OnOpen(hwnd);
1860 break;
1861 /* Cancel button */
1862 case IDCANCEL:
1863 FILEDLG95_Clean(hwnd);
1864 EndDialog(hwnd, FALSE);
1865 break;
1866 /* Filetype combo box */
1867 case IDC_FILETYPE:
1868 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1869 break;
1870 /* LookIn combo box */
1871 case IDC_LOOKIN:
1872 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1873 break;
1875 /* --- toolbar --- */
1876 /* Up folder button */
1877 case FCIDM_TB_UPFOLDER:
1878 FILEDLG95_SHELL_UpFolder(hwnd);
1879 break;
1880 /* New folder button */
1881 case FCIDM_TB_NEWFOLDER:
1882 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1883 break;
1884 /* List option button */
1885 case FCIDM_TB_SMALLICON:
1886 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1887 break;
1888 /* Details option button */
1889 case FCIDM_TB_REPORTVIEW:
1890 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1891 break;
1892 /* Details option button */
1893 case FCIDM_TB_DESKTOP:
1894 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1895 break;
1897 case IDC_FILENAME:
1898 break;
1901 /* Do not use the listview selection anymore */
1902 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1903 return 0;
1906 /***********************************************************************
1907 * FILEDLG95_OnWMGetIShellBrowser
1909 * WM_GETISHELLBROWSER message handler
1911 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1913 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1915 TRACE("\n");
1917 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1919 return TRUE;
1923 /***********************************************************************
1924 * FILEDLG95_SendFileOK
1926 * Sends the CDN_FILEOK notification if required
1928 * RETURNS
1929 * TRUE if the dialog should close
1930 * FALSE if the dialog should not be closed
1932 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1934 /* ask the hook if we can close */
1935 if(IsHooked(fodInfos))
1937 LRESULT retval = 0;
1939 TRACE("---\n");
1940 /* First send CDN_FILEOK as MSDN doc says */
1941 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1942 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1943 if( retval)
1945 TRACE("canceled\n");
1946 return FALSE;
1949 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1950 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1951 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1952 if( retval)
1954 TRACE("canceled\n");
1955 return FALSE;
1958 return TRUE;
1961 /***********************************************************************
1962 * FILEDLG95_OnOpenMultipleFiles
1964 * Handles the opening of multiple files.
1966 * FIXME
1967 * check destination buffer size
1969 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1971 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1972 UINT nCount, nSizePath;
1973 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1975 TRACE("\n");
1977 if(fodInfos->unicode)
1979 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1980 ofn->lpstrFile[0] = '\0';
1982 else
1984 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1985 ofn->lpstrFile[0] = '\0';
1988 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1990 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1991 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1992 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1994 LPWSTR lpstrTemp = lpstrFileList;
1996 for ( nCount = 0; nCount < nFileCount; nCount++ )
1998 LPITEMIDLIST pidl;
2000 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2001 if (!pidl)
2003 WCHAR lpstrNotFound[100];
2004 WCHAR lpstrMsg[100];
2005 WCHAR tmp[400];
2006 static const WCHAR nl[] = {'\n',0};
2008 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2009 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2011 lstrcpyW(tmp, lpstrTemp);
2012 lstrcatW(tmp, nl);
2013 lstrcatW(tmp, lpstrNotFound);
2014 lstrcatW(tmp, nl);
2015 lstrcatW(tmp, lpstrMsg);
2017 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2018 return FALSE;
2021 /* move to the next file in the list of files */
2022 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2023 COMDLG32_SHFree(pidl);
2027 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2028 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2030 /* For "oldstyle" dialog the components have to
2031 be separated by blanks (not '\0'!) and short
2032 filenames have to be used! */
2033 FIXME("Components have to be separated by blanks\n");
2035 if(fodInfos->unicode)
2037 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2038 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2039 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2041 else
2043 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2045 if (ofn->lpstrFile != NULL)
2047 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2048 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2049 if (ofn->nMaxFile > nSizePath)
2051 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2052 ofn->lpstrFile + nSizePath,
2053 ofn->nMaxFile - nSizePath, NULL, NULL);
2058 fodInfos->ofnInfos->nFileOffset = nSizePath;
2059 fodInfos->ofnInfos->nFileExtension = 0;
2061 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2062 return FALSE;
2064 /* clean and exit */
2065 FILEDLG95_Clean(hwnd);
2066 return EndDialog(hwnd,TRUE);
2069 /* Returns the 'slot name' of the given module_name in the registry's
2070 * most-recently-used list. This will be an ASCII value in the
2071 * range ['a','z'). Returns zero on error.
2073 * The slot's value in the registry has the form:
2074 * module_name\0mru_path\0
2076 * If stored_path is given, then stored_path will contain the path name
2077 * stored in the registry's MRU list for the given module_name.
2079 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2080 * MRU list key for the given module_name.
2082 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2084 WCHAR mru_list[32], *cur_mru_slot;
2085 BOOL taken[25] = {0};
2086 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2087 HKEY hkey_tmp, *hkey;
2088 LONG ret;
2090 if(hkey_ret)
2091 hkey = hkey_ret;
2092 else
2093 hkey = &hkey_tmp;
2095 if(stored_path)
2096 *stored_path = '\0';
2098 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2099 if(ret){
2100 WARN("Unable to create MRU key: %d\n", ret);
2101 return 0;
2104 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2105 (LPBYTE)mru_list, &mru_list_size);
2106 if(ret || key_type != REG_SZ){
2107 if(ret == ERROR_FILE_NOT_FOUND)
2108 return 'a';
2110 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2111 RegCloseKey(*hkey);
2112 return 0;
2115 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2116 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2117 DWORD value_data_size = sizeof(value_data);
2119 *value_name = *cur_mru_slot;
2121 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2122 &key_type, (LPBYTE)value_data, &value_data_size);
2123 if(ret || key_type != REG_BINARY){
2124 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2125 continue;
2128 if(!strcmpiW(module_name, value_data)){
2129 if(!hkey_ret)
2130 RegCloseKey(*hkey);
2131 if(stored_path)
2132 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2133 return *value_name;
2137 if(!hkey_ret)
2138 RegCloseKey(*hkey);
2140 /* the module name isn't in the registry, so find the next open slot */
2141 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2142 taken[*cur_mru_slot - 'a'] = TRUE;
2143 for(i = 0; i < 25; ++i){
2144 if(!taken[i])
2145 return i + 'a';
2148 /* all slots are taken, so return the last one in MRUList */
2149 --cur_mru_slot;
2150 return *cur_mru_slot;
2153 /* save the given filename as most-recently-used path for this module */
2154 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2156 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2157 LONG ret;
2158 HKEY hkey;
2160 /* get the current executable's name */
2161 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2162 WARN("GotModuleFileName failed: %d\n", GetLastError());
2163 return;
2165 module_name = strrchrW(module_path, '\\');
2166 if(!module_name)
2167 module_name = module_path;
2168 else
2169 module_name += 1;
2171 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2172 if(!slot)
2173 return;
2174 *slot_name = slot;
2176 { /* update the slot's info */
2177 WCHAR *path_ends, *final;
2178 DWORD path_len, final_len;
2180 /* use only the path segment of `filename' */
2181 path_ends = strrchrW(filename, '\\');
2182 path_len = path_ends - filename;
2184 final_len = path_len + lstrlenW(module_name) + 2;
2186 final = MemAlloc(final_len * sizeof(WCHAR));
2187 if(!final)
2188 return;
2189 lstrcpyW(final, module_name);
2190 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2191 final[final_len-1] = '\0';
2193 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2194 final_len * sizeof(WCHAR));
2195 if(ret){
2196 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2197 MemFree(final);
2198 RegCloseKey(hkey);
2199 return;
2202 MemFree(final);
2205 { /* update MRUList value */
2206 WCHAR old_mru_list[32], new_mru_list[32];
2207 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2208 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2210 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2211 (LPBYTE)old_mru_list, &mru_list_size);
2212 if(ret || key_type != REG_SZ){
2213 if(ret == ERROR_FILE_NOT_FOUND){
2214 new_mru_list[0] = slot;
2215 new_mru_list[1] = '\0';
2216 }else{
2217 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2218 RegCloseKey(hkey);
2219 return;
2221 }else{
2222 /* copy old list data over so that the new slot is at the start
2223 * of the list */
2224 *new_mru_slot++ = slot;
2225 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2226 if(*old_mru_slot != slot)
2227 *new_mru_slot++ = *old_mru_slot;
2229 *new_mru_slot = '\0';
2232 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2233 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2234 if(ret){
2235 WARN("Error saving MRUList data: %d\n", ret);
2236 RegCloseKey(hkey);
2237 return;
2242 /* load the most-recently-used path for this module */
2243 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2245 WCHAR module_path[MAX_PATH], *module_name;
2247 /* get the current executable's name */
2248 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2249 WARN("GotModuleFileName failed: %d\n", GetLastError());
2250 return;
2252 module_name = strrchrW(module_path, '\\');
2253 if(!module_name)
2254 module_name = module_path;
2255 else
2256 module_name += 1;
2258 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2259 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2262 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2264 WCHAR strMsgTitle[MAX_PATH];
2265 WCHAR strMsgText [MAX_PATH];
2266 if (idCaption)
2267 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2268 else
2269 strMsgTitle[0] = '\0';
2270 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2271 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2274 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2275 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2277 int nOpenAction = defAction;
2278 LPWSTR lpszTemp, lpszTemp1;
2279 LPITEMIDLIST pidl = NULL;
2280 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2282 /* check for invalid chars */
2283 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2285 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2286 return FALSE;
2289 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2291 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2292 while (lpszTemp1)
2294 LPSHELLFOLDER lpsfChild;
2295 WCHAR lpwstrTemp[MAX_PATH];
2296 DWORD dwEaten, dwAttributes;
2297 LPWSTR p;
2299 lstrcpyW(lpwstrTemp, lpszTemp);
2300 p = PathFindNextComponentW(lpwstrTemp);
2302 if (!p) break; /* end of path */
2304 *p = 0;
2305 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2307 /* There are no wildcards when OFN_NOVALIDATE is set */
2308 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2310 static const WCHAR wszWild[] = { '*', '?', 0 };
2311 /* if the last element is a wildcard do a search */
2312 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2314 nOpenAction = ONOPEN_SEARCH;
2315 break;
2318 lpszTemp1 = lpszTemp;
2320 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2322 /* append a backslash to drive letters */
2323 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2324 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2325 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2327 PathAddBackslashW(lpwstrTemp);
2330 dwAttributes = SFGAO_FOLDER;
2331 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2333 /* the path component is valid, we have a pidl of the next path component */
2334 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2335 if(dwAttributes & SFGAO_FOLDER)
2337 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2339 ERR("bind to failed\n"); /* should not fail */
2340 break;
2342 IShellFolder_Release(*ppsf);
2343 *ppsf = lpsfChild;
2344 lpsfChild = NULL;
2346 else
2348 TRACE("value\n");
2350 /* end dialog, return value */
2351 nOpenAction = ONOPEN_OPEN;
2352 break;
2354 COMDLG32_SHFree(pidl);
2355 pidl = NULL;
2357 else if (!(flags & OFN_NOVALIDATE))
2359 if(*lpszTemp || /* points to trailing null for last path element */
2360 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2362 if(flags & OFN_PATHMUSTEXIST)
2364 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2365 break;
2368 else
2370 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2372 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2373 break;
2376 /* change to the current folder */
2377 nOpenAction = ONOPEN_OPEN;
2378 break;
2380 else
2382 nOpenAction = ONOPEN_OPEN;
2383 break;
2386 if(pidl) COMDLG32_SHFree(pidl);
2388 return nOpenAction;
2391 /***********************************************************************
2392 * FILEDLG95_OnOpen
2394 * Ok button WM_COMMAND message handler
2396 * If the function succeeds, the return value is nonzero.
2398 BOOL FILEDLG95_OnOpen(HWND hwnd)
2400 LPWSTR lpstrFileList;
2401 UINT nFileCount = 0;
2402 UINT sizeUsed = 0;
2403 BOOL ret = TRUE;
2404 WCHAR lpstrPathAndFile[MAX_PATH];
2405 LPSHELLFOLDER lpsf = NULL;
2406 int nOpenAction;
2407 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2409 TRACE("hwnd=%p\n", hwnd);
2411 /* try to browse the selected item */
2412 if(BrowseSelectedFolder(hwnd))
2413 return FALSE;
2415 /* get the files from the edit control */
2416 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2418 if(nFileCount == 0)
2419 return FALSE;
2421 if(nFileCount > 1)
2423 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2424 goto ret;
2427 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2430 Step 1: Build a complete path name from the current folder and
2431 the filename or path in the edit box.
2432 Special cases:
2433 - the path in the edit box is a root path
2434 (with or without drive letter)
2435 - the edit box contains ".." (or a path with ".." in it)
2438 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2439 MemFree(lpstrFileList);
2442 Step 2: here we have a cleaned up path
2444 We have to parse the path step by step to see if we have to browse
2445 to a folder if the path points to a directory or the last
2446 valid element is a directory.
2448 valid variables:
2449 lpstrPathAndFile: cleaned up path
2452 if (nFileCount &&
2453 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2454 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2455 nOpenAction = ONOPEN_OPEN;
2456 else
2457 nOpenAction = ONOPEN_BROWSE;
2459 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2460 fodInfos->ofnInfos->Flags,
2461 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2462 nOpenAction);
2463 if(!nOpenAction)
2464 goto ret;
2467 Step 3: here we have a cleaned up and validated path
2469 valid variables:
2470 lpsf: ShellFolder bound to the rightmost valid path component
2471 lpstrPathAndFile: cleaned up path
2472 nOpenAction: action to do
2474 TRACE("end validate sf=%p\n", lpsf);
2476 switch(nOpenAction)
2478 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2479 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2481 int iPos;
2482 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2483 DWORD len;
2485 /* replace the current filter */
2486 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2487 len = lstrlenW(lpszTemp)+1;
2488 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2489 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2491 /* set the filter cb to the extension when possible */
2492 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2493 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2495 /* fall through */
2496 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2497 TRACE("ONOPEN_BROWSE\n");
2499 IPersistFolder2 * ppf2;
2500 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2502 LPITEMIDLIST pidlCurrent;
2503 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2504 IPersistFolder2_Release(ppf2);
2505 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2507 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2508 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2510 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2513 else if( nOpenAction == ONOPEN_SEARCH )
2515 if (fodInfos->Shell.FOIShellView)
2516 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2518 COMDLG32_SHFree(pidlCurrent);
2519 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2522 ret = FALSE;
2523 break;
2524 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2525 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2527 WCHAR *ext = NULL;
2529 /* update READONLY check box flag */
2530 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2531 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2532 else
2533 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2535 /* Attach the file extension with file name*/
2536 ext = PathFindExtensionW(lpstrPathAndFile);
2537 if (! *ext)
2539 /* if no extension is specified with file name, then */
2540 /* attach the extension from file filter or default one */
2542 const WCHAR *filterExt = NULL;
2543 LPWSTR lpstrFilter = NULL;
2544 static const WCHAR szwDot[] = {'.',0};
2545 int PathLength = lstrlenW(lpstrPathAndFile);
2547 /*Get the file extension from file type filter*/
2548 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2549 fodInfos->ofnInfos->nFilterIndex-1);
2551 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2552 filterExt = PathFindExtensionW(lpstrFilter);
2554 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2555 filterExt = filterExt + 1;
2556 else if ( fodInfos->defext ) /* attach the default file extension*/
2557 filterExt = fodInfos->defext;
2559 /* If extension contains a glob, ignore it */
2560 if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
2562 /* Attach the dot*/
2563 lstrcatW(lpstrPathAndFile, szwDot);
2564 /* Attach the extension */
2565 lstrcatW(lpstrPathAndFile, filterExt );
2568 /* In Open dialog: if file does not exist try without extension */
2569 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2570 lpstrPathAndFile[PathLength] = '\0';
2573 if (fodInfos->defext) /* add default extension */
2575 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2576 if (*ext)
2577 ext++;
2578 if (!lstrcmpiW(fodInfos->defext, ext))
2579 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2580 else
2581 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2584 /* In Save dialog: check if the file already exists */
2585 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2586 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2587 && PathFileExistsW(lpstrPathAndFile))
2589 WCHAR lpstrOverwrite[100];
2590 int answer;
2592 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2593 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2594 MB_YESNO | MB_ICONEXCLAMATION);
2595 if (answer == IDNO || answer == IDCANCEL)
2597 ret = FALSE;
2598 goto ret;
2602 /* In Open dialog: check if it should be created if it doesn't exist */
2603 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2604 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2605 && !PathFileExistsW(lpstrPathAndFile))
2607 WCHAR lpstrCreate[100];
2608 int answer;
2610 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2611 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2612 MB_YESNO | MB_ICONEXCLAMATION);
2613 if (answer == IDNO || answer == IDCANCEL)
2615 ret = FALSE;
2616 goto ret;
2620 /* Check that the size of the file does not exceed buffer size.
2621 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2622 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2623 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2626 /* fill destination buffer */
2627 if (fodInfos->ofnInfos->lpstrFile)
2629 if(fodInfos->unicode)
2631 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2633 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2634 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2635 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2637 else
2639 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2641 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2642 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2643 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2644 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2648 if(fodInfos->unicode)
2650 LPWSTR lpszTemp;
2652 /* set filename offset */
2653 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2654 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2656 /* set extension offset */
2657 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2658 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2660 else
2662 LPSTR lpszTemp;
2663 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2665 /* set filename offset */
2666 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2667 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2669 /* set extension offset */
2670 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2671 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2674 /* set the lpstrFileTitle */
2675 if(fodInfos->ofnInfos->lpstrFileTitle)
2677 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2678 if(fodInfos->unicode)
2680 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2681 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2683 else
2685 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2686 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2687 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2691 /* copy currently selected filter to lpstrCustomFilter */
2692 if (fodInfos->ofnInfos->lpstrCustomFilter)
2694 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2695 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2696 NULL, 0, NULL, NULL);
2697 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2699 LPSTR s = ofn->lpstrCustomFilter;
2700 s += strlen(ofn->lpstrCustomFilter)+1;
2701 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2702 s, len, NULL, NULL);
2707 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2708 goto ret;
2710 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2712 TRACE("close\n");
2713 FILEDLG95_Clean(hwnd);
2714 ret = EndDialog(hwnd, TRUE);
2716 else
2718 WORD size;
2720 size = lstrlenW(lpstrPathAndFile) + 1;
2721 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2722 size += 1;
2723 /* return needed size in first two bytes of lpstrFile */
2724 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2725 FILEDLG95_Clean(hwnd);
2726 ret = EndDialog(hwnd, FALSE);
2727 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2730 break;
2733 ret:
2734 if(lpsf) IShellFolder_Release(lpsf);
2735 return ret;
2738 /***********************************************************************
2739 * FILEDLG95_SHELL_Init
2741 * Initialisation of the shell objects
2743 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2745 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2747 TRACE("\n");
2750 * Initialisation of the FileOpenDialogInfos structure
2753 /* Shell */
2755 /*ShellInfos */
2756 fodInfos->ShellInfos.hwndOwner = hwnd;
2758 /* Disable multi-select if flag not set */
2759 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2761 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2763 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2764 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2766 /* Construct the IShellBrowser interface */
2767 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2769 return NOERROR;
2772 /***********************************************************************
2773 * FILEDLG95_SHELL_ExecuteCommand
2775 * Change the folder option and refresh the view
2776 * If the function succeeds, the return value is nonzero.
2778 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2780 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2781 IContextMenu * pcm;
2783 TRACE("(%p,%p)\n", hwnd, lpVerb);
2785 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2786 SVGIO_BACKGROUND,
2787 &IID_IContextMenu,
2788 (LPVOID*)&pcm)))
2790 CMINVOKECOMMANDINFO ci;
2791 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2792 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2793 ci.lpVerb = lpVerb;
2794 ci.hwnd = hwnd;
2796 IContextMenu_InvokeCommand(pcm, &ci);
2797 IContextMenu_Release(pcm);
2800 return FALSE;
2803 /***********************************************************************
2804 * FILEDLG95_SHELL_UpFolder
2806 * Browse to the specified object
2807 * If the function succeeds, the return value is nonzero.
2809 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2811 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2813 TRACE("\n");
2815 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2816 NULL,
2817 SBSP_PARENT)))
2819 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2820 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2821 return TRUE;
2823 return FALSE;
2826 /***********************************************************************
2827 * FILEDLG95_SHELL_BrowseToDesktop
2829 * Browse to the Desktop
2830 * If the function succeeds, the return value is nonzero.
2832 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2834 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2835 LPITEMIDLIST pidl;
2836 HRESULT hres;
2838 TRACE("\n");
2840 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2841 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2842 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2843 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2844 COMDLG32_SHFree(pidl);
2845 return SUCCEEDED(hres);
2847 /***********************************************************************
2848 * FILEDLG95_SHELL_Clean
2850 * Cleans the memory used by shell objects
2852 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2854 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2856 TRACE("\n");
2858 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2860 /* clean Shell interfaces */
2861 if (fodInfos->Shell.FOIShellView)
2863 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2864 IShellView_Release(fodInfos->Shell.FOIShellView);
2866 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2867 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2868 if (fodInfos->Shell.FOIDataObject)
2869 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2872 /***********************************************************************
2873 * FILEDLG95_FILETYPE_Init
2875 * Initialisation of the file type combo box
2877 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2879 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2880 int nFilters = 0; /* number of filters */
2881 int nFilterIndexCB;
2883 TRACE("\n");
2885 if(fodInfos->customfilter)
2887 /* customfilter has one entry... title\0ext\0
2888 * Set first entry of combo box item with customfilter
2890 LPWSTR lpstrExt;
2891 LPCWSTR lpstrPos = fodInfos->customfilter;
2893 /* Get the title */
2894 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2896 /* Copy the extensions */
2897 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2898 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2899 lstrcpyW(lpstrExt,lpstrPos);
2901 /* Add the item at the end of the combo */
2902 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2903 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2904 nFilters++;
2906 if(fodInfos->filter)
2908 LPCWSTR lpstrPos = fodInfos->filter;
2910 for(;;)
2912 /* filter is a list... title\0ext\0......\0\0
2913 * Set the combo item text to the title and the item data
2914 * to the ext
2916 LPCWSTR lpstrDisplay;
2917 LPWSTR lpstrExt;
2919 /* Get the title */
2920 if(! *lpstrPos) break; /* end */
2921 lpstrDisplay = lpstrPos;
2922 lpstrPos += lstrlenW(lpstrPos) + 1;
2924 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2926 nFilters++;
2928 /* Copy the extensions */
2929 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2930 lstrcpyW(lpstrExt,lpstrPos);
2931 lpstrPos += lstrlenW(lpstrPos) + 1;
2933 /* Add the item at the end of the combo */
2934 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2936 /* malformed filters are added anyway... */
2937 if (!*lpstrExt) break;
2942 * Set the current filter to the one specified
2943 * in the initialisation structure
2945 if (fodInfos->filter || fodInfos->customfilter)
2947 LPWSTR lpstrFilter;
2949 /* Check to make sure our index isn't out of bounds. */
2950 if ( fodInfos->ofnInfos->nFilterIndex >
2951 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2952 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2954 /* set default filter index */
2955 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2956 fodInfos->ofnInfos->nFilterIndex = 1;
2958 /* calculate index of Combo Box item */
2959 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2960 if (fodInfos->customfilter == NULL)
2961 nFilterIndexCB--;
2963 /* Set the current index selection. */
2964 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2966 /* Get the corresponding text string from the combo box. */
2967 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2968 nFilterIndexCB);
2970 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2971 lpstrFilter = NULL;
2973 if(lpstrFilter)
2975 DWORD len;
2976 CharLowerW(lpstrFilter); /* lowercase */
2977 len = lstrlenW(lpstrFilter)+1;
2978 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2979 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2981 } else
2982 fodInfos->ofnInfos->nFilterIndex = 0;
2983 return S_OK;
2986 /***********************************************************************
2987 * FILEDLG95_FILETYPE_OnCommand
2989 * WM_COMMAND of the file type combo box
2990 * If the function succeeds, the return value is nonzero.
2992 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2994 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2996 switch(wNotifyCode)
2998 case CBN_SELENDOK:
3000 LPWSTR lpstrFilter;
3002 /* Get the current item of the filetype combo box */
3003 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3005 /* set the current filter index */
3006 fodInfos->ofnInfos->nFilterIndex = iItem +
3007 (fodInfos->customfilter == NULL ? 1 : 0);
3009 /* Set the current filter with the current selection */
3010 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3012 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3013 iItem);
3014 if((INT_PTR)lpstrFilter != CB_ERR)
3016 DWORD len;
3017 CharLowerW(lpstrFilter); /* lowercase */
3018 len = lstrlenW(lpstrFilter)+1;
3019 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3020 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3021 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3022 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3025 /* Refresh the actual view to display the included items*/
3026 if (fodInfos->Shell.FOIShellView)
3027 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3030 return FALSE;
3032 /***********************************************************************
3033 * FILEDLG95_FILETYPE_SearchExt
3035 * searches for an extension in the filetype box
3037 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3039 int i, iCount = CBGetCount(hwnd);
3041 TRACE("%s\n", debugstr_w(lpstrExt));
3043 if(iCount != CB_ERR)
3045 for(i=0;i<iCount;i++)
3047 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3048 return i;
3051 return -1;
3054 /***********************************************************************
3055 * FILEDLG95_FILETYPE_Clean
3057 * Clean the memory used by the filetype combo box
3059 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3061 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3062 int iPos;
3063 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3065 TRACE("\n");
3067 /* Delete each string of the combo and their associated data */
3068 if(iCount != CB_ERR)
3070 for(iPos = iCount-1;iPos>=0;iPos--)
3072 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3073 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3076 /* Current filter */
3077 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3081 /***********************************************************************
3082 * FILEDLG95_LOOKIN_Init
3084 * Initialisation of the look in combo box
3087 /* Small helper function, to determine if the unixfs shell extension is rooted
3088 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3090 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3091 HKEY hKey;
3092 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3093 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3094 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3095 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3096 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3097 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3098 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3100 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3101 return FALSE;
3103 RegCloseKey(hKey);
3104 return TRUE;
3107 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3109 IShellFolder *psfRoot, *psfDrives;
3110 IEnumIDList *lpeRoot, *lpeDrives;
3111 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3113 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3115 TRACE("\n");
3117 liInfos->iMaxIndentation = 0;
3119 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3121 /* set item height for both text field and listbox */
3122 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3123 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3125 /* Turn on the extended UI for the combo box like Windows does */
3126 CBSetExtendedUI(hwndCombo, TRUE);
3128 /* Initialise data of Desktop folder */
3129 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3130 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3131 COMDLG32_SHFree(pidlTmp);
3133 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3135 SHGetDesktopFolder(&psfRoot);
3137 if (psfRoot)
3139 /* enumerate the contents of the desktop */
3140 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3142 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3144 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3146 /* If the unixfs extension is rooted, we don't expand the drives by default */
3147 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3149 /* special handling for CSIDL_DRIVES */
3150 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3152 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3154 /* enumerate the drives */
3155 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3157 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3159 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3160 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3161 COMDLG32_SHFree(pidlAbsTmp);
3162 COMDLG32_SHFree(pidlTmp1);
3164 IEnumIDList_Release(lpeDrives);
3166 IShellFolder_Release(psfDrives);
3171 COMDLG32_SHFree(pidlTmp);
3173 IEnumIDList_Release(lpeRoot);
3175 IShellFolder_Release(psfRoot);
3178 COMDLG32_SHFree(pidlDrives);
3181 /***********************************************************************
3182 * FILEDLG95_LOOKIN_DrawItem
3184 * WM_DRAWITEM message handler
3186 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3188 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3189 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3190 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3191 RECT rectText;
3192 RECT rectIcon;
3193 SHFILEINFOW sfi;
3194 HIMAGELIST ilItemImage;
3195 int iIndentation;
3196 TEXTMETRICW tm;
3197 LPSFOLDER tmpFolder;
3198 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3200 TRACE("\n");
3202 if(pDIStruct->itemID == -1)
3203 return 0;
3205 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3206 pDIStruct->itemID)))
3207 return 0;
3210 if(pDIStruct->itemID == liInfos->uSelectedItem)
3212 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3214 &sfi,
3215 sizeof (sfi),
3216 SHGFI_PIDL | SHGFI_SMALLICON |
3217 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3218 SHGFI_DISPLAYNAME );
3220 else
3222 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3224 &sfi,
3225 sizeof (sfi),
3226 SHGFI_PIDL | SHGFI_SMALLICON |
3227 SHGFI_SYSICONINDEX |
3228 SHGFI_DISPLAYNAME);
3231 /* Is this item selected ? */
3232 if(pDIStruct->itemState & ODS_SELECTED)
3234 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3235 SetBkColor(pDIStruct->hDC,crHighLight);
3236 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3238 else
3240 SetTextColor(pDIStruct->hDC,crText);
3241 SetBkColor(pDIStruct->hDC,crWin);
3242 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3245 /* Do not indent item if drawing in the edit of the combo */
3246 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3248 iIndentation = 0;
3249 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3251 &sfi,
3252 sizeof (sfi),
3253 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3254 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3257 else
3259 iIndentation = tmpFolder->m_iIndent;
3261 /* Draw text and icon */
3263 /* Initialise the icon display area */
3264 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3265 rectIcon.top = pDIStruct->rcItem.top;
3266 rectIcon.right = rectIcon.left + ICONWIDTH;
3267 rectIcon.bottom = pDIStruct->rcItem.bottom;
3269 /* Initialise the text display area */
3270 GetTextMetricsW(pDIStruct->hDC, &tm);
3271 rectText.left = rectIcon.right;
3272 rectText.top =
3273 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3274 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3275 rectText.bottom =
3276 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3278 /* Draw the icon from the image list */
3279 ImageList_Draw(ilItemImage,
3280 sfi.iIcon,
3281 pDIStruct->hDC,
3282 rectIcon.left,
3283 rectIcon.top,
3284 ILD_TRANSPARENT );
3286 /* Draw the associated text */
3287 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3288 return NOERROR;
3291 /***********************************************************************
3292 * FILEDLG95_LOOKIN_OnCommand
3294 * LookIn combo box WM_COMMAND message handler
3295 * If the function succeeds, the return value is nonzero.
3297 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3299 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3301 TRACE("%p\n", fodInfos);
3303 switch(wNotifyCode)
3305 case CBN_SELENDOK:
3307 LPSFOLDER tmpFolder;
3308 int iItem;
3310 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3312 if( iItem == CB_ERR) return FALSE;
3314 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3315 iItem)))
3316 return FALSE;
3319 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3320 tmpFolder->pidlItem,
3321 SBSP_ABSOLUTE)))
3323 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3324 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3325 return TRUE;
3327 break;
3331 return FALSE;
3334 /***********************************************************************
3335 * FILEDLG95_LOOKIN_AddItem
3337 * Adds an absolute pidl item to the lookin combo box
3338 * returns the index of the inserted item
3340 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3342 LPITEMIDLIST pidlNext;
3343 SHFILEINFOW sfi;
3344 SFOLDER *tmpFolder;
3345 LookInInfos *liInfos;
3347 TRACE("%08x\n", iInsertId);
3349 if(!pidl)
3350 return -1;
3352 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3353 return -1;
3355 tmpFolder = MemAlloc(sizeof(SFOLDER));
3356 tmpFolder->m_iIndent = 0;
3358 /* Calculate the indentation of the item in the lookin*/
3359 pidlNext = pidl;
3360 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3362 tmpFolder->m_iIndent++;
3365 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3367 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3368 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3370 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3371 SHGetFileInfoW((LPCWSTR)pidl,
3373 &sfi,
3374 sizeof(sfi),
3375 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3376 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3378 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3380 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3382 int iItemID;
3384 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3386 /* Add the item at the end of the list */
3387 if(iInsertId < 0)
3389 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3391 /* Insert the item at the iInsertId position*/
3392 else
3394 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3397 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3398 return iItemID;
3401 COMDLG32_SHFree( tmpFolder->pidlItem );
3402 MemFree( tmpFolder );
3403 return -1;
3407 /***********************************************************************
3408 * FILEDLG95_LOOKIN_InsertItemAfterParent
3410 * Insert an item below its parent
3412 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3415 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3416 int iParentPos;
3418 TRACE("\n");
3420 if (pidl == pidlParent)
3421 return -1;
3423 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3425 if(iParentPos < 0)
3427 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3430 /* Free pidlParent memory */
3431 COMDLG32_SHFree(pidlParent);
3433 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3436 /***********************************************************************
3437 * FILEDLG95_LOOKIN_SelectItem
3439 * Adds an absolute pidl item to the lookin combo box
3440 * returns the index of the inserted item
3442 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3444 int iItemPos;
3445 LookInInfos *liInfos;
3447 TRACE("\n");
3449 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3451 liInfos = GetPropA(hwnd,LookInInfosStr);
3453 if(iItemPos < 0)
3455 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3456 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3459 else
3461 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3462 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3464 int iRemovedItem;
3466 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3467 break;
3468 if(iRemovedItem < iItemPos)
3469 iItemPos--;
3473 CBSetCurSel(hwnd,iItemPos);
3474 liInfos->uSelectedItem = iItemPos;
3476 return 0;
3480 /***********************************************************************
3481 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3483 * Remove the item with an expansion level over iExpansionLevel
3485 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3487 int iItemPos;
3488 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3490 TRACE("\n");
3492 if(liInfos->iMaxIndentation <= 2)
3493 return -1;
3495 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3497 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3498 COMDLG32_SHFree(tmpFolder->pidlItem);
3499 MemFree(tmpFolder);
3500 CBDeleteString(hwnd,iItemPos);
3501 liInfos->iMaxIndentation--;
3503 return iItemPos;
3506 return -1;
3509 /***********************************************************************
3510 * FILEDLG95_LOOKIN_SearchItem
3512 * Search for pidl in the lookin combo box
3513 * returns the index of the found item
3515 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3517 int i = 0;
3518 int iCount = CBGetCount(hwnd);
3520 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3522 if (iCount != CB_ERR)
3524 for(;i<iCount;i++)
3526 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3528 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3529 return i;
3530 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3531 return i;
3535 return -1;
3538 /***********************************************************************
3539 * FILEDLG95_LOOKIN_Clean
3541 * Clean the memory used by the lookin combo box
3543 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3545 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3546 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3547 int iPos;
3548 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3550 TRACE("\n");
3552 /* Delete each string of the combo and their associated data */
3553 if (iCount != CB_ERR)
3555 for(iPos = iCount-1;iPos>=0;iPos--)
3557 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3558 COMDLG32_SHFree(tmpFolder->pidlItem);
3559 MemFree(tmpFolder);
3560 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3564 /* LookInInfos structure */
3565 MemFree(liInfos);
3566 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3569 /***********************************************************************
3570 * FILEDLG95_FILENAME_FillFromSelection
3572 * fills the edit box from the cached DataObject
3574 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3576 FileOpenDlgInfos *fodInfos;
3577 LPITEMIDLIST pidl;
3578 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3579 WCHAR lpstrTemp[MAX_PATH];
3580 LPWSTR lpstrAllFile, lpstrCurrFile;
3582 TRACE("\n");
3583 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3585 /* Count how many files we have */
3586 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3588 /* calculate the string length, count files */
3589 if (nFileSelected >= 1)
3591 nLength += 3; /* first and last quotes, trailing \0 */
3592 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3594 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3596 if (pidl)
3598 /* get the total length of the selected file names */
3599 lpstrTemp[0] = '\0';
3600 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3602 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3604 nLength += lstrlenW( lpstrTemp ) + 3;
3605 nFiles++;
3607 COMDLG32_SHFree( pidl );
3612 /* allocate the buffer */
3613 if (nFiles <= 1) nLength = MAX_PATH;
3614 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3616 /* Generate the string for the edit control */
3617 if(nFiles >= 1)
3619 lpstrCurrFile = lpstrAllFile;
3620 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3622 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3624 if (pidl)
3626 /* get the file name */
3627 lpstrTemp[0] = '\0';
3628 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3630 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3632 if ( nFiles > 1)
3634 *lpstrCurrFile++ = '\"';
3635 lstrcpyW( lpstrCurrFile, lpstrTemp );
3636 lpstrCurrFile += lstrlenW( lpstrTemp );
3637 *lpstrCurrFile++ = '\"';
3638 *lpstrCurrFile++ = ' ';
3639 *lpstrCurrFile = 0;
3641 else
3643 lstrcpyW( lpstrAllFile, lpstrTemp );
3646 COMDLG32_SHFree( pidl );
3649 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3651 /* Select the file name like Windows does */
3652 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3654 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3658 /* copied from shell32 to avoid linking to it
3659 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3660 * is dependent on whether emulated OS is unicode or not.
3662 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3664 switch (src->uType)
3666 case STRRET_WSTR:
3667 lstrcpynW(dest, src->u.pOleStr, len);
3668 COMDLG32_SHFree(src->u.pOleStr);
3669 break;
3671 case STRRET_CSTR:
3672 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3673 dest[len-1] = 0;
3674 break;
3676 case STRRET_OFFSET:
3677 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3678 dest[len-1] = 0;
3679 break;
3681 default:
3682 FIXME("unknown type %x!\n", src->uType);
3683 if (len) *dest = '\0';
3684 return E_FAIL;
3686 return S_OK;
3689 /***********************************************************************
3690 * FILEDLG95_FILENAME_GetFileNames
3692 * Copies the filenames to a delimited string list.
3694 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3696 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3697 UINT nFileCount = 0; /* number of files */
3698 UINT nStrLen = 0; /* length of string in edit control */
3699 LPWSTR lpstrEdit; /* buffer for string from edit control */
3701 TRACE("\n");
3703 /* get the filenames from the edit control */
3704 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3705 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3706 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3708 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3710 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3711 MemFree(lpstrEdit);
3712 return nFileCount;
3715 #define SETDefFormatEtc(fe,cf,med) \
3717 (fe).cfFormat = cf;\
3718 (fe).dwAspect = DVASPECT_CONTENT; \
3719 (fe).ptd =NULL;\
3720 (fe).tymed = med;\
3721 (fe).lindex = -1;\
3725 * DATAOBJECT Helper functions
3728 /***********************************************************************
3729 * COMCTL32_ReleaseStgMedium
3731 * like ReleaseStgMedium from ole32
3733 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3735 if(medium.pUnkForRelease)
3737 IUnknown_Release(medium.pUnkForRelease);
3739 else
3741 GlobalUnlock(medium.u.hGlobal);
3742 GlobalFree(medium.u.hGlobal);
3746 /***********************************************************************
3747 * GetPidlFromDataObject
3749 * Return pidl(s) by number from the cached DataObject
3751 * nPidlIndex=0 gets the fully qualified root path
3753 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3756 STGMEDIUM medium;
3757 FORMATETC formatetc;
3758 LPITEMIDLIST pidl = NULL;
3760 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3762 if (!doSelected)
3763 return NULL;
3765 /* Set the FORMATETC structure*/
3766 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3768 /* Get the pidls from IDataObject */
3769 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3771 LPIDA cida = GlobalLock(medium.u.hGlobal);
3772 if(nPidlIndex <= cida->cidl)
3774 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3776 COMCTL32_ReleaseStgMedium(medium);
3778 return pidl;
3781 /***********************************************************************
3782 * GetNumSelected
3784 * Return the number of selected items in the DataObject.
3787 static UINT GetNumSelected( IDataObject *doSelected )
3789 UINT retVal = 0;
3790 STGMEDIUM medium;
3791 FORMATETC formatetc;
3793 TRACE("sv=%p\n", doSelected);
3795 if (!doSelected) return 0;
3797 /* Set the FORMATETC structure*/
3798 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3800 /* Get the pidls from IDataObject */
3801 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3803 LPIDA cida = GlobalLock(medium.u.hGlobal);
3804 retVal = cida->cidl;
3805 COMCTL32_ReleaseStgMedium(medium);
3806 return retVal;
3808 return 0;
3812 * TOOLS
3815 /***********************************************************************
3816 * GetName
3818 * Get the pidl's display name (relative to folder) and
3819 * put it in lpstrFileName.
3821 * Return NOERROR on success,
3822 * E_FAIL otherwise
3825 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3827 STRRET str;
3828 HRESULT hRes;
3830 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3832 if(!lpsf)
3834 SHGetDesktopFolder(&lpsf);
3835 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3836 IShellFolder_Release(lpsf);
3837 return hRes;
3840 /* Get the display name of the pidl relative to the folder */
3841 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3843 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3845 return E_FAIL;
3848 /***********************************************************************
3849 * GetShellFolderFromPidl
3851 * pidlRel is the item pidl relative
3852 * Return the IShellFolder of the absolute pidl
3854 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3856 IShellFolder *psf = NULL,*psfParent;
3858 TRACE("%p\n", pidlAbs);
3860 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3862 psf = psfParent;
3863 if(pidlAbs && pidlAbs->mkid.cb)
3865 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3867 IShellFolder_Release(psfParent);
3868 return psf;
3871 /* return the desktop */
3872 return psfParent;
3874 return NULL;
3877 /***********************************************************************
3878 * GetParentPidl
3880 * Return the LPITEMIDLIST to the parent of the pidl in the list
3882 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3884 LPITEMIDLIST pidlParent;
3886 TRACE("%p\n", pidl);
3888 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3889 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3891 return pidlParent;
3894 /***********************************************************************
3895 * GetPidlFromName
3897 * returns the pidl of the file name relative to folder
3898 * NULL if an error occurred
3900 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3902 LPITEMIDLIST pidl = NULL;
3903 ULONG ulEaten;
3905 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3907 if(!lpcstrFileName) return NULL;
3908 if(!*lpcstrFileName) return NULL;
3910 if(!lpsf)
3912 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3913 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3914 IShellFolder_Release(lpsf);
3917 else
3919 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3921 return pidl;
3926 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3928 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3929 HRESULT ret;
3931 TRACE("%p, %p\n", psf, pidl);
3933 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3935 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3936 /* see documentation shell 4.1*/
3937 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3940 /***********************************************************************
3941 * BrowseSelectedFolder
3943 static BOOL BrowseSelectedFolder(HWND hwnd)
3945 BOOL bBrowseSelFolder = FALSE;
3946 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3948 TRACE("\n");
3950 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3952 LPITEMIDLIST pidlSelection;
3954 /* get the file selected */
3955 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3956 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3958 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3959 pidlSelection, SBSP_RELATIVE ) ) )
3961 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3962 ' ','n','o','t',' ','e','x','i','s','t',0};
3963 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3965 bBrowseSelFolder = TRUE;
3966 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3967 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3969 COMDLG32_SHFree( pidlSelection );
3972 return bBrowseSelFolder;
3976 * Memory allocation methods */
3977 static void *MemAlloc(UINT size)
3979 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3982 static void MemFree(void *mem)
3984 HeapFree(GetProcessHeap(),0,mem);
3988 * Old-style (win3.1) dialogs */
3990 /***********************************************************************
3991 * FD32_GetTemplate [internal]
3993 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3994 * by a 32 bits application
3997 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3999 LPOPENFILENAMEW ofnW = lfs->ofnW;
4000 LPOPENFILENAMEA ofnA = lfs->ofnA;
4001 HANDLE hDlgTmpl;
4003 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
4005 if (!(lfs->template = LockResource( ofnW->hInstance )))
4007 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4008 return FALSE;
4011 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
4013 HRSRC hResInfo;
4014 if (ofnA)
4015 hResInfo = FindResourceA(ofnA->hInstance,
4016 ofnA->lpTemplateName,
4017 (LPSTR)RT_DIALOG);
4018 else
4019 hResInfo = FindResourceW(ofnW->hInstance,
4020 ofnW->lpTemplateName,
4021 (LPWSTR)RT_DIALOG);
4022 if (!hResInfo)
4024 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4025 return FALSE;
4027 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4028 hResInfo)) ||
4029 !(lfs->template = LockResource(hDlgTmpl)))
4031 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4032 return FALSE;
4034 } else { /* get it from internal Wine resource */
4035 HRSRC hResInfo;
4036 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4037 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4039 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4040 return FALSE;
4042 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4043 !(lfs->template = LockResource( hDlgTmpl )))
4045 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4046 return FALSE;
4049 return TRUE;
4053 /***********************************************************************
4054 * FD32_WMMeasureItem [internal]
4056 static LONG FD32_WMMeasureItem(LPARAM lParam)
4058 LPMEASUREITEMSTRUCT lpmeasure;
4060 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4061 lpmeasure->itemHeight = FD31_GetFldrHeight();
4062 return TRUE;
4066 /***********************************************************************
4067 * FileOpenDlgProc [internal]
4068 * Used for open and save, in fact.
4070 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4071 WPARAM wParam, LPARAM lParam)
4073 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4075 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4076 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4078 INT_PTR lRet;
4079 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4080 if (lRet)
4081 return lRet; /* else continue message processing */
4083 switch (wMsg)
4085 case WM_INITDIALOG:
4086 return FD31_WMInitDialog(hWnd, wParam, lParam);
4088 case WM_MEASUREITEM:
4089 return FD32_WMMeasureItem(lParam);
4091 case WM_DRAWITEM:
4092 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4094 case WM_COMMAND:
4095 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4096 #if 0
4097 case WM_CTLCOLOR:
4098 SetBkColor((HDC16)wParam, 0x00C0C0C0);
4099 switch (HIWORD(lParam))
4101 case CTLCOLOR_BTN:
4102 SetTextColor((HDC16)wParam, 0x00000000);
4103 return hGRAYBrush;
4104 case CTLCOLOR_STATIC:
4105 SetTextColor((HDC16)wParam, 0x00000000);
4106 return hGRAYBrush;
4108 break;
4109 #endif
4111 return FALSE;
4115 /***********************************************************************
4116 * GetFileName31A [internal]
4118 * Creates a win31 style dialog box for the user to select a file to open/save.
4120 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4121 UINT dlgType /* type dialogue : open/save */
4124 BOOL bRet = FALSE;
4125 PFD31_DATA lfs;
4127 if (!lpofn || !FD31_Init()) return FALSE;
4129 TRACE("ofn flags %08x\n", lpofn->Flags);
4130 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4131 if (lfs)
4133 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4134 FD32_FileOpenDlgProc, (LPARAM)lfs);
4135 FD31_DestroyPrivate(lfs);
4138 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4139 return bRet;
4142 /***********************************************************************
4143 * GetFileName31W [internal]
4145 * Creates a win31 style dialog box for the user to select a file to open/save
4147 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4148 UINT dlgType /* type dialogue : open/save */
4151 BOOL bRet = FALSE;
4152 PFD31_DATA lfs;
4154 if (!lpofn || !FD31_Init()) return FALSE;
4156 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4157 if (lfs)
4159 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4160 FD32_FileOpenDlgProc, (LPARAM)lfs);
4161 FD31_DestroyPrivate(lfs);
4164 TRACE("file %s, file offset %d, ext offset %d\n",
4165 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4166 return bRet;
4169 /* ------------------ APIs ---------------------- */
4171 /***********************************************************************
4172 * GetOpenFileNameA (COMDLG32.@)
4174 * Creates a dialog box for the user to select a file to open.
4176 * RETURNS
4177 * TRUE on success: user enters a valid file
4178 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4181 BOOL WINAPI GetOpenFileNameA(
4182 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4184 BOOL win16look = FALSE;
4186 TRACE("flags %08x\n", ofn->Flags);
4188 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4189 if (ofn->Flags & OFN_FILEMUSTEXIST)
4190 ofn->Flags |= OFN_PATHMUSTEXIST;
4192 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4193 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4195 if (win16look)
4196 return GetFileName31A(ofn, OPEN_DIALOG);
4197 else
4198 return GetFileDialog95A(ofn, OPEN_DIALOG);
4201 /***********************************************************************
4202 * GetOpenFileNameW (COMDLG32.@)
4204 * Creates a dialog box for the user to select a file to open.
4206 * RETURNS
4207 * TRUE on success: user enters a valid file
4208 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4211 BOOL WINAPI GetOpenFileNameW(
4212 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4214 BOOL win16look = FALSE;
4216 TRACE("flags %08x\n", ofn->Flags);
4218 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4219 if (ofn->Flags & OFN_FILEMUSTEXIST)
4220 ofn->Flags |= OFN_PATHMUSTEXIST;
4222 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4223 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4225 if (win16look)
4226 return GetFileName31W(ofn, OPEN_DIALOG);
4227 else
4228 return GetFileDialog95W(ofn, OPEN_DIALOG);
4232 /***********************************************************************
4233 * GetSaveFileNameA (COMDLG32.@)
4235 * Creates a dialog box for the user to select a file to save.
4237 * RETURNS
4238 * TRUE on success: user enters a valid file
4239 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4242 BOOL WINAPI GetSaveFileNameA(
4243 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4245 BOOL win16look = FALSE;
4247 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4248 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4250 if (win16look)
4251 return GetFileName31A(ofn, SAVE_DIALOG);
4252 else
4253 return GetFileDialog95A(ofn, SAVE_DIALOG);
4256 /***********************************************************************
4257 * GetSaveFileNameW (COMDLG32.@)
4259 * Creates a dialog box for the user to select a file to save.
4261 * RETURNS
4262 * TRUE on success: user enters a valid file
4263 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4266 BOOL WINAPI GetSaveFileNameW(
4267 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4269 BOOL win16look = FALSE;
4271 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4272 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4274 if (win16look)
4275 return GetFileName31W(ofn, SAVE_DIALOG);
4276 else
4277 return GetFileDialog95W(ofn, SAVE_DIALOG);
4280 /***********************************************************************
4281 * GetFileTitleA (COMDLG32.@)
4283 * See GetFileTitleW.
4285 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4287 int ret;
4288 UNICODE_STRING strWFile;
4289 LPWSTR lpWTitle;
4291 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4292 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4293 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4294 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4295 RtlFreeUnicodeString( &strWFile );
4296 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4297 return ret;
4301 /***********************************************************************
4302 * GetFileTitleW (COMDLG32.@)
4304 * Get the name of a file.
4306 * PARAMS
4307 * lpFile [I] name and location of file
4308 * lpTitle [O] returned file name
4309 * cbBuf [I] buffer size of lpTitle
4311 * RETURNS
4312 * Success: zero
4313 * Failure: negative number.
4315 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4317 int i, len;
4318 static const WCHAR brkpoint[] = {'*','[',']',0};
4319 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4321 if(lpFile == NULL || lpTitle == NULL)
4322 return -1;
4324 len = lstrlenW(lpFile);
4326 if (len == 0)
4327 return -1;
4329 if(strpbrkW(lpFile, brkpoint))
4330 return -1;
4332 len--;
4334 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4335 return -1;
4337 for(i = len; i >= 0; i--)
4339 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4341 i++;
4342 break;
4346 if(i == -1)
4347 i++;
4349 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4351 len = lstrlenW(lpFile+i)+1;
4352 if(cbBuf < len)
4353 return len;
4355 lstrcpyW(lpTitle, &lpFile[i]);
4356 return 0;