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)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
80 #include "filedlgbrowser.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex
; /* Index of picture in image list */
100 int m_iIndent
; /* Indentation index */
101 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
103 } SFOLDER
,*LPSFOLDER
;
105 typedef struct tagLookInInfo
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE
, *PFD32_PRIVATE
;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
185 /* Internal functions used by the dialog */
186 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
187 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
188 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
189 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
190 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
191 static void FILEDLG95_Clean(HWND hwnd
);
193 /* Functions used by the shell navigation */
194 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
196 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
198 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
);
203 /* Functions used by the filetype combo box */
204 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
205 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
211 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
212 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
220 /* Miscellaneous tool functions */
221 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
222 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
223 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
224 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size
);
228 static void MemFree(void *mem
);
230 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
231 void SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
232 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
233 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
234 static BOOL
BrowseSelectedFolder(HWND hwnd
);
236 /***********************************************************************
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
254 /* test for missing functionality */
255 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
257 FIXME("Flags 0x%08lx not yet implemented\n",
258 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
261 /* Create the dialog from a template */
263 if(!(hRes
= FindResourceA(COMDLG32_hInstance
,MAKEINTRESOURCEA(NEWFILEOPENORD
),(LPSTR
)RT_DIALOG
)))
265 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
268 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
269 !(template = LockResource( hDlgTmpl
)))
271 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
275 /* old style hook messages */
276 if (IsHooked(fodInfos
))
278 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
279 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
280 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
281 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
284 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
285 (LPDLGTEMPLATEA
) template,
286 fodInfos
->ofnInfos
->hwndOwner
,
290 /* Unable to create the dialog */
297 /***********************************************************************
300 * Call GetFileName95 with this structure and clean the memory.
302 * IN : The OPENFILENAMEA initialisation structure passed to
303 * GetOpenFileNameA win api function (see filedlg.c)
305 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
308 FileOpenDlgInfos fodInfos
;
309 LPSTR lpstrSavDir
= NULL
;
311 LPWSTR defext
= NULL
;
312 LPWSTR filter
= NULL
;
313 LPWSTR customfilter
= NULL
;
315 /* Initialize FileOpenDlgInfos structure */
316 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
318 /* Pass in the original ofn */
319 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
321 /* save current directory */
322 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
324 lpstrSavDir
= MemAlloc(MAX_PATH
);
325 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
328 fodInfos
.unicode
= FALSE
;
330 /* convert all the input strings to unicode */
331 if(ofn
->lpstrInitialDir
)
333 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
334 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
335 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
338 fodInfos
.initdir
= NULL
;
342 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
343 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
346 fodInfos
.filename
= NULL
;
350 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
351 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
352 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
354 fodInfos
.defext
= defext
;
358 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
359 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
360 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
362 fodInfos
.title
= title
;
364 if (ofn
->lpstrFilter
)
369 /* filter is a list... title\0ext\0......\0\0 */
370 s
= ofn
->lpstrFilter
;
371 while (*s
) s
= s
+strlen(s
)+1;
373 n
= s
- ofn
->lpstrFilter
;
374 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
375 filter
= MemAlloc(len
*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
378 fodInfos
.filter
= filter
;
380 /* convert lpstrCustomFilter */
381 if (ofn
->lpstrCustomFilter
)
386 /* customfilter contains a pair of strings... title\0ext\0 */
387 s
= ofn
->lpstrCustomFilter
;
388 if (*s
) s
= s
+strlen(s
)+1;
389 if (*s
) s
= s
+strlen(s
)+1;
390 n
= s
- ofn
->lpstrCustomFilter
;
391 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
392 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
393 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
395 fodInfos
.customfilter
= customfilter
;
397 /* Initialize the dialog property */
398 fodInfos
.DlgInfos
.dwDlgProp
= 0;
399 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
404 ret
= GetFileName95(&fodInfos
);
407 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
408 ret
= GetFileName95(&fodInfos
);
416 SetCurrentDirectoryA(lpstrSavDir
);
417 MemFree(lpstrSavDir
);
427 MemFree(customfilter
);
429 MemFree(fodInfos
.initdir
);
431 if(fodInfos
.filename
)
432 MemFree(fodInfos
.filename
);
434 TRACE("selected file: %s\n",ofn
->lpstrFile
);
439 /***********************************************************************
442 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
443 * Call GetFileName95 with this structure and clean the memory.
446 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
449 FileOpenDlgInfos fodInfos
;
450 LPWSTR lpstrSavDir
= NULL
;
452 /* Initialize FileOpenDlgInfos structure */
453 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
455 /* Pass in the original ofn */
456 fodInfos
.ofnInfos
= ofn
;
458 fodInfos
.title
= ofn
->lpstrTitle
;
459 fodInfos
.defext
= ofn
->lpstrDefExt
;
460 fodInfos
.filter
= ofn
->lpstrFilter
;
461 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
463 /* convert string arguments, save others */
466 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
467 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
470 fodInfos
.filename
= NULL
;
472 if(ofn
->lpstrInitialDir
)
474 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
475 DWORD len
= strlenW(ofn
->lpstrInitialDir
)+1;
476 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
477 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
480 fodInfos
.initdir
= NULL
;
482 /* save current directory */
483 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
485 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
486 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
489 fodInfos
.unicode
= TRUE
;
494 ret
= GetFileName95(&fodInfos
);
497 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
498 ret
= GetFileName95(&fodInfos
);
506 SetCurrentDirectoryW(lpstrSavDir
);
507 MemFree(lpstrSavDir
);
510 /* restore saved IN arguments and convert OUT arguments back */
511 MemFree(fodInfos
.filename
);
512 MemFree(fodInfos
.initdir
);
516 /******************************************************************************
517 * COMDLG32_GetDisplayNameOf [internal]
519 * Helper function to get the display name for a pidl.
521 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
522 LPSHELLFOLDER psfDesktop
;
525 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
528 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
529 IShellFolder_Release(psfDesktop
);
533 IShellFolder_Release(psfDesktop
);
534 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
537 /***********************************************************************
538 * ArrangeCtrlPositions [internal]
540 * NOTE: Do not change anything here without a lot of testing.
542 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
544 HWND hwndChild
, hwndStc32
;
545 RECT rectParent
, rectChild
, rectStc32
;
546 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
548 /* Take into account if open as read only checkbox and help button
553 RECT rectHelp
, rectCancel
;
554 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
555 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
556 /* subtract the height of the help button plus the space between
557 * the help button and the cancel button to the height of the dialog
559 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
563 There are two possibilities to add components to the default file dialog box.
565 By default, all the new components are added below the standard dialog box (the else case).
567 However, if there is a static text component with the stc32 id, a special case happens.
568 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
569 in the window and the cx and cy indicate how to size the window.
570 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
571 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
575 GetClientRect(hwndParentDlg
, &rectParent
);
577 /* when arranging controls we have to use fixed parent size */
578 rectParent
.bottom
-= help_fixup
;
580 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
583 GetWindowRect(hwndStc32
, &rectStc32
);
584 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
586 /* set the size of the stc32 control according to the size of
587 * client area of the parent dialog
589 SetWindowPos(hwndStc32
, 0,
591 rectParent
.right
, rectParent
.bottom
,
592 SWP_NOMOVE
| SWP_NOZORDER
);
595 SetRectEmpty(&rectStc32
);
597 /* this part moves controls of the child dialog */
598 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
601 if (hwndChild
!= hwndStc32
)
603 GetWindowRect(hwndChild
, &rectChild
);
604 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
606 /* move only if stc32 exist */
607 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
609 LONG old_left
= rectChild
.left
;
611 /* move to the right of visible controls of the parent dialog */
612 rectChild
.left
+= rectParent
.right
;
613 rectChild
.left
-= rectStc32
.right
;
615 child_width_fixup
= rectChild
.left
- old_left
;
617 /* move even if stc32 doesn't exist */
618 if (rectChild
.top
>= rectStc32
.bottom
)
620 LONG old_top
= rectChild
.top
;
622 /* move below visible controls of the parent dialog */
623 rectChild
.top
+= rectParent
.bottom
;
624 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
626 child_height_fixup
= rectChild
.top
- old_top
;
629 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
630 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
632 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
635 /* this part moves controls of the parent dialog */
636 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
639 if (hwndChild
!= hwndChildDlg
)
641 GetWindowRect(hwndChild
, &rectChild
);
642 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
644 /* left,top of stc32 marks the position of controls
645 * from the parent dialog
647 rectChild
.left
+= rectStc32
.left
;
648 rectChild
.top
+= rectStc32
.top
;
650 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
651 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
653 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
656 /* calculate the size of the resulting dialog */
658 /* here we have to use original parent size */
659 GetClientRect(hwndParentDlg
, &rectParent
);
660 GetClientRect(hwndChildDlg
, &rectChild
);
664 rectChild
.right
+= child_width_fixup
;
665 rectChild
.bottom
+= child_height_fixup
;
667 if (rectParent
.right
> rectChild
.right
)
669 rectParent
.right
+= rectChild
.right
;
670 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
674 rectParent
.right
= rectChild
.right
;
677 if (rectParent
.bottom
> rectChild
.bottom
)
679 rectParent
.bottom
+= rectChild
.bottom
;
680 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
684 /* child dialog is higher, unconditionally set new dialog
685 * height to its size (help_fixup will be subtracted below)
687 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
692 rectParent
.bottom
+= rectChild
.bottom
;
695 /* finally use fixed parent size */
696 rectParent
.bottom
-= help_fixup
;
698 /* save the size of the parent's client area */
699 rectChild
.right
= rectParent
.right
;
700 rectChild
.bottom
= rectParent
.bottom
;
702 /* set the size of the parent dialog */
703 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
704 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
705 SetWindowPos(hwndParentDlg
, 0,
707 rectParent
.right
- rectParent
.left
,
708 rectParent
.bottom
- rectParent
.top
,
709 SWP_NOMOVE
| SWP_NOZORDER
);
711 /* set the size of the child dialog */
712 SetWindowPos(hwndChildDlg
, HWND_BOTTOM
,
713 0, 0, rectChild
.right
, rectChild
.bottom
, SWP_NOACTIVATE
);
716 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
725 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
735 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
736 * structure's hInstance parameter is not a HINSTANCE, but
737 * instead a pointer to a template resource to use.
739 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
742 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
745 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
747 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
753 hinst
= fodInfos
->ofnInfos
->hInstance
;
754 if(fodInfos
->unicode
)
756 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
757 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
761 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
762 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
766 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
769 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
770 !(template = LockResource( hDlgTmpl
)))
772 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
776 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, template, hwnd
,
777 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
778 (LPARAM
)fodInfos
->ofnInfos
);
781 ShowWindow(hChildDlg
,SW_SHOW
);
785 else if( IsHooked(fodInfos
))
790 WORD menu
,class,title
;
792 GetClientRect(hwnd
,&rectHwnd
);
793 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
794 temp
.tmplate
.dwExtendedStyle
= 0;
795 temp
.tmplate
.cdit
= 0;
800 temp
.menu
= temp
.class = temp
.title
= 0;
802 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
803 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
810 /***********************************************************************
811 * SendCustomDlgNotificationMessage
813 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
816 void SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
818 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
820 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
822 if(!fodInfos
) return;
824 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
826 TRACE("CALL NOTIFY for %x\n", uCode
);
827 if(fodInfos
->unicode
)
830 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
831 ofnNotify
.hdr
.idFrom
=0;
832 ofnNotify
.hdr
.code
= uCode
;
833 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
834 ofnNotify
.pszFile
= NULL
;
835 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
840 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
841 ofnNotify
.hdr
.idFrom
=0;
842 ofnNotify
.hdr
.code
= uCode
;
843 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
844 ofnNotify
.pszFile
= NULL
;
845 SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
847 TRACE("RET NOTIFY\n");
851 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
853 INT_PTR sizeUsed
= 0, n
, total
;
854 LPWSTR lpstrFileList
= NULL
;
855 WCHAR lpstrCurrentDir
[MAX_PATH
];
856 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
858 TRACE("CDM_GETFILEPATH:\n");
860 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
863 /* get path and filenames */
864 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrCurrentDir
);
865 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
867 TRACE("path >%s< filespec >%s< %d files\n",
868 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
870 if( fodInfos
->unicode
)
872 LPWSTR bufW
= buffer
;
873 total
= strlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
875 /* Prepend the current path */
876 n
= strlenW(lpstrCurrentDir
) + 1;
877 memcpy( bufW
, lpstrCurrentDir
, min(n
,size
) * sizeof(WCHAR
));
880 /* 'n' includes trailing \0 */
882 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
884 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
889 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
890 NULL
, 0, NULL
, NULL
);
891 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
892 NULL
, 0, NULL
, NULL
);
894 /* Prepend the current path */
895 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
896 bufA
, size
, NULL
, NULL
);
900 /* 'n' includes trailing \0 */
902 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
903 &bufA
[n
], size
-n
, NULL
, NULL
);
906 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
908 MemFree(lpstrFileList
);
913 static INT_PTR
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
915 INT_PTR sizeUsed
= 0;
916 LPWSTR lpstrFileList
= NULL
;
917 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
919 TRACE("CDM_GETSPEC:\n");
921 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
922 if( fodInfos
->unicode
)
924 LPWSTR bufW
= buffer
;
925 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
930 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
931 NULL
, 0, NULL
, NULL
);
932 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
933 bufA
, size
, NULL
, NULL
);
935 MemFree(lpstrFileList
);
940 /***********************************************************************
941 * FILEDLG95_HandleCustomDialogMessages
943 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
945 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
947 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
948 WCHAR lpstrPath
[MAX_PATH
];
951 if(!fodInfos
) return FALSE
;
955 case CDM_GETFILEPATH
:
956 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
959 case CDM_GETFOLDERPATH
:
960 TRACE("CDM_GETFOLDERPATH:\n");
961 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
964 if (fodInfos
->unicode
)
965 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
967 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
968 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
970 retval
= strlenW(lpstrPath
);
974 retval
= FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
977 case CDM_SETCONTROLTEXT
:
978 TRACE("CDM_SETCONTROLTEXT:\n");
981 if( fodInfos
->unicode
)
982 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
984 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
989 case CDM_HIDECONTROL
:
991 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
998 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1002 /***********************************************************************
1005 * File open dialog procedure
1007 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1010 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
1017 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1019 /* Adds the FileOpenDlgInfos in the property list of the dialog
1020 so it will be easily accessible through a GetPropA(...) */
1021 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
1023 fodInfos
->DlgInfos
.hwndCustomDlg
=
1024 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1026 FILEDLG95_InitControls(hwnd
);
1028 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1029 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1030 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1032 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1034 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1035 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1036 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1040 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1043 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1046 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1052 case WM_GETISHELLBROWSER
:
1053 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1056 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1061 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1064 /* set up the button tooltips strings */
1065 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1067 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1068 switch(lpnmh
->idFrom
)
1070 /* Up folder button */
1071 case FCIDM_TB_UPFOLDER
:
1072 stringId
= IDS_UPFOLDER
;
1074 /* New folder button */
1075 case FCIDM_TB_NEWFOLDER
:
1076 stringId
= IDS_NEWFOLDER
;
1078 /* List option button */
1079 case FCIDM_TB_SMALLICON
:
1080 stringId
= IDS_LISTVIEW
;
1082 /* Details option button */
1083 case FCIDM_TB_REPORTVIEW
:
1084 stringId
= IDS_REPORTVIEW
;
1086 /* Desktop button */
1087 case FCIDM_TB_DESKTOP
:
1088 stringId
= IDS_TODESKTOP
;
1093 lpdi
->hinst
= COMDLG32_hInstance
;
1094 lpdi
->lpszText
= (LPSTR
) stringId
;
1099 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1100 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1105 /***********************************************************************
1106 * FILEDLG95_InitControls
1108 * WM_INITDIALOG message handler (before hook notification)
1110 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1112 int win2000plus
= 0;
1114 int handledPath
= FALSE
;
1115 OSVERSIONINFOA osVi
;
1116 static const WCHAR szwSlash
[] = { '\\', 0 };
1117 static const WCHAR szwStar
[] = { '*',0 };
1121 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1122 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1123 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1124 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1125 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1126 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1127 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1128 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1129 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1134 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1136 tba
[0].hInst
= HINST_COMMCTRL
;
1137 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1138 tba
[1].hInst
= COMDLG32_hInstance
;
1141 TRACE("%p\n", fodInfos
);
1143 /* Get windows version emulating */
1144 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1145 GetVersionExA(&osVi
);
1146 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1147 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1148 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1149 win2000plus
= (osVi
.dwMajorVersion
> 4);
1150 if (win2000plus
) win98plus
= TRUE
;
1152 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1154 /* Get the hwnd of the controls */
1155 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1156 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1157 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1159 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1160 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1162 /* construct the toolbar */
1163 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1164 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1166 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1167 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1168 rectTB
.left
= rectlook
.right
;
1169 rectTB
.top
= rectlook
.top
-1;
1171 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1172 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1173 rectTB
.left
, rectTB
.top
,
1174 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1175 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1177 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1179 /* FIXME: use TB_LOADIMAGES when implemented */
1180 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1181 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1182 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1184 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1185 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1187 /* Set the window text with the text specified in the OPENFILENAME structure */
1190 SetWindowTextW(hwnd
,fodInfos
->title
);
1192 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1195 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1196 SetWindowTextW(hwnd
, buf
);
1199 /* Initialise the file name edit control */
1200 handledPath
= FALSE
;
1201 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1203 if(fodInfos
->filename
)
1205 /* 1. If win2000 or higher and filename contains a path, use it
1206 in preference over the lpstrInitialDir */
1207 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1208 WCHAR tmpBuf
[MAX_PATH
];
1212 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1215 /* nameBit is always shorter than the original filename */
1216 strcpyW(fodInfos
->filename
,nameBit
);
1219 if (fodInfos
->initdir
== NULL
)
1220 MemFree(fodInfos
->initdir
);
1221 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1222 strcpyW(fodInfos
->initdir
, tmpBuf
);
1224 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1225 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1227 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1230 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1234 /* 2. (All platforms) If initdir is not null, then use it */
1235 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1236 (*fodInfos
->initdir
!=0x00))
1238 /* Work out the proper path as supplied one might be relative */
1239 /* (Here because supplying '.' as dir browses to My Computer) */
1240 if (handledPath
==FALSE
) {
1241 WCHAR tmpBuf
[MAX_PATH
];
1242 WCHAR tmpBuf2
[MAX_PATH
];
1246 strcpyW(tmpBuf
, fodInfos
->initdir
);
1247 if( PathFileExistsW(tmpBuf
) ) {
1248 /* initdir does not have to be a directory. If a file is
1249 * specified, the dir part is taken */
1250 if( PathIsDirectoryW(tmpBuf
)) {
1251 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1252 strcatW(tmpBuf
, szwSlash
);
1254 strcatW(tmpBuf
, szwStar
);
1256 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1259 if (fodInfos
->initdir
)
1260 MemFree(fodInfos
->initdir
);
1261 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1262 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1264 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1267 else if (fodInfos
->initdir
)
1269 MemFree(fodInfos
->initdir
);
1270 fodInfos
->initdir
= NULL
;
1271 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1276 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1277 (*fodInfos
->initdir
==0x00)))
1279 /* 3. All except w2k+: if filename contains a path use it */
1280 if (!win2000plus
&& fodInfos
->filename
&&
1281 *fodInfos
->filename
&&
1282 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1283 WCHAR tmpBuf
[MAX_PATH
];
1287 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1292 /* nameBit is always shorter than the original filename */
1293 strcpyW(fodInfos
->filename
, nameBit
);
1296 len
= strlenW(tmpBuf
);
1297 if(fodInfos
->initdir
)
1298 MemFree(fodInfos
->initdir
);
1299 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1300 strcpyW(fodInfos
->initdir
, tmpBuf
);
1303 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1304 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1306 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1309 /* 4. win98+ and win2000+ if any files of specified filter types in
1310 current directory, use it */
1311 if ( win98plus
&& handledPath
== FALSE
&&
1312 fodInfos
->filter
&& *fodInfos
->filter
) {
1314 BOOL searchMore
= TRUE
;
1315 LPCWSTR lpstrPos
= fodInfos
->filter
;
1316 WIN32_FIND_DATAW FindFileData
;
1321 /* filter is a list... title\0ext\0......\0\0 */
1323 /* Skip the title */
1324 if(! *lpstrPos
) break; /* end */
1325 lpstrPos
+= strlenW(lpstrPos
) + 1;
1327 /* See if any files exist in the current dir with this extension */
1328 if(! *lpstrPos
) break; /* end */
1330 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1332 if (hFind
== INVALID_HANDLE_VALUE
) {
1333 /* None found - continue search */
1334 lpstrPos
+= strlenW(lpstrPos
) + 1;
1339 if(fodInfos
->initdir
)
1340 MemFree(fodInfos
->initdir
);
1341 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1342 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1345 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1346 debugstr_w(lpstrPos
));
1352 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1354 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1355 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1356 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1358 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1360 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1363 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1364 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1366 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1369 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1372 } else if (handledPath
==FALSE
) {
1373 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1374 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1376 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1379 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1380 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1382 /* Must the open as read only check box be checked ?*/
1383 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1385 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1388 /* Must the open as read only check box be hidden? */
1389 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1391 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1392 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1395 /* Must the help button be hidden? */
1396 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1398 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1399 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1402 /* Resize the height, if open as read only checkbox ad help button
1403 are hidden and we are not using a custom template nor a customDialog
1405 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1406 (!(fodInfos
->ofnInfos
->Flags
&
1407 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))) &&
1408 (!fodInfos
->DlgInfos
.hwndCustomDlg
))
1410 RECT rectDlg
, rectHelp
, rectCancel
;
1411 GetWindowRect(hwnd
, &rectDlg
);
1412 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1413 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1414 /* subtract the height of the help button plus the space between
1415 the help button and the cancel button to the height of the dialog */
1416 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1417 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1418 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1420 /* change Open to Save */
1421 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1424 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1425 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1426 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1427 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1432 /***********************************************************************
1433 * FILEDLG95_FillControls
1435 * WM_INITDIALOG message handler (after hook notification)
1437 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1439 LPITEMIDLIST pidlItemId
= NULL
;
1441 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1443 TRACE("dir=%s file=%s\n",
1444 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1446 /* Get the initial directory pidl */
1448 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1450 WCHAR path
[MAX_PATH
];
1452 GetCurrentDirectoryW(MAX_PATH
,path
);
1453 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1456 /* Initialise shell objects */
1457 FILEDLG95_SHELL_Init(hwnd
);
1459 /* Initialize the Look In combo box */
1460 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1462 /* Initialize the filter combo box */
1463 FILEDLG95_FILETYPE_Init(hwnd
);
1465 /* Browse to the initial directory */
1466 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1468 /* Free pidlItem memory */
1469 COMDLG32_SHFree(pidlItemId
);
1473 /***********************************************************************
1476 * Regroups all the cleaning functions of the filedlg
1478 void FILEDLG95_Clean(HWND hwnd
)
1480 FILEDLG95_FILETYPE_Clean(hwnd
);
1481 FILEDLG95_LOOKIN_Clean(hwnd
);
1482 FILEDLG95_SHELL_Clean(hwnd
);
1484 /***********************************************************************
1485 * FILEDLG95_OnWMCommand
1487 * WM_COMMAND message handler
1489 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1491 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1492 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1493 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1499 FILEDLG95_OnOpen(hwnd
);
1503 FILEDLG95_Clean(hwnd
);
1504 EndDialog(hwnd
, FALSE
);
1506 /* Filetype combo box */
1508 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1510 /* LookIn combo box */
1512 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1515 /* --- toolbar --- */
1516 /* Up folder button */
1517 case FCIDM_TB_UPFOLDER
:
1518 FILEDLG95_SHELL_UpFolder(hwnd
);
1520 /* New folder button */
1521 case FCIDM_TB_NEWFOLDER
:
1522 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1524 /* List option button */
1525 case FCIDM_TB_SMALLICON
:
1526 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1528 /* Details option button */
1529 case FCIDM_TB_REPORTVIEW
:
1530 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1532 /* Details option button */
1533 case FCIDM_TB_DESKTOP
:
1534 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1541 /* Do not use the listview selection anymore */
1542 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1546 /***********************************************************************
1547 * FILEDLG95_OnWMGetIShellBrowser
1549 * WM_GETISHELLBROWSER message handler
1551 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1554 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1558 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1564 /***********************************************************************
1565 * FILEDLG95_SendFileOK
1567 * Sends the CDN_FILEOK notification if required
1570 * TRUE if the dialog should close
1571 * FALSE if the dialog should not be closed
1573 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1575 /* ask the hook if we can close */
1576 if(IsHooked(fodInfos
))
1579 /* First send CDN_FILEOK as MSDN doc says */
1580 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1581 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1583 TRACE("canceled\n");
1587 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1588 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1589 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1590 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1592 TRACE("canceled\n");
1599 /***********************************************************************
1600 * FILEDLG95_OnOpenMultipleFiles
1602 * Handles the opening of multiple files.
1605 * check destination buffer size
1607 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1609 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1610 UINT nCount
, nSizePath
;
1611 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1615 if(fodInfos
->unicode
)
1617 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1618 ofn
->lpstrFile
[0] = '\0';
1622 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1623 ofn
->lpstrFile
[0] = '\0';
1626 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1628 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1629 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1630 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1632 LPWSTR lpstrTemp
= lpstrFileList
;
1634 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1638 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1641 WCHAR lpstrNotFound
[100];
1642 WCHAR lpstrMsg
[100];
1644 static const WCHAR nl
[] = {'\n',0};
1646 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1647 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1649 strcpyW(tmp
, lpstrTemp
);
1651 strcatW(tmp
, lpstrNotFound
);
1653 strcatW(tmp
, lpstrMsg
);
1655 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1659 /* move to the next file in the list of files */
1660 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1661 COMDLG32_SHFree(pidl
);
1665 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1666 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1668 /* For "oldstyle" dialog the components have to
1669 be separated by blanks (not '\0'!) and short
1670 filenames have to be used! */
1671 FIXME("Components have to be separated by blanks\n");
1673 if(fodInfos
->unicode
)
1675 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1676 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1677 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1681 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1683 if (ofn
->lpstrFile
!= NULL
)
1685 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1686 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1687 if (ofn
->nMaxFile
> nSizePath
)
1689 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1690 ofn
->lpstrFile
+ nSizePath
,
1691 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1696 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1697 fodInfos
->ofnInfos
->nFileExtension
= 0;
1699 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1702 /* clean and exit */
1703 FILEDLG95_Clean(hwnd
);
1704 return EndDialog(hwnd
,TRUE
);
1707 /***********************************************************************
1710 * Ok button WM_COMMAND message handler
1712 * If the function succeeds, the return value is nonzero.
1714 #define ONOPEN_OPEN 1
1715 #define ONOPEN_SEARCH 2
1716 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1718 WCHAR strMsgTitle
[MAX_PATH
];
1719 WCHAR strMsgText
[MAX_PATH
];
1721 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1723 strMsgTitle
[0] = '\0';
1724 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1725 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1728 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1730 LPWSTR lpstrFileList
;
1731 UINT nFileCount
= 0;
1734 WCHAR lpstrPathAndFile
[MAX_PATH
];
1735 WCHAR lpstrTemp
[MAX_PATH
];
1736 LPSHELLFOLDER lpsf
= NULL
;
1738 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1740 TRACE("hwnd=%p\n", hwnd
);
1742 if(BrowseSelectedFolder(hwnd
))
1745 /* get the files from the edit control */
1746 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1748 /* try if the user selected a folder in the shellview */
1754 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1758 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1761 Step 1: Build a complete path name from the current folder and
1762 the filename or path in the edit box.
1764 - the path in the edit box is a root path
1765 (with or without drive letter)
1766 - the edit box contains ".." (or a path with ".." in it)
1769 /* Get the current directory name */
1770 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1773 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1775 PathAddBackslashW(lpstrPathAndFile
);
1777 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1779 /* if the user specifyed a fully qualified path use it */
1780 if(PathIsRelativeW(lpstrFileList
))
1782 strcatW(lpstrPathAndFile
, lpstrFileList
);
1786 /* does the path have a drive letter? */
1787 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1788 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1790 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1793 /* resolve "." and ".." */
1794 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1795 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1796 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1798 MemFree(lpstrFileList
);
1801 Step 2: here we have a cleaned up path
1803 We have to parse the path step by step to see if we have to browse
1804 to a folder if the path points to a directory or the last
1805 valid element is a directory.
1808 lpstrPathAndFile: cleaned up path
1811 nOpenAction
= ONOPEN_OPEN
;
1813 /* don't apply any checks with OFN_NOVALIDATE */
1815 LPWSTR lpszTemp
, lpszTemp1
;
1816 LPITEMIDLIST pidl
= NULL
;
1817 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1819 /* check for invalid chars */
1820 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1822 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1827 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1829 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1832 LPSHELLFOLDER lpsfChild
;
1833 WCHAR lpwstrTemp
[MAX_PATH
];
1834 DWORD dwEaten
, dwAttributes
;
1837 strcpyW(lpwstrTemp
, lpszTemp
);
1838 p
= PathFindNextComponentW(lpwstrTemp
);
1840 if (!p
) break; /* end of path */
1843 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1847 static const WCHAR wszWild
[] = { '*', '?', 0 };
1848 /* if the last element is a wildcard do a search */
1849 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1851 nOpenAction
= ONOPEN_SEARCH
;
1855 lpszTemp1
= lpszTemp
;
1857 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1859 /* append a backslash to drive letters */
1860 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1861 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1862 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1864 PathAddBackslashW(lpwstrTemp
);
1867 dwAttributes
= SFGAO_FOLDER
;
1868 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1870 /* the path component is valid, we have a pidl of the next path component */
1871 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1872 if(dwAttributes
& SFGAO_FOLDER
)
1874 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1876 ERR("bind to failed\n"); /* should not fail */
1879 IShellFolder_Release(lpsf
);
1887 /* end dialog, return value */
1888 nOpenAction
= ONOPEN_OPEN
;
1891 COMDLG32_SHFree(pidl
);
1894 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1896 if(*lpszTemp
) /* points to trailing null for last path element */
1898 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1900 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1906 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1907 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1909 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1913 /* change to the current folder */
1914 nOpenAction
= ONOPEN_OPEN
;
1919 nOpenAction
= ONOPEN_OPEN
;
1923 if(pidl
) COMDLG32_SHFree(pidl
);
1927 Step 3: here we have a cleaned up and validated path
1930 lpsf: ShellFolder bound to the rightmost valid path component
1931 lpstrPathAndFile: cleaned up path
1932 nOpenAction: action to do
1934 TRACE("end validate sf=%p\n", lpsf
);
1938 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1939 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1942 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1944 IPersistFolder2
* ppf2
;
1946 /* replace the current filter */
1947 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1948 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1949 len
= strlenW(lpszTemp
)+1;
1950 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1951 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1953 /* set the filter cb to the extension when possible */
1954 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1955 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1957 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1959 LPITEMIDLIST pidlCurrent
;
1960 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1961 IPersistFolder2_Release(ppf2
);
1962 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1964 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1968 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1970 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
1971 COMDLG32_SHFree(pidlCurrent
);
1976 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1977 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1981 /* update READONLY check box flag */
1982 if ((SendMessageA(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
1983 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
1985 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
1987 /* Attach the file extension with file name*/
1989 if(!PathIsDirectoryW(lpstrPathAndFile
))
1991 if((ext
= PathFindExtensionW(lpstrPathAndFile
)) == NULL
)
1993 /* if no extension is specified with file name, then */
1994 /* attach the extension from file filter or default one */
1996 WCHAR
*filterExt
= NULL
;
1997 LPWSTR lpstrFilter
= NULL
;
1998 static const WCHAR szwDot
[] = {'.',0};
1999 int PathLength
= strlenW(lpstrPathAndFile
);
2002 strcatW(lpstrPathAndFile
, szwDot
);
2004 /*Get the file extension from file type filter*/
2005 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2006 fodInfos
->ofnInfos
->nFilterIndex
-1);
2008 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2009 filterExt
= PathFindExtensionW(lpstrFilter
);
2011 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2012 strcatW(lpstrPathAndFile
, filterExt
+ 1);
2013 else if ( fodInfos
->defext
) /* attach the default file extension*/
2014 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
2016 /* In Open dialog: if file does not exist try without extension */
2017 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2018 lpstrPathAndFile
[PathLength
] = '\0';
2021 if (fodInfos
->defext
) /* add default extension */
2023 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2026 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2027 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2029 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2033 /* In Save dialog: check if the file already exists */
2034 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2035 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2036 && PathFileExistsW(lpstrPathAndFile
))
2038 WCHAR lpstrOverwrite
[100];
2041 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2042 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2043 MB_YESNO
| MB_ICONEXCLAMATION
);
2051 /* Check that the size of the file does not exceed buffer size.
2052 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2053 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2054 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2058 /* fill destination buffer */
2059 if (fodInfos
->ofnInfos
->lpstrFile
)
2061 if(fodInfos
->unicode
)
2063 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2065 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2066 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2067 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2071 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2073 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2074 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2075 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2076 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2080 /* set filename offset */
2081 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2082 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2084 /* set extension offset */
2085 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2086 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2088 /* set the lpstrFileTitle */
2089 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2091 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2092 if(fodInfos
->unicode
)
2094 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2095 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2099 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2100 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2101 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2105 /* copy currently selected filter to lpstrCustomFilter */
2106 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2108 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2109 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2110 NULL
, 0, NULL
, NULL
);
2111 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2113 LPSTR s
= ofn
->lpstrCustomFilter
;
2114 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2115 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2116 s
, len
, NULL
, NULL
);
2121 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2125 FILEDLG95_Clean(hwnd
);
2126 ret
= EndDialog(hwnd
, TRUE
);
2132 size
= strlenW(lpstrPathAndFile
) + 1;
2133 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2135 /* return needed size in first two bytes of lpstrFile */
2136 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2137 FILEDLG95_Clean(hwnd
);
2138 ret
= EndDialog(hwnd
, FALSE
);
2139 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2147 if(lpsf
) IShellFolder_Release(lpsf
);
2151 /***********************************************************************
2152 * FILEDLG95_SHELL_Init
2154 * Initialisation of the shell objects
2156 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2158 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2163 * Initialisation of the FileOpenDialogInfos structure
2169 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2171 /* Disable multi-select if flag not set */
2172 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2174 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2176 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2177 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2179 /* Construct the IShellBrowser interface */
2180 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2185 /***********************************************************************
2186 * FILEDLG95_SHELL_ExecuteCommand
2188 * Change the folder option and refresh the view
2189 * If the function succeeds, the return value is nonzero.
2191 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2193 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2196 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2198 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2203 CMINVOKECOMMANDINFO ci
;
2204 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2205 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2209 IContextMenu_InvokeCommand(pcm
, &ci
);
2210 IContextMenu_Release(pcm
);
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_UpFolder
2219 * Browse to the specified object
2220 * If the function succeeds, the return value is nonzero.
2222 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2224 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2228 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2232 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2238 /***********************************************************************
2239 * FILEDLG95_SHELL_BrowseToDesktop
2241 * Browse to the Desktop
2242 * If the function succeeds, the return value is nonzero.
2244 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2246 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2252 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2253 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2254 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2255 COMDLG32_SHFree(pidl
);
2256 return SUCCEEDED(hres
);
2258 /***********************************************************************
2259 * FILEDLG95_SHELL_Clean
2261 * Cleans the memory used by shell objects
2263 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2265 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2269 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2271 /* clean Shell interfaces */
2272 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2273 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2274 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2275 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2276 if (fodInfos
->Shell
.FOIDataObject
)
2277 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2280 /***********************************************************************
2281 * FILEDLG95_FILETYPE_Init
2283 * Initialisation of the file type combo box
2285 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2287 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2288 int nFilters
= 0; /* number of filters */
2293 if(fodInfos
->customfilter
)
2295 /* customfilter has one entry... title\0ext\0
2296 * Set first entry of combo box item with customfilter
2299 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2302 lpstrPos
+= strlenW(fodInfos
->customfilter
) + 1;
2304 /* Copy the extensions */
2305 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2306 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2307 strcpyW(lpstrExt
,lpstrPos
);
2309 /* Add the item at the end of the combo */
2310 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2311 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2314 if(fodInfos
->filter
)
2316 LPCWSTR lpstrPos
= fodInfos
->filter
;
2320 /* filter is a list... title\0ext\0......\0\0
2321 * Set the combo item text to the title and the item data
2324 LPCWSTR lpstrDisplay
;
2328 if(! *lpstrPos
) break; /* end */
2329 lpstrDisplay
= lpstrPos
;
2330 lpstrPos
+= strlenW(lpstrPos
) + 1;
2332 /* Copy the extensions */
2333 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2334 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2335 strcpyW(lpstrExt
,lpstrPos
);
2336 lpstrPos
+= strlenW(lpstrPos
) + 1;
2338 /* Add the item at the end of the combo */
2339 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2340 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2346 * Set the current filter to the one specified
2347 * in the initialisation structure
2349 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2353 /* Check to make sure our index isn't out of bounds. */
2354 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2355 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2356 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2358 /* set default filter index */
2359 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2360 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2362 /* calculate index of Combo Box item */
2363 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2364 if (fodInfos
->customfilter
== NULL
)
2367 /* Set the current index selection. */
2368 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2370 /* Get the corresponding text string from the combo box. */
2371 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2374 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2380 CharLowerW(lpstrFilter
); /* lowercase */
2381 len
= strlenW(lpstrFilter
)+1;
2382 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2383 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2386 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2390 /***********************************************************************
2391 * FILEDLG95_FILETYPE_OnCommand
2393 * WM_COMMAND of the file type combo box
2394 * If the function succeeds, the return value is nonzero.
2396 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2398 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2406 /* Get the current item of the filetype combo box */
2407 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2409 /* set the current filter index */
2410 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2411 (fodInfos
->customfilter
== NULL
? 1 : 0);
2413 /* Set the current filter with the current selection */
2414 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2415 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2417 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2419 if((int)lpstrFilter
!= CB_ERR
)
2422 CharLowerW(lpstrFilter
); /* lowercase */
2423 len
= strlenW(lpstrFilter
)+1;
2424 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2425 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2426 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2429 /* Refresh the actual view to display the included items*/
2430 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2435 /***********************************************************************
2436 * FILEDLG95_FILETYPE_SearchExt
2438 * searches for an extension in the filetype box
2440 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2442 int i
, iCount
= CBGetCount(hwnd
);
2444 TRACE("%s\n", debugstr_w(lpstrExt
));
2446 if(iCount
!= CB_ERR
)
2448 for(i
=0;i
<iCount
;i
++)
2450 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2457 /***********************************************************************
2458 * FILEDLG95_FILETYPE_Clean
2460 * Clean the memory used by the filetype combo box
2462 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2464 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2466 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2470 /* Delete each string of the combo and their associated data */
2471 if(iCount
!= CB_ERR
)
2473 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2475 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2476 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2479 /* Current filter */
2480 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2481 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2485 /***********************************************************************
2486 * FILEDLG95_LOOKIN_Init
2488 * Initialisation of the look in combo box
2491 /* Small helper function, to determine if the unixfs shell extension is rooted
2492 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2494 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2496 const static WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2497 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2498 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2499 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2500 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2501 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2502 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2504 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2511 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2513 IShellFolder
*psfRoot
, *psfDrives
;
2514 IEnumIDList
*lpeRoot
, *lpeDrives
;
2515 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2517 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2521 liInfos
->iMaxIndentation
= 0;
2523 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2525 /* set item height for both text field and listbox */
2526 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2527 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2529 /* Turn on the extended UI for the combo box like Windows does */
2530 CBSetExtendedUI(hwndCombo
, TRUE
);
2532 /* Initialise data of Desktop folder */
2533 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2534 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2535 COMDLG32_SHFree(pidlTmp
);
2537 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2539 SHGetDesktopFolder(&psfRoot
);
2543 /* enumerate the contents of the desktop */
2544 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2546 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2548 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2550 /* If the unixfs extension is rooted, we don't expand the drives by default */
2551 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2553 /* special handling for CSIDL_DRIVES */
2554 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2556 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2558 /* enumerate the drives */
2559 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2561 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2563 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2564 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2565 COMDLG32_SHFree(pidlAbsTmp
);
2566 COMDLG32_SHFree(pidlTmp1
);
2568 IEnumIDList_Release(lpeDrives
);
2570 IShellFolder_Release(psfDrives
);
2575 COMDLG32_SHFree(pidlTmp
);
2577 IEnumIDList_Release(lpeRoot
);
2579 IShellFolder_Release(psfRoot
);
2582 COMDLG32_SHFree(pidlDrives
);
2585 /***********************************************************************
2586 * FILEDLG95_LOOKIN_DrawItem
2588 * WM_DRAWITEM message handler
2590 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2592 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2593 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2594 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2598 HIMAGELIST ilItemImage
;
2601 LPSFOLDER tmpFolder
;
2604 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2608 if(pDIStruct
->itemID
== -1)
2611 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2612 pDIStruct
->itemID
)))
2616 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2618 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2621 sizeof (SHFILEINFOA
),
2622 SHGFI_PIDL
| SHGFI_SMALLICON
|
2623 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2624 SHGFI_DISPLAYNAME
);
2628 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2631 sizeof (SHFILEINFOA
),
2632 SHGFI_PIDL
| SHGFI_SMALLICON
|
2633 SHGFI_SYSICONINDEX
|
2637 /* Is this item selected ? */
2638 if(pDIStruct
->itemState
& ODS_SELECTED
)
2640 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2641 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2642 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2646 SetTextColor(pDIStruct
->hDC
,crText
);
2647 SetBkColor(pDIStruct
->hDC
,crWin
);
2648 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2651 /* Do not indent item if drawing in the edit of the combo */
2652 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2655 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2658 sizeof (SHFILEINFOA
),
2659 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2660 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2665 iIndentation
= tmpFolder
->m_iIndent
;
2667 /* Draw text and icon */
2669 /* Initialise the icon display area */
2670 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2671 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2672 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2673 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2675 /* Initialise the text display area */
2676 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2677 rectText
.left
= rectIcon
.right
;
2679 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2680 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2682 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2684 /* Draw the icon from the image list */
2685 ImageList_Draw(ilItemImage
,
2692 /* Draw the associated text */
2693 if(sfi
.szDisplayName
)
2694 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2700 /***********************************************************************
2701 * FILEDLG95_LOOKIN_OnCommand
2703 * LookIn combo box WM_COMMAND message handler
2704 * If the function succeeds, the return value is nonzero.
2706 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2708 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2710 TRACE("%p\n", fodInfos
);
2716 LPSFOLDER tmpFolder
;
2719 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2721 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2726 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2727 tmpFolder
->pidlItem
,
2730 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2740 /***********************************************************************
2741 * FILEDLG95_LOOKIN_AddItem
2743 * Adds an absolute pidl item to the lookin combo box
2744 * returns the index of the inserted item
2746 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2748 LPITEMIDLIST pidlNext
;
2751 LookInInfos
*liInfos
;
2753 TRACE("%08x\n", iInsertId
);
2758 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2761 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2762 tmpFolder
->m_iIndent
= 0;
2764 /* Calculate the indentation of the item in the lookin*/
2766 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2768 tmpFolder
->m_iIndent
++;
2771 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2773 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2774 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2776 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2777 SHGetFileInfoA((LPSTR
)pidl
,
2781 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2782 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2784 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2786 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2790 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2792 /* Add the item at the end of the list */
2795 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2797 /* Insert the item at the iInsertId position*/
2800 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2803 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2807 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2808 MemFree( tmpFolder
);
2813 /***********************************************************************
2814 * FILEDLG95_LOOKIN_InsertItemAfterParent
2816 * Insert an item below its parent
2818 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2821 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2826 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2830 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2833 /* Free pidlParent memory */
2834 COMDLG32_SHFree((LPVOID
)pidlParent
);
2836 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2839 /***********************************************************************
2840 * FILEDLG95_LOOKIN_SelectItem
2842 * Adds an absolute pidl item to the lookin combo box
2843 * returns the index of the inserted item
2845 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2848 LookInInfos
*liInfos
;
2852 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2854 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2858 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2859 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2864 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2865 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2869 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2871 if(iRemovedItem
< iItemPos
)
2876 CBSetCurSel(hwnd
,iItemPos
);
2877 liInfos
->uSelectedItem
= iItemPos
;
2883 /***********************************************************************
2884 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2886 * Remove the item with an expansion level over iExpansionLevel
2888 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2892 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2896 if(liInfos
->iMaxIndentation
<= 2)
2899 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2901 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2902 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2904 CBDeleteString(hwnd
,iItemPos
);
2905 liInfos
->iMaxIndentation
--;
2913 /***********************************************************************
2914 * FILEDLG95_LOOKIN_SearchItem
2916 * Search for pidl in the lookin combo box
2917 * returns the index of the found item
2919 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2922 int iCount
= CBGetCount(hwnd
);
2924 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2926 if (iCount
!= CB_ERR
)
2930 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2932 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2934 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2942 /***********************************************************************
2943 * FILEDLG95_LOOKIN_Clean
2945 * Clean the memory used by the lookin combo box
2947 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2949 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2951 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2955 /* Delete each string of the combo and their associated data */
2956 if (iCount
!= CB_ERR
)
2958 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2960 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2961 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2963 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2967 /* LookInInfos structure */
2968 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2971 /***********************************************************************
2972 * FILEDLG95_FILENAME_FillFromSelection
2974 * fills the edit box from the cached DataObject
2976 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2978 FileOpenDlgInfos
*fodInfos
;
2980 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2981 char lpstrTemp
[MAX_PATH
];
2982 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2985 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2987 /* Count how many files we have */
2988 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2990 /* calculate the string length, count files */
2991 if (nFileSelected
>= 1)
2993 nLength
+= 3; /* first and last quotes, trailing \0 */
2994 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2996 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3000 /* get the total length of the selected file names */
3001 lpstrTemp
[0] = '\0';
3002 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3004 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3006 nLength
+= strlen( lpstrTemp
) + 3;
3009 COMDLG32_SHFree( pidl
);
3014 /* allocate the buffer */
3015 if (nFiles
<= 1) nLength
= MAX_PATH
;
3016 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
3017 lpstrAllFile
[0] = '\0';
3019 /* Generate the string for the edit control */
3022 lpstrCurrFile
= lpstrAllFile
;
3023 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3025 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3029 /* get the file name */
3030 lpstrTemp
[0] = '\0';
3031 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3033 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3037 *lpstrCurrFile
++ = '\"';
3038 strcpy( lpstrCurrFile
, lpstrTemp
);
3039 lpstrCurrFile
+= strlen( lpstrTemp
);
3040 strcpy( lpstrCurrFile
, "\" " );
3045 strcpy( lpstrAllFile
, lpstrTemp
);
3048 COMDLG32_SHFree( (LPVOID
) pidl
);
3051 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3053 /* Select the file name like Windows does */
3054 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)-1);
3056 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3060 /* copied from shell32 to avoid linking to it
3061 * FIXME: why? shell32 is already linked
3063 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3068 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
3069 COMDLG32_SHFree(src
->u
.pOleStr
);
3073 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
3077 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
3081 FIXME("unknown type!\n");
3084 *(LPSTR
)dest
= '\0';
3091 /***********************************************************************
3092 * FILEDLG95_FILENAME_GetFileNames
3094 * Copies the filenames to a delimited string list.
3095 * The delimiter is specified by the parameter 'separator',
3096 * usually either a space or a nul
3098 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3100 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3101 UINT nStrCharCount
= 0; /* index in src buffer */
3102 UINT nFileIndex
= 0; /* index in dest buffer */
3103 UINT nFileCount
= 0; /* number of files */
3104 UINT nStrLen
= 0; /* length of string in edit control */
3105 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3109 /* get the filenames from the edit control */
3110 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3111 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3112 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3114 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3116 /* we might get single filename without any '"',
3117 * so we need nStrLen + terminating \0 + end-of-list \0 */
3118 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3121 /* build delimited file list from filenames */
3122 while ( nStrCharCount
<= nStrLen
)
3124 if ( lpstrEdit
[nStrCharCount
]=='"' )
3127 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3129 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3133 (*lpstrFileList
)[nFileIndex
++] = separator
;
3140 /* single, unquoted string */
3141 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3143 strcpyW(*lpstrFileList
, lpstrEdit
);
3144 nFileIndex
= strlenW(lpstrEdit
) + 1;
3145 (*sizeUsed
) = nFileIndex
;
3150 (*lpstrFileList
)[nFileIndex
] = '\0';
3157 #define SETDefFormatEtc(fe,cf,med) \
3159 (fe).cfFormat = cf;\
3160 (fe).dwAspect = DVASPECT_CONTENT; \
3167 * DATAOBJECT Helper functions
3170 /***********************************************************************
3171 * COMCTL32_ReleaseStgMedium
3173 * like ReleaseStgMedium from ole32
3175 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3177 if(medium
.pUnkForRelease
)
3179 IUnknown_Release(medium
.pUnkForRelease
);
3183 GlobalUnlock(medium
.u
.hGlobal
);
3184 GlobalFree(medium
.u
.hGlobal
);
3188 /***********************************************************************
3189 * GetPidlFromDataObject
3191 * Return pidl(s) by number from the cached DataObject
3193 * nPidlIndex=0 gets the fully qualified root path
3195 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3199 FORMATETC formatetc
;
3200 LPITEMIDLIST pidl
= NULL
;
3202 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3204 /* Set the FORMATETC structure*/
3205 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3207 /* Get the pidls from IDataObject */
3208 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3210 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3211 if(nPidlIndex
<= cida
->cidl
)
3213 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3215 COMCTL32_ReleaseStgMedium(medium
);
3220 /***********************************************************************
3223 * Return the number of selected items in the DataObject.
3226 UINT
GetNumSelected( IDataObject
*doSelected
)
3230 FORMATETC formatetc
;
3232 TRACE("sv=%p\n", doSelected
);
3234 if (!doSelected
) return 0;
3236 /* Set the FORMATETC structure*/
3237 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3239 /* Get the pidls from IDataObject */
3240 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3242 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3243 retVal
= cida
->cidl
;
3244 COMCTL32_ReleaseStgMedium(medium
);
3254 /***********************************************************************
3257 * Get the pidl's display name (relative to folder) and
3258 * put it in lpstrFileName.
3260 * Return NOERROR on success,
3264 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
3269 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3273 SHGetDesktopFolder(&lpsf
);
3274 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3275 IShellFolder_Release(lpsf
);
3279 /* Get the display name of the pidl relative to the folder */
3280 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3282 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3287 /***********************************************************************
3288 * GetShellFolderFromPidl
3290 * pidlRel is the item pidl relative
3291 * Return the IShellFolder of the absolute pidl
3293 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3295 IShellFolder
*psf
= NULL
,*psfParent
;
3297 TRACE("%p\n", pidlAbs
);
3299 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3302 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3304 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3306 IShellFolder_Release(psfParent
);
3310 /* return the desktop */
3316 /***********************************************************************
3319 * Return the LPITEMIDLIST to the parent of the pidl in the list
3321 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3323 LPITEMIDLIST pidlParent
;
3325 TRACE("%p\n", pidl
);
3327 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3328 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3333 /***********************************************************************
3336 * returns the pidl of the file name relative to folder
3337 * NULL if an error occurred
3339 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3341 LPITEMIDLIST pidl
= NULL
;
3344 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3346 if(!lpcstrFileName
) return NULL
;
3347 if(!*lpcstrFileName
) return NULL
;
3351 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3352 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3353 IShellFolder_Release(lpsf
);
3358 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3365 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3367 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3370 TRACE("%p, %p\n", psf
, pidl
);
3372 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3374 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3375 /* see documentation shell 4.1*/
3376 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3379 /***********************************************************************
3380 * BrowseSelectedFolder
3382 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3384 BOOL bBrowseSelFolder
= FALSE
;
3385 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3389 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3391 LPITEMIDLIST pidlSelection
;
3393 /* get the file selected */
3394 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3395 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3397 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3398 pidlSelection
, SBSP_RELATIVE
) ) )
3400 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3401 ' ','n','o','t',' ','e','x','i','s','t',0};
3402 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3404 bBrowseSelFolder
= TRUE
;
3405 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3407 COMDLG32_SHFree( pidlSelection
);
3410 return bBrowseSelFolder
;
3414 * Memory allocation methods */
3415 static void *MemAlloc(UINT size
)
3417 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3420 static void MemFree(void *mem
)
3422 HeapFree(GetProcessHeap(),0,mem
);
3426 * Old-style (win3.1) dialogs */
3428 /***********************************************************************
3429 * FD32_GetTemplate [internal]
3431 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3432 * by a 32 bits application
3435 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3437 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3438 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3441 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3443 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3445 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3449 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3453 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3454 priv
->ofnA
->lpTemplateName
,
3457 hResInfo
= FindResourceW(ofnW
->hInstance
,
3458 ofnW
->lpTemplateName
,
3462 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3465 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3467 !(lfs
->template = LockResource(hDlgTmpl
)))
3469 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3472 } else { /* get it from internal Wine resource */
3474 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3475 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3477 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3480 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3481 !(lfs
->template = LockResource( hDlgTmpl
)))
3483 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3491 /************************************************************************
3492 * FD32_Init [internal]
3493 * called from the common 16/32 code to initialize 32 bit data
3495 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3497 BOOL IsUnicode
= (BOOL
) data
;
3500 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3501 lfs
->private1632
= priv
;
3502 if (NULL
== lfs
->private1632
) return FALSE
;
3505 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3506 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3507 if (lfs
->ofnW
->lpfnHook
)
3512 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3513 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3514 if (priv
->ofnA
->lpfnHook
)
3516 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3517 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3520 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3525 /***********************************************************************
3526 * FD32_CallWindowProc [internal]
3528 * called from the common 16/32 code to call the appropriate hook
3530 static BOOL CALLBACK
FD32_CallWindowProc(PFD31_DATA lfs
, UINT wMsg
, WPARAM wParam
,
3534 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3538 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3539 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3540 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3541 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3542 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3546 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3547 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3548 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3549 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3550 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3554 /***********************************************************************
3555 * FD32_UpdateResult [internal]
3556 * update the real client structures if any
3558 static void CALLBACK
FD32_UpdateResult(PFD31_DATA lfs
)
3560 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3561 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3565 if (ofnW
->nMaxFile
&&
3566 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3567 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3568 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3569 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3570 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
3574 /***********************************************************************
3575 * FD32_UpdateFileTitle [internal]
3576 * update the real client structures if any
3578 static void CALLBACK
FD32_UpdateFileTitle(PFD31_DATA lfs
)
3580 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3581 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3585 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3586 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3587 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3592 /***********************************************************************
3593 * FD32_SendLbGetCurSel [internal]
3594 * retrieve selected listbox item
3596 static LRESULT CALLBACK
FD32_SendLbGetCurSel(PFD31_DATA lfs
)
3598 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3602 /************************************************************************
3603 * FD32_Destroy [internal]
3604 * called from the common 16/32 code to cleanup 32 bit data
3606 static void CALLBACK
FD32_Destroy(PFD31_DATA lfs
)
3608 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3610 /* if ofnW has been allocated, have to free everything in it */
3611 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3613 FD31_FreeOfnW(lfs
->ofnW
);
3614 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3618 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3620 callbacks
->Init
= FD32_Init
;
3621 callbacks
->CWP
= FD32_CallWindowProc
;
3622 callbacks
->UpdateResult
= FD32_UpdateResult
;
3623 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3624 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3625 callbacks
->Destroy
= FD32_Destroy
;
3628 /***********************************************************************
3629 * FD32_WMMeasureItem [internal]
3631 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3633 LPMEASUREITEMSTRUCT lpmeasure
;
3635 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3636 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3641 /***********************************************************************
3642 * FileOpenDlgProc [internal]
3643 * Used for open and save, in fact.
3645 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3646 WPARAM wParam
, LPARAM lParam
)
3648 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3650 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg
, wParam
, lParam
);
3651 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3654 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3656 return lRet
; /* else continue message processing */
3661 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3663 case WM_MEASUREITEM
:
3664 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3667 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3670 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3673 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3674 switch (HIWORD(lParam
))
3677 SetTextColor((HDC16
)wParam
, 0x00000000);
3679 case CTLCOLOR_STATIC
:
3680 SetTextColor((HDC16
)wParam
, 0x00000000);
3690 /***********************************************************************
3691 * GetFileName31A [internal]
3693 * Creates a win31 style dialog box for the user to select a file to open/save.
3695 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* addess of structure with data*/
3696 UINT dlgType
/* type dialogue : open/save */
3702 FD31_CALLBACKS callbacks
;
3704 if (!lpofn
|| !FD31_Init()) return FALSE
;
3706 TRACE("ofn flags %08lx\n", lpofn
->Flags
);
3707 FD32_SetupCallbacks(&callbacks
);
3708 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3711 hInst
= (HINSTANCE
)GetWindowLongPtrA( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3712 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3713 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3714 FD31_DestroyPrivate(lfs
);
3717 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3721 /***********************************************************************
3722 * GetFileName31W [internal]
3724 * Creates a win31 style dialog box for the user to select a file to open/save
3726 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* addess of structure with data*/
3727 UINT dlgType
/* type dialogue : open/save */
3733 FD31_CALLBACKS callbacks
;
3735 if (!lpofn
|| !FD31_Init()) return FALSE
;
3737 FD32_SetupCallbacks(&callbacks
);
3738 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3741 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3742 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3743 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3744 FD31_DestroyPrivate(lfs
);
3747 TRACE("file %s, file offset %d, ext offset %d\n",
3748 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3752 /* ------------------ APIs ---------------------- */
3754 /***********************************************************************
3755 * GetOpenFileNameA (COMDLG32.@)
3757 * Creates a dialog box for the user to select a file to open.
3760 * TRUE on success: user enters a valid file
3761 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3764 BOOL WINAPI
GetOpenFileNameA(
3765 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3767 BOOL win16look
= FALSE
;
3769 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3770 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3771 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3773 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3774 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3777 return GetFileName31A(ofn
, OPEN_DIALOG
);
3779 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3782 /***********************************************************************
3783 * GetOpenFileNameW (COMDLG32.@)
3785 * Creates a dialog box for the user to select a file to open.
3788 * TRUE on success: user enters a valid file
3789 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3792 BOOL WINAPI
GetOpenFileNameW(
3793 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3795 BOOL win16look
= FALSE
;
3797 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3798 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3801 return GetFileName31W(ofn
, OPEN_DIALOG
);
3803 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3807 /***********************************************************************
3808 * GetSaveFileNameA (COMDLG32.@)
3810 * Creates a dialog box for the user to select a file to save.
3813 * TRUE on success: user enters a valid file
3814 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3817 BOOL WINAPI
GetSaveFileNameA(
3818 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3820 BOOL win16look
= FALSE
;
3822 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3823 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3826 return GetFileName31A(ofn
, SAVE_DIALOG
);
3828 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3831 /***********************************************************************
3832 * GetSaveFileNameW (COMDLG32.@)
3834 * Creates a dialog box for the user to select a file to save.
3837 * TRUE on success: user enters a valid file
3838 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3841 BOOL WINAPI
GetSaveFileNameW(
3842 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3844 BOOL win16look
= FALSE
;
3846 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3847 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3850 return GetFileName31W(ofn
, SAVE_DIALOG
);
3852 return GetFileDialog95W(ofn
, SAVE_DIALOG
);