comdlg32: Fix NULL lpstrFile uses in FILEDLG95_OnOpen.
[wine/multimedia.git] / dlls / comdlg32 / filedlg.c
blob3e7ee4f2f4e0b4073488fca44c329e398551f009
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[64];
1508 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, 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 MemFree(fodInfos->initdir);
1533 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1534 lstrcpyW(fodInfos->initdir, tmpBuf);
1535 handledPath = TRUE;
1536 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1537 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1539 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1541 } else {
1542 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1546 /* 2. (All platforms) If initdir is not null, then use it */
1547 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1548 (*fodInfos->initdir!=0x00))
1550 /* Work out the proper path as supplied one might be relative */
1551 /* (Here because supplying '.' as dir browses to My Computer) */
1552 if (handledPath==FALSE) {
1553 WCHAR tmpBuf[MAX_PATH];
1554 WCHAR tmpBuf2[MAX_PATH];
1555 WCHAR *nameBit;
1556 DWORD result;
1558 lstrcpyW(tmpBuf, fodInfos->initdir);
1559 if( PathFileExistsW(tmpBuf) ) {
1560 /* initdir does not have to be a directory. If a file is
1561 * specified, the dir part is taken */
1562 if( PathIsDirectoryW(tmpBuf)) {
1563 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1564 lstrcatW(tmpBuf, szwSlash);
1566 lstrcatW(tmpBuf, szwStar);
1568 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1569 if (result) {
1570 *nameBit = 0x00;
1571 MemFree(fodInfos->initdir);
1572 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1573 lstrcpyW(fodInfos->initdir, tmpBuf2);
1574 handledPath = TRUE;
1575 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1578 else if (fodInfos->initdir)
1580 MemFree(fodInfos->initdir);
1581 fodInfos->initdir = NULL;
1582 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1587 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1588 (*fodInfos->initdir==0x00)))
1590 /* 3. All except w2k+: if filename contains a path use it */
1591 if (!win2000plus && fodInfos->filename &&
1592 *fodInfos->filename &&
1593 strpbrkW(fodInfos->filename, szwSlash)) {
1594 WCHAR tmpBuf[MAX_PATH];
1595 WCHAR *nameBit;
1596 DWORD result;
1598 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1599 tmpBuf, &nameBit);
1600 if (result) {
1601 int len;
1603 /* nameBit is always shorter than the original filename */
1604 lstrcpyW(fodInfos->filename, nameBit);
1605 *nameBit = 0x00;
1607 len = lstrlenW(tmpBuf);
1608 MemFree(fodInfos->initdir);
1609 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1610 lstrcpyW(fodInfos->initdir, tmpBuf);
1612 handledPath = TRUE;
1613 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1614 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1616 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1619 /* 4. Win2000+: Recently used */
1620 if (handledPath == FALSE && win2000plus) {
1621 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1622 fodInfos->initdir[0] = '\0';
1624 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1626 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1627 handledPath = TRUE;
1628 }else{
1629 MemFree(fodInfos->initdir);
1630 fodInfos->initdir = NULL;
1634 /* 5. win98+ and win2000+ if any files of specified filter types in
1635 current directory, use it */
1636 if ( win98plus && handledPath == FALSE &&
1637 fodInfos->filter && *fodInfos->filter) {
1639 LPCWSTR lpstrPos = fodInfos->filter;
1640 WIN32_FIND_DATAW FindFileData;
1641 HANDLE hFind;
1643 while (1)
1645 /* filter is a list... title\0ext\0......\0\0 */
1647 /* Skip the title */
1648 if(! *lpstrPos) break; /* end */
1649 lpstrPos += lstrlenW(lpstrPos) + 1;
1651 /* See if any files exist in the current dir with this extension */
1652 if(! *lpstrPos) break; /* end */
1654 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1656 if (hFind == INVALID_HANDLE_VALUE) {
1657 /* None found - continue search */
1658 lpstrPos += lstrlenW(lpstrPos) + 1;
1660 } else {
1662 MemFree(fodInfos->initdir);
1663 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1664 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1666 handledPath = TRUE;
1667 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1668 debugstr_w(lpstrPos));
1669 FindClose(hFind);
1670 break;
1675 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1676 if (handledPath == FALSE && (win2000plus || win98plus)) {
1677 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1679 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1681 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1683 /* last fallback */
1684 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1685 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1686 } else {
1687 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1689 } else {
1690 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1692 handledPath = TRUE;
1693 } else if (handledPath==FALSE) {
1694 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1695 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1696 handledPath = TRUE;
1697 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1700 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1701 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1703 /* Must the open as read only check box be checked ?*/
1704 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1706 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1709 /* Must the open as read only check box be hidden? */
1710 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1712 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1713 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1716 /* Must the help button be hidden? */
1717 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1719 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1720 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1723 /* change Open to Save */
1724 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1726 WCHAR buf[16];
1727 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1728 SetDlgItemTextW(hwnd, IDOK, buf);
1729 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1730 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1733 /* Initialize the filter combo box */
1734 FILEDLG95_FILETYPE_Init(hwnd);
1736 return 0;
1739 /***********************************************************************
1740 * FILEDLG95_ResizeControls
1742 * WM_INITDIALOG message handler (after hook notification)
1744 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1746 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1748 if (fodInfos->DlgInfos.hwndCustomDlg)
1750 RECT rc;
1751 UINT flags = SWP_NOACTIVATE;
1753 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1754 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1756 /* resize the custom dialog to the parent size */
1757 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1758 GetClientRect(hwnd, &rc);
1759 else
1761 /* our own fake template is zero sized and doesn't have children, so
1762 * there is no need to resize it. Picasa depends on it.
1764 flags |= SWP_NOSIZE;
1765 SetRectEmpty(&rc);
1767 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1768 0, 0, rc.right, rc.bottom, flags);
1770 else
1772 /* Resize the height, if open as read only checkbox ad help button are
1773 * hidden and we are not using a custom template nor a customDialog
1775 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1776 (!(fodInfos->ofnInfos->Flags &
1777 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1779 RECT rectDlg, rectHelp, rectCancel;
1780 GetWindowRect(hwnd, &rectDlg);
1781 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1782 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1783 /* subtract the height of the help button plus the space between the help
1784 * button and the cancel button to the height of the dialog
1786 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1787 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1788 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1791 return TRUE;
1794 /***********************************************************************
1795 * FILEDLG95_FillControls
1797 * WM_INITDIALOG message handler (after hook notification)
1799 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1801 LPITEMIDLIST pidlItemId = NULL;
1803 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1805 TRACE("dir=%s file=%s\n",
1806 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1808 /* Get the initial directory pidl */
1810 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1812 WCHAR path[MAX_PATH];
1814 GetCurrentDirectoryW(MAX_PATH,path);
1815 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1818 /* Initialise shell objects */
1819 FILEDLG95_SHELL_Init(hwnd);
1821 /* Initialize the Look In combo box */
1822 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1824 /* Browse to the initial directory */
1825 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1827 /* Free pidlItem memory */
1828 COMDLG32_SHFree(pidlItemId);
1830 return TRUE;
1832 /***********************************************************************
1833 * FILEDLG95_Clean
1835 * Regroups all the cleaning functions of the filedlg
1837 void FILEDLG95_Clean(HWND hwnd)
1839 FILEDLG95_FILETYPE_Clean(hwnd);
1840 FILEDLG95_LOOKIN_Clean(hwnd);
1841 FILEDLG95_SHELL_Clean(hwnd);
1843 /***********************************************************************
1844 * FILEDLG95_OnWMCommand
1846 * WM_COMMAND message handler
1848 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1850 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1851 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1852 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1854 switch(wID)
1856 /* OK button */
1857 case IDOK:
1858 FILEDLG95_OnOpen(hwnd);
1859 break;
1860 /* Cancel button */
1861 case IDCANCEL:
1862 FILEDLG95_Clean(hwnd);
1863 EndDialog(hwnd, FALSE);
1864 break;
1865 /* Filetype combo box */
1866 case IDC_FILETYPE:
1867 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1868 break;
1869 /* LookIn combo box */
1870 case IDC_LOOKIN:
1871 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1872 break;
1874 /* --- toolbar --- */
1875 /* Up folder button */
1876 case FCIDM_TB_UPFOLDER:
1877 FILEDLG95_SHELL_UpFolder(hwnd);
1878 break;
1879 /* New folder button */
1880 case FCIDM_TB_NEWFOLDER:
1881 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1882 break;
1883 /* List option button */
1884 case FCIDM_TB_SMALLICON:
1885 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1886 break;
1887 /* Details option button */
1888 case FCIDM_TB_REPORTVIEW:
1889 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1890 break;
1891 /* Details option button */
1892 case FCIDM_TB_DESKTOP:
1893 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1894 break;
1896 case IDC_FILENAME:
1897 break;
1900 /* Do not use the listview selection anymore */
1901 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1902 return 0;
1905 /***********************************************************************
1906 * FILEDLG95_OnWMGetIShellBrowser
1908 * WM_GETISHELLBROWSER message handler
1910 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1912 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1914 TRACE("\n");
1916 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1918 return TRUE;
1922 /***********************************************************************
1923 * FILEDLG95_SendFileOK
1925 * Sends the CDN_FILEOK notification if required
1927 * RETURNS
1928 * TRUE if the dialog should close
1929 * FALSE if the dialog should not be closed
1931 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1933 /* ask the hook if we can close */
1934 if(IsHooked(fodInfos))
1936 LRESULT retval = 0;
1938 TRACE("---\n");
1939 /* First send CDN_FILEOK as MSDN doc says */
1940 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1941 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1942 if( retval)
1944 TRACE("canceled\n");
1945 return FALSE;
1948 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1949 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1950 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1951 if( retval)
1953 TRACE("canceled\n");
1954 return FALSE;
1957 return TRUE;
1960 /***********************************************************************
1961 * FILEDLG95_OnOpenMultipleFiles
1963 * Handles the opening of multiple files.
1965 * FIXME
1966 * check destination buffer size
1968 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1970 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1971 UINT nCount, nSizePath;
1972 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1974 TRACE("\n");
1976 if(fodInfos->unicode)
1978 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1979 ofn->lpstrFile[0] = '\0';
1981 else
1983 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1984 ofn->lpstrFile[0] = '\0';
1987 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1989 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1990 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1991 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1993 LPWSTR lpstrTemp = lpstrFileList;
1995 for ( nCount = 0; nCount < nFileCount; nCount++ )
1997 LPITEMIDLIST pidl;
1999 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2000 if (!pidl)
2002 WCHAR lpstrNotFound[100];
2003 WCHAR lpstrMsg[100];
2004 WCHAR tmp[400];
2005 static const WCHAR nl[] = {'\n',0};
2007 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2008 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2010 lstrcpyW(tmp, lpstrTemp);
2011 lstrcatW(tmp, nl);
2012 lstrcatW(tmp, lpstrNotFound);
2013 lstrcatW(tmp, nl);
2014 lstrcatW(tmp, lpstrMsg);
2016 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2017 return FALSE;
2020 /* move to the next file in the list of files */
2021 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2022 COMDLG32_SHFree(pidl);
2026 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2027 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2029 /* For "oldstyle" dialog the components have to
2030 be separated by blanks (not '\0'!) and short
2031 filenames have to be used! */
2032 FIXME("Components have to be separated by blanks\n");
2034 if(fodInfos->unicode)
2036 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2037 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2038 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2040 else
2042 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2044 if (ofn->lpstrFile != NULL)
2046 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2047 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2048 if (ofn->nMaxFile > nSizePath)
2050 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2051 ofn->lpstrFile + nSizePath,
2052 ofn->nMaxFile - nSizePath, NULL, NULL);
2057 fodInfos->ofnInfos->nFileOffset = nSizePath;
2058 fodInfos->ofnInfos->nFileExtension = 0;
2060 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2061 return FALSE;
2063 /* clean and exit */
2064 FILEDLG95_Clean(hwnd);
2065 return EndDialog(hwnd,TRUE);
2068 /* Returns the 'slot name' of the given module_name in the registry's
2069 * most-recently-used list. This will be an ASCII value in the
2070 * range ['a','z'). Returns zero on error.
2072 * The slot's value in the registry has the form:
2073 * module_name\0mru_path\0
2075 * If stored_path is given, then stored_path will contain the path name
2076 * stored in the registry's MRU list for the given module_name.
2078 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2079 * MRU list key for the given module_name.
2081 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2083 WCHAR mru_list[32], *cur_mru_slot;
2084 BOOL taken[25] = {0};
2085 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2086 HKEY hkey_tmp, *hkey;
2087 LONG ret;
2089 if(hkey_ret)
2090 hkey = hkey_ret;
2091 else
2092 hkey = &hkey_tmp;
2094 if(stored_path)
2095 *stored_path = '\0';
2097 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2098 if(ret){
2099 WARN("Unable to create MRU key: %d\n", ret);
2100 return 0;
2103 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2104 (LPBYTE)mru_list, &mru_list_size);
2105 if(ret || key_type != REG_SZ){
2106 if(ret == ERROR_FILE_NOT_FOUND)
2107 return 'a';
2109 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2110 RegCloseKey(*hkey);
2111 return 0;
2114 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2115 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2116 DWORD value_data_size = sizeof(value_data);
2118 *value_name = *cur_mru_slot;
2120 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2121 &key_type, (LPBYTE)value_data, &value_data_size);
2122 if(ret || key_type != REG_BINARY){
2123 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2124 continue;
2127 if(!strcmpiW(module_name, value_data)){
2128 if(!hkey_ret)
2129 RegCloseKey(*hkey);
2130 if(stored_path)
2131 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2132 return *value_name;
2136 if(!hkey_ret)
2137 RegCloseKey(*hkey);
2139 /* the module name isn't in the registry, so find the next open slot */
2140 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2141 taken[*cur_mru_slot - 'a'] = TRUE;
2142 for(i = 0; i < 25; ++i){
2143 if(!taken[i])
2144 return i + 'a';
2147 /* all slots are taken, so return the last one in MRUList */
2148 --cur_mru_slot;
2149 return *cur_mru_slot;
2152 /* save the given filename as most-recently-used path for this module */
2153 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2155 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2156 LONG ret;
2157 HKEY hkey;
2159 /* get the current executable's name */
2160 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2161 WARN("GotModuleFileName failed: %d\n", GetLastError());
2162 return;
2164 module_name = strrchrW(module_path, '\\');
2165 if(!module_name)
2166 module_name = module_path;
2167 else
2168 module_name += 1;
2170 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2171 if(!slot)
2172 return;
2173 *slot_name = slot;
2175 { /* update the slot's info */
2176 WCHAR *path_ends, *final;
2177 DWORD path_len, final_len;
2179 /* use only the path segment of `filename' */
2180 path_ends = strrchrW(filename, '\\');
2181 path_len = path_ends - filename;
2183 final_len = path_len + lstrlenW(module_name) + 2;
2185 final = MemAlloc(final_len * sizeof(WCHAR));
2186 if(!final)
2187 return;
2188 lstrcpyW(final, module_name);
2189 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2190 final[final_len-1] = '\0';
2192 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2193 final_len * sizeof(WCHAR));
2194 if(ret){
2195 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2196 MemFree(final);
2197 RegCloseKey(hkey);
2198 return;
2201 MemFree(final);
2204 { /* update MRUList value */
2205 WCHAR old_mru_list[32], new_mru_list[32];
2206 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2207 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2209 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2210 (LPBYTE)old_mru_list, &mru_list_size);
2211 if(ret || key_type != REG_SZ){
2212 if(ret == ERROR_FILE_NOT_FOUND){
2213 new_mru_list[0] = slot;
2214 new_mru_list[1] = '\0';
2215 }else{
2216 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2217 RegCloseKey(hkey);
2218 return;
2220 }else{
2221 /* copy old list data over so that the new slot is at the start
2222 * of the list */
2223 *new_mru_slot++ = slot;
2224 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2225 if(*old_mru_slot != slot)
2226 *new_mru_slot++ = *old_mru_slot;
2228 *new_mru_slot = '\0';
2231 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2232 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2233 if(ret){
2234 WARN("Error saving MRUList data: %d\n", ret);
2235 RegCloseKey(hkey);
2236 return;
2241 /* load the most-recently-used path for this module */
2242 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2244 WCHAR module_path[MAX_PATH], *module_name;
2246 /* get the current executable's name */
2247 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2248 WARN("GotModuleFileName failed: %d\n", GetLastError());
2249 return;
2251 module_name = strrchrW(module_path, '\\');
2252 if(!module_name)
2253 module_name = module_path;
2254 else
2255 module_name += 1;
2257 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2258 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2261 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2263 WCHAR strMsgTitle[MAX_PATH];
2264 WCHAR strMsgText [MAX_PATH];
2265 if (idCaption)
2266 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2267 else
2268 strMsgTitle[0] = '\0';
2269 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2270 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2273 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2274 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2276 int nOpenAction = defAction;
2277 LPWSTR lpszTemp, lpszTemp1;
2278 LPITEMIDLIST pidl = NULL;
2279 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2281 /* check for invalid chars */
2282 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2284 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2285 return FALSE;
2288 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2290 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2291 while (lpszTemp1)
2293 LPSHELLFOLDER lpsfChild;
2294 WCHAR lpwstrTemp[MAX_PATH];
2295 DWORD dwEaten, dwAttributes;
2296 LPWSTR p;
2298 lstrcpyW(lpwstrTemp, lpszTemp);
2299 p = PathFindNextComponentW(lpwstrTemp);
2301 if (!p) break; /* end of path */
2303 *p = 0;
2304 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2306 /* There are no wildcards when OFN_NOVALIDATE is set */
2307 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2309 static const WCHAR wszWild[] = { '*', '?', 0 };
2310 /* if the last element is a wildcard do a search */
2311 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2313 nOpenAction = ONOPEN_SEARCH;
2314 break;
2317 lpszTemp1 = lpszTemp;
2319 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2321 /* append a backslash to drive letters */
2322 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2323 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2324 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2326 PathAddBackslashW(lpwstrTemp);
2329 dwAttributes = SFGAO_FOLDER;
2330 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2332 /* the path component is valid, we have a pidl of the next path component */
2333 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2334 if(dwAttributes & SFGAO_FOLDER)
2336 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2338 ERR("bind to failed\n"); /* should not fail */
2339 break;
2341 IShellFolder_Release(*ppsf);
2342 *ppsf = lpsfChild;
2343 lpsfChild = NULL;
2345 else
2347 TRACE("value\n");
2349 /* end dialog, return value */
2350 nOpenAction = ONOPEN_OPEN;
2351 break;
2353 COMDLG32_SHFree(pidl);
2354 pidl = NULL;
2356 else if (!(flags & OFN_NOVALIDATE))
2358 if(*lpszTemp || /* points to trailing null for last path element */
2359 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2361 if(flags & OFN_PATHMUSTEXIST)
2363 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2364 break;
2367 else
2369 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2371 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2372 break;
2375 /* change to the current folder */
2376 nOpenAction = ONOPEN_OPEN;
2377 break;
2379 else
2381 nOpenAction = ONOPEN_OPEN;
2382 break;
2385 if(pidl) COMDLG32_SHFree(pidl);
2387 return nOpenAction;
2390 /***********************************************************************
2391 * FILEDLG95_OnOpen
2393 * Ok button WM_COMMAND message handler
2395 * If the function succeeds, the return value is nonzero.
2397 BOOL FILEDLG95_OnOpen(HWND hwnd)
2399 LPWSTR lpstrFileList;
2400 UINT nFileCount = 0;
2401 UINT sizeUsed = 0;
2402 BOOL ret = TRUE;
2403 WCHAR lpstrPathAndFile[MAX_PATH];
2404 LPSHELLFOLDER lpsf = NULL;
2405 int nOpenAction;
2406 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2408 TRACE("hwnd=%p\n", hwnd);
2410 /* try to browse the selected item */
2411 if(BrowseSelectedFolder(hwnd))
2412 return FALSE;
2414 /* get the files from the edit control */
2415 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2417 if(nFileCount == 0)
2418 return FALSE;
2420 if(nFileCount > 1)
2422 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2423 goto ret;
2426 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2429 Step 1: Build a complete path name from the current folder and
2430 the filename or path in the edit box.
2431 Special cases:
2432 - the path in the edit box is a root path
2433 (with or without drive letter)
2434 - the edit box contains ".." (or a path with ".." in it)
2437 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2438 MemFree(lpstrFileList);
2441 Step 2: here we have a cleaned up path
2443 We have to parse the path step by step to see if we have to browse
2444 to a folder if the path points to a directory or the last
2445 valid element is a directory.
2447 valid variables:
2448 lpstrPathAndFile: cleaned up path
2451 if (nFileCount &&
2452 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2453 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2454 nOpenAction = ONOPEN_OPEN;
2455 else
2456 nOpenAction = ONOPEN_BROWSE;
2458 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2459 fodInfos->ofnInfos->Flags,
2460 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2461 nOpenAction);
2462 if(!nOpenAction)
2463 goto ret;
2466 Step 3: here we have a cleaned up and validated path
2468 valid variables:
2469 lpsf: ShellFolder bound to the rightmost valid path component
2470 lpstrPathAndFile: cleaned up path
2471 nOpenAction: action to do
2473 TRACE("end validate sf=%p\n", lpsf);
2475 switch(nOpenAction)
2477 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2478 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2480 int iPos;
2481 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2482 DWORD len;
2484 /* replace the current filter */
2485 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2486 len = lstrlenW(lpszTemp)+1;
2487 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2488 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2490 /* set the filter cb to the extension when possible */
2491 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2492 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2494 /* fall through */
2495 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2496 TRACE("ONOPEN_BROWSE\n");
2498 IPersistFolder2 * ppf2;
2499 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2501 LPITEMIDLIST pidlCurrent;
2502 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2503 IPersistFolder2_Release(ppf2);
2504 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2506 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2507 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2509 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2512 else if( nOpenAction == ONOPEN_SEARCH )
2514 if (fodInfos->Shell.FOIShellView)
2515 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2517 COMDLG32_SHFree(pidlCurrent);
2518 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2521 ret = FALSE;
2522 break;
2523 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2524 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2526 WCHAR *ext = NULL;
2528 /* update READONLY check box flag */
2529 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2530 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2531 else
2532 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2534 /* Attach the file extension with file name*/
2535 ext = PathFindExtensionW(lpstrPathAndFile);
2536 if (! *ext && fodInfos->defext)
2538 /* if no extension is specified with file name, then */
2539 /* attach the extension from file filter or default one */
2541 WCHAR *filterExt = NULL;
2542 LPWSTR lpstrFilter = NULL;
2543 static const WCHAR szwDot[] = {'.',0};
2544 int PathLength = lstrlenW(lpstrPathAndFile);
2546 /*Get the file extension from file type filter*/
2547 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2548 fodInfos->ofnInfos->nFilterIndex-1);
2550 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2552 WCHAR* filterSearchIndex;
2553 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2554 strcpyW(filterExt, lpstrFilter);
2556 /* if a semicolon-separated list of file extensions was given, do not include the
2557 semicolon or anything after it in the extension.
2558 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2559 filterSearchIndex = strchrW(filterExt, ';');
2560 if (filterSearchIndex)
2562 filterSearchIndex[0] = '\0';
2565 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2566 /* if the extension is invalid or contains a glob, ignore it */
2567 filterSearchIndex = PathFindExtensionW(filterExt);
2568 if (*filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2570 strcpyW(filterExt, filterSearchIndex);
2572 else
2574 HeapFree(GetProcessHeap(), 0, filterExt);
2575 filterExt = NULL;
2579 if (!filterExt)
2581 /* use the default file extension */
2582 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2583 strcpyW(filterExt, fodInfos->defext);
2586 if (*filterExt) /* ignore filterExt="" */
2588 /* Attach the dot*/
2589 lstrcatW(lpstrPathAndFile, szwDot);
2590 /* Attach the extension */
2591 lstrcatW(lpstrPathAndFile, filterExt);
2594 HeapFree(GetProcessHeap(), 0, filterExt);
2596 /* In Open dialog: if file does not exist try without extension */
2597 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2598 lpstrPathAndFile[PathLength] = '\0';
2600 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2601 if (*ext)
2602 ext++;
2603 if (!lstrcmpiW(fodInfos->defext, ext))
2604 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2605 else
2606 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2609 /* In Save dialog: check if the file already exists */
2610 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2611 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2612 && PathFileExistsW(lpstrPathAndFile))
2614 WCHAR lpstrOverwrite[100];
2615 int answer;
2617 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2618 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2619 MB_YESNO | MB_ICONEXCLAMATION);
2620 if (answer == IDNO || answer == IDCANCEL)
2622 ret = FALSE;
2623 goto ret;
2627 /* In Open dialog: check if it should be created if it doesn't exist */
2628 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2629 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2630 && !PathFileExistsW(lpstrPathAndFile))
2632 WCHAR lpstrCreate[100];
2633 int answer;
2635 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2636 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2637 MB_YESNO | MB_ICONEXCLAMATION);
2638 if (answer == IDNO || answer == IDCANCEL)
2640 ret = FALSE;
2641 goto ret;
2645 /* Check that the size of the file does not exceed buffer size.
2646 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2647 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2648 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2651 /* fill destination buffer */
2652 if (fodInfos->ofnInfos->lpstrFile)
2654 if(fodInfos->unicode)
2656 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2658 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2659 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2660 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2662 else
2664 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2666 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2667 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2668 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2669 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2673 if(fodInfos->unicode)
2675 LPWSTR lpszTemp;
2677 /* set filename offset */
2678 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2679 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2681 /* set extension offset */
2682 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2683 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2685 else
2687 LPSTR lpszTemp;
2688 CHAR tempFileA[MAX_PATH];
2690 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2691 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2692 tempFileA, sizeof(tempFileA), NULL, NULL);
2694 /* set filename offset */
2695 lpszTemp = PathFindFileNameA(tempFileA);
2696 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2698 /* set extension offset */
2699 lpszTemp = PathFindExtensionA(tempFileA);
2700 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2703 /* set the lpstrFileTitle */
2704 if(fodInfos->ofnInfos->lpstrFileTitle)
2706 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2707 if(fodInfos->unicode)
2709 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2710 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2712 else
2714 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2715 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2716 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2720 /* copy currently selected filter to lpstrCustomFilter */
2721 if (fodInfos->ofnInfos->lpstrCustomFilter)
2723 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2724 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2725 NULL, 0, NULL, NULL);
2726 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2728 LPSTR s = ofn->lpstrCustomFilter;
2729 s += strlen(ofn->lpstrCustomFilter)+1;
2730 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2731 s, len, NULL, NULL);
2736 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2737 goto ret;
2739 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2741 TRACE("close\n");
2742 FILEDLG95_Clean(hwnd);
2743 ret = EndDialog(hwnd, TRUE);
2745 else
2747 WORD size;
2749 size = lstrlenW(lpstrPathAndFile) + 1;
2750 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2751 size += 1;
2752 /* return needed size in first two bytes of lpstrFile */
2753 if(fodInfos->ofnInfos->lpstrFile)
2754 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2755 FILEDLG95_Clean(hwnd);
2756 ret = EndDialog(hwnd, FALSE);
2757 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2760 break;
2763 ret:
2764 if(lpsf) IShellFolder_Release(lpsf);
2765 return ret;
2768 /***********************************************************************
2769 * FILEDLG95_SHELL_Init
2771 * Initialisation of the shell objects
2773 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2775 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2777 TRACE("\n");
2780 * Initialisation of the FileOpenDialogInfos structure
2783 /* Shell */
2785 /*ShellInfos */
2786 fodInfos->ShellInfos.hwndOwner = hwnd;
2788 /* Disable multi-select if flag not set */
2789 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2791 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2793 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2794 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2796 /* Construct the IShellBrowser interface */
2797 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2799 return NOERROR;
2802 /***********************************************************************
2803 * FILEDLG95_SHELL_ExecuteCommand
2805 * Change the folder option and refresh the view
2806 * If the function succeeds, the return value is nonzero.
2808 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2810 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2811 IContextMenu * pcm;
2813 TRACE("(%p,%p)\n", hwnd, lpVerb);
2815 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2816 SVGIO_BACKGROUND,
2817 &IID_IContextMenu,
2818 (LPVOID*)&pcm)))
2820 CMINVOKECOMMANDINFO ci;
2821 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2822 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2823 ci.lpVerb = lpVerb;
2824 ci.hwnd = hwnd;
2826 IContextMenu_InvokeCommand(pcm, &ci);
2827 IContextMenu_Release(pcm);
2830 return FALSE;
2833 /***********************************************************************
2834 * FILEDLG95_SHELL_UpFolder
2836 * Browse to the specified object
2837 * If the function succeeds, the return value is nonzero.
2839 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2841 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2843 TRACE("\n");
2845 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2846 NULL,
2847 SBSP_PARENT)))
2849 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2850 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2851 return TRUE;
2853 return FALSE;
2856 /***********************************************************************
2857 * FILEDLG95_SHELL_BrowseToDesktop
2859 * Browse to the Desktop
2860 * If the function succeeds, the return value is nonzero.
2862 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2864 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2865 LPITEMIDLIST pidl;
2866 HRESULT hres;
2868 TRACE("\n");
2870 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2871 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2872 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2873 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2874 COMDLG32_SHFree(pidl);
2875 return SUCCEEDED(hres);
2877 /***********************************************************************
2878 * FILEDLG95_SHELL_Clean
2880 * Cleans the memory used by shell objects
2882 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2884 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2886 TRACE("\n");
2888 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2890 /* clean Shell interfaces */
2891 if (fodInfos->Shell.FOIShellView)
2893 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2894 IShellView_Release(fodInfos->Shell.FOIShellView);
2896 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2897 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2898 if (fodInfos->Shell.FOIDataObject)
2899 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2902 /***********************************************************************
2903 * FILEDLG95_FILETYPE_Init
2905 * Initialisation of the file type combo box
2907 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2909 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2910 int nFilters = 0; /* number of filters */
2911 int nFilterIndexCB;
2913 TRACE("\n");
2915 if(fodInfos->customfilter)
2917 /* customfilter has one entry... title\0ext\0
2918 * Set first entry of combo box item with customfilter
2920 LPWSTR lpstrExt;
2921 LPCWSTR lpstrPos = fodInfos->customfilter;
2923 /* Get the title */
2924 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2926 /* Copy the extensions */
2927 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2928 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2929 lstrcpyW(lpstrExt,lpstrPos);
2931 /* Add the item at the end of the combo */
2932 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2933 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2934 nFilters++;
2936 if(fodInfos->filter)
2938 LPCWSTR lpstrPos = fodInfos->filter;
2940 for(;;)
2942 /* filter is a list... title\0ext\0......\0\0
2943 * Set the combo item text to the title and the item data
2944 * to the ext
2946 LPCWSTR lpstrDisplay;
2947 LPWSTR lpstrExt;
2949 /* Get the title */
2950 if(! *lpstrPos) break; /* end */
2951 lpstrDisplay = lpstrPos;
2952 lpstrPos += lstrlenW(lpstrPos) + 1;
2954 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2956 nFilters++;
2958 /* Copy the extensions */
2959 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2960 lstrcpyW(lpstrExt,lpstrPos);
2961 lpstrPos += lstrlenW(lpstrPos) + 1;
2963 /* Add the item at the end of the combo */
2964 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2966 /* malformed filters are added anyway... */
2967 if (!*lpstrExt) break;
2972 * Set the current filter to the one specified
2973 * in the initialisation structure
2975 if (fodInfos->filter || fodInfos->customfilter)
2977 LPWSTR lpstrFilter;
2979 /* Check to make sure our index isn't out of bounds. */
2980 if ( fodInfos->ofnInfos->nFilterIndex >
2981 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2982 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2984 /* set default filter index */
2985 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2986 fodInfos->ofnInfos->nFilterIndex = 1;
2988 /* calculate index of Combo Box item */
2989 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2990 if (fodInfos->customfilter == NULL)
2991 nFilterIndexCB--;
2993 /* Set the current index selection. */
2994 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2996 /* Get the corresponding text string from the combo box. */
2997 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2998 nFilterIndexCB);
3000 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3001 lpstrFilter = NULL;
3003 if(lpstrFilter)
3005 DWORD len;
3006 CharLowerW(lpstrFilter); /* lowercase */
3007 len = lstrlenW(lpstrFilter)+1;
3008 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3009 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3011 } else
3012 fodInfos->ofnInfos->nFilterIndex = 0;
3013 return S_OK;
3016 /***********************************************************************
3017 * FILEDLG95_FILETYPE_OnCommand
3019 * WM_COMMAND of the file type combo box
3020 * If the function succeeds, the return value is nonzero.
3022 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3024 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3026 switch(wNotifyCode)
3028 case CBN_SELENDOK:
3030 LPWSTR lpstrFilter;
3032 /* Get the current item of the filetype combo box */
3033 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3035 /* set the current filter index */
3036 fodInfos->ofnInfos->nFilterIndex = iItem +
3037 (fodInfos->customfilter == NULL ? 1 : 0);
3039 /* Set the current filter with the current selection */
3040 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3042 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3043 iItem);
3044 if((INT_PTR)lpstrFilter != CB_ERR)
3046 DWORD len;
3047 CharLowerW(lpstrFilter); /* lowercase */
3048 len = lstrlenW(lpstrFilter)+1;
3049 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3050 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3051 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3052 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3055 /* Refresh the actual view to display the included items*/
3056 if (fodInfos->Shell.FOIShellView)
3057 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3060 return FALSE;
3062 /***********************************************************************
3063 * FILEDLG95_FILETYPE_SearchExt
3065 * searches for an extension in the filetype box
3067 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3069 int i, iCount = CBGetCount(hwnd);
3071 TRACE("%s\n", debugstr_w(lpstrExt));
3073 if(iCount != CB_ERR)
3075 for(i=0;i<iCount;i++)
3077 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3078 return i;
3081 return -1;
3084 /***********************************************************************
3085 * FILEDLG95_FILETYPE_Clean
3087 * Clean the memory used by the filetype combo box
3089 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3091 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3092 int iPos;
3093 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3095 TRACE("\n");
3097 /* Delete each string of the combo and their associated data */
3098 if(iCount != CB_ERR)
3100 for(iPos = iCount-1;iPos>=0;iPos--)
3102 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3103 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3106 /* Current filter */
3107 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3111 /***********************************************************************
3112 * FILEDLG95_LOOKIN_Init
3114 * Initialisation of the look in combo box
3117 /* Small helper function, to determine if the unixfs shell extension is rooted
3118 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3120 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3121 HKEY hKey;
3122 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3123 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3125 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3126 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3127 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3128 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3130 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3131 return FALSE;
3133 RegCloseKey(hKey);
3134 return TRUE;
3137 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3139 IShellFolder *psfRoot, *psfDrives;
3140 IEnumIDList *lpeRoot, *lpeDrives;
3141 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3143 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3145 TRACE("\n");
3147 liInfos->iMaxIndentation = 0;
3149 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3151 /* set item height for both text field and listbox */
3152 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3153 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3155 /* Turn on the extended UI for the combo box like Windows does */
3156 CBSetExtendedUI(hwndCombo, TRUE);
3158 /* Initialise data of Desktop folder */
3159 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3160 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3161 COMDLG32_SHFree(pidlTmp);
3163 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3165 SHGetDesktopFolder(&psfRoot);
3167 if (psfRoot)
3169 /* enumerate the contents of the desktop */
3170 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3172 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3174 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3176 /* If the unixfs extension is rooted, we don't expand the drives by default */
3177 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3179 /* special handling for CSIDL_DRIVES */
3180 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3182 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3184 /* enumerate the drives */
3185 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3187 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3189 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3190 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3191 COMDLG32_SHFree(pidlAbsTmp);
3192 COMDLG32_SHFree(pidlTmp1);
3194 IEnumIDList_Release(lpeDrives);
3196 IShellFolder_Release(psfDrives);
3201 COMDLG32_SHFree(pidlTmp);
3203 IEnumIDList_Release(lpeRoot);
3205 IShellFolder_Release(psfRoot);
3208 COMDLG32_SHFree(pidlDrives);
3211 /***********************************************************************
3212 * FILEDLG95_LOOKIN_DrawItem
3214 * WM_DRAWITEM message handler
3216 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3218 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3219 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3220 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3221 RECT rectText;
3222 RECT rectIcon;
3223 SHFILEINFOW sfi;
3224 HIMAGELIST ilItemImage;
3225 int iIndentation;
3226 TEXTMETRICW tm;
3227 LPSFOLDER tmpFolder;
3228 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3230 TRACE("\n");
3232 if(pDIStruct->itemID == -1)
3233 return 0;
3235 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3236 pDIStruct->itemID)))
3237 return 0;
3240 if(pDIStruct->itemID == liInfos->uSelectedItem)
3242 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3244 &sfi,
3245 sizeof (sfi),
3246 SHGFI_PIDL | SHGFI_SMALLICON |
3247 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3248 SHGFI_DISPLAYNAME );
3250 else
3252 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3254 &sfi,
3255 sizeof (sfi),
3256 SHGFI_PIDL | SHGFI_SMALLICON |
3257 SHGFI_SYSICONINDEX |
3258 SHGFI_DISPLAYNAME);
3261 /* Is this item selected ? */
3262 if(pDIStruct->itemState & ODS_SELECTED)
3264 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3265 SetBkColor(pDIStruct->hDC,crHighLight);
3266 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3268 else
3270 SetTextColor(pDIStruct->hDC,crText);
3271 SetBkColor(pDIStruct->hDC,crWin);
3272 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3275 /* Do not indent item if drawing in the edit of the combo */
3276 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3278 iIndentation = 0;
3279 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3281 &sfi,
3282 sizeof (sfi),
3283 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3284 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3287 else
3289 iIndentation = tmpFolder->m_iIndent;
3291 /* Draw text and icon */
3293 /* Initialise the icon display area */
3294 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3295 rectIcon.top = pDIStruct->rcItem.top;
3296 rectIcon.right = rectIcon.left + ICONWIDTH;
3297 rectIcon.bottom = pDIStruct->rcItem.bottom;
3299 /* Initialise the text display area */
3300 GetTextMetricsW(pDIStruct->hDC, &tm);
3301 rectText.left = rectIcon.right;
3302 rectText.top =
3303 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3304 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3305 rectText.bottom =
3306 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3308 /* Draw the icon from the image list */
3309 ImageList_Draw(ilItemImage,
3310 sfi.iIcon,
3311 pDIStruct->hDC,
3312 rectIcon.left,
3313 rectIcon.top,
3314 ILD_TRANSPARENT );
3316 /* Draw the associated text */
3317 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3318 return NOERROR;
3321 /***********************************************************************
3322 * FILEDLG95_LOOKIN_OnCommand
3324 * LookIn combo box WM_COMMAND message handler
3325 * If the function succeeds, the return value is nonzero.
3327 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3329 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3331 TRACE("%p\n", fodInfos);
3333 switch(wNotifyCode)
3335 case CBN_SELENDOK:
3337 LPSFOLDER tmpFolder;
3338 int iItem;
3340 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3342 if( iItem == CB_ERR) return FALSE;
3344 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3345 iItem)))
3346 return FALSE;
3349 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3350 tmpFolder->pidlItem,
3351 SBSP_ABSOLUTE)))
3353 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3354 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3355 return TRUE;
3357 break;
3361 return FALSE;
3364 /***********************************************************************
3365 * FILEDLG95_LOOKIN_AddItem
3367 * Adds an absolute pidl item to the lookin combo box
3368 * returns the index of the inserted item
3370 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3372 LPITEMIDLIST pidlNext;
3373 SHFILEINFOW sfi;
3374 SFOLDER *tmpFolder;
3375 LookInInfos *liInfos;
3377 TRACE("%08x\n", iInsertId);
3379 if(!pidl)
3380 return -1;
3382 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3383 return -1;
3385 tmpFolder = MemAlloc(sizeof(SFOLDER));
3386 tmpFolder->m_iIndent = 0;
3388 /* Calculate the indentation of the item in the lookin*/
3389 pidlNext = pidl;
3390 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3392 tmpFolder->m_iIndent++;
3395 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3397 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3398 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3400 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3401 SHGetFileInfoW((LPCWSTR)pidl,
3403 &sfi,
3404 sizeof(sfi),
3405 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3406 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3408 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3410 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3412 int iItemID;
3414 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3416 /* Add the item at the end of the list */
3417 if(iInsertId < 0)
3419 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3421 /* Insert the item at the iInsertId position*/
3422 else
3424 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3427 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3428 return iItemID;
3431 COMDLG32_SHFree( tmpFolder->pidlItem );
3432 MemFree( tmpFolder );
3433 return -1;
3437 /***********************************************************************
3438 * FILEDLG95_LOOKIN_InsertItemAfterParent
3440 * Insert an item below its parent
3442 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3445 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3446 int iParentPos;
3448 TRACE("\n");
3450 if (pidl == pidlParent)
3451 return -1;
3453 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3455 if(iParentPos < 0)
3457 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3460 /* Free pidlParent memory */
3461 COMDLG32_SHFree(pidlParent);
3463 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3466 /***********************************************************************
3467 * FILEDLG95_LOOKIN_SelectItem
3469 * Adds an absolute pidl item to the lookin combo box
3470 * returns the index of the inserted item
3472 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3474 int iItemPos;
3475 LookInInfos *liInfos;
3477 TRACE("\n");
3479 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3481 liInfos = GetPropA(hwnd,LookInInfosStr);
3483 if(iItemPos < 0)
3485 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3486 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3489 else
3491 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3492 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3494 int iRemovedItem;
3496 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3497 break;
3498 if(iRemovedItem < iItemPos)
3499 iItemPos--;
3503 CBSetCurSel(hwnd,iItemPos);
3504 liInfos->uSelectedItem = iItemPos;
3506 return 0;
3510 /***********************************************************************
3511 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3513 * Remove the item with an expansion level over iExpansionLevel
3515 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3517 int iItemPos;
3518 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3520 TRACE("\n");
3522 if(liInfos->iMaxIndentation <= 2)
3523 return -1;
3525 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3527 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3528 COMDLG32_SHFree(tmpFolder->pidlItem);
3529 MemFree(tmpFolder);
3530 CBDeleteString(hwnd,iItemPos);
3531 liInfos->iMaxIndentation--;
3533 return iItemPos;
3536 return -1;
3539 /***********************************************************************
3540 * FILEDLG95_LOOKIN_SearchItem
3542 * Search for pidl in the lookin combo box
3543 * returns the index of the found item
3545 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3547 int i = 0;
3548 int iCount = CBGetCount(hwnd);
3550 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3552 if (iCount != CB_ERR)
3554 for(;i<iCount;i++)
3556 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3558 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3559 return i;
3560 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3561 return i;
3565 return -1;
3568 /***********************************************************************
3569 * FILEDLG95_LOOKIN_Clean
3571 * Clean the memory used by the lookin combo box
3573 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3575 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3576 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3577 int iPos;
3578 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3580 TRACE("\n");
3582 /* Delete each string of the combo and their associated data */
3583 if (iCount != CB_ERR)
3585 for(iPos = iCount-1;iPos>=0;iPos--)
3587 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3588 COMDLG32_SHFree(tmpFolder->pidlItem);
3589 MemFree(tmpFolder);
3590 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3594 /* LookInInfos structure */
3595 MemFree(liInfos);
3596 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3599 /***********************************************************************
3600 * FILEDLG95_FILENAME_FillFromSelection
3602 * fills the edit box from the cached DataObject
3604 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3606 FileOpenDlgInfos *fodInfos;
3607 LPITEMIDLIST pidl;
3608 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3609 WCHAR lpstrTemp[MAX_PATH];
3610 LPWSTR lpstrAllFile, lpstrCurrFile;
3612 TRACE("\n");
3613 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3615 /* Count how many files we have */
3616 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3618 /* calculate the string length, count files */
3619 if (nFileSelected >= 1)
3621 nLength += 3; /* first and last quotes, trailing \0 */
3622 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3624 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3626 if (pidl)
3628 /* get the total length of the selected file names */
3629 lpstrTemp[0] = '\0';
3630 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3632 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3634 nLength += lstrlenW( lpstrTemp ) + 3;
3635 nFiles++;
3637 COMDLG32_SHFree( pidl );
3642 /* allocate the buffer */
3643 if (nFiles <= 1) nLength = MAX_PATH;
3644 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3646 /* Generate the string for the edit control */
3647 if(nFiles >= 1)
3649 lpstrCurrFile = lpstrAllFile;
3650 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3652 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3654 if (pidl)
3656 /* get the file name */
3657 lpstrTemp[0] = '\0';
3658 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3660 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3662 if ( nFiles > 1)
3664 *lpstrCurrFile++ = '\"';
3665 lstrcpyW( lpstrCurrFile, lpstrTemp );
3666 lpstrCurrFile += lstrlenW( lpstrTemp );
3667 *lpstrCurrFile++ = '\"';
3668 *lpstrCurrFile++ = ' ';
3669 *lpstrCurrFile = 0;
3671 else
3673 lstrcpyW( lpstrAllFile, lpstrTemp );
3676 COMDLG32_SHFree( pidl );
3679 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3681 /* Select the file name like Windows does */
3682 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3684 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3688 /* copied from shell32 to avoid linking to it
3689 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3690 * is dependent on whether emulated OS is unicode or not.
3692 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3694 switch (src->uType)
3696 case STRRET_WSTR:
3697 lstrcpynW(dest, src->u.pOleStr, len);
3698 COMDLG32_SHFree(src->u.pOleStr);
3699 break;
3701 case STRRET_CSTR:
3702 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3703 dest[len-1] = 0;
3704 break;
3706 case STRRET_OFFSET:
3707 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3708 dest[len-1] = 0;
3709 break;
3711 default:
3712 FIXME("unknown type %x!\n", src->uType);
3713 if (len) *dest = '\0';
3714 return E_FAIL;
3716 return S_OK;
3719 /***********************************************************************
3720 * FILEDLG95_FILENAME_GetFileNames
3722 * Copies the filenames to a delimited string list.
3724 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3726 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3727 UINT nFileCount = 0; /* number of files */
3728 UINT nStrLen = 0; /* length of string in edit control */
3729 LPWSTR lpstrEdit; /* buffer for string from edit control */
3731 TRACE("\n");
3733 /* get the filenames from the edit control */
3734 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3735 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3736 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3738 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3740 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3741 MemFree(lpstrEdit);
3742 return nFileCount;
3745 #define SETDefFormatEtc(fe,cf,med) \
3747 (fe).cfFormat = cf;\
3748 (fe).dwAspect = DVASPECT_CONTENT; \
3749 (fe).ptd =NULL;\
3750 (fe).tymed = med;\
3751 (fe).lindex = -1;\
3755 * DATAOBJECT Helper functions
3758 /***********************************************************************
3759 * COMCTL32_ReleaseStgMedium
3761 * like ReleaseStgMedium from ole32
3763 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3765 if(medium.pUnkForRelease)
3767 IUnknown_Release(medium.pUnkForRelease);
3769 else
3771 GlobalUnlock(medium.u.hGlobal);
3772 GlobalFree(medium.u.hGlobal);
3776 /***********************************************************************
3777 * GetPidlFromDataObject
3779 * Return pidl(s) by number from the cached DataObject
3781 * nPidlIndex=0 gets the fully qualified root path
3783 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3786 STGMEDIUM medium;
3787 FORMATETC formatetc;
3788 LPITEMIDLIST pidl = NULL;
3790 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3792 if (!doSelected)
3793 return NULL;
3795 /* Set the FORMATETC structure*/
3796 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3798 /* Get the pidls from IDataObject */
3799 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3801 LPIDA cida = GlobalLock(medium.u.hGlobal);
3802 if(nPidlIndex <= cida->cidl)
3804 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3806 COMCTL32_ReleaseStgMedium(medium);
3808 return pidl;
3811 /***********************************************************************
3812 * GetNumSelected
3814 * Return the number of selected items in the DataObject.
3817 static UINT GetNumSelected( IDataObject *doSelected )
3819 UINT retVal = 0;
3820 STGMEDIUM medium;
3821 FORMATETC formatetc;
3823 TRACE("sv=%p\n", doSelected);
3825 if (!doSelected) return 0;
3827 /* Set the FORMATETC structure*/
3828 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3830 /* Get the pidls from IDataObject */
3831 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3833 LPIDA cida = GlobalLock(medium.u.hGlobal);
3834 retVal = cida->cidl;
3835 COMCTL32_ReleaseStgMedium(medium);
3836 return retVal;
3838 return 0;
3842 * TOOLS
3845 /***********************************************************************
3846 * GetName
3848 * Get the pidl's display name (relative to folder) and
3849 * put it in lpstrFileName.
3851 * Return NOERROR on success,
3852 * E_FAIL otherwise
3855 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3857 STRRET str;
3858 HRESULT hRes;
3860 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3862 if(!lpsf)
3864 SHGetDesktopFolder(&lpsf);
3865 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3866 IShellFolder_Release(lpsf);
3867 return hRes;
3870 /* Get the display name of the pidl relative to the folder */
3871 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3873 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3875 return E_FAIL;
3878 /***********************************************************************
3879 * GetShellFolderFromPidl
3881 * pidlRel is the item pidl relative
3882 * Return the IShellFolder of the absolute pidl
3884 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3886 IShellFolder *psf = NULL,*psfParent;
3888 TRACE("%p\n", pidlAbs);
3890 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3892 psf = psfParent;
3893 if(pidlAbs && pidlAbs->mkid.cb)
3895 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3897 IShellFolder_Release(psfParent);
3898 return psf;
3901 /* return the desktop */
3902 return psfParent;
3904 return NULL;
3907 /***********************************************************************
3908 * GetParentPidl
3910 * Return the LPITEMIDLIST to the parent of the pidl in the list
3912 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3914 LPITEMIDLIST pidlParent;
3916 TRACE("%p\n", pidl);
3918 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3919 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3921 return pidlParent;
3924 /***********************************************************************
3925 * GetPidlFromName
3927 * returns the pidl of the file name relative to folder
3928 * NULL if an error occurred
3930 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3932 LPITEMIDLIST pidl = NULL;
3933 ULONG ulEaten;
3935 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3937 if(!lpcstrFileName) return NULL;
3938 if(!*lpcstrFileName) return NULL;
3940 if(!lpsf)
3942 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3943 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3944 IShellFolder_Release(lpsf);
3947 else
3949 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3951 return pidl;
3956 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3958 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3959 HRESULT ret;
3961 TRACE("%p, %p\n", psf, pidl);
3963 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3965 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3966 /* see documentation shell 4.1*/
3967 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3970 /***********************************************************************
3971 * BrowseSelectedFolder
3973 static BOOL BrowseSelectedFolder(HWND hwnd)
3975 BOOL bBrowseSelFolder = FALSE;
3976 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3978 TRACE("\n");
3980 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3982 LPITEMIDLIST pidlSelection;
3984 /* get the file selected */
3985 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3986 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3988 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3989 pidlSelection, SBSP_RELATIVE ) ) )
3991 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3992 ' ','n','o','t',' ','e','x','i','s','t',0};
3993 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3995 bBrowseSelFolder = TRUE;
3996 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3997 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3999 COMDLG32_SHFree( pidlSelection );
4002 return bBrowseSelFolder;
4006 * Memory allocation methods */
4007 static void *MemAlloc(UINT size)
4009 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4012 static void MemFree(void *mem)
4014 HeapFree(GetProcessHeap(),0,mem);
4018 * Old-style (win3.1) dialogs */
4020 /***********************************************************************
4021 * FD32_GetTemplate [internal]
4023 * Get a template (or FALSE if failure) when 16 bits dialogs are used
4024 * by a 32 bits application
4027 BOOL FD32_GetTemplate(PFD31_DATA lfs)
4029 LPOPENFILENAMEW ofnW = lfs->ofnW;
4030 LPOPENFILENAMEA ofnA = lfs->ofnA;
4031 HANDLE hDlgTmpl;
4033 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
4035 if (!(lfs->template = LockResource( ofnW->hInstance )))
4037 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4038 return FALSE;
4041 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
4043 HRSRC hResInfo;
4044 if (ofnA)
4045 hResInfo = FindResourceA(ofnA->hInstance,
4046 ofnA->lpTemplateName,
4047 (LPSTR)RT_DIALOG);
4048 else
4049 hResInfo = FindResourceW(ofnW->hInstance,
4050 ofnW->lpTemplateName,
4051 (LPWSTR)RT_DIALOG);
4052 if (!hResInfo)
4054 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4055 return FALSE;
4057 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4058 hResInfo)) ||
4059 !(lfs->template = LockResource(hDlgTmpl)))
4061 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4062 return FALSE;
4064 } else { /* get it from internal Wine resource */
4065 HRSRC hResInfo;
4066 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4067 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4069 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4070 return FALSE;
4072 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4073 !(lfs->template = LockResource( hDlgTmpl )))
4075 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4076 return FALSE;
4079 return TRUE;
4083 /***********************************************************************
4084 * FD32_WMMeasureItem [internal]
4086 static LONG FD32_WMMeasureItem(LPARAM lParam)
4088 LPMEASUREITEMSTRUCT lpmeasure;
4090 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4091 lpmeasure->itemHeight = FD31_GetFldrHeight();
4092 return TRUE;
4096 /***********************************************************************
4097 * FileOpenDlgProc [internal]
4098 * Used for open and save, in fact.
4100 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4101 WPARAM wParam, LPARAM lParam)
4103 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4105 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4106 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4108 INT_PTR lRet;
4109 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4110 if (lRet)
4111 return lRet; /* else continue message processing */
4113 switch (wMsg)
4115 case WM_INITDIALOG:
4116 return FD31_WMInitDialog(hWnd, wParam, lParam);
4118 case WM_MEASUREITEM:
4119 return FD32_WMMeasureItem(lParam);
4121 case WM_DRAWITEM:
4122 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4124 case WM_COMMAND:
4125 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4126 #if 0
4127 case WM_CTLCOLOR:
4128 SetBkColor((HDC16)wParam, 0x00C0C0C0);
4129 switch (HIWORD(lParam))
4131 case CTLCOLOR_BTN:
4132 SetTextColor((HDC16)wParam, 0x00000000);
4133 return hGRAYBrush;
4134 case CTLCOLOR_STATIC:
4135 SetTextColor((HDC16)wParam, 0x00000000);
4136 return hGRAYBrush;
4138 break;
4139 #endif
4141 return FALSE;
4145 /***********************************************************************
4146 * GetFileName31A [internal]
4148 * Creates a win31 style dialog box for the user to select a file to open/save.
4150 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4151 UINT dlgType /* type dialogue : open/save */
4154 BOOL bRet = FALSE;
4155 PFD31_DATA lfs;
4157 if (!lpofn || !FD31_Init()) return FALSE;
4159 TRACE("ofn flags %08x\n", lpofn->Flags);
4160 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4161 if (lfs)
4163 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4164 FD32_FileOpenDlgProc, (LPARAM)lfs);
4165 FD31_DestroyPrivate(lfs);
4168 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4169 return bRet;
4172 /***********************************************************************
4173 * GetFileName31W [internal]
4175 * Creates a win31 style dialog box for the user to select a file to open/save
4177 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4178 UINT dlgType /* type dialogue : open/save */
4181 BOOL bRet = FALSE;
4182 PFD31_DATA lfs;
4184 if (!lpofn || !FD31_Init()) return FALSE;
4186 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4187 if (lfs)
4189 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4190 FD32_FileOpenDlgProc, (LPARAM)lfs);
4191 FD31_DestroyPrivate(lfs);
4194 TRACE("file %s, file offset %d, ext offset %d\n",
4195 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4196 return bRet;
4199 /* ------------------ APIs ---------------------- */
4201 /***********************************************************************
4202 * GetOpenFileNameA (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 GetOpenFileNameA(
4212 LPOPENFILENAMEA 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 GetFileName31A(ofn, OPEN_DIALOG);
4227 else
4228 return GetFileDialog95A(ofn, OPEN_DIALOG);
4231 /***********************************************************************
4232 * GetOpenFileNameW (COMDLG32.@)
4234 * Creates a dialog box for the user to select a file to open.
4236 * RETURNS
4237 * TRUE on success: user enters a valid file
4238 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4241 BOOL WINAPI GetOpenFileNameW(
4242 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4244 BOOL win16look = FALSE;
4246 TRACE("flags %08x\n", ofn->Flags);
4248 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4249 if (ofn->Flags & OFN_FILEMUSTEXIST)
4250 ofn->Flags |= OFN_PATHMUSTEXIST;
4252 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4253 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4255 if (win16look)
4256 return GetFileName31W(ofn, OPEN_DIALOG);
4257 else
4258 return GetFileDialog95W(ofn, OPEN_DIALOG);
4262 /***********************************************************************
4263 * GetSaveFileNameA (COMDLG32.@)
4265 * Creates a dialog box for the user to select a file to save.
4267 * RETURNS
4268 * TRUE on success: user enters a valid file
4269 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4272 BOOL WINAPI GetSaveFileNameA(
4273 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4275 BOOL win16look = FALSE;
4277 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4278 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4280 if (win16look)
4281 return GetFileName31A(ofn, SAVE_DIALOG);
4282 else
4283 return GetFileDialog95A(ofn, SAVE_DIALOG);
4286 /***********************************************************************
4287 * GetSaveFileNameW (COMDLG32.@)
4289 * Creates a dialog box for the user to select a file to save.
4291 * RETURNS
4292 * TRUE on success: user enters a valid file
4293 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4296 BOOL WINAPI GetSaveFileNameW(
4297 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4299 BOOL win16look = FALSE;
4301 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4302 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4304 if (win16look)
4305 return GetFileName31W(ofn, SAVE_DIALOG);
4306 else
4307 return GetFileDialog95W(ofn, SAVE_DIALOG);
4310 /***********************************************************************
4311 * GetFileTitleA (COMDLG32.@)
4313 * See GetFileTitleW.
4315 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4317 int ret;
4318 UNICODE_STRING strWFile;
4319 LPWSTR lpWTitle;
4321 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4322 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4323 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4324 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4325 RtlFreeUnicodeString( &strWFile );
4326 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4327 return ret;
4331 /***********************************************************************
4332 * GetFileTitleW (COMDLG32.@)
4334 * Get the name of a file.
4336 * PARAMS
4337 * lpFile [I] name and location of file
4338 * lpTitle [O] returned file name
4339 * cbBuf [I] buffer size of lpTitle
4341 * RETURNS
4342 * Success: zero
4343 * Failure: negative number.
4345 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4347 int i, len;
4348 static const WCHAR brkpoint[] = {'*','[',']',0};
4349 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4351 if(lpFile == NULL || lpTitle == NULL)
4352 return -1;
4354 len = lstrlenW(lpFile);
4356 if (len == 0)
4357 return -1;
4359 if(strpbrkW(lpFile, brkpoint))
4360 return -1;
4362 len--;
4364 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4365 return -1;
4367 for(i = len; i >= 0; i--)
4369 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4371 i++;
4372 break;
4376 if(i == -1)
4377 i++;
4379 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4381 len = lstrlenW(lpFile+i)+1;
4382 if(cbBuf < len)
4383 return len;
4385 lstrcpyW(lpTitle, &lpFile[i]);
4386 return 0;