msxml3: Orphan a node removed with removeChild().
[wine/multimedia.git] / dlls / comdlg32 / filedlg.c
blob2fb0969abb4f457629372f7e24c5e3afe06e7ffd
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 * ArrangeCtrlPositions [internal]
574 * NOTE: Make sure to add testcases for any changes made here.
576 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
578 HWND hwndChild, hwndStc32;
579 RECT rectParent, rectChild, rectStc32;
580 INT help_fixup = 0;
581 int chgx, chgy;
583 /* Take into account if open as read only checkbox and help button
584 * are hidden
586 if (hide_help)
588 RECT rectHelp, rectCancel;
589 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
590 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
591 /* subtract the height of the help button plus the space between
592 * the help button and the cancel button to the height of the dialog
594 help_fixup = rectHelp.bottom - rectCancel.bottom;
598 There are two possibilities to add components to the default file dialog box.
600 By default, all the new components are added below the standard dialog box (the else case).
602 However, if there is a static text component with the stc32 id, a special case happens.
603 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
604 in the window and the cx and cy indicate how to size the window.
605 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
606 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
610 GetClientRect(hwndParentDlg, &rectParent);
612 /* when arranging controls we have to use fixed parent size */
613 rectParent.bottom -= help_fixup;
615 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
616 if (hwndStc32)
618 GetWindowRect(hwndStc32, &rectStc32);
619 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
621 /* set the size of the stc32 control according to the size of
622 * client area of the parent dialog
624 SetWindowPos(hwndStc32, 0,
625 0, 0,
626 rectParent.right, rectParent.bottom,
627 SWP_NOMOVE | SWP_NOZORDER);
629 else
630 SetRectEmpty(&rectStc32);
632 /* this part moves controls of the child dialog */
633 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
634 while (hwndChild)
636 if (hwndChild != hwndStc32)
638 GetWindowRect(hwndChild, &rectChild);
639 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
641 /* move only if stc32 exist */
642 if (hwndStc32 && rectChild.left > rectStc32.right)
644 /* move to the right of visible controls of the parent dialog */
645 rectChild.left += rectParent.right;
646 rectChild.left -= rectStc32.right;
648 /* move even if stc32 doesn't exist */
649 if (rectChild.top >= rectStc32.bottom)
651 /* move below visible controls of the parent dialog */
652 rectChild.top += rectParent.bottom;
653 rectChild.top -= rectStc32.bottom - rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* this part moves controls of the parent dialog */
663 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
664 while (hwndChild)
666 if (hwndChild != hwndChildDlg)
668 GetWindowRect(hwndChild, &rectChild);
669 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
671 /* left,top of stc32 marks the position of controls
672 * from the parent dialog
674 rectChild.left += rectStc32.left;
675 rectChild.top += rectStc32.top;
677 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
678 0, 0, SWP_NOSIZE | SWP_NOZORDER);
680 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
683 /* calculate the size of the resulting dialog */
685 /* here we have to use original parent size */
686 GetClientRect(hwndParentDlg, &rectParent);
687 GetClientRect(hwndChildDlg, &rectChild);
688 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
689 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
691 if (hwndStc32)
693 /* width */
694 if (rectParent.right > rectStc32.right - rectStc32.left)
695 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
696 else
697 chgx = rectChild.right - rectParent.right;
698 /* height */
699 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
700 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
701 else
702 /* Unconditionally set new dialog
703 * height to that of the child
705 chgy = rectChild.bottom - rectParent.bottom;
707 else
709 chgx = 0;
710 chgy = rectChild.bottom - help_fixup;
712 /* set the size of the parent dialog */
713 GetWindowRect(hwndParentDlg, &rectParent);
714 SetWindowPos(hwndParentDlg, 0,
715 0, 0,
716 rectParent.right - rectParent.left + chgx,
717 rectParent.bottom - rectParent.top + chgy,
718 SWP_NOMOVE | SWP_NOZORDER);
721 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
723 switch(uMsg) {
724 case WM_INITDIALOG:
725 return TRUE;
727 return FALSE;
730 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
732 LPCVOID template;
733 HRSRC hRes;
734 HANDLE hDlgTmpl = 0;
735 HWND hChildDlg = 0;
737 TRACE("\n");
740 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
741 * structure's hInstance parameter is not a HINSTANCE, but
742 * instead a pointer to a template resource to use.
744 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
746 HINSTANCE hinst;
747 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
749 hinst = COMDLG32_hInstance;
750 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
752 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
753 return NULL;
756 else
758 hinst = fodInfos->ofnInfos->hInstance;
759 if(fodInfos->unicode)
761 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
762 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
764 else
766 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
767 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
769 if (!hRes)
771 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
772 return NULL;
774 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
775 !(template = LockResource( hDlgTmpl )))
777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
778 return NULL;
781 if (fodInfos->unicode)
782 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
785 else
786 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
787 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
788 (LPARAM)fodInfos->ofnInfos);
789 return hChildDlg;
791 else if( IsHooked(fodInfos))
793 RECT rectHwnd;
794 struct {
795 DLGTEMPLATE tmplate;
796 WORD menu,class,title;
797 } temp;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
802 temp.tmplate.x = 0;
803 temp.tmplate.y = 0;
804 temp.tmplate.cx = 0;
805 temp.tmplate.cy = 0;
806 temp.menu = temp.class = temp.title = 0;
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 return hChildDlg;
813 return NULL;
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 LRESULT hook_result = 0;
825 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
827 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
829 if(!fodInfos) return 0;
831 if(fodInfos->DlgInfos.hwndCustomDlg)
833 TRACE("CALL NOTIFY for %x\n", uCode);
834 if(fodInfos->unicode)
836 OFNOTIFYW ofnNotify;
837 ofnNotify.hdr.hwndFrom=hwndParentDlg;
838 ofnNotify.hdr.idFrom=0;
839 ofnNotify.hdr.code = uCode;
840 ofnNotify.lpOFN = fodInfos->ofnInfos;
841 ofnNotify.pszFile = NULL;
842 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
844 else
846 OFNOTIFYA ofnNotify;
847 ofnNotify.hdr.hwndFrom=hwndParentDlg;
848 ofnNotify.hdr.idFrom=0;
849 ofnNotify.hdr.code = uCode;
850 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
851 ofnNotify.pszFile = NULL;
852 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
854 TRACE("RET NOTIFY\n");
856 TRACE("Retval: 0x%08lx\n", hook_result);
857 return hook_result;
860 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
862 UINT len, total;
863 WCHAR *p, *buffer;
864 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
866 TRACE("CDM_GETFILEPATH:\n");
868 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
869 return -1;
871 /* get path and filenames */
872 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
873 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
874 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
875 if (len)
877 p = buffer + strlenW(buffer);
878 *p++ = '\\';
879 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
881 if (fodInfos->unicode)
883 total = strlenW( buffer) + 1;
884 if (result) lstrcpynW( result, buffer, size );
885 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
887 else
889 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
890 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
891 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
893 HeapFree( GetProcessHeap(), 0, buffer );
894 return total;
897 /***********************************************************************
898 * FILEDLG95_HandleCustomDialogMessages
900 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
902 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
904 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
905 WCHAR lpstrPath[MAX_PATH];
906 INT_PTR retval;
908 if(!fodInfos) return FALSE;
910 switch(uMsg)
912 case CDM_GETFILEPATH:
913 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
914 break;
916 case CDM_GETFOLDERPATH:
917 TRACE("CDM_GETFOLDERPATH:\n");
918 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
919 if (lParam)
921 if (fodInfos->unicode)
922 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
923 else
924 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
925 (LPSTR)lParam, (int)wParam, NULL, NULL);
927 retval = lstrlenW(lpstrPath) + 1;
928 break;
930 case CDM_GETFOLDERIDLIST:
931 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
932 if (retval <= wParam)
933 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
934 break;
936 case CDM_GETSPEC:
937 TRACE("CDM_GETSPEC:\n");
938 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
939 if (lParam)
941 if (fodInfos->unicode)
942 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
943 else
944 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
946 break;
948 case CDM_SETCONTROLTEXT:
949 TRACE("CDM_SETCONTROLTEXT:\n");
950 if ( lParam )
952 if( fodInfos->unicode )
953 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
954 else
955 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
957 retval = TRUE;
958 break;
960 case CDM_HIDECONTROL:
961 /* MSDN states that it should fail for not OFN_EXPLORER case */
962 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
964 HWND control = GetDlgItem( hwnd, wParam );
965 if (control) ShowWindow( control, SW_HIDE );
966 retval = TRUE;
968 else retval = FALSE;
969 break;
971 default:
972 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
973 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
974 return FALSE;
976 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
977 return TRUE;
980 /***********************************************************************
981 * FILEDLG95_OnWMGetMMI
983 * WM_GETMINMAXINFO message handler for resizable dialogs
985 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
987 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
988 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
989 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
991 mmiptr->ptMinTrackSize = fodInfos->initial_size;
993 return TRUE;
996 /***********************************************************************
997 * FILEDLG95_OnWMSize
999 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1001 * FIXME: this could be made more elaborate. Now use a simple scheme
1002 * where the file view is enlarged and the controls are either moved
1003 * vertically or horizontally to get out of the way. Only the "grip"
1004 * is moved in both directions to stay in the corner.
1006 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1008 RECT rc, rcview;
1009 int chgx, chgy;
1010 HWND ctrl;
1011 HDWP hdwp;
1012 FileOpenDlgInfos *fodInfos;
1014 if( wParam != SIZE_RESTORED) return FALSE;
1015 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1016 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1017 /* get the new dialog rectangle */
1018 GetWindowRect( hwnd, &rc);
1019 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1020 rc.right -rc.left, rc.bottom -rc.top);
1021 /* not initialized yet */
1022 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1023 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1024 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1025 return FALSE;
1026 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1027 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1028 fodInfos->sizedlg.cx = rc.right - rc.left;
1029 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1030 /* change the size of the view window */
1031 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1032 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1033 hdwp = BeginDeferWindowPos( 10);
1034 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1035 rcview.right - rcview.left + chgx,
1036 rcview.bottom - rcview.top + chgy,
1037 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1038 /* change position and sizes of the controls */
1039 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1041 int ctrlid = GetDlgCtrlID( ctrl);
1042 GetWindowRect( ctrl, &rc);
1043 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1044 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1046 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1047 0, 0,
1048 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1050 else if( rc.top > rcview.bottom)
1052 /* if it was below the shell view
1053 * move to bottom */
1054 switch( ctrlid)
1056 /* file name box and file types combo change also width */
1057 case edt1:
1058 case cmb1:
1059 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1060 rc.right - rc.left + chgx, rc.bottom - rc.top,
1061 SWP_NOACTIVATE | SWP_NOZORDER);
1062 break;
1063 /* then these buttons must move out of the way */
1064 case IDOK:
1065 case IDCANCEL:
1066 case pshHelp:
1067 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1068 0, 0,
1069 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1070 break;
1071 default:
1072 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1073 0, 0,
1074 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1077 else if( rc.left > rcview.right)
1079 /* if it was to the right of the shell view
1080 * move to right */
1081 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1082 0, 0,
1083 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1085 else
1086 /* special cases */
1088 switch( ctrlid)
1090 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1091 case IDC_LOOKIN:
1092 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1093 rc.right - rc.left + chgx, rc.bottom - rc.top,
1094 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1095 break;
1096 case IDC_TOOLBARSTATIC:
1097 case IDC_TOOLBAR:
1098 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1099 0, 0,
1100 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1101 break;
1102 #endif
1103 /* not resized in windows. Since wine uses this invisible control
1104 * to size the browser view it needs to be resized */
1105 case IDC_SHELLSTATIC:
1106 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1107 rc.right - rc.left + chgx,
1108 rc.bottom - rc.top + chgy,
1109 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1110 break;
1114 if(fodInfos->DlgInfos.hwndCustomDlg &&
1115 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1117 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1118 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1120 GetWindowRect( ctrl, &rc);
1121 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1122 if( rc.top > rcview.bottom)
1124 /* if it was below the shell view
1125 * move to bottom */
1126 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1127 rc.right - rc.left, rc.bottom - rc.top,
1128 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1130 else if( rc.left > rcview.right)
1132 /* if it was to the right of the shell view
1133 * move to right */
1134 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1135 rc.right - rc.left, rc.bottom - rc.top,
1136 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1139 /* size the custom dialog at the end: some applications do some
1140 * control re-arranging at this point */
1141 GetClientRect(hwnd, &rc);
1142 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1143 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1145 EndDeferWindowPos( hdwp);
1146 /* should not be needed */
1147 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1148 return TRUE;
1151 /***********************************************************************
1152 * FileOpenDlgProc95
1154 * File open dialog procedure
1156 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1158 #if 0
1159 TRACE("%p 0x%04x\n", hwnd, uMsg);
1160 #endif
1162 switch(uMsg)
1164 case WM_INITDIALOG:
1166 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1167 RECT rc, rcstc;
1168 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1169 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1171 /* Adds the FileOpenDlgInfos in the property list of the dialog
1172 so it will be easily accessible through a GetPropA(...) */
1173 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1175 FILEDLG95_InitControls(hwnd);
1177 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1179 GetWindowRect( hwnd, &rc);
1180 fodInfos->DlgInfos.hwndGrip =
1181 CreateWindowExA( 0, "SCROLLBAR", NULL,
1182 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1183 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1184 rc.right - gripx, rc.bottom - gripy,
1185 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1188 fodInfos->DlgInfos.hwndCustomDlg =
1189 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1191 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1192 FILEDLG95_FillControls(hwnd, wParam, lParam);
1194 if( fodInfos->DlgInfos.hwndCustomDlg)
1195 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1197 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1198 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1199 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1202 /* if the app has changed the position of the invisible listbox,
1203 * change that of the listview (browser) as well */
1204 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1205 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1206 if( !EqualRect( &rc, &rcstc))
1208 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1209 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1210 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1211 SWP_NOACTIVATE | SWP_NOZORDER);
1214 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1216 GetWindowRect( hwnd, &rc);
1217 fodInfos->sizedlg.cx = rc.right - rc.left;
1218 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1219 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1220 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1221 GetClientRect( hwnd, &rc);
1222 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1223 rc.right - gripx, rc.bottom - gripy,
1224 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1225 /* resize the dialog to the previous invocation */
1226 if( MemDialogSize.cx && MemDialogSize.cy)
1227 SetWindowPos( hwnd, NULL,
1228 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1229 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1232 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1233 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1235 return 0;
1237 case WM_SIZE:
1238 return FILEDLG95_OnWMSize(hwnd, wParam);
1239 case WM_GETMINMAXINFO:
1240 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1241 case WM_COMMAND:
1242 return FILEDLG95_OnWMCommand(hwnd, wParam);
1243 case WM_DRAWITEM:
1245 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1247 case IDC_LOOKIN:
1248 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1249 return TRUE;
1252 return FALSE;
1254 case WM_GETISHELLBROWSER:
1255 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1257 case WM_DESTROY:
1259 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1260 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1261 MemDialogSize = fodInfos->sizedlg;
1262 RemovePropA(hwnd, FileOpenDlgInfosStr);
1263 return FALSE;
1265 case WM_NOTIFY:
1267 LPNMHDR lpnmh = (LPNMHDR)lParam;
1268 UINT stringId = -1;
1270 /* set up the button tooltips strings */
1271 if(TTN_GETDISPINFOA == lpnmh->code )
1273 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1274 switch(lpnmh->idFrom )
1276 /* Up folder button */
1277 case FCIDM_TB_UPFOLDER:
1278 stringId = IDS_UPFOLDER;
1279 break;
1280 /* New folder button */
1281 case FCIDM_TB_NEWFOLDER:
1282 stringId = IDS_NEWFOLDER;
1283 break;
1284 /* List option button */
1285 case FCIDM_TB_SMALLICON:
1286 stringId = IDS_LISTVIEW;
1287 break;
1288 /* Details option button */
1289 case FCIDM_TB_REPORTVIEW:
1290 stringId = IDS_REPORTVIEW;
1291 break;
1292 /* Desktop button */
1293 case FCIDM_TB_DESKTOP:
1294 stringId = IDS_TODESKTOP;
1295 break;
1296 default:
1297 stringId = 0;
1299 lpdi->hinst = COMDLG32_hInstance;
1300 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1302 return FALSE;
1304 default :
1305 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1306 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1307 return FALSE;
1311 /***********************************************************************
1312 * FILEDLG95_InitControls
1314 * WM_INITDIALOG message handler (before hook notification)
1316 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1318 int win2000plus = 0;
1319 int win98plus = 0;
1320 int handledPath = FALSE;
1321 OSVERSIONINFOW osVi;
1322 static const WCHAR szwSlash[] = { '\\', 0 };
1323 static const WCHAR szwStar[] = { '*',0 };
1325 static const TBBUTTON tbb[] =
1327 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1328 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1329 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1330 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1331 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1332 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1333 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1334 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1335 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1337 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1339 RECT rectTB;
1340 RECT rectlook;
1342 HIMAGELIST toolbarImageList;
1343 SHFILEINFOA shFileInfo;
1344 ITEMIDLIST *desktopPidl;
1346 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1348 TRACE("%p\n", fodInfos);
1350 /* Get windows version emulating */
1351 osVi.dwOSVersionInfoSize = sizeof(osVi);
1352 GetVersionExW(&osVi);
1353 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1354 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1355 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1356 win2000plus = (osVi.dwMajorVersion > 4);
1357 if (win2000plus) win98plus = TRUE;
1359 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1361 /* Get the hwnd of the controls */
1362 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1363 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1364 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1366 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1367 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1369 /* construct the toolbar */
1370 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1371 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1373 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1374 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1375 rectTB.left = rectlook.right;
1376 rectTB.top = rectlook.top-1;
1378 if (fodInfos->unicode)
1379 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1380 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1381 rectTB.left, rectTB.top,
1382 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1383 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1384 else
1385 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1386 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1387 rectTB.left, rectTB.top,
1388 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1389 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1391 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1393 /* FIXME: use TB_LOADIMAGES when implemented */
1394 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1395 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1396 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1398 /* Retrieve and add desktop icon to the toolbar */
1399 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1400 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1401 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1402 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1403 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1405 DestroyIcon(shFileInfo.hIcon);
1406 CoTaskMemFree(desktopPidl);
1408 /* Finish Toolbar Construction */
1409 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1410 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1412 /* Set the window text with the text specified in the OPENFILENAME structure */
1413 if(fodInfos->title)
1415 SetWindowTextW(hwnd,fodInfos->title);
1417 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1419 WCHAR buf[16];
1420 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1421 SetWindowTextW(hwnd, buf);
1424 /* Initialise the file name edit control */
1425 handledPath = FALSE;
1426 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1428 if(fodInfos->filename)
1430 /* 1. If win2000 or higher and filename contains a path, use it
1431 in preference over the lpstrInitialDir */
1432 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1433 WCHAR tmpBuf[MAX_PATH];
1434 WCHAR *nameBit;
1435 DWORD result;
1437 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1438 if (result) {
1440 /* nameBit is always shorter than the original filename */
1441 lstrcpyW(fodInfos->filename,nameBit);
1443 *nameBit = 0x00;
1444 if (fodInfos->initdir == NULL)
1445 MemFree(fodInfos->initdir);
1446 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1447 lstrcpyW(fodInfos->initdir, tmpBuf);
1448 handledPath = TRUE;
1449 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1450 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1452 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1454 } else {
1455 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1459 /* 2. (All platforms) If initdir is not null, then use it */
1460 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1461 (*fodInfos->initdir!=0x00))
1463 /* Work out the proper path as supplied one might be relative */
1464 /* (Here because supplying '.' as dir browses to My Computer) */
1465 if (handledPath==FALSE) {
1466 WCHAR tmpBuf[MAX_PATH];
1467 WCHAR tmpBuf2[MAX_PATH];
1468 WCHAR *nameBit;
1469 DWORD result;
1471 lstrcpyW(tmpBuf, fodInfos->initdir);
1472 if( PathFileExistsW(tmpBuf) ) {
1473 /* initdir does not have to be a directory. If a file is
1474 * specified, the dir part is taken */
1475 if( PathIsDirectoryW(tmpBuf)) {
1476 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1477 lstrcatW(tmpBuf, szwSlash);
1479 lstrcatW(tmpBuf, szwStar);
1481 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1482 if (result) {
1483 *nameBit = 0x00;
1484 MemFree(fodInfos->initdir);
1485 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1486 lstrcpyW(fodInfos->initdir, tmpBuf2);
1487 handledPath = TRUE;
1488 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1491 else if (fodInfos->initdir)
1493 MemFree(fodInfos->initdir);
1494 fodInfos->initdir = NULL;
1495 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1500 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1501 (*fodInfos->initdir==0x00)))
1503 /* 3. All except w2k+: if filename contains a path use it */
1504 if (!win2000plus && fodInfos->filename &&
1505 *fodInfos->filename &&
1506 strpbrkW(fodInfos->filename, szwSlash)) {
1507 WCHAR tmpBuf[MAX_PATH];
1508 WCHAR *nameBit;
1509 DWORD result;
1511 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1512 tmpBuf, &nameBit);
1513 if (result) {
1514 int len;
1516 /* nameBit is always shorter than the original filename */
1517 lstrcpyW(fodInfos->filename, nameBit);
1518 *nameBit = 0x00;
1520 len = lstrlenW(tmpBuf);
1521 MemFree(fodInfos->initdir);
1522 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1523 lstrcpyW(fodInfos->initdir, tmpBuf);
1525 handledPath = TRUE;
1526 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1527 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1529 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1532 /* 4. Win2000+: Recently used */
1533 if (handledPath == FALSE && win2000plus) {
1534 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1535 fodInfos->initdir[0] = '\0';
1537 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1539 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1540 handledPath = TRUE;
1541 }else{
1542 MemFree(fodInfos->initdir);
1543 fodInfos->initdir = NULL;
1547 /* 5. win98+ and win2000+ if any files of specified filter types in
1548 current directory, use it */
1549 if ( win98plus && handledPath == FALSE &&
1550 fodInfos->filter && *fodInfos->filter) {
1552 LPCWSTR lpstrPos = fodInfos->filter;
1553 WIN32_FIND_DATAW FindFileData;
1554 HANDLE hFind;
1556 while (1)
1558 /* filter is a list... title\0ext\0......\0\0 */
1560 /* Skip the title */
1561 if(! *lpstrPos) break; /* end */
1562 lpstrPos += lstrlenW(lpstrPos) + 1;
1564 /* See if any files exist in the current dir with this extension */
1565 if(! *lpstrPos) break; /* end */
1567 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1569 if (hFind == INVALID_HANDLE_VALUE) {
1570 /* None found - continue search */
1571 lpstrPos += lstrlenW(lpstrPos) + 1;
1573 } else {
1575 MemFree(fodInfos->initdir);
1576 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1577 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1579 handledPath = TRUE;
1580 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1581 debugstr_w(lpstrPos));
1582 FindClose(hFind);
1583 break;
1588 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1589 if (handledPath == FALSE && (win2000plus || win98plus)) {
1590 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1592 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1594 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1596 /* last fallback */
1597 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1598 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1599 } else {
1600 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1602 } else {
1603 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1605 handledPath = TRUE;
1606 } else if (handledPath==FALSE) {
1607 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1608 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1609 handledPath = TRUE;
1610 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1613 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1614 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1616 /* Must the open as read only check box be checked ?*/
1617 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1619 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1622 /* Must the open as read only check box be hidden? */
1623 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1625 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1626 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1629 /* Must the help button be hidden? */
1630 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1632 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1633 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1636 /* change Open to Save */
1637 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1639 WCHAR buf[16];
1640 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1641 SetDlgItemTextW(hwnd, IDOK, buf);
1642 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1643 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1646 /* Initialize the filter combo box */
1647 FILEDLG95_FILETYPE_Init(hwnd);
1649 return 0;
1652 /***********************************************************************
1653 * FILEDLG95_ResizeControls
1655 * WM_INITDIALOG message handler (after hook notification)
1657 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1659 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1661 if (fodInfos->DlgInfos.hwndCustomDlg)
1663 RECT rc;
1664 UINT flags = SWP_NOACTIVATE;
1666 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1667 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1669 /* resize the custom dialog to the parent size */
1670 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1671 GetClientRect(hwnd, &rc);
1672 else
1674 /* our own fake template is zero sized and doesn't have children, so
1675 * there is no need to resize it. Picasa depends on it.
1677 flags |= SWP_NOSIZE;
1678 SetRectEmpty(&rc);
1680 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1681 0, 0, rc.right, rc.bottom, flags);
1683 else
1685 /* Resize the height, if open as read only checkbox ad help button are
1686 * hidden and we are not using a custom template nor a customDialog
1688 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1689 (!(fodInfos->ofnInfos->Flags &
1690 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1692 RECT rectDlg, rectHelp, rectCancel;
1693 GetWindowRect(hwnd, &rectDlg);
1694 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1695 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1696 /* subtract the height of the help button plus the space between the help
1697 * button and the cancel button to the height of the dialog
1699 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1700 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1701 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1704 return TRUE;
1707 /***********************************************************************
1708 * FILEDLG95_FillControls
1710 * WM_INITDIALOG message handler (after hook notification)
1712 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1714 LPITEMIDLIST pidlItemId = NULL;
1716 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1718 TRACE("dir=%s file=%s\n",
1719 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1721 /* Get the initial directory pidl */
1723 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1725 WCHAR path[MAX_PATH];
1727 GetCurrentDirectoryW(MAX_PATH,path);
1728 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1731 /* Initialise shell objects */
1732 FILEDLG95_SHELL_Init(hwnd);
1734 /* Initialize the Look In combo box */
1735 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1737 /* Browse to the initial directory */
1738 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1740 /* Free pidlItem memory */
1741 COMDLG32_SHFree(pidlItemId);
1743 return TRUE;
1745 /***********************************************************************
1746 * FILEDLG95_Clean
1748 * Regroups all the cleaning functions of the filedlg
1750 void FILEDLG95_Clean(HWND hwnd)
1752 FILEDLG95_FILETYPE_Clean(hwnd);
1753 FILEDLG95_LOOKIN_Clean(hwnd);
1754 FILEDLG95_SHELL_Clean(hwnd);
1756 /***********************************************************************
1757 * FILEDLG95_OnWMCommand
1759 * WM_COMMAND message handler
1761 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1763 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1764 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1765 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1767 switch(wID)
1769 /* OK button */
1770 case IDOK:
1771 FILEDLG95_OnOpen(hwnd);
1772 break;
1773 /* Cancel button */
1774 case IDCANCEL:
1775 FILEDLG95_Clean(hwnd);
1776 EndDialog(hwnd, FALSE);
1777 break;
1778 /* Filetype combo box */
1779 case IDC_FILETYPE:
1780 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1781 break;
1782 /* LookIn combo box */
1783 case IDC_LOOKIN:
1784 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1785 break;
1787 /* --- toolbar --- */
1788 /* Up folder button */
1789 case FCIDM_TB_UPFOLDER:
1790 FILEDLG95_SHELL_UpFolder(hwnd);
1791 break;
1792 /* New folder button */
1793 case FCIDM_TB_NEWFOLDER:
1794 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1795 break;
1796 /* List option button */
1797 case FCIDM_TB_SMALLICON:
1798 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1799 break;
1800 /* Details option button */
1801 case FCIDM_TB_REPORTVIEW:
1802 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1803 break;
1804 /* Details option button */
1805 case FCIDM_TB_DESKTOP:
1806 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1807 break;
1809 case IDC_FILENAME:
1810 break;
1813 /* Do not use the listview selection anymore */
1814 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1815 return 0;
1818 /***********************************************************************
1819 * FILEDLG95_OnWMGetIShellBrowser
1821 * WM_GETISHELLBROWSER message handler
1823 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1825 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1827 TRACE("\n");
1829 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1831 return TRUE;
1835 /***********************************************************************
1836 * FILEDLG95_SendFileOK
1838 * Sends the CDN_FILEOK notification if required
1840 * RETURNS
1841 * TRUE if the dialog should close
1842 * FALSE if the dialog should not be closed
1844 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1846 /* ask the hook if we can close */
1847 if(IsHooked(fodInfos))
1849 LRESULT retval = 0;
1851 TRACE("---\n");
1852 /* First send CDN_FILEOK as MSDN doc says */
1853 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1854 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1855 if( retval)
1857 TRACE("canceled\n");
1858 return FALSE;
1861 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1862 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1863 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1864 if( retval)
1866 TRACE("canceled\n");
1867 return FALSE;
1870 return TRUE;
1873 /***********************************************************************
1874 * FILEDLG95_OnOpenMultipleFiles
1876 * Handles the opening of multiple files.
1878 * FIXME
1879 * check destination buffer size
1881 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1883 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1884 UINT nCount, nSizePath;
1885 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1887 TRACE("\n");
1889 if(fodInfos->unicode)
1891 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1892 ofn->lpstrFile[0] = '\0';
1894 else
1896 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1897 ofn->lpstrFile[0] = '\0';
1900 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1902 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1903 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1904 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1906 LPWSTR lpstrTemp = lpstrFileList;
1908 for ( nCount = 0; nCount < nFileCount; nCount++ )
1910 LPITEMIDLIST pidl;
1912 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1913 if (!pidl)
1915 WCHAR lpstrNotFound[100];
1916 WCHAR lpstrMsg[100];
1917 WCHAR tmp[400];
1918 static const WCHAR nl[] = {'\n',0};
1920 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1921 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1923 lstrcpyW(tmp, lpstrTemp);
1924 lstrcatW(tmp, nl);
1925 lstrcatW(tmp, lpstrNotFound);
1926 lstrcatW(tmp, nl);
1927 lstrcatW(tmp, lpstrMsg);
1929 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1930 return FALSE;
1933 /* move to the next file in the list of files */
1934 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1935 COMDLG32_SHFree(pidl);
1939 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1940 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1942 /* For "oldstyle" dialog the components have to
1943 be separated by blanks (not '\0'!) and short
1944 filenames have to be used! */
1945 FIXME("Components have to be separated by blanks\n");
1947 if(fodInfos->unicode)
1949 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1950 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1951 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1953 else
1955 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1957 if (ofn->lpstrFile != NULL)
1959 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1960 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1961 if (ofn->nMaxFile > nSizePath)
1963 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1964 ofn->lpstrFile + nSizePath,
1965 ofn->nMaxFile - nSizePath, NULL, NULL);
1970 fodInfos->ofnInfos->nFileOffset = nSizePath;
1971 fodInfos->ofnInfos->nFileExtension = 0;
1973 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1974 return FALSE;
1976 /* clean and exit */
1977 FILEDLG95_Clean(hwnd);
1978 return EndDialog(hwnd,TRUE);
1981 /* Returns the 'slot name' of the given module_name in the registry's
1982 * most-recently-used list. This will be an ASCII value in the
1983 * range ['a','z'). Returns zero on error.
1985 * The slot's value in the registry has the form:
1986 * module_name\0mru_path\0
1988 * If stored_path is given, then stored_path will contain the path name
1989 * stored in the registry's MRU list for the given module_name.
1991 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
1992 * MRU list key for the given module_name.
1994 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
1996 WCHAR mru_list[32], *cur_mru_slot;
1997 BOOL taken[25] = {0};
1998 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
1999 HKEY hkey_tmp, *hkey;
2000 LONG ret;
2002 if(hkey_ret)
2003 hkey = hkey_ret;
2004 else
2005 hkey = &hkey_tmp;
2007 if(stored_path)
2008 *stored_path = '\0';
2010 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2011 if(ret){
2012 WARN("Unable to create MRU key: %d\n", ret);
2013 return 0;
2016 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2017 (LPBYTE)mru_list, &mru_list_size);
2018 if(ret || key_type != REG_SZ){
2019 if(ret == ERROR_FILE_NOT_FOUND)
2020 return 'a';
2022 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2023 RegCloseKey(*hkey);
2024 return 0;
2027 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2028 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2029 DWORD value_data_size = sizeof(value_data);
2031 *value_name = *cur_mru_slot;
2033 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2034 &key_type, (LPBYTE)value_data, &value_data_size);
2035 if(ret || key_type != REG_BINARY){
2036 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2037 continue;
2040 if(!strcmpiW(module_name, value_data)){
2041 if(!hkey_ret)
2042 RegCloseKey(*hkey);
2043 if(stored_path)
2044 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2045 return *value_name;
2049 if(!hkey_ret)
2050 RegCloseKey(*hkey);
2052 /* the module name isn't in the registry, so find the next open slot */
2053 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2054 taken[*cur_mru_slot - 'a'] = TRUE;
2055 for(i = 0; i < 25; ++i){
2056 if(!taken[i])
2057 return i + 'a';
2060 /* all slots are taken, so return the last one in MRUList */
2061 --cur_mru_slot;
2062 return *cur_mru_slot;
2065 /* save the given filename as most-recently-used path for this module */
2066 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2068 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2069 LONG ret;
2070 HKEY hkey;
2072 /* get the current executable's name */
2073 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2074 WARN("GotModuleFileName failed: %d\n", GetLastError());
2075 return;
2077 module_name = strrchrW(module_path, '\\');
2078 if(!module_name)
2079 module_name = module_path;
2080 else
2081 module_name += 1;
2083 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2084 if(!slot)
2085 return;
2086 *slot_name = slot;
2088 { /* update the slot's info */
2089 WCHAR *path_ends, *final;
2090 DWORD path_len, final_len;
2092 /* use only the path segment of `filename' */
2093 path_ends = strrchrW(filename, '\\');
2094 path_len = path_ends - filename;
2096 final_len = path_len + lstrlenW(module_name) + 2;
2098 final = MemAlloc(final_len * sizeof(WCHAR));
2099 if(!final)
2100 return;
2101 lstrcpyW(final, module_name);
2102 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2103 final[final_len-1] = '\0';
2105 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2106 final_len * sizeof(WCHAR));
2107 if(ret){
2108 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2109 MemFree(final);
2110 RegCloseKey(hkey);
2111 return;
2114 MemFree(final);
2117 { /* update MRUList value */
2118 WCHAR old_mru_list[32], new_mru_list[32];
2119 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2120 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2122 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2123 (LPBYTE)old_mru_list, &mru_list_size);
2124 if(ret || key_type != REG_SZ){
2125 if(ret == ERROR_FILE_NOT_FOUND){
2126 new_mru_list[0] = slot;
2127 new_mru_list[1] = '\0';
2128 }else{
2129 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2130 RegCloseKey(hkey);
2131 return;
2133 }else{
2134 /* copy old list data over so that the new slot is at the start
2135 * of the list */
2136 *new_mru_slot++ = slot;
2137 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2138 if(*old_mru_slot != slot)
2139 *new_mru_slot++ = *old_mru_slot;
2141 *new_mru_slot = '\0';
2144 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2145 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2146 if(ret){
2147 WARN("Error saving MRUList data: %d\n", ret);
2148 RegCloseKey(hkey);
2149 return;
2154 /* load the most-recently-used path for this module */
2155 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2157 WCHAR module_path[MAX_PATH], *module_name;
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 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2171 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2174 /***********************************************************************
2175 * FILEDLG95_OnOpen
2177 * Ok button WM_COMMAND message handler
2179 * If the function succeeds, the return value is nonzero.
2181 #define ONOPEN_BROWSE 1
2182 #define ONOPEN_OPEN 2
2183 #define ONOPEN_SEARCH 3
2184 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2186 WCHAR strMsgTitle[MAX_PATH];
2187 WCHAR strMsgText [MAX_PATH];
2188 if (idCaption)
2189 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2190 else
2191 strMsgTitle[0] = '\0';
2192 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2193 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2196 BOOL FILEDLG95_OnOpen(HWND hwnd)
2198 LPWSTR lpstrFileList;
2199 UINT nFileCount = 0;
2200 UINT sizeUsed = 0;
2201 BOOL ret = TRUE;
2202 WCHAR lpstrPathAndFile[MAX_PATH];
2203 WCHAR lpstrTemp[MAX_PATH];
2204 LPSHELLFOLDER lpsf = NULL;
2205 int nOpenAction;
2206 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2208 TRACE("hwnd=%p\n", hwnd);
2210 /* try to browse the selected item */
2211 if(BrowseSelectedFolder(hwnd))
2212 return FALSE;
2214 /* get the files from the edit control */
2215 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2217 if(nFileCount == 0)
2218 return FALSE;
2220 if(nFileCount > 1)
2222 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2223 goto ret;
2226 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2229 Step 1: Build a complete path name from the current folder and
2230 the filename or path in the edit box.
2231 Special cases:
2232 - the path in the edit box is a root path
2233 (with or without drive letter)
2234 - the edit box contains ".." (or a path with ".." in it)
2237 /* Get the current directory name */
2238 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2240 /* last fallback */
2241 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2243 PathAddBackslashW(lpstrPathAndFile);
2245 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2247 /* if the user specified a fully qualified path use it */
2248 if(PathIsRelativeW(lpstrFileList))
2250 lstrcatW(lpstrPathAndFile, lpstrFileList);
2252 else
2254 /* does the path have a drive letter? */
2255 if (PathGetDriveNumberW(lpstrFileList) == -1)
2256 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2257 else
2258 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2261 /* resolve "." and ".." */
2262 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2263 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2264 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2266 MemFree(lpstrFileList);
2269 Step 2: here we have a cleaned up path
2271 We have to parse the path step by step to see if we have to browse
2272 to a folder if the path points to a directory or the last
2273 valid element is a directory.
2275 valid variables:
2276 lpstrPathAndFile: cleaned up path
2279 if (nFileCount &&
2280 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2281 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2282 nOpenAction = ONOPEN_OPEN;
2283 else
2284 nOpenAction = ONOPEN_BROWSE;
2286 /* don't apply any checks with OFN_NOVALIDATE */
2288 LPWSTR lpszTemp, lpszTemp1;
2289 LPITEMIDLIST pidl = NULL;
2290 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2292 /* check for invalid chars */
2293 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2295 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2296 ret = FALSE;
2297 goto ret;
2300 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2302 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2303 while (lpszTemp1)
2305 LPSHELLFOLDER lpsfChild;
2306 WCHAR lpwstrTemp[MAX_PATH];
2307 DWORD dwEaten, dwAttributes;
2308 LPWSTR p;
2310 lstrcpyW(lpwstrTemp, lpszTemp);
2311 p = PathFindNextComponentW(lpwstrTemp);
2313 if (!p) break; /* end of path */
2315 *p = 0;
2316 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2318 /* There are no wildcards when OFN_NOVALIDATE is set */
2319 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2321 static const WCHAR wszWild[] = { '*', '?', 0 };
2322 /* if the last element is a wildcard do a search */
2323 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2325 nOpenAction = ONOPEN_SEARCH;
2326 break;
2329 lpszTemp1 = lpszTemp;
2331 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2333 /* append a backslash to drive letters */
2334 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2335 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2336 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2338 PathAddBackslashW(lpwstrTemp);
2341 dwAttributes = SFGAO_FOLDER;
2342 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2344 /* the path component is valid, we have a pidl of the next path component */
2345 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2346 if(dwAttributes & SFGAO_FOLDER)
2348 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2350 ERR("bind to failed\n"); /* should not fail */
2351 break;
2353 IShellFolder_Release(lpsf);
2354 lpsf = lpsfChild;
2355 lpsfChild = NULL;
2357 else
2359 TRACE("value\n");
2361 /* end dialog, return value */
2362 nOpenAction = ONOPEN_OPEN;
2363 break;
2365 COMDLG32_SHFree(pidl);
2366 pidl = NULL;
2368 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2370 if(*lpszTemp || /* points to trailing null for last path element */
2371 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2373 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2375 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2376 break;
2379 else
2381 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2382 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2384 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2385 break;
2388 /* change to the current folder */
2389 nOpenAction = ONOPEN_OPEN;
2390 break;
2392 else
2394 nOpenAction = ONOPEN_OPEN;
2395 break;
2398 if(pidl) COMDLG32_SHFree(pidl);
2402 Step 3: here we have a cleaned up and validated path
2404 valid variables:
2405 lpsf: ShellFolder bound to the rightmost valid path component
2406 lpstrPathAndFile: cleaned up path
2407 nOpenAction: action to do
2409 TRACE("end validate sf=%p\n", lpsf);
2411 switch(nOpenAction)
2413 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2414 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2416 int iPos;
2417 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2418 DWORD len;
2420 /* replace the current filter */
2421 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2422 len = lstrlenW(lpszTemp)+1;
2423 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2424 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2426 /* set the filter cb to the extension when possible */
2427 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2428 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2430 /* fall through */
2431 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2432 TRACE("ONOPEN_BROWSE\n");
2434 IPersistFolder2 * ppf2;
2435 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2437 LPITEMIDLIST pidlCurrent;
2438 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2439 IPersistFolder2_Release(ppf2);
2440 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2442 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2443 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2445 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2448 else if( nOpenAction == ONOPEN_SEARCH )
2450 if (fodInfos->Shell.FOIShellView)
2451 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2453 COMDLG32_SHFree(pidlCurrent);
2454 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2457 ret = FALSE;
2458 break;
2459 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2460 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2462 WCHAR *ext = NULL;
2464 /* update READONLY check box flag */
2465 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2466 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2467 else
2468 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2470 /* Attach the file extension with file name*/
2471 ext = PathFindExtensionW(lpstrPathAndFile);
2472 if (! *ext)
2474 /* if no extension is specified with file name, then */
2475 /* attach the extension from file filter or default one */
2477 const WCHAR *filterExt = NULL;
2478 LPWSTR lpstrFilter = NULL;
2479 static const WCHAR szwDot[] = {'.',0};
2480 int PathLength = lstrlenW(lpstrPathAndFile);
2482 /*Get the file extension from file type filter*/
2483 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2484 fodInfos->ofnInfos->nFilterIndex-1);
2486 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2487 filterExt = PathFindExtensionW(lpstrFilter);
2489 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2490 filterExt = filterExt + 1;
2491 else if ( fodInfos->defext ) /* attach the default file extension*/
2492 filterExt = fodInfos->defext;
2494 /* If extension contains a glob, ignore it */
2495 if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
2497 /* Attach the dot*/
2498 lstrcatW(lpstrPathAndFile, szwDot);
2499 /* Attach the extension */
2500 lstrcatW(lpstrPathAndFile, filterExt );
2503 /* In Open dialog: if file does not exist try without extension */
2504 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2505 lpstrPathAndFile[PathLength] = '\0';
2508 if (fodInfos->defext) /* add default extension */
2510 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2511 if (*ext)
2512 ext++;
2513 if (!lstrcmpiW(fodInfos->defext, ext))
2514 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2515 else
2516 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2519 /* In Save dialog: check if the file already exists */
2520 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2521 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2522 && PathFileExistsW(lpstrPathAndFile))
2524 WCHAR lpstrOverwrite[100];
2525 int answer;
2527 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2528 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2529 MB_YESNO | MB_ICONEXCLAMATION);
2530 if (answer == IDNO || answer == IDCANCEL)
2532 ret = FALSE;
2533 goto ret;
2537 /* In Open dialog: check if it should be created if it doesn't exist */
2538 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2539 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2540 && !PathFileExistsW(lpstrPathAndFile))
2542 WCHAR lpstrCreate[100];
2543 int answer;
2545 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2546 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2547 MB_YESNO | MB_ICONEXCLAMATION);
2548 if (answer == IDNO || answer == IDCANCEL)
2550 ret = FALSE;
2551 goto ret;
2555 /* Check that the size of the file does not exceed buffer size.
2556 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2557 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2558 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2561 /* fill destination buffer */
2562 if (fodInfos->ofnInfos->lpstrFile)
2564 if(fodInfos->unicode)
2566 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2568 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2569 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2570 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2572 else
2574 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2576 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2577 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2578 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2579 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2583 if(fodInfos->unicode)
2585 LPWSTR lpszTemp;
2587 /* set filename offset */
2588 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2589 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2591 /* set extension offset */
2592 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2593 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2595 else
2597 LPSTR lpszTemp;
2598 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2600 /* set filename offset */
2601 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2602 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2604 /* set extension offset */
2605 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2606 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2609 /* set the lpstrFileTitle */
2610 if(fodInfos->ofnInfos->lpstrFileTitle)
2612 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2613 if(fodInfos->unicode)
2615 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2616 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2618 else
2620 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2621 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2622 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2626 /* copy currently selected filter to lpstrCustomFilter */
2627 if (fodInfos->ofnInfos->lpstrCustomFilter)
2629 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2630 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2631 NULL, 0, NULL, NULL);
2632 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2634 LPSTR s = ofn->lpstrCustomFilter;
2635 s += strlen(ofn->lpstrCustomFilter)+1;
2636 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2637 s, len, NULL, NULL);
2642 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2643 goto ret;
2645 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2647 TRACE("close\n");
2648 FILEDLG95_Clean(hwnd);
2649 ret = EndDialog(hwnd, TRUE);
2651 else
2653 WORD size;
2655 size = lstrlenW(lpstrPathAndFile) + 1;
2656 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2657 size += 1;
2658 /* return needed size in first two bytes of lpstrFile */
2659 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2660 FILEDLG95_Clean(hwnd);
2661 ret = EndDialog(hwnd, FALSE);
2662 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2665 break;
2668 ret:
2669 if(lpsf) IShellFolder_Release(lpsf);
2670 return ret;
2673 /***********************************************************************
2674 * FILEDLG95_SHELL_Init
2676 * Initialisation of the shell objects
2678 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2680 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2682 TRACE("\n");
2685 * Initialisation of the FileOpenDialogInfos structure
2688 /* Shell */
2690 /*ShellInfos */
2691 fodInfos->ShellInfos.hwndOwner = hwnd;
2693 /* Disable multi-select if flag not set */
2694 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2696 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2698 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2699 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2701 /* Construct the IShellBrowser interface */
2702 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2704 return NOERROR;
2707 /***********************************************************************
2708 * FILEDLG95_SHELL_ExecuteCommand
2710 * Change the folder option and refresh the view
2711 * If the function succeeds, the return value is nonzero.
2713 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2715 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2716 IContextMenu * pcm;
2718 TRACE("(%p,%p)\n", hwnd, lpVerb);
2720 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2721 SVGIO_BACKGROUND,
2722 &IID_IContextMenu,
2723 (LPVOID*)&pcm)))
2725 CMINVOKECOMMANDINFO ci;
2726 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2727 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2728 ci.lpVerb = lpVerb;
2729 ci.hwnd = hwnd;
2731 IContextMenu_InvokeCommand(pcm, &ci);
2732 IContextMenu_Release(pcm);
2735 return FALSE;
2738 /***********************************************************************
2739 * FILEDLG95_SHELL_UpFolder
2741 * Browse to the specified object
2742 * If the function succeeds, the return value is nonzero.
2744 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2746 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2748 TRACE("\n");
2750 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2751 NULL,
2752 SBSP_PARENT)))
2754 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2755 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2756 return TRUE;
2758 return FALSE;
2761 /***********************************************************************
2762 * FILEDLG95_SHELL_BrowseToDesktop
2764 * Browse to the Desktop
2765 * If the function succeeds, the return value is nonzero.
2767 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2769 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2770 LPITEMIDLIST pidl;
2771 HRESULT hres;
2773 TRACE("\n");
2775 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2776 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2777 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2778 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2779 COMDLG32_SHFree(pidl);
2780 return SUCCEEDED(hres);
2782 /***********************************************************************
2783 * FILEDLG95_SHELL_Clean
2785 * Cleans the memory used by shell objects
2787 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2789 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2791 TRACE("\n");
2793 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2795 /* clean Shell interfaces */
2796 if (fodInfos->Shell.FOIShellView)
2798 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2799 IShellView_Release(fodInfos->Shell.FOIShellView);
2801 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2802 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2803 if (fodInfos->Shell.FOIDataObject)
2804 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2807 /***********************************************************************
2808 * FILEDLG95_FILETYPE_Init
2810 * Initialisation of the file type combo box
2812 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2814 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2815 int nFilters = 0; /* number of filters */
2816 int nFilterIndexCB;
2818 TRACE("\n");
2820 if(fodInfos->customfilter)
2822 /* customfilter has one entry... title\0ext\0
2823 * Set first entry of combo box item with customfilter
2825 LPWSTR lpstrExt;
2826 LPCWSTR lpstrPos = fodInfos->customfilter;
2828 /* Get the title */
2829 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2831 /* Copy the extensions */
2832 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2833 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2834 lstrcpyW(lpstrExt,lpstrPos);
2836 /* Add the item at the end of the combo */
2837 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2838 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2839 nFilters++;
2841 if(fodInfos->filter)
2843 LPCWSTR lpstrPos = fodInfos->filter;
2845 for(;;)
2847 /* filter is a list... title\0ext\0......\0\0
2848 * Set the combo item text to the title and the item data
2849 * to the ext
2851 LPCWSTR lpstrDisplay;
2852 LPWSTR lpstrExt;
2854 /* Get the title */
2855 if(! *lpstrPos) break; /* end */
2856 lpstrDisplay = lpstrPos;
2857 lpstrPos += lstrlenW(lpstrPos) + 1;
2859 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2861 nFilters++;
2863 /* Copy the extensions */
2864 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2865 lstrcpyW(lpstrExt,lpstrPos);
2866 lpstrPos += lstrlenW(lpstrPos) + 1;
2868 /* Add the item at the end of the combo */
2869 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2871 /* malformed filters are added anyway... */
2872 if (!*lpstrExt) break;
2877 * Set the current filter to the one specified
2878 * in the initialisation structure
2880 if (fodInfos->filter || fodInfos->customfilter)
2882 LPWSTR lpstrFilter;
2884 /* Check to make sure our index isn't out of bounds. */
2885 if ( fodInfos->ofnInfos->nFilterIndex >
2886 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2887 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2889 /* set default filter index */
2890 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2891 fodInfos->ofnInfos->nFilterIndex = 1;
2893 /* calculate index of Combo Box item */
2894 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2895 if (fodInfos->customfilter == NULL)
2896 nFilterIndexCB--;
2898 /* Set the current index selection. */
2899 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2901 /* Get the corresponding text string from the combo box. */
2902 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2903 nFilterIndexCB);
2905 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2906 lpstrFilter = NULL;
2908 if(lpstrFilter)
2910 DWORD len;
2911 CharLowerW(lpstrFilter); /* lowercase */
2912 len = lstrlenW(lpstrFilter)+1;
2913 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2914 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2916 } else
2917 fodInfos->ofnInfos->nFilterIndex = 0;
2918 return S_OK;
2921 /***********************************************************************
2922 * FILEDLG95_FILETYPE_OnCommand
2924 * WM_COMMAND of the file type combo box
2925 * If the function succeeds, the return value is nonzero.
2927 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2929 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2931 switch(wNotifyCode)
2933 case CBN_SELENDOK:
2935 LPWSTR lpstrFilter;
2937 /* Get the current item of the filetype combo box */
2938 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2940 /* set the current filter index */
2941 fodInfos->ofnInfos->nFilterIndex = iItem +
2942 (fodInfos->customfilter == NULL ? 1 : 0);
2944 /* Set the current filter with the current selection */
2945 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2947 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2948 iItem);
2949 if((INT_PTR)lpstrFilter != CB_ERR)
2951 DWORD len;
2952 CharLowerW(lpstrFilter); /* lowercase */
2953 len = lstrlenW(lpstrFilter)+1;
2954 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2955 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2956 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2957 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2960 /* Refresh the actual view to display the included items*/
2961 if (fodInfos->Shell.FOIShellView)
2962 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2965 return FALSE;
2967 /***********************************************************************
2968 * FILEDLG95_FILETYPE_SearchExt
2970 * searches for an extension in the filetype box
2972 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2974 int i, iCount = CBGetCount(hwnd);
2976 TRACE("%s\n", debugstr_w(lpstrExt));
2978 if(iCount != CB_ERR)
2980 for(i=0;i<iCount;i++)
2982 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2983 return i;
2986 return -1;
2989 /***********************************************************************
2990 * FILEDLG95_FILETYPE_Clean
2992 * Clean the memory used by the filetype combo box
2994 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2996 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2997 int iPos;
2998 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3000 TRACE("\n");
3002 /* Delete each string of the combo and their associated data */
3003 if(iCount != CB_ERR)
3005 for(iPos = iCount-1;iPos>=0;iPos--)
3007 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3008 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3011 /* Current filter */
3012 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3016 /***********************************************************************
3017 * FILEDLG95_LOOKIN_Init
3019 * Initialisation of the look in combo box
3022 /* Small helper function, to determine if the unixfs shell extension is rooted
3023 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3025 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3026 HKEY hKey;
3027 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3028 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3029 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3030 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3031 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3032 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3033 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3035 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3036 return FALSE;
3038 RegCloseKey(hKey);
3039 return TRUE;
3042 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3044 IShellFolder *psfRoot, *psfDrives;
3045 IEnumIDList *lpeRoot, *lpeDrives;
3046 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3048 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3050 TRACE("\n");
3052 liInfos->iMaxIndentation = 0;
3054 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3056 /* set item height for both text field and listbox */
3057 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
3058 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
3060 /* Turn on the extended UI for the combo box like Windows does */
3061 CBSetExtendedUI(hwndCombo, TRUE);
3063 /* Initialise data of Desktop folder */
3064 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3065 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3066 COMDLG32_SHFree(pidlTmp);
3068 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3070 SHGetDesktopFolder(&psfRoot);
3072 if (psfRoot)
3074 /* enumerate the contents of the desktop */
3075 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3077 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3079 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3081 /* If the unixfs extension is rooted, we don't expand the drives by default */
3082 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3084 /* special handling for CSIDL_DRIVES */
3085 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3087 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3089 /* enumerate the drives */
3090 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3092 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3094 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3095 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3096 COMDLG32_SHFree(pidlAbsTmp);
3097 COMDLG32_SHFree(pidlTmp1);
3099 IEnumIDList_Release(lpeDrives);
3101 IShellFolder_Release(psfDrives);
3106 COMDLG32_SHFree(pidlTmp);
3108 IEnumIDList_Release(lpeRoot);
3110 IShellFolder_Release(psfRoot);
3113 COMDLG32_SHFree(pidlDrives);
3116 /***********************************************************************
3117 * FILEDLG95_LOOKIN_DrawItem
3119 * WM_DRAWITEM message handler
3121 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3123 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3124 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3125 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3126 RECT rectText;
3127 RECT rectIcon;
3128 SHFILEINFOW sfi;
3129 HIMAGELIST ilItemImage;
3130 int iIndentation;
3131 TEXTMETRICW tm;
3132 LPSFOLDER tmpFolder;
3133 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
3135 TRACE("\n");
3137 if(pDIStruct->itemID == -1)
3138 return 0;
3140 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3141 pDIStruct->itemID)))
3142 return 0;
3145 if(pDIStruct->itemID == liInfos->uSelectedItem)
3147 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3149 &sfi,
3150 sizeof (sfi),
3151 SHGFI_PIDL | SHGFI_SMALLICON |
3152 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
3153 SHGFI_DISPLAYNAME );
3155 else
3157 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3159 &sfi,
3160 sizeof (sfi),
3161 SHGFI_PIDL | SHGFI_SMALLICON |
3162 SHGFI_SYSICONINDEX |
3163 SHGFI_DISPLAYNAME);
3166 /* Is this item selected ? */
3167 if(pDIStruct->itemState & ODS_SELECTED)
3169 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3170 SetBkColor(pDIStruct->hDC,crHighLight);
3171 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3173 else
3175 SetTextColor(pDIStruct->hDC,crText);
3176 SetBkColor(pDIStruct->hDC,crWin);
3177 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3180 /* Do not indent item if drawing in the edit of the combo */
3181 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3183 iIndentation = 0;
3184 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3186 &sfi,
3187 sizeof (sfi),
3188 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
3189 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
3192 else
3194 iIndentation = tmpFolder->m_iIndent;
3196 /* Draw text and icon */
3198 /* Initialise the icon display area */
3199 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
3200 rectIcon.top = pDIStruct->rcItem.top;
3201 rectIcon.right = rectIcon.left + ICONWIDTH;
3202 rectIcon.bottom = pDIStruct->rcItem.bottom;
3204 /* Initialise the text display area */
3205 GetTextMetricsW(pDIStruct->hDC, &tm);
3206 rectText.left = rectIcon.right;
3207 rectText.top =
3208 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3209 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
3210 rectText.bottom =
3211 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3213 /* Draw the icon from the image list */
3214 ImageList_Draw(ilItemImage,
3215 sfi.iIcon,
3216 pDIStruct->hDC,
3217 rectIcon.left,
3218 rectIcon.top,
3219 ILD_TRANSPARENT );
3221 /* Draw the associated text */
3222 if(sfi.szDisplayName)
3223 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3226 return NOERROR;
3229 /***********************************************************************
3230 * FILEDLG95_LOOKIN_OnCommand
3232 * LookIn combo box WM_COMMAND message handler
3233 * If the function succeeds, the return value is nonzero.
3235 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3237 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3239 TRACE("%p\n", fodInfos);
3241 switch(wNotifyCode)
3243 case CBN_SELENDOK:
3245 LPSFOLDER tmpFolder;
3246 int iItem;
3248 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3250 if( iItem == CB_ERR) return FALSE;
3252 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3253 iItem)))
3254 return FALSE;
3257 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3258 tmpFolder->pidlItem,
3259 SBSP_ABSOLUTE)))
3261 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3262 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3263 return TRUE;
3265 break;
3269 return FALSE;
3272 /***********************************************************************
3273 * FILEDLG95_LOOKIN_AddItem
3275 * Adds an absolute pidl item to the lookin combo box
3276 * returns the index of the inserted item
3278 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3280 LPITEMIDLIST pidlNext;
3281 SHFILEINFOW sfi;
3282 SFOLDER *tmpFolder;
3283 LookInInfos *liInfos;
3285 TRACE("%08x\n", iInsertId);
3287 if(!pidl)
3288 return -1;
3290 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3291 return -1;
3293 tmpFolder = MemAlloc(sizeof(SFOLDER));
3294 tmpFolder->m_iIndent = 0;
3296 /* Calculate the indentation of the item in the lookin*/
3297 pidlNext = pidl;
3298 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3300 tmpFolder->m_iIndent++;
3303 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3305 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3306 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3308 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3309 SHGetFileInfoW((LPCWSTR)pidl,
3311 &sfi,
3312 sizeof(sfi),
3313 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3314 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3316 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3318 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3320 int iItemID;
3322 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3324 /* Add the item at the end of the list */
3325 if(iInsertId < 0)
3327 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3329 /* Insert the item at the iInsertId position*/
3330 else
3332 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3335 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3336 return iItemID;
3339 COMDLG32_SHFree( tmpFolder->pidlItem );
3340 MemFree( tmpFolder );
3341 return -1;
3345 /***********************************************************************
3346 * FILEDLG95_LOOKIN_InsertItemAfterParent
3348 * Insert an item below its parent
3350 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3353 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3354 int iParentPos;
3356 TRACE("\n");
3358 if (pidl == pidlParent)
3359 return -1;
3361 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3363 if(iParentPos < 0)
3365 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3368 /* Free pidlParent memory */
3369 COMDLG32_SHFree(pidlParent);
3371 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3374 /***********************************************************************
3375 * FILEDLG95_LOOKIN_SelectItem
3377 * Adds an absolute pidl item to the lookin combo box
3378 * returns the index of the inserted item
3380 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3382 int iItemPos;
3383 LookInInfos *liInfos;
3385 TRACE("\n");
3387 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3389 liInfos = GetPropA(hwnd,LookInInfosStr);
3391 if(iItemPos < 0)
3393 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3394 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3397 else
3399 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3400 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3402 int iRemovedItem;
3404 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3405 break;
3406 if(iRemovedItem < iItemPos)
3407 iItemPos--;
3411 CBSetCurSel(hwnd,iItemPos);
3412 liInfos->uSelectedItem = iItemPos;
3414 return 0;
3418 /***********************************************************************
3419 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3421 * Remove the item with an expansion level over iExpansionLevel
3423 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3425 int iItemPos;
3426 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3428 TRACE("\n");
3430 if(liInfos->iMaxIndentation <= 2)
3431 return -1;
3433 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3435 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3436 COMDLG32_SHFree(tmpFolder->pidlItem);
3437 MemFree(tmpFolder);
3438 CBDeleteString(hwnd,iItemPos);
3439 liInfos->iMaxIndentation--;
3441 return iItemPos;
3444 return -1;
3447 /***********************************************************************
3448 * FILEDLG95_LOOKIN_SearchItem
3450 * Search for pidl in the lookin combo box
3451 * returns the index of the found item
3453 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3455 int i = 0;
3456 int iCount = CBGetCount(hwnd);
3458 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3460 if (iCount != CB_ERR)
3462 for(;i<iCount;i++)
3464 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3466 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3467 return i;
3468 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3469 return i;
3473 return -1;
3476 /***********************************************************************
3477 * FILEDLG95_LOOKIN_Clean
3479 * Clean the memory used by the lookin combo box
3481 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3483 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3484 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3485 int iPos;
3486 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3488 TRACE("\n");
3490 /* Delete each string of the combo and their associated data */
3491 if (iCount != CB_ERR)
3493 for(iPos = iCount-1;iPos>=0;iPos--)
3495 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3496 COMDLG32_SHFree(tmpFolder->pidlItem);
3497 MemFree(tmpFolder);
3498 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3502 /* LookInInfos structure */
3503 MemFree(liInfos);
3504 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3507 /***********************************************************************
3508 * FILEDLG95_FILENAME_FillFromSelection
3510 * fills the edit box from the cached DataObject
3512 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3514 FileOpenDlgInfos *fodInfos;
3515 LPITEMIDLIST pidl;
3516 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3517 WCHAR lpstrTemp[MAX_PATH];
3518 LPWSTR lpstrAllFile, lpstrCurrFile;
3520 TRACE("\n");
3521 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3523 /* Count how many files we have */
3524 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3526 /* calculate the string length, count files */
3527 if (nFileSelected >= 1)
3529 nLength += 3; /* first and last quotes, trailing \0 */
3530 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3532 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3534 if (pidl)
3536 /* get the total length of the selected file names */
3537 lpstrTemp[0] = '\0';
3538 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3540 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3542 nLength += lstrlenW( lpstrTemp ) + 3;
3543 nFiles++;
3545 COMDLG32_SHFree( pidl );
3550 /* allocate the buffer */
3551 if (nFiles <= 1) nLength = MAX_PATH;
3552 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3554 /* Generate the string for the edit control */
3555 if(nFiles >= 1)
3557 lpstrCurrFile = lpstrAllFile;
3558 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3560 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3562 if (pidl)
3564 /* get the file name */
3565 lpstrTemp[0] = '\0';
3566 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3568 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3570 if ( nFiles > 1)
3572 *lpstrCurrFile++ = '\"';
3573 lstrcpyW( lpstrCurrFile, lpstrTemp );
3574 lpstrCurrFile += lstrlenW( lpstrTemp );
3575 *lpstrCurrFile++ = '\"';
3576 *lpstrCurrFile++ = ' ';
3577 *lpstrCurrFile = 0;
3579 else
3581 lstrcpyW( lpstrAllFile, lpstrTemp );
3584 COMDLG32_SHFree( pidl );
3587 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3589 /* Select the file name like Windows does */
3590 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3592 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3596 /* copied from shell32 to avoid linking to it
3597 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3598 * is dependent on whether emulated OS is unicode or not.
3600 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3602 switch (src->uType)
3604 case STRRET_WSTR:
3605 lstrcpynW(dest, src->u.pOleStr, len);
3606 COMDLG32_SHFree(src->u.pOleStr);
3607 break;
3609 case STRRET_CSTR:
3610 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3611 dest[len-1] = 0;
3612 break;
3614 case STRRET_OFFSET:
3615 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3616 dest[len-1] = 0;
3617 break;
3619 default:
3620 FIXME("unknown type %x!\n", src->uType);
3621 if (len) *dest = '\0';
3622 return E_FAIL;
3624 return S_OK;
3627 /***********************************************************************
3628 * FILEDLG95_FILENAME_GetFileNames
3630 * Copies the filenames to a delimited string list.
3631 * The delimiter is specified by the parameter 'separator',
3632 * usually either a space or a nul
3634 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3636 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3637 UINT nStrCharCount = 0; /* index in src buffer */
3638 UINT nFileIndex = 0; /* index in dest buffer */
3639 UINT nFileCount = 0; /* number of files */
3640 UINT nStrLen = 0; /* length of string in edit control */
3641 LPWSTR lpstrEdit; /* buffer for string from edit control */
3643 TRACE("\n");
3645 /* get the filenames from the edit control */
3646 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3647 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3648 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3650 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3652 /* we might get single filename without any '"',
3653 * so we need nStrLen + terminating \0 + end-of-list \0 */
3654 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3655 *sizeUsed = 0;
3657 /* build delimited file list from filenames */
3658 while ( nStrCharCount <= nStrLen )
3660 if ( lpstrEdit[nStrCharCount]=='"' )
3662 nStrCharCount++;
3663 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3665 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3666 nStrCharCount++;
3668 (*lpstrFileList)[nFileIndex++] = 0;
3669 nFileCount++;
3671 nStrCharCount++;
3674 /* single, unquoted string */
3675 if ((nStrLen > 0) && (nFileIndex == 0) )
3677 lstrcpyW(*lpstrFileList, lpstrEdit);
3678 nFileIndex = lstrlenW(lpstrEdit) + 1;
3679 nFileCount = 1;
3682 /* trailing \0 */
3683 (*lpstrFileList)[nFileIndex++] = '\0';
3685 *sizeUsed = nFileIndex;
3686 MemFree(lpstrEdit);
3687 return nFileCount;
3690 #define SETDefFormatEtc(fe,cf,med) \
3692 (fe).cfFormat = cf;\
3693 (fe).dwAspect = DVASPECT_CONTENT; \
3694 (fe).ptd =NULL;\
3695 (fe).tymed = med;\
3696 (fe).lindex = -1;\
3700 * DATAOBJECT Helper functions
3703 /***********************************************************************
3704 * COMCTL32_ReleaseStgMedium
3706 * like ReleaseStgMedium from ole32
3708 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3710 if(medium.pUnkForRelease)
3712 IUnknown_Release(medium.pUnkForRelease);
3714 else
3716 GlobalUnlock(medium.u.hGlobal);
3717 GlobalFree(medium.u.hGlobal);
3721 /***********************************************************************
3722 * GetPidlFromDataObject
3724 * Return pidl(s) by number from the cached DataObject
3726 * nPidlIndex=0 gets the fully qualified root path
3728 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3731 STGMEDIUM medium;
3732 FORMATETC formatetc;
3733 LPITEMIDLIST pidl = NULL;
3735 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3737 if (!doSelected)
3738 return NULL;
3740 /* Set the FORMATETC structure*/
3741 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3743 /* Get the pidls from IDataObject */
3744 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3746 LPIDA cida = GlobalLock(medium.u.hGlobal);
3747 if(nPidlIndex <= cida->cidl)
3749 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3751 COMCTL32_ReleaseStgMedium(medium);
3753 return pidl;
3756 /***********************************************************************
3757 * GetNumSelected
3759 * Return the number of selected items in the DataObject.
3762 static UINT GetNumSelected( IDataObject *doSelected )
3764 UINT retVal = 0;
3765 STGMEDIUM medium;
3766 FORMATETC formatetc;
3768 TRACE("sv=%p\n", doSelected);
3770 if (!doSelected) return 0;
3772 /* Set the FORMATETC structure*/
3773 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3775 /* Get the pidls from IDataObject */
3776 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3778 LPIDA cida = GlobalLock(medium.u.hGlobal);
3779 retVal = cida->cidl;
3780 COMCTL32_ReleaseStgMedium(medium);
3781 return retVal;
3783 return 0;
3787 * TOOLS
3790 /***********************************************************************
3791 * GetName
3793 * Get the pidl's display name (relative to folder) and
3794 * put it in lpstrFileName.
3796 * Return NOERROR on success,
3797 * E_FAIL otherwise
3800 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3802 STRRET str;
3803 HRESULT hRes;
3805 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3807 if(!lpsf)
3809 SHGetDesktopFolder(&lpsf);
3810 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3811 IShellFolder_Release(lpsf);
3812 return hRes;
3815 /* Get the display name of the pidl relative to the folder */
3816 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3818 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3820 return E_FAIL;
3823 /***********************************************************************
3824 * GetShellFolderFromPidl
3826 * pidlRel is the item pidl relative
3827 * Return the IShellFolder of the absolute pidl
3829 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3831 IShellFolder *psf = NULL,*psfParent;
3833 TRACE("%p\n", pidlAbs);
3835 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3837 psf = psfParent;
3838 if(pidlAbs && pidlAbs->mkid.cb)
3840 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3842 IShellFolder_Release(psfParent);
3843 return psf;
3846 /* return the desktop */
3847 return psfParent;
3849 return NULL;
3852 /***********************************************************************
3853 * GetParentPidl
3855 * Return the LPITEMIDLIST to the parent of the pidl in the list
3857 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3859 LPITEMIDLIST pidlParent;
3861 TRACE("%p\n", pidl);
3863 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3864 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3866 return pidlParent;
3869 /***********************************************************************
3870 * GetPidlFromName
3872 * returns the pidl of the file name relative to folder
3873 * NULL if an error occurred
3875 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3877 LPITEMIDLIST pidl = NULL;
3878 ULONG ulEaten;
3880 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3882 if(!lpcstrFileName) return NULL;
3883 if(!*lpcstrFileName) return NULL;
3885 if(!lpsf)
3887 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3888 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3889 IShellFolder_Release(lpsf);
3892 else
3894 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3896 return pidl;
3901 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3903 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3904 HRESULT ret;
3906 TRACE("%p, %p\n", psf, pidl);
3908 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3910 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3911 /* see documentation shell 4.1*/
3912 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3915 /***********************************************************************
3916 * BrowseSelectedFolder
3918 static BOOL BrowseSelectedFolder(HWND hwnd)
3920 BOOL bBrowseSelFolder = FALSE;
3921 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3923 TRACE("\n");
3925 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3927 LPITEMIDLIST pidlSelection;
3929 /* get the file selected */
3930 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3931 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3933 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3934 pidlSelection, SBSP_RELATIVE ) ) )
3936 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3937 ' ','n','o','t',' ','e','x','i','s','t',0};
3938 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3940 bBrowseSelFolder = TRUE;
3941 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3942 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3944 COMDLG32_SHFree( pidlSelection );
3947 return bBrowseSelFolder;
3951 * Memory allocation methods */
3952 static void *MemAlloc(UINT size)
3954 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3957 static void MemFree(void *mem)
3959 HeapFree(GetProcessHeap(),0,mem);
3963 * Old-style (win3.1) dialogs */
3965 /***********************************************************************
3966 * FD32_GetTemplate [internal]
3968 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3969 * by a 32 bits application
3972 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3974 LPOPENFILENAMEW ofnW = lfs->ofnW;
3975 LPOPENFILENAMEA ofnA = lfs->ofnA;
3976 HANDLE hDlgTmpl;
3978 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3980 if (!(lfs->template = LockResource( ofnW->hInstance )))
3982 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3983 return FALSE;
3986 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3988 HRSRC hResInfo;
3989 if (ofnA)
3990 hResInfo = FindResourceA(ofnA->hInstance,
3991 ofnA->lpTemplateName,
3992 (LPSTR)RT_DIALOG);
3993 else
3994 hResInfo = FindResourceW(ofnW->hInstance,
3995 ofnW->lpTemplateName,
3996 (LPWSTR)RT_DIALOG);
3997 if (!hResInfo)
3999 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4000 return FALSE;
4002 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
4003 hResInfo)) ||
4004 !(lfs->template = LockResource(hDlgTmpl)))
4006 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4007 return FALSE;
4009 } else { /* get it from internal Wine resource */
4010 HRSRC hResInfo;
4011 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
4012 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
4014 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
4015 return FALSE;
4017 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
4018 !(lfs->template = LockResource( hDlgTmpl )))
4020 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4021 return FALSE;
4024 return TRUE;
4028 /***********************************************************************
4029 * FD32_WMMeasureItem [internal]
4031 static LONG FD32_WMMeasureItem(LPARAM lParam)
4033 LPMEASUREITEMSTRUCT lpmeasure;
4035 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
4036 lpmeasure->itemHeight = FD31_GetFldrHeight();
4037 return TRUE;
4041 /***********************************************************************
4042 * FileOpenDlgProc [internal]
4043 * Used for open and save, in fact.
4045 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
4046 WPARAM wParam, LPARAM lParam)
4048 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
4050 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
4051 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
4053 INT_PTR lRet;
4054 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
4055 if (lRet)
4056 return lRet; /* else continue message processing */
4058 switch (wMsg)
4060 case WM_INITDIALOG:
4061 return FD31_WMInitDialog(hWnd, wParam, lParam);
4063 case WM_MEASUREITEM:
4064 return FD32_WMMeasureItem(lParam);
4066 case WM_DRAWITEM:
4067 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
4069 case WM_COMMAND:
4070 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
4071 #if 0
4072 case WM_CTLCOLOR:
4073 SetBkColor((HDC16)wParam, 0x00C0C0C0);
4074 switch (HIWORD(lParam))
4076 case CTLCOLOR_BTN:
4077 SetTextColor((HDC16)wParam, 0x00000000);
4078 return hGRAYBrush;
4079 case CTLCOLOR_STATIC:
4080 SetTextColor((HDC16)wParam, 0x00000000);
4081 return hGRAYBrush;
4083 break;
4084 #endif
4086 return FALSE;
4090 /***********************************************************************
4091 * GetFileName31A [internal]
4093 * Creates a win31 style dialog box for the user to select a file to open/save.
4095 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4096 UINT dlgType /* type dialogue : open/save */
4099 BOOL bRet = FALSE;
4100 PFD31_DATA lfs;
4102 if (!lpofn || !FD31_Init()) return FALSE;
4104 TRACE("ofn flags %08x\n", lpofn->Flags);
4105 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
4106 if (lfs)
4108 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4109 FD32_FileOpenDlgProc, (LPARAM)lfs);
4110 FD31_DestroyPrivate(lfs);
4113 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4114 return bRet;
4117 /***********************************************************************
4118 * GetFileName31W [internal]
4120 * Creates a win31 style dialog box for the user to select a file to open/save
4122 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4123 UINT dlgType /* type dialogue : open/save */
4126 BOOL bRet = FALSE;
4127 PFD31_DATA lfs;
4129 if (!lpofn || !FD31_Init()) return FALSE;
4131 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
4132 if (lfs)
4134 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
4135 FD32_FileOpenDlgProc, (LPARAM)lfs);
4136 FD31_DestroyPrivate(lfs);
4139 TRACE("file %s, file offset %d, ext offset %d\n",
4140 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4141 return bRet;
4144 /* ------------------ APIs ---------------------- */
4146 /***********************************************************************
4147 * GetOpenFileNameA (COMDLG32.@)
4149 * Creates a dialog box for the user to select a file to open.
4151 * RETURNS
4152 * TRUE on success: user enters a valid file
4153 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4156 BOOL WINAPI GetOpenFileNameA(
4157 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4159 BOOL win16look = FALSE;
4161 TRACE("flags %08x\n", ofn->Flags);
4163 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4164 if (ofn->Flags & OFN_FILEMUSTEXIST)
4165 ofn->Flags |= OFN_PATHMUSTEXIST;
4167 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4168 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4170 if (win16look)
4171 return GetFileName31A(ofn, OPEN_DIALOG);
4172 else
4173 return GetFileDialog95A(ofn, OPEN_DIALOG);
4176 /***********************************************************************
4177 * GetOpenFileNameW (COMDLG32.@)
4179 * Creates a dialog box for the user to select a file to open.
4181 * RETURNS
4182 * TRUE on success: user enters a valid file
4183 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4186 BOOL WINAPI GetOpenFileNameW(
4187 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4189 BOOL win16look = FALSE;
4191 TRACE("flags %08x\n", ofn->Flags);
4193 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4194 if (ofn->Flags & OFN_FILEMUSTEXIST)
4195 ofn->Flags |= OFN_PATHMUSTEXIST;
4197 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4198 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4200 if (win16look)
4201 return GetFileName31W(ofn, OPEN_DIALOG);
4202 else
4203 return GetFileDialog95W(ofn, OPEN_DIALOG);
4207 /***********************************************************************
4208 * GetSaveFileNameA (COMDLG32.@)
4210 * Creates a dialog box for the user to select a file to save.
4212 * RETURNS
4213 * TRUE on success: user enters a valid file
4214 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4217 BOOL WINAPI GetSaveFileNameA(
4218 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4220 BOOL win16look = FALSE;
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, SAVE_DIALOG);
4227 else
4228 return GetFileDialog95A(ofn, SAVE_DIALOG);
4231 /***********************************************************************
4232 * GetSaveFileNameW (COMDLG32.@)
4234 * Creates a dialog box for the user to select a file to save.
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 GetSaveFileNameW(
4242 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4244 BOOL win16look = FALSE;
4246 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4247 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4249 if (win16look)
4250 return GetFileName31W(ofn, SAVE_DIALOG);
4251 else
4252 return GetFileDialog95W(ofn, SAVE_DIALOG);
4255 /***********************************************************************
4256 * GetFileTitleA (COMDLG32.@)
4258 * See GetFileTitleW.
4260 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4262 int ret;
4263 UNICODE_STRING strWFile;
4264 LPWSTR lpWTitle;
4266 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4267 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4268 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4269 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4270 RtlFreeUnicodeString( &strWFile );
4271 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4272 return ret;
4276 /***********************************************************************
4277 * GetFileTitleW (COMDLG32.@)
4279 * Get the name of a file.
4281 * PARAMS
4282 * lpFile [I] name and location of file
4283 * lpTitle [O] returned file name
4284 * cbBuf [I] buffer size of lpTitle
4286 * RETURNS
4287 * Success: zero
4288 * Failure: negative number.
4290 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4292 int i, len;
4293 static const WCHAR brkpoint[] = {'*','[',']',0};
4294 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4296 if(lpFile == NULL || lpTitle == NULL)
4297 return -1;
4299 len = lstrlenW(lpFile);
4301 if (len == 0)
4302 return -1;
4304 if(strpbrkW(lpFile, brkpoint))
4305 return -1;
4307 len--;
4309 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4310 return -1;
4312 for(i = len; i >= 0; i--)
4314 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4316 i++;
4317 break;
4321 if(i == -1)
4322 i++;
4324 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4326 len = lstrlenW(lpFile+i)+1;
4327 if(cbBuf < len)
4328 return len;
4330 lstrcpyW(lpTitle, &lpFile[i]);
4331 return 0;