Fix definition of LookupPrivilegeNameW and declare it.
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blobd4ab689d923bea4bd5a0ee583594e8e7ecc0e5f7
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winreg.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wine/unicode.h"
66 #include "wingdi.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "wine/debug.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlguid.h"
76 #include "shlobj.h"
77 #include "filedlgbrowser.h"
78 #include "shlwapi.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
84 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
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;
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
119 #define ICONWIDTH 18
120 #define XTEXTOFFSET 3
122 /* AddItem flags*/
123 #define LISTEND -1
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
127 #define SEARCH_EXP 2
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
133 /* NOTE
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
141 #define CBAddStringW(hwnd,str) \
142 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
159 #define CBGetCurSel(hwnd) \
160 SendMessageA(hwnd,CB_GETCURSEL,0,0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
165 #define CBGetCount(hwnd) \
166 SendMessageA(hwnd,CB_GETCOUNT,0,0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
175 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
176 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the filetype combo box */
198 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
199 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
200 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
201 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
203 /* Functions used by the Look In combo box */
204 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
205 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
206 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
207 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
208 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
209 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
210 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
211 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
212 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
214 /* Miscellaneous tool functions */
215 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
216 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
217 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
218 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
219 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
221 /* Shell memory allocation */
222 static void *MemAlloc(UINT size);
223 static void MemFree(void *mem);
225 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
226 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
227 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
228 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
230 static BOOL BrowseSelectedFolder(HWND hwnd);
232 /***********************************************************************
233 * GetFileName95
235 * Creates an Open common dialog box that lets the user select
236 * the drive, directory, and the name of a file or set of files to open.
238 * IN : The FileOpenDlgInfos structure associated with the dialog
239 * OUT : TRUE on success
240 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
242 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
245 LRESULT lRes;
246 LPCVOID template;
247 HRSRC hRes;
248 HANDLE hDlgTmpl = 0;
250 /* test for missing functionality */
251 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
253 FIXME("Flags 0x%08lx not yet implemented\n",
254 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
257 /* Create the dialog from a template */
259 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
261 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
262 return FALSE;
264 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
265 !(template = LockResource( hDlgTmpl )))
267 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
268 return FALSE;
271 /* old style hook messages */
272 if (IsHooked(fodInfos))
274 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
275 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
276 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
277 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
280 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
281 (LPDLGTEMPLATEA) template,
282 fodInfos->ofnInfos->hwndOwner,
283 FileOpenDlgProc95,
284 (LPARAM) fodInfos);
286 /* Unable to create the dialog */
287 if( lRes == -1)
288 return FALSE;
290 return lRes;
293 /***********************************************************************
294 * GetFileDialog95A
296 * Call GetFileName95 with this structure and clean the memory.
298 * IN : The OPENFILENAMEA initialisation structure passed to
299 * GetOpenFileNameA win api function (see filedlg.c)
301 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
303 BOOL ret;
304 FileOpenDlgInfos fodInfos;
305 LPSTR lpstrSavDir = NULL;
306 LPWSTR title = NULL;
307 LPWSTR defext = NULL;
308 LPWSTR filter = NULL;
309 LPWSTR customfilter = NULL;
311 /* Initialize FileOpenDlgInfos structure */
312 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
314 /* Pass in the original ofn */
315 fodInfos.ofnInfos = ofn;
317 /* save current directory */
318 if (ofn->Flags & OFN_NOCHANGEDIR)
320 lpstrSavDir = MemAlloc(MAX_PATH);
321 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
324 fodInfos.unicode = FALSE;
326 /* convert all the input strings to unicode */
327 if(ofn->lpstrInitialDir)
329 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
330 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
331 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
333 else
334 fodInfos.initdir = NULL;
336 if(ofn->lpstrFile)
338 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
339 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
341 else
342 fodInfos.filename = NULL;
344 if(ofn->lpstrDefExt)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
347 defext = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
350 fodInfos.defext = defext;
352 if(ofn->lpstrTitle)
354 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
355 title = MemAlloc((len+1)*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
358 fodInfos.title = title;
360 if (ofn->lpstrFilter)
362 LPCSTR s;
363 int n, len;
365 /* filter is a list... title\0ext\0......\0\0 */
366 s = ofn->lpstrFilter;
367 while (*s) s = s+strlen(s)+1;
368 s++;
369 n = s - ofn->lpstrFilter;
370 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
371 filter = MemAlloc(len*sizeof(WCHAR));
372 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
374 fodInfos.filter = filter;
376 /* convert lpstrCustomFilter */
377 if (ofn->lpstrCustomFilter)
379 LPCSTR s;
380 int n, len;
382 /* customfilter contains a pair of strings... title\0ext\0 */
383 s = ofn->lpstrCustomFilter;
384 if (*s) s = s+strlen(s)+1;
385 if (*s) s = s+strlen(s)+1;
386 n = s - ofn->lpstrCustomFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
388 customfilter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
391 fodInfos.customfilter = customfilter;
393 /* Initialize the dialog property */
394 fodInfos.DlgInfos.dwDlgProp = 0;
395 fodInfos.DlgInfos.hwndCustomDlg = NULL;
397 switch(iDlgType)
399 case OPEN_DIALOG :
400 ret = GetFileName95(&fodInfos);
401 break;
402 case SAVE_DIALOG :
403 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
404 ret = GetFileName95(&fodInfos);
405 break;
406 default :
407 ret = 0;
410 if (lpstrSavDir)
412 SetCurrentDirectoryA(lpstrSavDir);
413 MemFree(lpstrSavDir);
416 if(title)
417 MemFree(title);
418 if(defext)
419 MemFree(defext);
420 if(filter)
421 MemFree(filter);
422 if(customfilter)
423 MemFree(customfilter);
424 if(fodInfos.initdir)
425 MemFree(fodInfos.initdir);
427 if(fodInfos.filename)
428 MemFree(fodInfos.filename);
430 TRACE("selected file: %s\n",ofn->lpstrFile);
432 return ret;
435 /***********************************************************************
436 * GetFileDialog95W
438 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
439 * Call GetFileName95 with this structure and clean the memory.
442 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
444 BOOL ret;
445 FileOpenDlgInfos fodInfos;
446 LPSTR lpstrSavDir = NULL;
448 /* Initialize FileOpenDlgInfos structure */
449 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
451 /* Pass in the original ofn */
452 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
454 fodInfos.title = ofn->lpstrTitle;
455 fodInfos.defext = ofn->lpstrDefExt;
456 fodInfos.filter = ofn->lpstrFilter;
457 fodInfos.customfilter = ofn->lpstrCustomFilter;
459 /* convert string arguments, save others */
460 if(ofn->lpstrFile)
462 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
463 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
465 else
466 fodInfos.filename = NULL;
468 if(ofn->lpstrInitialDir)
470 DWORD len = strlenW(ofn->lpstrInitialDir);
471 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
472 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
474 else
475 fodInfos.initdir = NULL;
477 /* save current directory */
478 if (ofn->Flags & OFN_NOCHANGEDIR)
480 lpstrSavDir = MemAlloc(MAX_PATH);
481 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
484 fodInfos.unicode = TRUE;
486 switch(iDlgType)
488 case OPEN_DIALOG :
489 ret = GetFileName95(&fodInfos);
490 break;
491 case SAVE_DIALOG :
492 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
493 ret = GetFileName95(&fodInfos);
494 break;
495 default :
496 ret = 0;
499 if (lpstrSavDir)
501 SetCurrentDirectoryA(lpstrSavDir);
502 MemFree(lpstrSavDir);
505 /* restore saved IN arguments and convert OUT arguments back */
506 MemFree(fodInfos.filename);
507 MemFree(fodInfos.initdir);
508 return ret;
511 /***********************************************************************
512 * ArrangeCtrlPositions [internal]
514 * NOTE: Do not change anything here without a lot of testing.
516 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
518 HWND hwndChild, hwndStc32;
519 RECT rectParent, rectChild, rectStc32;
520 INT help_fixup = 0;
522 /* Take into account if open as read only checkbox and help button
523 * are hidden
525 if (hide_help)
527 RECT rectHelp, rectCancel;
528 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
529 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
530 /* subtract the height of the help button plus the space between
531 * the help button and the cancel button to the height of the dialog
533 help_fixup = rectHelp.bottom - rectCancel.bottom;
537 There are two possibilities to add components to the default file dialog box.
539 By default, all the new components are added below the standard dialog box (the else case).
541 However, if there is a static text component with the stc32 id, a special case happens.
542 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
543 in the window and the cx and cy indicate how to size the window.
544 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
545 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
549 GetClientRect(hwndParentDlg, &rectParent);
551 /* when arranging controls we have to use fixed parent size */
552 rectParent.bottom -= help_fixup;
554 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
555 if (hwndStc32)
557 GetWindowRect(hwndStc32, &rectStc32);
558 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
560 /* set the size of the stc32 control according to the size of
561 * client area of the parent dialog
563 SetWindowPos(hwndStc32, 0,
564 0, 0,
565 rectParent.right, rectParent.bottom,
566 SWP_NOMOVE | SWP_NOZORDER);
568 else
569 SetRectEmpty(&rectStc32);
571 /* this part moves controls of the child dialog */
572 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
573 while (hwndChild)
575 if (hwndChild != hwndStc32)
577 GetWindowRect(hwndChild, &rectChild);
578 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
580 /* move only if stc32 exist */
581 if (hwndStc32 && rectChild.left > rectStc32.right)
583 /* move to the right of visible controls of the parent dialog */
584 rectChild.left += rectParent.right;
585 rectChild.left -= rectStc32.right;
587 /* move even if stc32 doesn't exist */
588 if (rectChild.top > rectStc32.bottom)
590 /* move below visible controls of the parent dialog */
591 rectChild.top += rectParent.bottom;
592 rectChild.top -= rectStc32.bottom - rectStc32.top;
595 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
596 0, 0, SWP_NOSIZE | SWP_NOZORDER);
598 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
601 /* this part moves controls of the parent dialog */
602 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
603 while (hwndChild)
605 if (hwndChild != hwndChildDlg)
607 GetWindowRect(hwndChild, &rectChild);
608 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
610 /* left,top of stc32 marks the position of controls
611 * from the parent dialog
613 rectChild.left += rectStc32.left;
614 rectChild.top += rectStc32.top;
616 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
617 0, 0, SWP_NOSIZE | SWP_NOZORDER);
619 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
622 /* calculate the size of the resulting dialog */
624 /* here we have to use original parent size */
625 GetClientRect(hwndParentDlg, &rectParent);
626 GetClientRect(hwndChildDlg, &rectChild);
628 if (hwndStc32)
630 if (rectParent.right > rectChild.right)
632 rectParent.right += rectChild.right;
633 rectParent.right -= rectStc32.right - rectStc32.left;
635 else
637 rectParent.right = rectChild.right;
640 if (rectParent.bottom > rectChild.bottom)
642 rectParent.bottom += rectChild.bottom;
643 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
645 else
647 rectParent.bottom = rectChild.bottom;
650 else
652 rectParent.bottom += rectChild.bottom;
655 /* finally use fixed parent size */
656 rectParent.bottom -= help_fixup;
658 /* save the size of the parent's client area */
659 rectChild.right = rectParent.right;
660 rectChild.bottom = rectParent.bottom;
662 /* set the size of the parent dialog */
663 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
664 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
665 SetWindowPos(hwndParentDlg, 0,
666 0, 0,
667 rectParent.right - rectParent.left,
668 rectParent.bottom - rectParent.top,
669 SWP_NOMOVE | SWP_NOZORDER);
671 /* set the size of the child dialog */
672 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
673 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
676 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
678 switch(uMsg) {
679 case WM_INITDIALOG:
680 return TRUE;
682 return FALSE;
685 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
687 LPCVOID template;
688 HRSRC hRes;
689 HANDLE hDlgTmpl = 0;
690 HWND hChildDlg = 0;
692 TRACE("\n");
695 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
696 * structure's hInstance parameter is not a HINSTANCE, but
697 * instead a pointer to a template resource to use.
699 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
701 HINSTANCE hinst;
702 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
704 hinst = 0;
705 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
707 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
708 return NULL;
711 else
713 hinst = fodInfos->ofnInfos->hInstance;
714 if(fodInfos->unicode)
716 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
717 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
719 else
721 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
722 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
724 if (!hRes)
726 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
727 return NULL;
729 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
730 !(template = LockResource( hDlgTmpl )))
732 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
733 return NULL;
736 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
737 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
738 (LPARAM)fodInfos->ofnInfos);
739 if(hChildDlg)
741 ShowWindow(hChildDlg,SW_SHOW);
742 return hChildDlg;
745 else if( IsHooked(fodInfos))
747 RECT rectHwnd;
748 struct {
749 DLGTEMPLATE tmplate;
750 WORD menu,class,title;
751 } temp;
752 GetClientRect(hwnd,&rectHwnd);
753 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
754 temp.tmplate.dwExtendedStyle = 0;
755 temp.tmplate.cdit = 0;
756 temp.tmplate.x = 0;
757 temp.tmplate.y = 0;
758 temp.tmplate.cx = 0;
759 temp.tmplate.cy = 0;
760 temp.menu = temp.class = temp.title = 0;
762 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
763 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
765 return hChildDlg;
767 return NULL;
770 /***********************************************************************
771 * SendCustomDlgNotificationMessage
773 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
776 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
778 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
780 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
782 if(!fodInfos) return 0;
784 if(fodInfos->DlgInfos.hwndCustomDlg)
786 HRESULT ret;
787 TRACE("CALL NOTIFY for %x\n", uCode);
788 if(fodInfos->unicode)
790 OFNOTIFYW ofnNotify;
791 ofnNotify.hdr.hwndFrom=hwndParentDlg;
792 ofnNotify.hdr.idFrom=0;
793 ofnNotify.hdr.code = uCode;
794 ofnNotify.lpOFN = (LPOPENFILENAMEW) fodInfos->ofnInfos;
795 ofnNotify.pszFile = NULL;
796 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
798 else
800 OFNOTIFYA ofnNotify;
801 ofnNotify.hdr.hwndFrom=hwndParentDlg;
802 ofnNotify.hdr.idFrom=0;
803 ofnNotify.hdr.code = uCode;
804 ofnNotify.lpOFN = fodInfos->ofnInfos;
805 ofnNotify.pszFile = NULL;
806 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
808 TRACE("RET NOTIFY\n");
809 return ret;
811 return TRUE;
814 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
816 UINT sizeUsed = 0, n, total;
817 LPWSTR lpstrFileList = NULL;
818 WCHAR lpstrCurrentDir[MAX_PATH];
819 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
821 TRACE("CDM_GETFILEPATH:\n");
823 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
824 return -1;
826 /* get path and filenames */
827 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
828 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
830 TRACE("path >%s< filespec >%s< %d files\n",
831 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
833 if( fodInfos->unicode )
835 LPWSTR bufW = buffer;
836 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
838 /* Prepend the current path */
839 n = strlenW(lpstrCurrentDir) + 1;
840 strncpyW( bufW, lpstrCurrentDir, size );
841 if(n<size)
843 /* 'n' includes trailing \0 */
844 bufW[n-1] = '\\';
845 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
847 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
849 else
851 LPSTR bufA = buffer;
852 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
853 NULL, 0, NULL, NULL);
854 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
855 NULL, 0, NULL, NULL);
857 /* Prepend the current path */
858 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
859 bufA, size, NULL, NULL);
861 if(n<size)
863 /* 'n' includes trailing \0 */
864 bufA[n-1] = '\\';
865 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
866 &bufA[n], size-n, NULL, NULL);
869 TRACE("returned -> %s\n",debugstr_an(bufA, total));
871 MemFree(lpstrFileList);
873 return total;
876 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
878 UINT sizeUsed = 0;
879 LPWSTR lpstrFileList = NULL;
880 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
882 TRACE("CDM_GETSPEC:\n");
884 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
885 if( fodInfos->unicode )
887 LPWSTR bufW = buffer;
888 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
890 else
892 LPSTR bufA = buffer;
893 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
894 NULL, 0, NULL, NULL);
895 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
896 bufA, size, NULL, NULL);
898 MemFree(lpstrFileList);
900 return sizeUsed;
903 /***********************************************************************
904 * FILEDLG95_HandleCustomDialogMessages
906 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
908 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
910 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
911 if(!fodInfos) return -1;
913 switch(uMsg)
915 case CDM_GETFILEPATH:
916 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
918 case CDM_GETFOLDERPATH:
919 TRACE("CDM_GETFOLDERPATH:\n");
920 if( fodInfos->unicode )
922 WCHAR lpstrPath[MAX_PATH], *bufW = (LPWSTR)lParam;
923 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
924 if (bufW)
925 lstrcpynW(bufW,lpstrPath,(int)wParam);
926 return strlenW(lpstrPath);
928 else
930 char lpstrPath[MAX_PATH], *bufA = (LPSTR)lParam;
931 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
932 if (bufA)
933 lstrcpynA(bufA,lpstrPath,(int)wParam);
934 return strlen(lpstrPath);
937 case CDM_GETSPEC:
938 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
940 case CDM_SETCONTROLTEXT:
941 TRACE("CDM_SETCONTROLTEXT:\n");
942 if ( lParam )
944 if( fodInfos->unicode )
945 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
946 else
947 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
949 return TRUE;
951 case CDM_HIDECONTROL:
952 case CDM_SETDEFEXT:
953 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
954 return -1;
956 return TRUE;
959 /***********************************************************************
960 * FileOpenDlgProc95
962 * File open dialog procedure
964 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
966 #if 0
967 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
968 #endif
970 switch(uMsg)
972 case WM_INITDIALOG:
974 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
976 /* Adds the FileOpenDlgInfos in the property list of the dialog
977 so it will be easily accessible through a GetPropA(...) */
978 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
980 fodInfos->DlgInfos.hwndCustomDlg =
981 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
983 FILEDLG95_InitControls(hwnd);
985 if (fodInfos->DlgInfos.hwndCustomDlg)
986 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
987 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
989 FILEDLG95_FillControls(hwnd, wParam, lParam);
991 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
992 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
993 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
994 return 0;
996 case WM_COMMAND:
997 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
998 case WM_DRAWITEM:
1000 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1002 case IDC_LOOKIN:
1003 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1004 return TRUE;
1007 return FALSE;
1009 case WM_GETISHELLBROWSER:
1010 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1012 case WM_DESTROY:
1013 RemovePropA(hwnd, FileOpenDlgInfosStr);
1014 return FALSE;
1016 case WM_NOTIFY:
1018 LPNMHDR lpnmh = (LPNMHDR)lParam;
1019 UINT stringId = -1;
1021 /* set up the button tooltips strings */
1022 if(TTN_GETDISPINFOA == lpnmh->code )
1024 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1025 switch(lpnmh->idFrom )
1027 /* Up folder button */
1028 case FCIDM_TB_UPFOLDER:
1029 stringId = IDS_UPFOLDER;
1030 break;
1031 /* New folder button */
1032 case FCIDM_TB_NEWFOLDER:
1033 stringId = IDS_NEWFOLDER;
1034 break;
1035 /* List option button */
1036 case FCIDM_TB_SMALLICON:
1037 stringId = IDS_LISTVIEW;
1038 break;
1039 /* Details option button */
1040 case FCIDM_TB_REPORTVIEW:
1041 stringId = IDS_REPORTVIEW;
1042 break;
1043 /* Desktop button */
1044 case FCIDM_TB_DESKTOP:
1045 stringId = IDS_TODESKTOP;
1046 break;
1047 default:
1048 stringId = 0;
1050 lpdi->hinst = COMDLG32_hInstance;
1051 lpdi->lpszText = (LPSTR) stringId;
1053 return FALSE;
1055 default :
1056 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1057 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1058 return FALSE;
1062 /***********************************************************************
1063 * FILEDLG95_InitControls
1065 * WM_INITDIALOG message handler (before hook notification)
1067 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1069 int win2000plus = 0;
1070 int win98plus = 0;
1071 int handledPath = FALSE;
1072 OSVERSIONINFOA osVi;
1073 static const WCHAR szwSlash[] = { '\\', 0 };
1074 static const WCHAR szwStar[] = { '*',0 };
1076 TBBUTTON tbb[] =
1078 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1079 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1080 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1081 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1082 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1083 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1084 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1085 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1086 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1088 TBADDBITMAP tba[2];
1089 RECT rectTB;
1090 RECT rectlook;
1091 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1093 tba[0].hInst = HINST_COMMCTRL;
1094 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1095 tba[1].hInst = COMDLG32_hInstance;
1096 tba[1].nID = 800;
1098 TRACE("%p\n", fodInfos);
1100 /* Get windows version emulating */
1101 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1102 GetVersionExA(&osVi);
1103 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1104 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1105 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1106 win2000plus = (osVi.dwMajorVersion > 4);
1107 if (win2000plus) win98plus = TRUE;
1109 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1111 /* Get the hwnd of the controls */
1112 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1113 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1114 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1116 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1117 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1119 /* construct the toolbar */
1120 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1121 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1123 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1124 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1125 rectTB.left = rectlook.right;
1126 rectTB.top = rectlook.top-1;
1128 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1129 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1130 rectTB.left, rectTB.top,
1131 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1132 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1134 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1136 /* FIXME: use TB_LOADIMAGES when implemented */
1137 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1138 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1139 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1141 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1142 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1144 /* Set the window text with the text specified in the OPENFILENAME structure */
1145 if(fodInfos->title)
1147 SetWindowTextW(hwnd,fodInfos->title);
1149 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1151 SetWindowTextA(hwnd,"Save");
1154 /* Initialise the file name edit control */
1155 handledPath = FALSE;
1156 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1158 if(fodInfos->filename)
1160 /* 1. If win2000 or higher and filename contains a path, use it
1161 in preference over the lpstrInitialDir */
1162 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1163 WCHAR tmpBuf[MAX_PATH];
1164 WCHAR *nameBit;
1165 DWORD result;
1167 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1168 if (result) {
1170 /* nameBit is always shorter than the original filename */
1171 strcpyW(fodInfos->filename,nameBit);
1173 *nameBit = 0x00;
1174 if (fodInfos->initdir == NULL)
1175 MemFree(fodInfos->initdir);
1176 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1177 strcpyW(fodInfos->initdir, tmpBuf);
1178 handledPath = TRUE;
1179 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1180 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1182 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1184 } else {
1185 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1189 /* 2. (All platforms) If initdir is not null, then use it */
1190 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1191 (*fodInfos->initdir!=0x00))
1193 /* Work out the proper path as supplied one might be relative */
1194 /* (Here because supplying '.' as dir browses to My Computer) */
1195 if (handledPath==FALSE) {
1196 WCHAR tmpBuf[MAX_PATH];
1197 WCHAR tmpBuf2[MAX_PATH];
1198 WCHAR *nameBit;
1199 DWORD result;
1201 strcpyW(tmpBuf, fodInfos->initdir);
1202 if( PathFileExistsW(tmpBuf) ) {
1203 /* initdir does not have to be a directory. If a file is
1204 * specified, the dir part is taken */
1205 if( PathIsDirectoryW(tmpBuf)) {
1206 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1207 strcatW(tmpBuf, szwSlash);
1209 strcatW(tmpBuf, szwStar);
1211 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1212 if (result) {
1213 *nameBit = 0x00;
1214 if (fodInfos->initdir)
1215 MemFree(fodInfos->initdir);
1216 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1217 strcpyW(fodInfos->initdir, tmpBuf2);
1218 handledPath = TRUE;
1219 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1222 else if (fodInfos->initdir)
1224 MemFree(fodInfos->initdir);
1225 fodInfos->initdir = NULL;
1226 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1231 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1232 (*fodInfos->initdir==0x00)))
1234 /* 3. All except w2k+: if filename contains a path use it */
1235 if (!win2000plus && fodInfos->filename &&
1236 *fodInfos->filename &&
1237 strpbrkW(fodInfos->filename, szwSlash)) {
1238 WCHAR tmpBuf[MAX_PATH];
1239 WCHAR *nameBit;
1240 DWORD result;
1242 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1243 tmpBuf, &nameBit);
1244 if (result) {
1245 int len;
1247 /* nameBit is always shorter than the original filename */
1248 strcpyW(fodInfos->filename, nameBit);
1249 *nameBit = 0x00;
1251 len = strlenW(tmpBuf);
1252 if(fodInfos->initdir)
1253 MemFree(fodInfos->initdir);
1254 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1255 strcpyW(fodInfos->initdir, tmpBuf);
1257 handledPath = TRUE;
1258 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1259 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1261 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1264 /* 4. win98+ and win2000+ if any files of specified filter types in
1265 current directory, use it */
1266 if ( win98plus && handledPath == FALSE &&
1267 fodInfos->filter && *fodInfos->filter) {
1269 BOOL searchMore = TRUE;
1270 LPCWSTR lpstrPos = fodInfos->filter;
1271 WIN32_FIND_DATAW FindFileData;
1272 HANDLE hFind;
1274 while (searchMore)
1276 /* filter is a list... title\0ext\0......\0\0 */
1278 /* Skip the title */
1279 if(! *lpstrPos) break; /* end */
1280 lpstrPos += strlenW(lpstrPos) + 1;
1282 /* See if any files exist in the current dir with this extension */
1283 if(! *lpstrPos) break; /* end */
1285 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1287 if (hFind == INVALID_HANDLE_VALUE) {
1288 /* None found - continue search */
1289 lpstrPos += strlenW(lpstrPos) + 1;
1291 } else {
1292 searchMore = FALSE;
1294 if(fodInfos->initdir)
1295 MemFree(fodInfos->initdir);
1296 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1297 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1299 handledPath = TRUE;
1300 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1301 debugstr_w(lpstrPos));
1302 break;
1307 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1309 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1310 if (handledPath == FALSE && (win2000plus || win98plus)) {
1311 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1313 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1315 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1317 /* last fallback */
1318 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1319 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1320 } else {
1321 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1323 } else {
1324 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1326 handledPath = TRUE;
1327 } else if (handledPath==FALSE) {
1328 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1329 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1330 handledPath = TRUE;
1331 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1334 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1335 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1337 /* Must the open as read only check box be checked ?*/
1338 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1340 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1343 /* Must the open as read only check box be hidden? */
1344 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1346 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1347 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1350 /* Must the help button be hidden? */
1351 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1353 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1354 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1357 /* Resize the height, if open as read only checkbox ad help button
1358 are hidden and we are not using a custom template nor a customDialog
1360 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1361 (!(fodInfos->ofnInfos->Flags &
1362 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1363 (!fodInfos->DlgInfos.hwndCustomDlg ))
1365 RECT rectDlg, rectHelp, rectCancel;
1366 GetWindowRect(hwnd, &rectDlg);
1367 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1368 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1369 /* subtract the height of the help button plus the space between
1370 the help button and the cancel button to the height of the dialog */
1371 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1372 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1373 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1375 /* change Open to Save FIXME: use resources */
1376 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1378 SetDlgItemTextA(hwnd,IDOK,"&Save");
1379 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1381 return 0;
1384 /***********************************************************************
1385 * FILEDLG95_FillControls
1387 * WM_INITDIALOG message handler (after hook notification)
1389 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1391 LPITEMIDLIST pidlItemId = NULL;
1393 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1395 TRACE("dir=%s file=%s\n",
1396 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1398 /* Get the initial directory pidl */
1400 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1402 WCHAR path[MAX_PATH];
1404 GetCurrentDirectoryW(MAX_PATH,path);
1405 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1408 /* Initialise shell objects */
1409 FILEDLG95_SHELL_Init(hwnd);
1411 /* Initialize the Look In combo box */
1412 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1414 /* Initialize the filter combo box */
1415 FILEDLG95_FILETYPE_Init(hwnd);
1417 /* Browse to the initial directory */
1418 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1420 /* Free pidlItem memory */
1421 COMDLG32_SHFree(pidlItemId);
1423 return TRUE;
1425 /***********************************************************************
1426 * FILEDLG95_Clean
1428 * Regroups all the cleaning functions of the filedlg
1430 void FILEDLG95_Clean(HWND hwnd)
1432 FILEDLG95_FILETYPE_Clean(hwnd);
1433 FILEDLG95_LOOKIN_Clean(hwnd);
1434 FILEDLG95_SHELL_Clean(hwnd);
1436 /***********************************************************************
1437 * FILEDLG95_OnWMCommand
1439 * WM_COMMAND message handler
1441 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1443 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1444 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1445 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1447 switch(wID)
1449 /* OK button */
1450 case IDOK:
1451 FILEDLG95_OnOpen(hwnd);
1452 break;
1453 /* Cancel button */
1454 case IDCANCEL:
1455 FILEDLG95_Clean(hwnd);
1456 EndDialog(hwnd, FALSE);
1457 break;
1458 /* Filetype combo box */
1459 case IDC_FILETYPE:
1460 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1461 break;
1462 /* LookIn combo box */
1463 case IDC_LOOKIN:
1464 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1465 break;
1467 /* --- toolbar --- */
1468 /* Up folder button */
1469 case FCIDM_TB_UPFOLDER:
1470 FILEDLG95_SHELL_UpFolder(hwnd);
1471 break;
1472 /* New folder button */
1473 case FCIDM_TB_NEWFOLDER:
1474 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1475 break;
1476 /* List option button */
1477 case FCIDM_TB_SMALLICON:
1478 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1479 break;
1480 /* Details option button */
1481 case FCIDM_TB_REPORTVIEW:
1482 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1483 break;
1484 /* Details option button */
1485 case FCIDM_TB_DESKTOP:
1486 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1487 break;
1489 case IDC_FILENAME:
1490 break;
1493 /* Do not use the listview selection anymore */
1494 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1495 return 0;
1498 /***********************************************************************
1499 * FILEDLG95_OnWMGetIShellBrowser
1501 * WM_GETISHELLBROWSER message handler
1503 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1506 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1508 TRACE("\n");
1510 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1512 return TRUE;
1516 /***********************************************************************
1517 * FILEDLG95_SendFileOK
1519 * Sends the CDN_FILEOK notification if required
1521 * RETURNS
1522 * TRUE if the dialog should close
1523 * FALSE if the dialog should not be closed
1525 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1527 /* ask the hook if we can close */
1528 if(IsHooked(fodInfos))
1530 TRACE("---\n");
1531 /* First send CDN_FILEOK as MSDN doc says */
1532 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1533 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1535 TRACE("canceled\n");
1536 return FALSE;
1539 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1540 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1541 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1542 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1544 TRACE("canceled\n");
1545 return FALSE;
1548 return TRUE;
1551 /***********************************************************************
1552 * FILEDLG95_OnOpenMultipleFiles
1554 * Handles the opening of multiple files.
1556 * FIXME
1557 * check destination buffer size
1559 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1561 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1562 UINT nCount, nSizePath;
1563 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1565 TRACE("\n");
1567 if(fodInfos->unicode)
1569 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1570 ofn->lpstrFile[0] = '\0';
1572 else
1574 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1575 ofn->lpstrFile[0] = '\0';
1578 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1580 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1581 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1582 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1584 LPWSTR lpstrTemp = lpstrFileList;
1586 for ( nCount = 0; nCount < nFileCount; nCount++ )
1588 LPITEMIDLIST pidl;
1590 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1591 if (!pidl)
1593 WCHAR lpstrNotFound[100];
1594 WCHAR lpstrMsg[100];
1595 WCHAR tmp[400];
1596 static const WCHAR nl[] = {'\n',0};
1598 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1599 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1601 strcpyW(tmp, lpstrTemp);
1602 strcatW(tmp, nl);
1603 strcatW(tmp, lpstrNotFound);
1604 strcatW(tmp, nl);
1605 strcatW(tmp, lpstrMsg);
1607 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1608 return FALSE;
1611 /* move to the next file in the list of files */
1612 lpstrTemp += strlenW(lpstrTemp) + 1;
1613 COMDLG32_SHFree(pidl);
1617 nSizePath = strlenW(lpstrPathSpec) + 1;
1618 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1620 /* For "oldstyle" dialog the components have to
1621 be separated by blanks (not '\0'!) and short
1622 filenames have to be used! */
1623 FIXME("Components have to be separated by blanks\n");
1625 if(fodInfos->unicode)
1627 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1628 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1629 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1631 else
1633 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1635 if (ofn->lpstrFile != NULL)
1637 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1638 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1639 if (ofn->nMaxFile > nSizePath)
1641 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1642 ofn->lpstrFile + nSizePath,
1643 ofn->nMaxFile - nSizePath, NULL, NULL);
1648 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1649 fodInfos->ofnInfos->nFileExtension = 0;
1651 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1652 return FALSE;
1654 /* clean and exit */
1655 FILEDLG95_Clean(hwnd);
1656 return EndDialog(hwnd,TRUE);
1659 /***********************************************************************
1660 * FILEDLG95_OnOpen
1662 * Ok button WM_COMMAND message handler
1664 * If the function succeeds, the return value is nonzero.
1666 #define ONOPEN_BROWSE 1
1667 #define ONOPEN_OPEN 2
1668 #define ONOPEN_SEARCH 3
1669 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1671 char strMsgTitle[MAX_PATH];
1672 char strMsgText [MAX_PATH];
1673 if (idCaption)
1674 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1675 else
1676 strMsgTitle[0] = '\0';
1677 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1678 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1681 BOOL FILEDLG95_OnOpen(HWND hwnd)
1683 LPWSTR lpstrFileList;
1684 UINT nFileCount = 0;
1685 UINT sizeUsed = 0;
1686 BOOL ret = TRUE;
1687 WCHAR lpstrPathAndFile[MAX_PATH];
1688 WCHAR lpstrTemp[MAX_PATH];
1689 LPSHELLFOLDER lpsf = NULL;
1690 int nOpenAction;
1691 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1693 TRACE("hwnd=%p\n", hwnd);
1695 /* get the files from the edit control */
1696 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1698 /* try if the user selected a folder in the shellview */
1699 if(nFileCount == 0)
1701 BrowseSelectedFolder(hwnd);
1702 return FALSE;
1705 if(nFileCount > 1)
1707 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1708 goto ret;
1711 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1714 Step 1: Build a complete path name from the current folder and
1715 the filename or path in the edit box.
1716 Special cases:
1717 - the path in the edit box is a root path
1718 (with or without drive letter)
1719 - the edit box contains ".." (or a path with ".." in it)
1722 /* Get the current directory name */
1723 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1725 /* we are in a special folder, default to desktop */
1726 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1728 /* last fallback */
1729 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1732 PathAddBackslashW(lpstrPathAndFile);
1734 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1736 /* if the user specifyed a fully qualified path use it */
1737 if(PathIsRelativeW(lpstrFileList))
1739 strcatW(lpstrPathAndFile, lpstrFileList);
1741 else
1743 /* does the path have a drive letter? */
1744 if (PathGetDriveNumberW(lpstrFileList) == -1)
1745 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1746 else
1747 strcpyW(lpstrPathAndFile, lpstrFileList);
1750 /* resolve "." and ".." */
1751 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1752 strcpyW(lpstrPathAndFile, lpstrTemp);
1753 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1755 MemFree(lpstrFileList);
1758 Step 2: here we have a cleaned up path
1760 We have to parse the path step by step to see if we have to browse
1761 to a folder if the path points to a directory or the last
1762 valid element is a directory.
1764 valid variables:
1765 lpstrPathAndFile: cleaned up path
1768 nOpenAction = ONOPEN_BROWSE;
1770 /* don't apply any checks with OFN_NOVALIDATE */
1772 LPWSTR lpszTemp, lpszTemp1;
1773 LPITEMIDLIST pidl = NULL;
1774 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1776 /* check for invalid chars */
1777 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1779 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1780 ret = FALSE;
1781 goto ret;
1784 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1786 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1787 while (lpszTemp1)
1789 LPSHELLFOLDER lpsfChild;
1790 WCHAR lpwstrTemp[MAX_PATH];
1791 DWORD dwEaten, dwAttributes;
1792 LPWSTR p;
1794 strcpyW(lpwstrTemp, lpszTemp);
1795 p = PathFindNextComponentW(lpwstrTemp);
1797 if (!p) break; /* end of path */
1799 *p = 0;
1800 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1802 if(*lpszTemp==0)
1804 static const WCHAR wszWild[] = { '*', '?', 0 };
1805 /* if the last element is a wildcard do a search */
1806 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1808 nOpenAction = ONOPEN_SEARCH;
1809 break;
1812 lpszTemp1 = lpszTemp;
1814 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1816 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1818 dwAttributes = SFGAO_FOLDER;
1819 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1821 /* the path component is valid, we have a pidl of the next path component */
1822 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1823 if(dwAttributes & SFGAO_FOLDER)
1825 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1827 ERR("bind to failed\n"); /* should not fail */
1828 break;
1830 IShellFolder_Release(lpsf);
1831 lpsf = lpsfChild;
1832 lpsfChild = NULL;
1834 else
1836 TRACE("value\n");
1838 /* end dialog, return value */
1839 nOpenAction = ONOPEN_OPEN;
1840 break;
1842 COMDLG32_SHFree(pidl);
1843 pidl = NULL;
1845 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1847 if(*lpszTemp) /* points to trailing null for last path element */
1849 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1851 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1852 break;
1855 else
1857 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1858 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1860 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1861 break;
1864 /* change to the current folder */
1865 nOpenAction = ONOPEN_OPEN;
1866 break;
1868 else
1870 nOpenAction = ONOPEN_OPEN;
1871 break;
1874 if(pidl) COMDLG32_SHFree(pidl);
1878 Step 3: here we have a cleaned up and validated path
1880 valid variables:
1881 lpsf: ShellFolder bound to the rightmost valid path component
1882 lpstrPathAndFile: cleaned up path
1883 nOpenAction: action to do
1885 TRACE("end validate sf=%p\n", lpsf);
1887 switch(nOpenAction)
1889 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1890 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1892 int iPos;
1893 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1894 DWORD len;
1896 /* replace the current filter */
1897 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1898 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1899 len = strlenW(lpszTemp)+1;
1900 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1901 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1903 /* set the filter cb to the extension when possible */
1904 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1905 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1907 /* fall through */
1908 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1909 TRACE("ONOPEN_BROWSE\n");
1911 IPersistFolder2 * ppf2;
1912 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1914 LPITEMIDLIST pidlCurrent;
1915 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1916 IPersistFolder2_Release(ppf2);
1917 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1919 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1921 else if( nOpenAction == ONOPEN_SEARCH )
1923 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1925 COMDLG32_SHFree(pidlCurrent);
1928 ret = FALSE;
1929 break;
1930 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1931 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1933 WCHAR *ext = NULL;
1935 /* update READONLY check box flag */
1936 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1937 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1938 else
1939 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1941 /* Attach the file extension with file name*/
1942 ext = PathFindExtensionW(lpstrPathAndFile);
1943 if (! *ext)
1945 /* if no extension is specified with file name, then */
1946 /* attach the extension from file filter or default one */
1948 WCHAR *filterExt = NULL;
1949 LPWSTR lpstrFilter = NULL;
1950 static const WCHAR szwDot[] = {'.',0};
1951 int PathLength = strlenW(lpstrPathAndFile);
1953 /* Attach the dot*/
1954 strcatW(lpstrPathAndFile, szwDot);
1956 /*Get the file extension from file type filter*/
1957 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1958 fodInfos->ofnInfos->nFilterIndex-1);
1960 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1961 filterExt = PathFindExtensionW(lpstrFilter);
1963 if ( *filterExt ) /* attach the file extension from file type filter*/
1964 strcatW(lpstrPathAndFile, filterExt + 1);
1965 else if ( fodInfos->defext ) /* attach the default file extension*/
1966 strcatW(lpstrPathAndFile, fodInfos->defext);
1968 /* In Open dialog: if file does not exist try without extension */
1969 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1970 lpstrPathAndFile[PathLength] = '\0';
1973 if (fodInfos->defext) /* add default extension */
1975 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1976 if (*ext)
1977 ext++;
1978 if (!lstrcmpiW(fodInfos->defext, ext))
1979 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1980 else
1981 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1984 /* In Save dialog: check if the file already exists */
1985 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1986 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1987 && PathFileExistsW(lpstrPathAndFile))
1989 WCHAR lpstrOverwrite[100];
1990 int answer;
1992 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1993 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1994 MB_YESNO | MB_ICONEXCLAMATION);
1995 if (answer == IDNO)
1997 ret = FALSE;
1998 goto ret;
2002 /* Check that the size of the file does not exceed buffer size.
2003 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2004 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2005 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2007 LPWSTR lpszTemp;
2009 /* fill destination buffer */
2010 if (fodInfos->ofnInfos->lpstrFile)
2012 if(fodInfos->unicode)
2014 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
2016 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2017 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2018 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2020 else
2022 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2024 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2025 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2026 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2027 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2031 /* set filename offset */
2032 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2033 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2035 /* set extension offset */
2036 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2037 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2039 /* set the lpstrFileTitle */
2040 if(fodInfos->ofnInfos->lpstrFileTitle)
2042 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2043 if(fodInfos->unicode)
2045 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
2046 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2048 else
2050 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2051 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2052 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2056 /* copy currently selected filter to lpstrCustomFilter */
2057 if (fodInfos->ofnInfos->lpstrCustomFilter)
2059 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2060 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2061 NULL, 0, NULL, NULL);
2062 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2064 LPSTR s = ofn->lpstrCustomFilter;
2065 s += strlen(ofn->lpstrCustomFilter)+1;
2066 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2067 s, len, NULL, NULL);
2072 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2073 goto ret;
2075 TRACE("close\n");
2076 FILEDLG95_Clean(hwnd);
2077 ret = EndDialog(hwnd, TRUE);
2079 else
2081 WORD size;
2083 size = strlenW(lpstrPathAndFile) + 1;
2084 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2085 size += 1;
2086 /* return needed size in first two bytes of lpstrFile */
2087 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2088 FILEDLG95_Clean(hwnd);
2089 ret = EndDialog(hwnd, FALSE);
2090 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2092 goto ret;
2094 break;
2097 ret:
2098 if(lpsf) IShellFolder_Release(lpsf);
2099 return ret;
2102 /***********************************************************************
2103 * FILEDLG95_SHELL_Init
2105 * Initialisation of the shell objects
2107 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2109 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2111 TRACE("\n");
2114 * Initialisation of the FileOpenDialogInfos structure
2117 /* Shell */
2119 /*ShellInfos */
2120 fodInfos->ShellInfos.hwndOwner = hwnd;
2122 /* Disable multi-select if flag not set */
2123 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2125 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2127 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2128 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2130 /* Construct the IShellBrowser interface */
2131 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2133 return NOERROR;
2136 /***********************************************************************
2137 * FILEDLG95_SHELL_ExecuteCommand
2139 * Change the folder option and refresh the view
2140 * If the function succeeds, the return value is nonzero.
2142 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2144 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2146 IContextMenu * pcm;
2147 TRACE("(%p,%p)\n", hwnd, lpVerb);
2149 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2150 SVGIO_BACKGROUND,
2151 &IID_IContextMenu,
2152 (LPVOID*)&pcm)))
2154 CMINVOKECOMMANDINFO ci;
2155 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2156 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2157 ci.lpVerb = lpVerb;
2158 ci.hwnd = hwnd;
2160 IContextMenu_InvokeCommand(pcm, &ci);
2161 IContextMenu_Release(pcm);
2164 return FALSE;
2167 /***********************************************************************
2168 * FILEDLG95_SHELL_UpFolder
2170 * Browse to the specified object
2171 * If the function succeeds, the return value is nonzero.
2173 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2175 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2177 TRACE("\n");
2179 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2180 NULL,
2181 SBSP_PARENT)))
2183 return TRUE;
2185 return FALSE;
2188 /***********************************************************************
2189 * FILEDLG95_SHELL_BrowseToDesktop
2191 * Browse to the Desktop
2192 * If the function succeeds, the return value is nonzero.
2194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2196 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2197 LPITEMIDLIST pidl;
2198 HRESULT hres;
2200 TRACE("\n");
2202 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2203 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2204 COMDLG32_SHFree(pidl);
2205 return SUCCEEDED(hres);
2207 /***********************************************************************
2208 * FILEDLG95_SHELL_Clean
2210 * Cleans the memory used by shell objects
2212 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2214 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2216 TRACE("\n");
2218 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2220 /* clean Shell interfaces */
2221 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2222 IShellView_Release(fodInfos->Shell.FOIShellView);
2223 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2224 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2225 if (fodInfos->Shell.FOIDataObject)
2226 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2229 /***********************************************************************
2230 * FILEDLG95_FILETYPE_Init
2232 * Initialisation of the file type combo box
2234 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2236 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2237 int nFilters = 0; /* number of filters */
2238 int nFilterIndexCB;
2240 TRACE("\n");
2242 if(fodInfos->customfilter)
2244 /* customfilter has one entry... title\0ext\0
2245 * Set first entry of combo box item with customfilter
2247 LPWSTR lpstrExt;
2248 LPCWSTR lpstrPos = fodInfos->customfilter;
2250 /* Get the title */
2251 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2253 /* Copy the extensions */
2254 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2255 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2256 strcpyW(lpstrExt,lpstrPos);
2258 /* Add the item at the end of the combo */
2259 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2260 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2261 nFilters++;
2263 if(fodInfos->filter)
2265 LPCWSTR lpstrPos = fodInfos->filter;
2267 for(;;)
2269 /* filter is a list... title\0ext\0......\0\0
2270 * Set the combo item text to the title and the item data
2271 * to the ext
2273 LPCWSTR lpstrDisplay;
2274 LPWSTR lpstrExt;
2276 /* Get the title */
2277 if(! *lpstrPos) break; /* end */
2278 lpstrDisplay = lpstrPos;
2279 lpstrPos += strlenW(lpstrPos) + 1;
2281 /* Copy the extensions */
2282 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2283 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2284 strcpyW(lpstrExt,lpstrPos);
2285 lpstrPos += strlenW(lpstrPos) + 1;
2287 /* Add the item at the end of the combo */
2288 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2289 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2290 nFilters++;
2295 * Set the current filter to the one specified
2296 * in the initialisation structure
2298 if (fodInfos->filter || fodInfos->customfilter)
2300 LPWSTR lpstrFilter;
2302 /* Check to make sure our index isn't out of bounds. */
2303 if ( fodInfos->ofnInfos->nFilterIndex >
2304 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2305 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2307 /* set default filter index */
2308 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2309 fodInfos->ofnInfos->nFilterIndex = 1;
2311 /* calculate index of Combo Box item */
2312 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2313 if (fodInfos->customfilter == NULL)
2314 nFilterIndexCB--;
2316 /* Set the current index selection. */
2317 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2319 /* Get the corresponding text string from the combo box. */
2320 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2321 nFilterIndexCB);
2323 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2324 lpstrFilter = NULL;
2326 if(lpstrFilter)
2328 DWORD len;
2329 CharLowerW(lpstrFilter); /* lowercase */
2330 len = strlenW(lpstrFilter)+1;
2331 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2332 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2334 } else
2335 fodInfos->ofnInfos->nFilterIndex = 0;
2337 return NOERROR;
2340 /***********************************************************************
2341 * FILEDLG95_FILETYPE_OnCommand
2343 * WM_COMMAND of the file type combo box
2344 * If the function succeeds, the return value is nonzero.
2346 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2348 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2350 switch(wNotifyCode)
2352 case CBN_SELENDOK:
2354 LPWSTR lpstrFilter;
2356 /* Get the current item of the filetype combo box */
2357 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2359 /* set the current filter index */
2360 fodInfos->ofnInfos->nFilterIndex = iItem +
2361 (fodInfos->customfilter == NULL ? 1 : 0);
2363 /* Set the current filter with the current selection */
2364 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2365 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2367 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2368 iItem);
2369 if((int)lpstrFilter != CB_ERR)
2371 DWORD len;
2372 CharLowerW(lpstrFilter); /* lowercase */
2373 len = strlenW(lpstrFilter)+1;
2374 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2375 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2376 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2379 /* Refresh the actual view to display the included items*/
2380 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2383 return FALSE;
2385 /***********************************************************************
2386 * FILEDLG95_FILETYPE_SearchExt
2388 * searches for a extension in the filetype box
2390 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2392 int i, iCount = CBGetCount(hwnd);
2394 TRACE("%s\n", debugstr_w(lpstrExt));
2396 if(iCount != CB_ERR)
2398 for(i=0;i<iCount;i++)
2400 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2401 return i;
2404 return -1;
2407 /***********************************************************************
2408 * FILEDLG95_FILETYPE_Clean
2410 * Clean the memory used by the filetype combo box
2412 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2414 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2415 int iPos;
2416 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2418 TRACE("\n");
2420 /* Delete each string of the combo and their associated data */
2421 if(iCount != CB_ERR)
2423 for(iPos = iCount-1;iPos>=0;iPos--)
2425 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2426 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2429 /* Current filter */
2430 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2431 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2435 /***********************************************************************
2436 * FILEDLG95_LOOKIN_Init
2438 * Initialisation of the look in combo box
2440 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2442 IShellFolder *psfRoot, *psfDrives;
2443 IEnumIDList *lpeRoot, *lpeDrives;
2444 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2446 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2448 TRACE("\n");
2450 liInfos->iMaxIndentation = 0;
2452 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2454 /* set item height for both text field and listbox */
2455 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2456 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2458 /* Turn on the extended UI for the combo box like Windows does */
2459 CBSetExtendedUI(hwndCombo, TRUE);
2461 /* Initialise data of Desktop folder */
2462 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2463 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2464 COMDLG32_SHFree(pidlTmp);
2466 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2468 SHGetDesktopFolder(&psfRoot);
2470 if (psfRoot)
2472 /* enumerate the contents of the desktop */
2473 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2475 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2477 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2479 /* special handling for CSIDL_DRIVES */
2480 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2482 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2484 /* enumerate the drives */
2485 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2487 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2489 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2490 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2491 COMDLG32_SHFree(pidlAbsTmp);
2492 COMDLG32_SHFree(pidlTmp1);
2494 IEnumIDList_Release(lpeDrives);
2496 IShellFolder_Release(psfDrives);
2499 COMDLG32_SHFree(pidlTmp);
2501 IEnumIDList_Release(lpeRoot);
2503 IShellFolder_Release(psfRoot);
2506 COMDLG32_SHFree(pidlDrives);
2507 return NOERROR;
2510 /***********************************************************************
2511 * FILEDLG95_LOOKIN_DrawItem
2513 * WM_DRAWITEM message handler
2515 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2517 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2518 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2519 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2520 RECT rectText;
2521 RECT rectIcon;
2522 SHFILEINFOA sfi;
2523 HIMAGELIST ilItemImage;
2524 int iIndentation;
2525 TEXTMETRICA tm;
2526 LPSFOLDER tmpFolder;
2529 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2531 TRACE("\n");
2533 if(pDIStruct->itemID == -1)
2534 return 0;
2536 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2537 pDIStruct->itemID)))
2538 return 0;
2541 if(pDIStruct->itemID == liInfos->uSelectedItem)
2543 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2545 &sfi,
2546 sizeof (SHFILEINFOA),
2547 SHGFI_PIDL | SHGFI_SMALLICON |
2548 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2549 SHGFI_DISPLAYNAME );
2551 else
2553 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2555 &sfi,
2556 sizeof (SHFILEINFOA),
2557 SHGFI_PIDL | SHGFI_SMALLICON |
2558 SHGFI_SYSICONINDEX |
2559 SHGFI_DISPLAYNAME);
2562 /* Is this item selected ? */
2563 if(pDIStruct->itemState & ODS_SELECTED)
2565 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2566 SetBkColor(pDIStruct->hDC,crHighLight);
2567 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2569 else
2571 SetTextColor(pDIStruct->hDC,crText);
2572 SetBkColor(pDIStruct->hDC,crWin);
2573 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2576 /* Do not indent item if drawing in the edit of the combo */
2577 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2579 iIndentation = 0;
2580 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2582 &sfi,
2583 sizeof (SHFILEINFOA),
2584 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2585 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2588 else
2590 iIndentation = tmpFolder->m_iIndent;
2592 /* Draw text and icon */
2594 /* Initialise the icon display area */
2595 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2596 rectIcon.top = pDIStruct->rcItem.top;
2597 rectIcon.right = rectIcon.left + ICONWIDTH;
2598 rectIcon.bottom = pDIStruct->rcItem.bottom;
2600 /* Initialise the text display area */
2601 GetTextMetricsA(pDIStruct->hDC, &tm);
2602 rectText.left = rectIcon.right;
2603 rectText.top =
2604 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2605 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2606 rectText.bottom =
2607 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2609 /* Draw the icon from the image list */
2610 ImageList_Draw(ilItemImage,
2611 sfi.iIcon,
2612 pDIStruct->hDC,
2613 rectIcon.left,
2614 rectIcon.top,
2615 ILD_TRANSPARENT );
2617 /* Draw the associated text */
2618 if(sfi.szDisplayName)
2619 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2622 return NOERROR;
2625 /***********************************************************************
2626 * FILEDLG95_LOOKIN_OnCommand
2628 * LookIn combo box WM_COMMAND message handler
2629 * If the function succeeds, the return value is nonzero.
2631 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2633 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2635 TRACE("%p\n", fodInfos);
2637 switch(wNotifyCode)
2639 case CBN_SELENDOK:
2641 LPSFOLDER tmpFolder;
2642 int iItem;
2644 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2646 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2647 iItem)))
2648 return FALSE;
2651 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2652 tmpFolder->pidlItem,
2653 SBSP_ABSOLUTE)))
2655 return TRUE;
2657 break;
2661 return FALSE;
2664 /***********************************************************************
2665 * FILEDLG95_LOOKIN_AddItem
2667 * Adds an absolute pidl item to the lookin combo box
2668 * returns the index of the inserted item
2670 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2672 LPITEMIDLIST pidlNext;
2673 SHFILEINFOA sfi;
2674 SFOLDER *tmpFolder;
2675 LookInInfos *liInfos;
2677 TRACE("%08x\n", iInsertId);
2679 if(!pidl)
2680 return -1;
2682 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2683 return -1;
2685 tmpFolder = MemAlloc(sizeof(SFOLDER));
2686 tmpFolder->m_iIndent = 0;
2688 /* Calculate the indentation of the item in the lookin*/
2689 pidlNext = pidl;
2690 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2692 tmpFolder->m_iIndent++;
2695 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2697 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2698 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2700 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2701 SHGetFileInfoA((LPSTR)pidl,
2703 &sfi,
2704 sizeof(sfi),
2705 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2706 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2708 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2710 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2712 int iItemID;
2714 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2716 /* Add the item at the end of the list */
2717 if(iInsertId < 0)
2719 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2721 /* Insert the item at the iInsertId position*/
2722 else
2724 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2727 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2728 return iItemID;
2731 COMDLG32_SHFree( tmpFolder->pidlItem );
2732 MemFree( tmpFolder );
2733 return -1;
2737 /***********************************************************************
2738 * FILEDLG95_LOOKIN_InsertItemAfterParent
2740 * Insert an item below its parent
2742 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2745 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2746 int iParentPos;
2748 TRACE("\n");
2750 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2752 if(iParentPos < 0)
2754 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2757 /* Free pidlParent memory */
2758 COMDLG32_SHFree((LPVOID)pidlParent);
2760 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2763 /***********************************************************************
2764 * FILEDLG95_LOOKIN_SelectItem
2766 * Adds an absolute pidl item to the lookin combo box
2767 * returns the index of the inserted item
2769 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2771 int iItemPos;
2772 LookInInfos *liInfos;
2774 TRACE("\n");
2776 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2778 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2780 if(iItemPos < 0)
2782 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2783 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2786 else
2788 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2789 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2791 int iRemovedItem;
2793 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2794 break;
2795 if(iRemovedItem < iItemPos)
2796 iItemPos--;
2800 CBSetCurSel(hwnd,iItemPos);
2801 liInfos->uSelectedItem = iItemPos;
2803 return 0;
2807 /***********************************************************************
2808 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2810 * Remove the item with an expansion level over iExpansionLevel
2812 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2814 int iItemPos;
2816 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2818 TRACE("\n");
2820 if(liInfos->iMaxIndentation <= 2)
2821 return -1;
2823 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2825 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2826 COMDLG32_SHFree(tmpFolder->pidlItem);
2827 MemFree(tmpFolder);
2828 CBDeleteString(hwnd,iItemPos);
2829 liInfos->iMaxIndentation--;
2831 return iItemPos;
2834 return -1;
2837 /***********************************************************************
2838 * FILEDLG95_LOOKIN_SearchItem
2840 * Search for pidl in the lookin combo box
2841 * returns the index of the found item
2843 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2845 int i = 0;
2846 int iCount = CBGetCount(hwnd);
2848 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2850 if (iCount != CB_ERR)
2852 for(;i<iCount;i++)
2854 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2856 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2857 return i;
2858 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2859 return i;
2863 return -1;
2866 /***********************************************************************
2867 * FILEDLG95_LOOKIN_Clean
2869 * Clean the memory used by the lookin combo box
2871 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2873 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2874 int iPos;
2875 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2877 TRACE("\n");
2879 /* Delete each string of the combo and their associated data */
2880 if (iCount != CB_ERR)
2882 for(iPos = iCount-1;iPos>=0;iPos--)
2884 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2885 COMDLG32_SHFree(tmpFolder->pidlItem);
2886 MemFree(tmpFolder);
2887 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2891 /* LookInInfos structure */
2892 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2895 /***********************************************************************
2896 * FILEDLG95_FILENAME_FillFromSelection
2898 * fills the edit box from the cached DataObject
2900 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2902 FileOpenDlgInfos *fodInfos;
2903 LPITEMIDLIST pidl;
2904 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2905 char lpstrTemp[MAX_PATH];
2906 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2908 TRACE("\n");
2909 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2911 /* Count how many files we have */
2912 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2914 /* calculate the string length, count files */
2915 if (nFileSelected >= 1)
2917 nLength += 3; /* first and last quotes, trailing \0 */
2918 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2920 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2922 if (pidl)
2924 /* get the total length of the selected file names */
2925 lpstrTemp[0] = '\0';
2926 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2928 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2930 nLength += strlen( lpstrTemp ) + 3;
2931 nFiles++;
2933 COMDLG32_SHFree( pidl );
2938 /* allocate the buffer */
2939 if (nFiles <= 1) nLength = MAX_PATH;
2940 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2941 lpstrAllFile[0] = '\0';
2943 /* Generate the string for the edit control */
2944 if(nFiles >= 1)
2946 lpstrCurrFile = lpstrAllFile;
2947 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2949 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2951 if (pidl)
2953 /* get the file name */
2954 lpstrTemp[0] = '\0';
2955 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2957 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2959 if ( nFiles > 1)
2961 *lpstrCurrFile++ = '\"';
2962 strcpy( lpstrCurrFile, lpstrTemp );
2963 lpstrCurrFile += strlen( lpstrTemp );
2964 strcpy( lpstrCurrFile, "\" " );
2965 lpstrCurrFile += 2;
2967 else
2969 strcpy( lpstrAllFile, lpstrTemp );
2972 COMDLG32_SHFree( (LPVOID) pidl );
2975 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2977 /* Select the file name like Windows does */
2978 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2980 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2984 /* copied from shell32 to avoid linking to it */
2985 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2987 switch (src->uType)
2989 case STRRET_WSTR:
2990 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2991 COMDLG32_SHFree(src->u.pOleStr);
2992 break;
2994 case STRRET_CSTR:
2995 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2996 break;
2998 case STRRET_OFFSET:
2999 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3000 break;
3002 default:
3003 FIXME("unknown type!\n");
3004 if (len)
3006 *(LPSTR)dest = '\0';
3008 return(FALSE);
3010 return S_OK;
3013 /***********************************************************************
3014 * FILEDLG95_FILENAME_GetFileNames
3016 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
3018 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3020 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3021 UINT nStrCharCount = 0; /* index in src buffer */
3022 UINT nFileIndex = 0; /* index in dest buffer */
3023 UINT nFileCount = 0; /* number of files */
3024 UINT nStrLen = 0; /* length of string in edit control */
3025 LPWSTR lpstrEdit; /* buffer for string from edit control */
3027 TRACE("\n");
3029 /* get the filenames from the edit control */
3030 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3031 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3032 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3034 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3036 /* we might get single filename without any '"',
3037 * so we need nStrLen + terminating \0 + end-of-list \0 */
3038 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3039 *sizeUsed = 0;
3041 /* build 0-delimited file list from filenames */
3042 while ( nStrCharCount <= nStrLen )
3044 if ( lpstrEdit[nStrCharCount]=='"' )
3046 nStrCharCount++;
3047 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3049 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3050 (*sizeUsed)++;
3051 nStrCharCount++;
3053 (*lpstrFileList)[nFileIndex++] = '\0';
3054 (*sizeUsed)++;
3055 nFileCount++;
3057 nStrCharCount++;
3060 /* single, unquoted string */
3061 if ((nStrLen > 0) && (*sizeUsed == 0) )
3063 strcpyW(*lpstrFileList, lpstrEdit);
3064 nFileIndex = strlenW(lpstrEdit) + 1;
3065 (*sizeUsed) = nFileIndex;
3066 nFileCount = 1;
3069 /* trailing \0 */
3070 (*lpstrFileList)[nFileIndex] = '\0';
3071 (*sizeUsed)++;
3073 MemFree(lpstrEdit);
3074 return nFileCount;
3077 #define SETDefFormatEtc(fe,cf,med) \
3079 (fe).cfFormat = cf;\
3080 (fe).dwAspect = DVASPECT_CONTENT; \
3081 (fe).ptd =NULL;\
3082 (fe).tymed = med;\
3083 (fe).lindex = -1;\
3087 * DATAOBJECT Helper functions
3090 /***********************************************************************
3091 * COMCTL32_ReleaseStgMedium
3093 * like ReleaseStgMedium from ole32
3095 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3097 if(medium.pUnkForRelease)
3099 IUnknown_Release(medium.pUnkForRelease);
3101 else
3103 GlobalUnlock(medium.u.hGlobal);
3104 GlobalFree(medium.u.hGlobal);
3108 /***********************************************************************
3109 * GetPidlFromDataObject
3111 * Return pidl(s) by number from the cached DataObject
3113 * nPidlIndex=0 gets the fully qualified root path
3115 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3118 STGMEDIUM medium;
3119 FORMATETC formatetc;
3120 LPITEMIDLIST pidl = NULL;
3122 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3124 /* Set the FORMATETC structure*/
3125 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3127 /* Get the pidls from IDataObject */
3128 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3130 LPIDA cida = GlobalLock(medium.u.hGlobal);
3131 if(nPidlIndex <= cida->cidl)
3133 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3135 COMCTL32_ReleaseStgMedium(medium);
3137 return pidl;
3140 /***********************************************************************
3141 * GetNumSelected
3143 * Return the number of selected items in the DataObject.
3146 UINT GetNumSelected( IDataObject *doSelected )
3148 UINT retVal = 0;
3149 STGMEDIUM medium;
3150 FORMATETC formatetc;
3152 TRACE("sv=%p\n", doSelected);
3154 if (!doSelected) return 0;
3156 /* Set the FORMATETC structure*/
3157 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3159 /* Get the pidls from IDataObject */
3160 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3162 LPIDA cida = GlobalLock(medium.u.hGlobal);
3163 retVal = cida->cidl;
3164 COMCTL32_ReleaseStgMedium(medium);
3165 return retVal;
3167 return 0;
3171 * TOOLS
3174 /***********************************************************************
3175 * GetName
3177 * Get the pidl's display name (relative to folder) and
3178 * put it in lpstrFileName.
3180 * Return NOERROR on success,
3181 * E_FAIL otherwise
3184 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3186 STRRET str;
3187 HRESULT hRes;
3189 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3191 if(!lpsf)
3193 HRESULT hRes;
3194 SHGetDesktopFolder(&lpsf);
3195 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3196 IShellFolder_Release(lpsf);
3197 return hRes;
3200 /* Get the display name of the pidl relative to the folder */
3201 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3203 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3205 return E_FAIL;
3208 /***********************************************************************
3209 * GetShellFolderFromPidl
3211 * pidlRel is the item pidl relative
3212 * Return the IShellFolder of the absolute pidl
3214 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3216 IShellFolder *psf = NULL,*psfParent;
3218 TRACE("%p\n", pidlAbs);
3220 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3222 psf = psfParent;
3223 if(pidlAbs && pidlAbs->mkid.cb)
3225 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3227 IShellFolder_Release(psfParent);
3228 return psf;
3231 /* return the desktop */
3232 return psfParent;
3234 return NULL;
3237 /***********************************************************************
3238 * GetParentPidl
3240 * Return the LPITEMIDLIST to the parent of the pidl in the list
3242 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3244 LPITEMIDLIST pidlParent;
3246 TRACE("%p\n", pidl);
3248 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3249 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3251 return pidlParent;
3254 /***********************************************************************
3255 * GetPidlFromName
3257 * returns the pidl of the file name relative to folder
3258 * NULL if an error occurred
3260 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3262 LPITEMIDLIST pidl = NULL;
3263 ULONG ulEaten;
3265 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3267 if(!lpcstrFileName) return NULL;
3268 if(!*lpcstrFileName) return NULL;
3270 if(!lpsf)
3272 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3273 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3274 IShellFolder_Release(lpsf);
3277 else
3279 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3281 return pidl;
3286 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3288 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3289 HRESULT ret;
3291 TRACE("%p, %p\n", psf, pidl);
3293 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3295 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3296 /* see documentation shell 4.1*/
3297 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3300 /***********************************************************************
3301 * BrowseSelectedFolder
3303 static BOOL BrowseSelectedFolder(HWND hwnd)
3305 BOOL bBrowseSelFolder = FALSE;
3306 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3308 TRACE("\n");
3310 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3312 LPITEMIDLIST pidlSelection;
3314 /* get the file selected */
3315 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3316 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3318 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3319 pidlSelection, SBSP_RELATIVE ) ) )
3321 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3322 ' ','n','o','t',' ','e','x','i','s','t',0};
3323 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3326 bBrowseSelFolder = TRUE;
3328 COMDLG32_SHFree( pidlSelection );
3331 return bBrowseSelFolder;
3335 * Memory allocation methods */
3336 static void *MemAlloc(UINT size)
3338 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3341 static void MemFree(void *mem)
3343 if(mem)
3345 HeapFree(GetProcessHeap(),0,mem);
3350 * Old-style (win3.1) dialogs */
3352 /***********************************************************************
3353 * FD32_GetTemplate [internal]
3355 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3356 * by a 32 bits application
3359 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3361 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3362 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3363 HANDLE hDlgTmpl;
3365 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3367 if (!(lfs->template = LockResource( ofnW->hInstance )))
3369 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3370 return FALSE;
3373 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3375 HRSRC hResInfo;
3376 if (priv->ofnA)
3377 hResInfo = FindResourceA(priv->ofnA->hInstance,
3378 priv->ofnA->lpTemplateName,
3379 (LPSTR)RT_DIALOG);
3380 else
3381 hResInfo = FindResourceW(ofnW->hInstance,
3382 ofnW->lpTemplateName,
3383 (LPWSTR)RT_DIALOG);
3384 if (!hResInfo)
3386 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3387 return FALSE;
3389 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3390 hResInfo)) ||
3391 !(lfs->template = LockResource(hDlgTmpl)))
3393 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3394 return FALSE;
3396 } else { /* get it from internal Wine resource */
3397 HRSRC hResInfo;
3398 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3399 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3401 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3402 return FALSE;
3404 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3405 !(lfs->template = LockResource( hDlgTmpl )))
3407 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3408 return FALSE;
3411 return TRUE;
3415 /************************************************************************
3416 * FD32_Init [internal]
3417 * called from the common 16/32 code to initialize 32 bit data
3419 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3421 BOOL IsUnicode = (BOOL) data;
3422 PFD32_PRIVATE priv;
3424 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3425 lfs->private1632 = priv;
3426 if (NULL == lfs->private1632) return FALSE;
3427 if (IsUnicode)
3429 lfs->ofnW = *((LPOPENFILENAMEW) lParam);
3430 if (lfs->ofnW.Flags & OFN_ENABLEHOOK)
3431 if (lfs->ofnW.lpfnHook)
3432 lfs->hook = TRUE;
3434 else
3436 priv->ofnA = (LPOPENFILENAMEA) lParam;
3437 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3438 if (priv->ofnA->lpfnHook)
3439 lfs->hook = TRUE;
3440 FD31_MapOfnStructA(priv->ofnA, &lfs->ofnW, lfs->open);
3443 if (! FD32_GetTemplate(lfs)) return FALSE;
3445 return TRUE;
3448 /***********************************************************************
3449 * FD32_CallWindowProc [internal]
3451 * called from the common 16/32 code to call the appropriate hook
3453 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3454 LPARAM lParam)
3456 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3458 if (priv->ofnA)
3460 return (BOOL) CallWindowProcA(
3461 (WNDPROC)priv->ofnA->lpfnHook, lfs->hwnd,
3462 wMsg, wParam, lParam);
3465 return (BOOL) CallWindowProcW(
3466 (WNDPROC)lfs->ofnW.lpfnHook, lfs->hwnd,
3467 wMsg, wParam, lParam);
3470 /***********************************************************************
3471 * FD32_UpdateResult [internal]
3472 * update the real client structures if any
3474 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3476 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3477 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3479 if (priv->ofnA)
3481 if (ofnW->nMaxFile &&
3482 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3483 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3484 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3485 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3486 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3490 /***********************************************************************
3491 * FD32_UpdateFileTitle [internal]
3492 * update the real client structures if any
3494 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3496 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3497 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3499 if (priv->ofnA)
3501 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3502 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3503 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3508 /***********************************************************************
3509 * FD32_SendLbGetCurSel [internal]
3510 * retrieve selected listbox item
3512 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3514 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3518 /************************************************************************
3519 * FD32_Destroy [internal]
3520 * called from the common 16/32 code to cleanup 32 bit data
3522 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3524 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3526 /* if ofnW has been allocated, have to free everything in it */
3527 if (NULL != priv && NULL != priv->ofnA)
3528 FD31_FreeOfnW(&lfs->ofnW);
3531 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3533 callbacks->Init = FD32_Init;
3534 callbacks->CWP = FD32_CallWindowProc;
3535 callbacks->UpdateResult = FD32_UpdateResult;
3536 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3537 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3538 callbacks->Destroy = FD32_Destroy;
3541 /***********************************************************************
3542 * FD32_WMMeasureItem [internal]
3544 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3546 LPMEASUREITEMSTRUCT lpmeasure;
3548 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3549 lpmeasure->itemHeight = FD31_GetFldrHeight();
3550 return TRUE;
3554 /***********************************************************************
3555 * FileOpenDlgProc [internal]
3556 * Used for open and save, in fact.
3558 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3559 WPARAM wParam, LPARAM lParam)
3561 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3563 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3564 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3566 INT_PTR lRet;
3567 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3568 if (lRet)
3569 return lRet; /* else continue message processing */
3571 switch (wMsg)
3573 case WM_INITDIALOG:
3574 return FD31_WMInitDialog(hWnd, wParam, lParam);
3576 case WM_MEASUREITEM:
3577 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3579 case WM_DRAWITEM:
3580 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3582 case WM_COMMAND:
3583 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3584 #if 0
3585 case WM_CTLCOLOR:
3586 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3587 switch (HIWORD(lParam))
3589 case CTLCOLOR_BTN:
3590 SetTextColor((HDC16)wParam, 0x00000000);
3591 return hGRAYBrush;
3592 case CTLCOLOR_STATIC:
3593 SetTextColor((HDC16)wParam, 0x00000000);
3594 return hGRAYBrush;
3596 break;
3597 #endif
3599 return FALSE;
3603 /***********************************************************************
3604 * GetFileName31A [internal]
3606 * Creates a win31 style dialog box for the user to select a file to open/save.
3608 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3609 UINT dlgType /* type dialogue : open/save */
3612 HINSTANCE hInst;
3613 BOOL bRet = FALSE;
3614 PFD31_DATA lfs;
3615 FD31_CALLBACKS callbacks;
3617 if (!lpofn || !FD31_Init()) return FALSE;
3619 TRACE("ofn flags %08lx\n", lpofn->Flags);
3620 FD32_SetupCallbacks(&callbacks);
3621 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3622 if (lfs)
3624 hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
3625 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3626 FD32_FileOpenDlgProc, (LPARAM)lfs);
3627 FD31_DestroyPrivate(lfs);
3630 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3631 return bRet;
3634 /***********************************************************************
3635 * GetFileName31W [internal]
3637 * Creates a win31 style dialog box for the user to select a file to open/save
3639 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3640 UINT dlgType /* type dialogue : open/save */
3643 HINSTANCE hInst;
3644 BOOL bRet = FALSE;
3645 PFD31_DATA lfs;
3646 FD31_CALLBACKS callbacks;
3648 if (!lpofn || !FD31_Init()) return FALSE;
3650 FD32_SetupCallbacks(&callbacks);
3651 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3652 if (lfs)
3654 hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
3655 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3656 FD32_FileOpenDlgProc, (LPARAM)lfs);
3657 FD31_DestroyPrivate(lfs);
3660 TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn->lpstrFile));
3661 return bRet;
3664 /* ------------------ APIs ---------------------- */
3666 /***********************************************************************
3667 * GetOpenFileNameA (COMDLG32.@)
3669 * Creates a dialog box for the user to select a file to open.
3671 * RETURNS
3672 * TRUE on success: user enters a valid file
3673 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3676 BOOL WINAPI GetOpenFileNameA(
3677 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3679 BOOL win16look = FALSE;
3681 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3682 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3684 if (win16look)
3685 return GetFileName31A(ofn, OPEN_DIALOG);
3686 else
3687 return GetFileDialog95A(ofn, OPEN_DIALOG);
3690 /***********************************************************************
3691 * GetOpenFileNameW (COMDLG32.@)
3693 * Creates a dialog box for the user to select a file to open.
3695 * RETURNS
3696 * TRUE on success: user enters a valid file
3697 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3700 BOOL WINAPI GetOpenFileNameW(
3701 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3703 BOOL win16look = FALSE;
3705 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3706 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3708 if (win16look)
3709 return GetFileName31W(ofn, OPEN_DIALOG);
3710 else
3711 return GetFileDialog95W(ofn, OPEN_DIALOG);
3715 /***********************************************************************
3716 * GetSaveFileNameA (COMDLG32.@)
3718 * Creates a dialog box for the user to select a file to save.
3720 * RETURNS
3721 * TRUE on success: user enters a valid file
3722 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3725 BOOL WINAPI GetSaveFileNameA(
3726 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3728 BOOL win16look = FALSE;
3730 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3731 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3733 if (win16look)
3734 return GetFileName31A(ofn, SAVE_DIALOG);
3735 else
3736 return GetFileDialog95A(ofn, SAVE_DIALOG);
3739 /***********************************************************************
3740 * GetSaveFileNameW (COMDLG32.@)
3742 * Creates a dialog box for the user to select a file to save.
3744 * RETURNS
3745 * TRUE on success: user enters a valid file
3746 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3749 BOOL WINAPI GetSaveFileNameW(
3750 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3752 BOOL win16look = FALSE;
3754 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3755 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3757 if (win16look)
3758 return GetFileName31W(ofn, SAVE_DIALOG);
3759 else
3760 return GetFileDialog95W(ofn, SAVE_DIALOG);