2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
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
72 #include "filedlg31.h"
76 #include "filedlgbrowser.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT | OFN_ENABLESIZING |\
86 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
87 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
89 #define IsHooked(fodInfos) \
90 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
91 /***********************************************************************
92 * Data structure and global variables
94 typedef struct SFolder
96 int m_iImageIndex
; /* Index of picture in image list */
98 int m_iIndent
; /* Indentation index */
99 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
101 } SFOLDER
,*LPSFOLDER
;
103 typedef struct tagLookInInfo
109 typedef struct tagFD32_PRIVATE
111 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
112 } FD32_PRIVATE
, *PFD32_PRIVATE
;
115 /***********************************************************************
116 * Defines and global variables
119 /* Draw item constant */
121 #define XTEXTOFFSET 3
126 /* SearchItem methods */
127 #define SEARCH_PIDL 1
129 #define ITEM_NOTFOUND -1
131 /* Undefined windows message sent by CreateViewObject*/
132 #define WM_GETISHELLBROWSER WM_USER+7
135 * Those macros exist in windowsx.h. However, you can't really use them since
136 * they rely on the UNICODE defines and can't be used inside Wine itself.
139 /* Combo box macros */
140 #define CBAddString(hwnd,str) \
141 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
143 #define CBInsertString(hwnd,str,pos) \
144 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
146 #define CBDeleteString(hwnd,pos) \
147 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
149 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
150 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
152 #define CBGetItemDataPtr(hwnd,iItemId) \
153 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
155 #define CBGetLBText(hwnd,iItemId,str) \
156 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
158 #define CBGetCurSel(hwnd) \
159 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
161 #define CBSetCurSel(hwnd,pos) \
162 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
164 #define CBGetCount(hwnd) \
165 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
166 #define CBShowDropDown(hwnd,show) \
167 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
168 #define CBSetItemHeight(hwnd,index,height) \
169 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
171 #define CBSetExtendedUI(hwnd,flag) \
172 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
174 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
175 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
177 /***********************************************************************
181 /* Internal functions used by the dialog */
182 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
183 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
184 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
185 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
186 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
187 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
188 static void FILEDLG95_Clean(HWND hwnd
);
190 /* Functions used by the shell navigation */
191 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
192 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
193 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
200 /* Functions used by the filetype combo box */
201 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
202 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
208 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
209 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
217 /* Miscellaneous tool functions */
218 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
219 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
220 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
221 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
222 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
223 static UINT
GetNumSelected( IDataObject
*doSelected
);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size
);
227 static void MemFree(void *mem
);
229 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
231 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
232 static BOOL
BrowseSelectedFolder(HWND hwnd
);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
253 /* test for missing functionality */
254 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
260 /* Create the dialog from a template */
262 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
267 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
268 !(template = LockResource( hDlgTmpl
)))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
274 /* old style hook messages */
275 if (IsHooked(fodInfos
))
277 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
278 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
279 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
280 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
283 /* Some shell namespace extensions depend on COM being initialized. */
284 hr
= OleInitialize(NULL
);
286 if (fodInfos
->unicode
)
287 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
289 fodInfos
->ofnInfos
->hwndOwner
,
293 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
295 fodInfos
->ofnInfos
->hwndOwner
,
301 /* Unable to create the dialog */
308 /***********************************************************************
311 * Call GetFileName95 with this structure and clean the memory.
313 * IN : The OPENFILENAMEA initialisation structure passed to
314 * GetOpenFileNameA win api function (see filedlg.c)
316 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
319 FileOpenDlgInfos fodInfos
;
320 LPSTR lpstrSavDir
= NULL
;
322 LPWSTR defext
= NULL
;
323 LPWSTR filter
= NULL
;
324 LPWSTR customfilter
= NULL
;
326 /* Initialize CommDlgExtendedError() */
327 COMDLG32_SetCommDlgExtendedError(0);
329 /* Initialize FileOpenDlgInfos structure */
330 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
332 /* Pass in the original ofn */
333 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
335 /* save current directory */
336 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
338 lpstrSavDir
= MemAlloc(MAX_PATH
);
339 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
342 fodInfos
.unicode
= FALSE
;
344 /* convert all the input strings to unicode */
345 if(ofn
->lpstrInitialDir
)
347 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
348 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
349 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
352 fodInfos
.initdir
= NULL
;
356 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
357 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
360 fodInfos
.filename
= NULL
;
364 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
365 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
366 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
368 fodInfos
.defext
= defext
;
372 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
373 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
374 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
376 fodInfos
.title
= title
;
378 if (ofn
->lpstrFilter
)
383 /* filter is a list... title\0ext\0......\0\0 */
384 s
= ofn
->lpstrFilter
;
385 while (*s
) s
= s
+strlen(s
)+1;
387 n
= s
- ofn
->lpstrFilter
;
388 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
389 filter
= MemAlloc(len
*sizeof(WCHAR
));
390 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
392 fodInfos
.filter
= filter
;
394 /* convert lpstrCustomFilter */
395 if (ofn
->lpstrCustomFilter
)
400 /* customfilter contains a pair of strings... title\0ext\0 */
401 s
= ofn
->lpstrCustomFilter
;
402 if (*s
) s
= s
+strlen(s
)+1;
403 if (*s
) s
= s
+strlen(s
)+1;
404 n
= s
- ofn
->lpstrCustomFilter
;
405 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
406 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
407 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
409 fodInfos
.customfilter
= customfilter
;
411 /* Initialize the dialog property */
412 fodInfos
.DlgInfos
.dwDlgProp
= 0;
413 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
418 ret
= GetFileName95(&fodInfos
);
421 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
422 ret
= GetFileName95(&fodInfos
);
430 SetCurrentDirectoryA(lpstrSavDir
);
431 MemFree(lpstrSavDir
);
437 MemFree(customfilter
);
438 MemFree(fodInfos
.initdir
);
439 MemFree(fodInfos
.filename
);
441 TRACE("selected file: %s\n",ofn
->lpstrFile
);
446 /***********************************************************************
449 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
450 * Call GetFileName95 with this structure and clean the memory.
453 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
456 FileOpenDlgInfos fodInfos
;
457 LPWSTR lpstrSavDir
= NULL
;
459 /* Initialize CommDlgExtendedError() */
460 COMDLG32_SetCommDlgExtendedError(0);
462 /* Initialize FileOpenDlgInfos structure */
463 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
465 /* Pass in the original ofn */
466 fodInfos
.ofnInfos
= ofn
;
468 fodInfos
.title
= ofn
->lpstrTitle
;
469 fodInfos
.defext
= ofn
->lpstrDefExt
;
470 fodInfos
.filter
= ofn
->lpstrFilter
;
471 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
473 /* convert string arguments, save others */
476 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
477 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
480 fodInfos
.filename
= NULL
;
482 if(ofn
->lpstrInitialDir
)
484 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
485 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
486 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
487 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
490 fodInfos
.initdir
= NULL
;
492 /* save current directory */
493 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
495 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
496 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
499 fodInfos
.unicode
= TRUE
;
504 ret
= GetFileName95(&fodInfos
);
507 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
508 ret
= GetFileName95(&fodInfos
);
516 SetCurrentDirectoryW(lpstrSavDir
);
517 MemFree(lpstrSavDir
);
520 /* restore saved IN arguments and convert OUT arguments back */
521 MemFree(fodInfos
.filename
);
522 MemFree(fodInfos
.initdir
);
526 /******************************************************************************
527 * COMDLG32_GetDisplayNameOf [internal]
529 * Helper function to get the display name for a pidl.
531 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
532 LPSHELLFOLDER psfDesktop
;
535 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
538 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
539 IShellFolder_Release(psfDesktop
);
543 IShellFolder_Release(psfDesktop
);
544 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
547 /***********************************************************************
548 * ArrangeCtrlPositions [internal]
550 * NOTE: Do not change anything here without a lot of testing.
552 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
554 HWND hwndChild
, hwndStc32
;
555 RECT rectParent
, rectChild
, rectStc32
;
556 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
558 /* Take into account if open as read only checkbox and help button
563 RECT rectHelp
, rectCancel
;
564 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
565 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
566 /* subtract the height of the help button plus the space between
567 * the help button and the cancel button to the height of the dialog
569 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
573 There are two possibilities to add components to the default file dialog box.
575 By default, all the new components are added below the standard dialog box (the else case).
577 However, if there is a static text component with the stc32 id, a special case happens.
578 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
579 in the window and the cx and cy indicate how to size the window.
580 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
581 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
585 GetClientRect(hwndParentDlg
, &rectParent
);
587 /* when arranging controls we have to use fixed parent size */
588 rectParent
.bottom
-= help_fixup
;
590 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
593 GetWindowRect(hwndStc32
, &rectStc32
);
594 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
596 /* set the size of the stc32 control according to the size of
597 * client area of the parent dialog
599 SetWindowPos(hwndStc32
, 0,
601 rectParent
.right
, rectParent
.bottom
,
602 SWP_NOMOVE
| SWP_NOZORDER
);
605 SetRectEmpty(&rectStc32
);
607 /* this part moves controls of the child dialog */
608 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
611 if (hwndChild
!= hwndStc32
)
613 GetWindowRect(hwndChild
, &rectChild
);
614 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
616 /* move only if stc32 exist */
617 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
619 LONG old_left
= rectChild
.left
;
621 /* move to the right of visible controls of the parent dialog */
622 rectChild
.left
+= rectParent
.right
;
623 rectChild
.left
-= rectStc32
.right
;
625 child_width_fixup
= rectChild
.left
- old_left
;
627 /* move even if stc32 doesn't exist */
628 if (rectChild
.top
>= rectStc32
.bottom
)
630 LONG old_top
= rectChild
.top
;
632 /* move below visible controls of the parent dialog */
633 rectChild
.top
+= rectParent
.bottom
;
634 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
636 child_height_fixup
= rectChild
.top
- old_top
;
639 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
640 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
642 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
645 /* this part moves controls of the parent dialog */
646 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
649 if (hwndChild
!= hwndChildDlg
)
651 GetWindowRect(hwndChild
, &rectChild
);
652 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
654 /* left,top of stc32 marks the position of controls
655 * from the parent dialog
657 rectChild
.left
+= rectStc32
.left
;
658 rectChild
.top
+= rectStc32
.top
;
660 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
661 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
663 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
666 /* calculate the size of the resulting dialog */
668 /* here we have to use original parent size */
669 GetClientRect(hwndParentDlg
, &rectParent
);
670 GetClientRect(hwndChildDlg
, &rectChild
);
674 rectChild
.right
+= child_width_fixup
;
675 rectChild
.bottom
+= child_height_fixup
;
677 if (rectParent
.right
> rectChild
.right
)
679 rectParent
.right
+= rectChild
.right
;
680 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
684 rectParent
.right
= rectChild
.right
;
687 if (rectParent
.bottom
> rectChild
.bottom
)
689 rectParent
.bottom
+= rectChild
.bottom
;
690 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
694 /* child dialog is higher, unconditionally set new dialog
695 * height to its size (help_fixup will be subtracted below)
697 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
702 rectParent
.bottom
+= rectChild
.bottom
;
705 /* finally use fixed parent size */
706 rectParent
.bottom
-= help_fixup
;
708 /* set the size of the parent dialog */
709 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
710 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
711 SetWindowPos(hwndParentDlg
, 0,
713 rectParent
.right
- rectParent
.left
,
714 rectParent
.bottom
- rectParent
.top
,
715 SWP_NOMOVE
| SWP_NOZORDER
);
718 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
727 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
737 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
738 * structure's hInstance parameter is not a HINSTANCE, but
739 * instead a pointer to a template resource to use.
741 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
744 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
746 hinst
= COMDLG32_hInstance
;
747 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
749 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
755 hinst
= fodInfos
->ofnInfos
->hInstance
;
756 if(fodInfos
->unicode
)
758 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
759 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
763 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
764 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
768 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
771 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
772 !(template = LockResource( hDlgTmpl
)))
774 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
778 if (fodInfos
->unicode
)
779 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
780 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
781 (LPARAM
)fodInfos
->ofnInfos
);
783 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
784 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
785 (LPARAM
)fodInfos
->ofnInfos
);
788 ShowWindow(hChildDlg
,SW_SHOW
);
792 else if( IsHooked(fodInfos
))
797 WORD menu
,class,title
;
799 GetClientRect(hwnd
,&rectHwnd
);
800 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
801 temp
.tmplate
.dwExtendedStyle
= 0;
802 temp
.tmplate
.cdit
= 0;
807 temp
.menu
= temp
.class = temp
.title
= 0;
809 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
810 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
817 /***********************************************************************
818 * SendCustomDlgNotificationMessage
820 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
823 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
825 LRESULT hook_result
= 0;
826 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
828 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
830 if(!fodInfos
) return 0;
832 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
834 TRACE("CALL NOTIFY for %x\n", uCode
);
835 if(fodInfos
->unicode
)
838 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
839 ofnNotify
.hdr
.idFrom
=0;
840 ofnNotify
.hdr
.code
= uCode
;
841 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
842 ofnNotify
.pszFile
= NULL
;
843 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
848 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
849 ofnNotify
.hdr
.idFrom
=0;
850 ofnNotify
.hdr
.code
= uCode
;
851 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
852 ofnNotify
.pszFile
= NULL
;
853 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
855 TRACE("RET NOTIFY\n");
857 TRACE("Retval: 0x%08lx\n", hook_result
);
861 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
865 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
867 TRACE("CDM_GETFILEPATH:\n");
869 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
872 /* get path and filenames */
873 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
874 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
875 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
878 p
= buffer
+ strlenW(buffer
);
880 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
882 if (fodInfos
->unicode
)
884 total
= strlenW( buffer
) + 1;
885 if (result
) lstrcpynW( result
, buffer
, size
);
886 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
890 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
891 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
894 HeapFree( GetProcessHeap(), 0, buffer
);
898 /***********************************************************************
899 * FILEDLG95_HandleCustomDialogMessages
901 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
903 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
905 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
906 WCHAR lpstrPath
[MAX_PATH
];
909 if(!fodInfos
) return FALSE
;
913 case CDM_GETFILEPATH
:
914 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
917 case CDM_GETFOLDERPATH
:
918 TRACE("CDM_GETFOLDERPATH:\n");
919 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
922 if (fodInfos
->unicode
)
923 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
925 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
926 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
928 retval
= lstrlenW(lpstrPath
);
931 case CDM_GETFOLDERIDLIST
:
932 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
933 if (retval
<= wParam
)
934 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
938 TRACE("CDM_GETSPEC:\n");
939 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
942 if (fodInfos
->unicode
)
943 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
945 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
949 case CDM_SETCONTROLTEXT
:
950 TRACE("CDM_SETCONTROLTEXT:\n");
953 if( fodInfos
->unicode
)
954 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
956 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
961 case CDM_HIDECONTROL
:
962 /* MSDN states that it should fail for not OFN_EXPLORER case */
963 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
965 HWND control
= GetDlgItem( hwnd
, wParam
);
966 if (control
) ShowWindow( control
, SW_HIDE
);
973 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
974 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
977 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
981 /***********************************************************************
984 * File open dialog procedure
986 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
989 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
996 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
998 /* Adds the FileOpenDlgInfos in the property list of the dialog
999 so it will be easily accessible through a GetPropA(...) */
1000 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1002 FILEDLG95_InitControls(hwnd
);
1004 fodInfos
->DlgInfos
.hwndCustomDlg
=
1005 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1007 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1008 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1010 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1011 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1012 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1016 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1019 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1022 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1028 case WM_GETISHELLBROWSER
:
1029 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1032 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1037 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1040 /* set up the button tooltips strings */
1041 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1043 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1044 switch(lpnmh
->idFrom
)
1046 /* Up folder button */
1047 case FCIDM_TB_UPFOLDER
:
1048 stringId
= IDS_UPFOLDER
;
1050 /* New folder button */
1051 case FCIDM_TB_NEWFOLDER
:
1052 stringId
= IDS_NEWFOLDER
;
1054 /* List option button */
1055 case FCIDM_TB_SMALLICON
:
1056 stringId
= IDS_LISTVIEW
;
1058 /* Details option button */
1059 case FCIDM_TB_REPORTVIEW
:
1060 stringId
= IDS_REPORTVIEW
;
1062 /* Desktop button */
1063 case FCIDM_TB_DESKTOP
:
1064 stringId
= IDS_TODESKTOP
;
1069 lpdi
->hinst
= COMDLG32_hInstance
;
1070 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1075 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1076 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1081 /***********************************************************************
1082 * FILEDLG95_InitControls
1084 * WM_INITDIALOG message handler (before hook notification)
1086 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1088 int win2000plus
= 0;
1090 int handledPath
= FALSE
;
1091 OSVERSIONINFOW osVi
;
1092 static const WCHAR szwSlash
[] = { '\\', 0 };
1093 static const WCHAR szwStar
[] = { '*',0 };
1095 static const TBBUTTON tbb
[] =
1097 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1098 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1099 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1100 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1101 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1102 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1103 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1104 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1105 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1110 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1112 tba
[0].hInst
= HINST_COMMCTRL
;
1113 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1114 tba
[1].hInst
= COMDLG32_hInstance
;
1117 TRACE("%p\n", fodInfos
);
1119 /* Get windows version emulating */
1120 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1121 GetVersionExW(&osVi
);
1122 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1123 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1124 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1125 win2000plus
= (osVi
.dwMajorVersion
> 4);
1126 if (win2000plus
) win98plus
= TRUE
;
1128 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1130 /* Get the hwnd of the controls */
1131 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1132 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1133 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1135 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1136 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1138 /* construct the toolbar */
1139 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1140 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1142 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1143 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1144 rectTB
.left
= rectlook
.right
;
1145 rectTB
.top
= rectlook
.top
-1;
1147 if (fodInfos
->unicode
)
1148 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1149 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1150 rectTB
.left
, rectTB
.top
,
1151 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1152 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1154 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1155 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1156 rectTB
.left
, rectTB
.top
,
1157 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1158 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1160 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1162 /* FIXME: use TB_LOADIMAGES when implemented */
1163 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1164 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
[0]);
1165 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 1, (LPARAM
) &tba
[1]);
1167 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1168 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1170 /* Set the window text with the text specified in the OPENFILENAME structure */
1173 SetWindowTextW(hwnd
,fodInfos
->title
);
1175 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1178 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1179 SetWindowTextW(hwnd
, buf
);
1182 /* Initialise the file name edit control */
1183 handledPath
= FALSE
;
1184 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1186 if(fodInfos
->filename
)
1188 /* 1. If win2000 or higher and filename contains a path, use it
1189 in preference over the lpstrInitialDir */
1190 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1191 WCHAR tmpBuf
[MAX_PATH
];
1195 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1198 /* nameBit is always shorter than the original filename */
1199 lstrcpyW(fodInfos
->filename
,nameBit
);
1202 if (fodInfos
->initdir
== NULL
)
1203 MemFree(fodInfos
->initdir
);
1204 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1205 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1207 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1208 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1210 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1213 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1217 /* 2. (All platforms) If initdir is not null, then use it */
1218 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1219 (*fodInfos
->initdir
!=0x00))
1221 /* Work out the proper path as supplied one might be relative */
1222 /* (Here because supplying '.' as dir browses to My Computer) */
1223 if (handledPath
==FALSE
) {
1224 WCHAR tmpBuf
[MAX_PATH
];
1225 WCHAR tmpBuf2
[MAX_PATH
];
1229 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1230 if( PathFileExistsW(tmpBuf
) ) {
1231 /* initdir does not have to be a directory. If a file is
1232 * specified, the dir part is taken */
1233 if( PathIsDirectoryW(tmpBuf
)) {
1234 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1235 lstrcatW(tmpBuf
, szwSlash
);
1237 lstrcatW(tmpBuf
, szwStar
);
1239 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1242 MemFree(fodInfos
->initdir
);
1243 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1244 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1246 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1249 else if (fodInfos
->initdir
)
1251 MemFree(fodInfos
->initdir
);
1252 fodInfos
->initdir
= NULL
;
1253 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1258 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1259 (*fodInfos
->initdir
==0x00)))
1261 /* 3. All except w2k+: if filename contains a path use it */
1262 if (!win2000plus
&& fodInfos
->filename
&&
1263 *fodInfos
->filename
&&
1264 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1265 WCHAR tmpBuf
[MAX_PATH
];
1269 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1274 /* nameBit is always shorter than the original filename */
1275 lstrcpyW(fodInfos
->filename
, nameBit
);
1278 len
= lstrlenW(tmpBuf
);
1279 MemFree(fodInfos
->initdir
);
1280 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1281 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1284 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1285 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1287 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1290 /* 4. win98+ and win2000+ if any files of specified filter types in
1291 current directory, use it */
1292 if ( win98plus
&& handledPath
== FALSE
&&
1293 fodInfos
->filter
&& *fodInfos
->filter
) {
1295 BOOL searchMore
= TRUE
;
1296 LPCWSTR lpstrPos
= fodInfos
->filter
;
1297 WIN32_FIND_DATAW FindFileData
;
1302 /* filter is a list... title\0ext\0......\0\0 */
1304 /* Skip the title */
1305 if(! *lpstrPos
) break; /* end */
1306 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1308 /* See if any files exist in the current dir with this extension */
1309 if(! *lpstrPos
) break; /* end */
1311 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1313 if (hFind
== INVALID_HANDLE_VALUE
) {
1314 /* None found - continue search */
1315 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1320 MemFree(fodInfos
->initdir
);
1321 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1322 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1325 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1326 debugstr_w(lpstrPos
));
1332 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1334 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1335 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1336 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1338 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1340 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1343 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1344 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1346 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1349 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1352 } else if (handledPath
==FALSE
) {
1353 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1354 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1356 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1359 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1360 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1362 /* Must the open as read only check box be checked ?*/
1363 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1365 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1368 /* Must the open as read only check box be hidden? */
1369 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1371 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1372 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1375 /* Must the help button be hidden? */
1376 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1378 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1379 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1382 /* change Open to Save */
1383 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1386 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1387 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1388 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1389 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1392 /* Initialize the filter combo box */
1393 FILEDLG95_FILETYPE_Init(hwnd
);
1398 /***********************************************************************
1399 * FILEDLG95_ResizeControls
1401 * WM_INITDIALOG message handler (after hook notification)
1403 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1405 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1407 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1410 UINT flags
= SWP_NOACTIVATE
;
1412 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1413 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1415 /* resize the custom dialog to the parent size */
1416 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1417 GetClientRect(hwnd
, &rc
);
1420 /* our own fake template is zero sized and doesn't have children, so
1421 * there is no need to resize it. Picasa depends on it.
1423 flags
|= SWP_NOSIZE
;
1426 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1427 0, 0, rc
.right
, rc
.bottom
, flags
);
1431 /* Resize the height, if open as read only checkbox ad help button are
1432 * hidden and we are not using a custom template nor a customDialog
1434 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1435 (!(fodInfos
->ofnInfos
->Flags
&
1436 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1438 RECT rectDlg
, rectHelp
, rectCancel
;
1439 GetWindowRect(hwnd
, &rectDlg
);
1440 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1441 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1442 /* subtract the height of the help button plus the space between the help
1443 * button and the cancel button to the height of the dialog
1445 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1446 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1447 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1453 /***********************************************************************
1454 * FILEDLG95_FillControls
1456 * WM_INITDIALOG message handler (after hook notification)
1458 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1460 LPITEMIDLIST pidlItemId
= NULL
;
1462 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1464 TRACE("dir=%s file=%s\n",
1465 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1467 /* Get the initial directory pidl */
1469 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1471 WCHAR path
[MAX_PATH
];
1473 GetCurrentDirectoryW(MAX_PATH
,path
);
1474 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1477 /* Initialise shell objects */
1478 FILEDLG95_SHELL_Init(hwnd
);
1480 /* Initialize the Look In combo box */
1481 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1483 /* Browse to the initial directory */
1484 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1486 /* Free pidlItem memory */
1487 COMDLG32_SHFree(pidlItemId
);
1491 /***********************************************************************
1494 * Regroups all the cleaning functions of the filedlg
1496 void FILEDLG95_Clean(HWND hwnd
)
1498 FILEDLG95_FILETYPE_Clean(hwnd
);
1499 FILEDLG95_LOOKIN_Clean(hwnd
);
1500 FILEDLG95_SHELL_Clean(hwnd
);
1502 /***********************************************************************
1503 * FILEDLG95_OnWMCommand
1505 * WM_COMMAND message handler
1507 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1509 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1510 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1511 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1517 FILEDLG95_OnOpen(hwnd
);
1521 FILEDLG95_Clean(hwnd
);
1522 EndDialog(hwnd
, FALSE
);
1524 /* Filetype combo box */
1526 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1528 /* LookIn combo box */
1530 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1533 /* --- toolbar --- */
1534 /* Up folder button */
1535 case FCIDM_TB_UPFOLDER
:
1536 FILEDLG95_SHELL_UpFolder(hwnd
);
1538 /* New folder button */
1539 case FCIDM_TB_NEWFOLDER
:
1540 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1542 /* List option button */
1543 case FCIDM_TB_SMALLICON
:
1544 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1546 /* Details option button */
1547 case FCIDM_TB_REPORTVIEW
:
1548 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1550 /* Details option button */
1551 case FCIDM_TB_DESKTOP
:
1552 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1559 /* Do not use the listview selection anymore */
1560 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1564 /***********************************************************************
1565 * FILEDLG95_OnWMGetIShellBrowser
1567 * WM_GETISHELLBROWSER message handler
1569 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1571 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1575 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1581 /***********************************************************************
1582 * FILEDLG95_SendFileOK
1584 * Sends the CDN_FILEOK notification if required
1587 * TRUE if the dialog should close
1588 * FALSE if the dialog should not be closed
1590 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1592 /* ask the hook if we can close */
1593 if(IsHooked(fodInfos
))
1598 /* First send CDN_FILEOK as MSDN doc says */
1599 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1600 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1602 TRACE("canceled\n");
1603 return (retval
== 0);
1606 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1607 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1608 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1609 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1611 TRACE("canceled\n");
1612 return (retval
== 0);
1618 /***********************************************************************
1619 * FILEDLG95_OnOpenMultipleFiles
1621 * Handles the opening of multiple files.
1624 * check destination buffer size
1626 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1628 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1629 UINT nCount
, nSizePath
;
1630 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1634 if(fodInfos
->unicode
)
1636 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1637 ofn
->lpstrFile
[0] = '\0';
1641 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1642 ofn
->lpstrFile
[0] = '\0';
1645 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1647 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1648 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1649 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1651 LPWSTR lpstrTemp
= lpstrFileList
;
1653 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1657 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1660 WCHAR lpstrNotFound
[100];
1661 WCHAR lpstrMsg
[100];
1663 static const WCHAR nl
[] = {'\n',0};
1665 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1666 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1668 lstrcpyW(tmp
, lpstrTemp
);
1670 lstrcatW(tmp
, lpstrNotFound
);
1672 lstrcatW(tmp
, lpstrMsg
);
1674 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1678 /* move to the next file in the list of files */
1679 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1680 COMDLG32_SHFree(pidl
);
1684 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1685 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1687 /* For "oldstyle" dialog the components have to
1688 be separated by blanks (not '\0'!) and short
1689 filenames have to be used! */
1690 FIXME("Components have to be separated by blanks\n");
1692 if(fodInfos
->unicode
)
1694 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1695 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1696 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1700 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1702 if (ofn
->lpstrFile
!= NULL
)
1704 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1705 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1706 if (ofn
->nMaxFile
> nSizePath
)
1708 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1709 ofn
->lpstrFile
+ nSizePath
,
1710 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1715 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1716 fodInfos
->ofnInfos
->nFileExtension
= 0;
1718 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1721 /* clean and exit */
1722 FILEDLG95_Clean(hwnd
);
1723 return EndDialog(hwnd
,TRUE
);
1726 /***********************************************************************
1729 * Ok button WM_COMMAND message handler
1731 * If the function succeeds, the return value is nonzero.
1733 #define ONOPEN_BROWSE 1
1734 #define ONOPEN_OPEN 2
1735 #define ONOPEN_SEARCH 3
1736 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1738 WCHAR strMsgTitle
[MAX_PATH
];
1739 WCHAR strMsgText
[MAX_PATH
];
1741 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1743 strMsgTitle
[0] = '\0';
1744 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1745 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1748 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1750 LPWSTR lpstrFileList
;
1751 UINT nFileCount
= 0;
1754 WCHAR lpstrPathAndFile
[MAX_PATH
];
1755 WCHAR lpstrTemp
[MAX_PATH
];
1756 LPSHELLFOLDER lpsf
= NULL
;
1758 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1760 TRACE("hwnd=%p\n", hwnd
);
1762 /* get the files from the edit control */
1763 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1765 /* try if the user selected a folder in the shellview */
1768 BrowseSelectedFolder(hwnd
);
1774 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1778 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1781 Step 1: Build a complete path name from the current folder and
1782 the filename or path in the edit box.
1784 - the path in the edit box is a root path
1785 (with or without drive letter)
1786 - the edit box contains ".." (or a path with ".." in it)
1789 /* Get the current directory name */
1790 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1793 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1795 PathAddBackslashW(lpstrPathAndFile
);
1797 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1799 /* if the user specified a fully qualified path use it */
1800 if(PathIsRelativeW(lpstrFileList
))
1802 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
1806 /* does the path have a drive letter? */
1807 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1808 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1810 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
1813 /* resolve "." and ".." */
1814 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1815 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
1816 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1818 MemFree(lpstrFileList
);
1821 Step 2: here we have a cleaned up path
1823 We have to parse the path step by step to see if we have to browse
1824 to a folder if the path points to a directory or the last
1825 valid element is a directory.
1828 lpstrPathAndFile: cleaned up path
1832 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1833 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
1834 nOpenAction
= ONOPEN_OPEN
;
1836 nOpenAction
= ONOPEN_BROWSE
;
1838 /* don't apply any checks with OFN_NOVALIDATE */
1840 LPWSTR lpszTemp
, lpszTemp1
;
1841 LPITEMIDLIST pidl
= NULL
;
1842 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1844 /* check for invalid chars */
1845 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1847 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1852 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1854 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1857 LPSHELLFOLDER lpsfChild
;
1858 WCHAR lpwstrTemp
[MAX_PATH
];
1859 DWORD dwEaten
, dwAttributes
;
1862 lstrcpyW(lpwstrTemp
, lpszTemp
);
1863 p
= PathFindNextComponentW(lpwstrTemp
);
1865 if (!p
) break; /* end of path */
1868 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
1870 /* There are no wildcards when OFN_NOVALIDATE is set */
1871 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1873 static const WCHAR wszWild
[] = { '*', '?', 0 };
1874 /* if the last element is a wildcard do a search */
1875 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1877 nOpenAction
= ONOPEN_SEARCH
;
1881 lpszTemp1
= lpszTemp
;
1883 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1885 /* append a backslash to drive letters */
1886 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1887 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1888 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1890 PathAddBackslashW(lpwstrTemp
);
1893 dwAttributes
= SFGAO_FOLDER
;
1894 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1896 /* the path component is valid, we have a pidl of the next path component */
1897 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
1898 if(dwAttributes
& SFGAO_FOLDER
)
1900 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1902 ERR("bind to failed\n"); /* should not fail */
1905 IShellFolder_Release(lpsf
);
1913 /* end dialog, return value */
1914 nOpenAction
= ONOPEN_OPEN
;
1917 COMDLG32_SHFree(pidl
);
1920 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1922 if(*lpszTemp
|| /* points to trailing null for last path element */
1923 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
1925 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1927 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1933 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1934 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1936 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1940 /* change to the current folder */
1941 nOpenAction
= ONOPEN_OPEN
;
1946 nOpenAction
= ONOPEN_OPEN
;
1950 if(pidl
) COMDLG32_SHFree(pidl
);
1954 Step 3: here we have a cleaned up and validated path
1957 lpsf: ShellFolder bound to the rightmost valid path component
1958 lpstrPathAndFile: cleaned up path
1959 nOpenAction: action to do
1961 TRACE("end validate sf=%p\n", lpsf
);
1965 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1966 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1969 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1972 /* replace the current filter */
1973 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1974 len
= lstrlenW(lpszTemp
)+1;
1975 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1976 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1978 /* set the filter cb to the extension when possible */
1979 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1980 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1983 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1984 TRACE("ONOPEN_BROWSE\n");
1986 IPersistFolder2
* ppf2
;
1987 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1989 LPITEMIDLIST pidlCurrent
;
1990 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1991 IPersistFolder2_Release(ppf2
);
1992 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1994 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
)))
1996 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
1999 else if( nOpenAction
== ONOPEN_SEARCH
)
2001 if (fodInfos
->Shell
.FOIShellView
)
2002 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2004 COMDLG32_SHFree(pidlCurrent
);
2005 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2010 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2011 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2015 /* update READONLY check box flag */
2016 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2017 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2019 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2021 /* Attach the file extension with file name*/
2022 ext
= PathFindExtensionW(lpstrPathAndFile
);
2025 /* if no extension is specified with file name, then */
2026 /* attach the extension from file filter or default one */
2028 WCHAR
*filterExt
= NULL
;
2029 LPWSTR lpstrFilter
= NULL
;
2030 static const WCHAR szwDot
[] = {'.',0};
2031 int PathLength
= lstrlenW(lpstrPathAndFile
);
2034 lstrcatW(lpstrPathAndFile
, szwDot
);
2036 /*Get the file extension from file type filter*/
2037 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2038 fodInfos
->ofnInfos
->nFilterIndex
-1);
2040 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2041 filterExt
= PathFindExtensionW(lpstrFilter
);
2043 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2044 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2045 else if ( fodInfos
->defext
) /* attach the default file extension*/
2046 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2048 /* In Open dialog: if file does not exist try without extension */
2049 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2050 lpstrPathAndFile
[PathLength
] = '\0';
2053 if (fodInfos
->defext
) /* add default extension */
2055 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2058 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2059 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2061 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2064 /* In Save dialog: check if the file already exists */
2065 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2066 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2067 && PathFileExistsW(lpstrPathAndFile
))
2069 WCHAR lpstrOverwrite
[100];
2072 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2073 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2074 MB_YESNO
| MB_ICONEXCLAMATION
);
2082 /* In Open dialog: check if it should be created if it doesn't exist */
2083 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2084 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2085 && !PathFileExistsW(lpstrPathAndFile
))
2087 WCHAR lpstrCreate
[100];
2090 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2091 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2092 MB_YESNO
| MB_ICONEXCLAMATION
);
2100 /* Check that the size of the file does not exceed buffer size.
2101 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2102 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2103 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2106 /* fill destination buffer */
2107 if (fodInfos
->ofnInfos
->lpstrFile
)
2109 if(fodInfos
->unicode
)
2111 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2113 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2114 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2115 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2119 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2121 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2122 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2123 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2124 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2128 if(fodInfos
->unicode
)
2132 /* set filename offset */
2133 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2134 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2136 /* set extension offset */
2137 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2138 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2143 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2145 /* set filename offset */
2146 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2147 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2149 /* set extension offset */
2150 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2151 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2154 /* set the lpstrFileTitle */
2155 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2157 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2158 if(fodInfos
->unicode
)
2160 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2161 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2165 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2166 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2167 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2171 /* copy currently selected filter to lpstrCustomFilter */
2172 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2174 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2175 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2176 NULL
, 0, NULL
, NULL
);
2177 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2179 LPSTR s
= ofn
->lpstrCustomFilter
;
2180 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2181 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2182 s
, len
, NULL
, NULL
);
2187 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2191 FILEDLG95_Clean(hwnd
);
2192 ret
= EndDialog(hwnd
, TRUE
);
2198 size
= lstrlenW(lpstrPathAndFile
) + 1;
2199 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2201 /* return needed size in first two bytes of lpstrFile */
2202 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2203 FILEDLG95_Clean(hwnd
);
2204 ret
= EndDialog(hwnd
, FALSE
);
2205 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2212 if(lpsf
) IShellFolder_Release(lpsf
);
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_Init
2219 * Initialisation of the shell objects
2221 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2223 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2228 * Initialisation of the FileOpenDialogInfos structure
2234 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2236 /* Disable multi-select if flag not set */
2237 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2239 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2241 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2242 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2244 /* Construct the IShellBrowser interface */
2245 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2250 /***********************************************************************
2251 * FILEDLG95_SHELL_ExecuteCommand
2253 * Change the folder option and refresh the view
2254 * If the function succeeds, the return value is nonzero.
2256 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2258 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2261 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2263 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2268 CMINVOKECOMMANDINFO ci
;
2269 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2270 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2274 IContextMenu_InvokeCommand(pcm
, &ci
);
2275 IContextMenu_Release(pcm
);
2281 /***********************************************************************
2282 * FILEDLG95_SHELL_UpFolder
2284 * Browse to the specified object
2285 * If the function succeeds, the return value is nonzero.
2287 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2289 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2293 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2297 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2303 /***********************************************************************
2304 * FILEDLG95_SHELL_BrowseToDesktop
2306 * Browse to the Desktop
2307 * If the function succeeds, the return value is nonzero.
2309 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2311 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2317 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2318 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2319 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2320 COMDLG32_SHFree(pidl
);
2321 return SUCCEEDED(hres
);
2323 /***********************************************************************
2324 * FILEDLG95_SHELL_Clean
2326 * Cleans the memory used by shell objects
2328 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2330 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2334 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2336 /* clean Shell interfaces */
2337 if (fodInfos
->Shell
.FOIShellView
)
2339 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2340 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2342 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2343 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2344 if (fodInfos
->Shell
.FOIDataObject
)
2345 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2348 /***********************************************************************
2349 * FILEDLG95_FILETYPE_Init
2351 * Initialisation of the file type combo box
2353 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2355 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2356 int nFilters
= 0; /* number of filters */
2361 if(fodInfos
->customfilter
)
2363 /* customfilter has one entry... title\0ext\0
2364 * Set first entry of combo box item with customfilter
2367 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2370 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2372 /* Copy the extensions */
2373 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2374 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2375 lstrcpyW(lpstrExt
,lpstrPos
);
2377 /* Add the item at the end of the combo */
2378 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2379 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2382 if(fodInfos
->filter
)
2384 LPCWSTR lpstrPos
= fodInfos
->filter
;
2388 /* filter is a list... title\0ext\0......\0\0
2389 * Set the combo item text to the title and the item data
2392 LPCWSTR lpstrDisplay
;
2396 if(! *lpstrPos
) break; /* end */
2397 lpstrDisplay
= lpstrPos
;
2398 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2400 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2404 /* Copy the extensions */
2405 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2406 lstrcpyW(lpstrExt
,lpstrPos
);
2407 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2409 /* Add the item at the end of the combo */
2410 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2412 /* malformed filters are added anyway... */
2413 if (!*lpstrExt
) break;
2418 * Set the current filter to the one specified
2419 * in the initialisation structure
2421 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2425 /* Check to make sure our index isn't out of bounds. */
2426 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2427 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2428 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2430 /* set default filter index */
2431 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2432 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2434 /* calculate index of Combo Box item */
2435 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2436 if (fodInfos
->customfilter
== NULL
)
2439 /* Set the current index selection. */
2440 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2442 /* Get the corresponding text string from the combo box. */
2443 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2446 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2452 CharLowerW(lpstrFilter
); /* lowercase */
2453 len
= lstrlenW(lpstrFilter
)+1;
2454 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2455 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2458 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2462 /***********************************************************************
2463 * FILEDLG95_FILETYPE_OnCommand
2465 * WM_COMMAND of the file type combo box
2466 * If the function succeeds, the return value is nonzero.
2468 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2470 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2478 /* Get the current item of the filetype combo box */
2479 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2481 /* set the current filter index */
2482 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2483 (fodInfos
->customfilter
== NULL
? 1 : 0);
2485 /* Set the current filter with the current selection */
2486 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2488 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2490 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2493 CharLowerW(lpstrFilter
); /* lowercase */
2494 len
= lstrlenW(lpstrFilter
)+1;
2495 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2496 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2497 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2500 /* Refresh the actual view to display the included items*/
2501 if (fodInfos
->Shell
.FOIShellView
)
2502 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2507 /***********************************************************************
2508 * FILEDLG95_FILETYPE_SearchExt
2510 * searches for an extension in the filetype box
2512 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2514 int i
, iCount
= CBGetCount(hwnd
);
2516 TRACE("%s\n", debugstr_w(lpstrExt
));
2518 if(iCount
!= CB_ERR
)
2520 for(i
=0;i
<iCount
;i
++)
2522 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2529 /***********************************************************************
2530 * FILEDLG95_FILETYPE_Clean
2532 * Clean the memory used by the filetype combo box
2534 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2536 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2538 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2542 /* Delete each string of the combo and their associated data */
2543 if(iCount
!= CB_ERR
)
2545 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2547 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2548 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2551 /* Current filter */
2552 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2556 /***********************************************************************
2557 * FILEDLG95_LOOKIN_Init
2559 * Initialisation of the look in combo box
2562 /* Small helper function, to determine if the unixfs shell extension is rooted
2563 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2565 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2567 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2568 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2569 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2570 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2571 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2572 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2573 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2575 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2582 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2584 IShellFolder
*psfRoot
, *psfDrives
;
2585 IEnumIDList
*lpeRoot
, *lpeDrives
;
2586 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2588 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2592 liInfos
->iMaxIndentation
= 0;
2594 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
2596 /* set item height for both text field and listbox */
2597 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2598 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2600 /* Turn on the extended UI for the combo box like Windows does */
2601 CBSetExtendedUI(hwndCombo
, TRUE
);
2603 /* Initialise data of Desktop folder */
2604 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2605 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2606 COMDLG32_SHFree(pidlTmp
);
2608 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2610 SHGetDesktopFolder(&psfRoot
);
2614 /* enumerate the contents of the desktop */
2615 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2617 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2619 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2621 /* If the unixfs extension is rooted, we don't expand the drives by default */
2622 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2624 /* special handling for CSIDL_DRIVES */
2625 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2627 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2629 /* enumerate the drives */
2630 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2632 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2634 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2635 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2636 COMDLG32_SHFree(pidlAbsTmp
);
2637 COMDLG32_SHFree(pidlTmp1
);
2639 IEnumIDList_Release(lpeDrives
);
2641 IShellFolder_Release(psfDrives
);
2646 COMDLG32_SHFree(pidlTmp
);
2648 IEnumIDList_Release(lpeRoot
);
2650 IShellFolder_Release(psfRoot
);
2653 COMDLG32_SHFree(pidlDrives
);
2656 /***********************************************************************
2657 * FILEDLG95_LOOKIN_DrawItem
2659 * WM_DRAWITEM message handler
2661 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2663 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2664 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2665 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2669 HIMAGELIST ilItemImage
;
2672 LPSFOLDER tmpFolder
;
2673 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2677 if(pDIStruct
->itemID
== -1)
2680 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2681 pDIStruct
->itemID
)))
2685 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2687 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2691 SHGFI_PIDL
| SHGFI_SMALLICON
|
2692 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2693 SHGFI_DISPLAYNAME
);
2697 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2701 SHGFI_PIDL
| SHGFI_SMALLICON
|
2702 SHGFI_SYSICONINDEX
|
2706 /* Is this item selected ? */
2707 if(pDIStruct
->itemState
& ODS_SELECTED
)
2709 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2710 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2711 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2715 SetTextColor(pDIStruct
->hDC
,crText
);
2716 SetBkColor(pDIStruct
->hDC
,crWin
);
2717 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2720 /* Do not indent item if drawing in the edit of the combo */
2721 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2724 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2728 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2729 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2734 iIndentation
= tmpFolder
->m_iIndent
;
2736 /* Draw text and icon */
2738 /* Initialise the icon display area */
2739 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2740 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2741 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2742 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2744 /* Initialise the text display area */
2745 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2746 rectText
.left
= rectIcon
.right
;
2748 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2749 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2751 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2753 /* Draw the icon from the image list */
2754 ImageList_Draw(ilItemImage
,
2761 /* Draw the associated text */
2762 if(sfi
.szDisplayName
)
2763 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
2769 /***********************************************************************
2770 * FILEDLG95_LOOKIN_OnCommand
2772 * LookIn combo box WM_COMMAND message handler
2773 * If the function succeeds, the return value is nonzero.
2775 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2777 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2779 TRACE("%p\n", fodInfos
);
2785 LPSFOLDER tmpFolder
;
2788 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2790 if( iItem
== CB_ERR
) return FALSE
;
2792 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2797 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2798 tmpFolder
->pidlItem
,
2801 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2811 /***********************************************************************
2812 * FILEDLG95_LOOKIN_AddItem
2814 * Adds an absolute pidl item to the lookin combo box
2815 * returns the index of the inserted item
2817 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2819 LPITEMIDLIST pidlNext
;
2822 LookInInfos
*liInfos
;
2824 TRACE("%08x\n", iInsertId
);
2829 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
2832 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2833 tmpFolder
->m_iIndent
= 0;
2835 /* Calculate the indentation of the item in the lookin*/
2837 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2839 tmpFolder
->m_iIndent
++;
2842 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2844 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2845 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2847 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2848 SHGetFileInfoW((LPCWSTR
)pidl
,
2852 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2853 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2855 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
2857 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2861 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
2863 /* Add the item at the end of the list */
2866 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2868 /* Insert the item at the iInsertId position*/
2871 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2874 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2878 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2879 MemFree( tmpFolder
);
2884 /***********************************************************************
2885 * FILEDLG95_LOOKIN_InsertItemAfterParent
2887 * Insert an item below its parent
2889 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2892 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2897 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2901 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2904 /* Free pidlParent memory */
2905 COMDLG32_SHFree(pidlParent
);
2907 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2910 /***********************************************************************
2911 * FILEDLG95_LOOKIN_SelectItem
2913 * Adds an absolute pidl item to the lookin combo box
2914 * returns the index of the inserted item
2916 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2919 LookInInfos
*liInfos
;
2923 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2925 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
2929 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2930 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2935 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2936 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2940 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2942 if(iRemovedItem
< iItemPos
)
2947 CBSetCurSel(hwnd
,iItemPos
);
2948 liInfos
->uSelectedItem
= iItemPos
;
2954 /***********************************************************************
2955 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2957 * Remove the item with an expansion level over iExpansionLevel
2959 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2962 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
2966 if(liInfos
->iMaxIndentation
<= 2)
2969 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2971 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2972 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2974 CBDeleteString(hwnd
,iItemPos
);
2975 liInfos
->iMaxIndentation
--;
2983 /***********************************************************************
2984 * FILEDLG95_LOOKIN_SearchItem
2986 * Search for pidl in the lookin combo box
2987 * returns the index of the found item
2989 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2992 int iCount
= CBGetCount(hwnd
);
2994 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
2996 if (iCount
!= CB_ERR
)
3000 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3002 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3004 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3012 /***********************************************************************
3013 * FILEDLG95_LOOKIN_Clean
3015 * Clean the memory used by the lookin combo box
3017 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3019 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3021 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3025 /* Delete each string of the combo and their associated data */
3026 if (iCount
!= CB_ERR
)
3028 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3030 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3031 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3033 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3037 /* LookInInfos structure */
3038 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3041 /***********************************************************************
3042 * FILEDLG95_FILENAME_FillFromSelection
3044 * fills the edit box from the cached DataObject
3046 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3048 FileOpenDlgInfos
*fodInfos
;
3050 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3051 WCHAR lpstrTemp
[MAX_PATH
];
3052 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3055 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3057 /* Count how many files we have */
3058 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3060 /* calculate the string length, count files */
3061 if (nFileSelected
>= 1)
3063 nLength
+= 3; /* first and last quotes, trailing \0 */
3064 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3066 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3070 /* get the total length of the selected file names */
3071 lpstrTemp
[0] = '\0';
3072 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3074 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3076 nLength
+= lstrlenW( lpstrTemp
) + 3;
3079 COMDLG32_SHFree( pidl
);
3084 /* allocate the buffer */
3085 if (nFiles
<= 1) nLength
= MAX_PATH
;
3086 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3088 /* Generate the string for the edit control */
3091 lpstrCurrFile
= lpstrAllFile
;
3092 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3094 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3098 /* get the file name */
3099 lpstrTemp
[0] = '\0';
3100 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3102 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3106 *lpstrCurrFile
++ = '\"';
3107 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3108 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3109 *lpstrCurrFile
++ = '\"';
3110 *lpstrCurrFile
++ = ' ';
3115 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3118 COMDLG32_SHFree( pidl
);
3121 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3123 /* Select the file name like Windows does */
3124 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3126 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3130 /* copied from shell32 to avoid linking to it
3131 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3132 * is dependent on whether emulated OS is unicode or not.
3134 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3139 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3140 COMDLG32_SHFree(src
->u
.pOleStr
);
3144 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3149 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3154 FIXME("unknown type %x!\n", src
->uType
);
3155 if (len
) *dest
= '\0';
3161 /***********************************************************************
3162 * FILEDLG95_FILENAME_GetFileNames
3164 * Copies the filenames to a delimited string list.
3165 * The delimiter is specified by the parameter 'separator',
3166 * usually either a space or a nul
3168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3170 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3171 UINT nStrCharCount
= 0; /* index in src buffer */
3172 UINT nFileIndex
= 0; /* index in dest buffer */
3173 UINT nFileCount
= 0; /* number of files */
3174 UINT nStrLen
= 0; /* length of string in edit control */
3175 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3179 /* get the filenames from the edit control */
3180 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3181 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3182 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3184 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3186 /* we might get single filename without any '"',
3187 * so we need nStrLen + terminating \0 + end-of-list \0 */
3188 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3191 /* build delimited file list from filenames */
3192 while ( nStrCharCount
<= nStrLen
)
3194 if ( lpstrEdit
[nStrCharCount
]=='"' )
3197 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3199 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3202 (*lpstrFileList
)[nFileIndex
++] = 0;
3208 /* single, unquoted string */
3209 if ((nStrLen
> 0) && (nFileIndex
== 0) )
3211 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3212 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3217 (*lpstrFileList
)[nFileIndex
++] = '\0';
3219 *sizeUsed
= nFileIndex
;
3224 #define SETDefFormatEtc(fe,cf,med) \
3226 (fe).cfFormat = cf;\
3227 (fe).dwAspect = DVASPECT_CONTENT; \
3234 * DATAOBJECT Helper functions
3237 /***********************************************************************
3238 * COMCTL32_ReleaseStgMedium
3240 * like ReleaseStgMedium from ole32
3242 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3244 if(medium
.pUnkForRelease
)
3246 IUnknown_Release(medium
.pUnkForRelease
);
3250 GlobalUnlock(medium
.u
.hGlobal
);
3251 GlobalFree(medium
.u
.hGlobal
);
3255 /***********************************************************************
3256 * GetPidlFromDataObject
3258 * Return pidl(s) by number from the cached DataObject
3260 * nPidlIndex=0 gets the fully qualified root path
3262 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3266 FORMATETC formatetc
;
3267 LPITEMIDLIST pidl
= NULL
;
3269 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3274 /* Set the FORMATETC structure*/
3275 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3277 /* Get the pidls from IDataObject */
3278 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3280 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3281 if(nPidlIndex
<= cida
->cidl
)
3283 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3285 COMCTL32_ReleaseStgMedium(medium
);
3290 /***********************************************************************
3293 * Return the number of selected items in the DataObject.
3296 static UINT
GetNumSelected( IDataObject
*doSelected
)
3300 FORMATETC formatetc
;
3302 TRACE("sv=%p\n", doSelected
);
3304 if (!doSelected
) return 0;
3306 /* Set the FORMATETC structure*/
3307 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3309 /* Get the pidls from IDataObject */
3310 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3312 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3313 retVal
= cida
->cidl
;
3314 COMCTL32_ReleaseStgMedium(medium
);
3324 /***********************************************************************
3327 * Get the pidl's display name (relative to folder) and
3328 * put it in lpstrFileName.
3330 * Return NOERROR on success,
3334 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3339 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3343 SHGetDesktopFolder(&lpsf
);
3344 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3345 IShellFolder_Release(lpsf
);
3349 /* Get the display name of the pidl relative to the folder */
3350 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3352 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3357 /***********************************************************************
3358 * GetShellFolderFromPidl
3360 * pidlRel is the item pidl relative
3361 * Return the IShellFolder of the absolute pidl
3363 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3365 IShellFolder
*psf
= NULL
,*psfParent
;
3367 TRACE("%p\n", pidlAbs
);
3369 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3372 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3374 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3376 IShellFolder_Release(psfParent
);
3380 /* return the desktop */
3386 /***********************************************************************
3389 * Return the LPITEMIDLIST to the parent of the pidl in the list
3391 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3393 LPITEMIDLIST pidlParent
;
3395 TRACE("%p\n", pidl
);
3397 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3398 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3403 /***********************************************************************
3406 * returns the pidl of the file name relative to folder
3407 * NULL if an error occurred
3409 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3411 LPITEMIDLIST pidl
= NULL
;
3414 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3416 if(!lpcstrFileName
) return NULL
;
3417 if(!*lpcstrFileName
) return NULL
;
3421 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3422 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3423 IShellFolder_Release(lpsf
);
3428 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3435 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3437 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3440 TRACE("%p, %p\n", psf
, pidl
);
3442 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3444 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3445 /* see documentation shell 4.1*/
3446 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3449 /***********************************************************************
3450 * BrowseSelectedFolder
3452 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3454 BOOL bBrowseSelFolder
= FALSE
;
3455 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3459 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3461 LPITEMIDLIST pidlSelection
;
3463 /* get the file selected */
3464 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3465 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3467 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3468 pidlSelection
, SBSP_RELATIVE
) ) )
3470 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3471 ' ','n','o','t',' ','e','x','i','s','t',0};
3472 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3474 bBrowseSelFolder
= TRUE
;
3475 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3477 COMDLG32_SHFree( pidlSelection
);
3480 return bBrowseSelFolder
;
3484 * Memory allocation methods */
3485 static void *MemAlloc(UINT size
)
3487 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3490 static void MemFree(void *mem
)
3492 HeapFree(GetProcessHeap(),0,mem
);
3496 * Old-style (win3.1) dialogs */
3498 /***********************************************************************
3499 * FD32_GetTemplate [internal]
3501 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3502 * by a 32 bits application
3505 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3507 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3508 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3511 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3513 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3515 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3519 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3523 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3524 priv
->ofnA
->lpTemplateName
,
3527 hResInfo
= FindResourceW(ofnW
->hInstance
,
3528 ofnW
->lpTemplateName
,
3532 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3535 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3537 !(lfs
->template = LockResource(hDlgTmpl
)))
3539 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3542 } else { /* get it from internal Wine resource */
3544 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3545 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3547 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3550 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3551 !(lfs
->template = LockResource( hDlgTmpl
)))
3553 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3561 /************************************************************************
3562 * FD32_Init [internal]
3563 * called from the common 16/32 code to initialize 32 bit data
3565 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3567 BOOL IsUnicode
= (BOOL
) data
;
3570 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3571 lfs
->private1632
= priv
;
3572 if (NULL
== lfs
->private1632
) return FALSE
;
3575 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3576 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3577 if (lfs
->ofnW
->lpfnHook
)
3582 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3583 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3584 if (priv
->ofnA
->lpfnHook
)
3586 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3587 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3590 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3595 /***********************************************************************
3596 * FD32_CallWindowProc [internal]
3598 * called from the common 16/32 code to call the appropriate hook
3600 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3604 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3608 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3609 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3610 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3611 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3612 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3616 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3617 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3618 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3619 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3620 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3624 /***********************************************************************
3625 * FD32_UpdateResult [internal]
3626 * update the real client structures if any
3628 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3630 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3631 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3636 if (ofnW
->nMaxFile
&&
3637 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3638 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3639 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3641 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3642 /* set filename offset */
3643 lpszTemp
= PathFindFileNameA(priv
->ofnA
->lpstrFile
);
3644 priv
->ofnA
->nFileOffset
= (lpszTemp
- priv
->ofnA
->lpstrFile
);
3646 /* set extension offset */
3647 lpszTemp
= PathFindExtensionA(priv
->ofnA
->lpstrFile
);
3648 priv
->ofnA
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- priv
->ofnA
->lpstrFile
) + 1 : 0;
3652 /***********************************************************************
3653 * FD32_UpdateFileTitle [internal]
3654 * update the real client structures if any
3656 static void CALLBACK
FD32_UpdateFileTitle(const FD31_DATA
*lfs
)
3658 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3659 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3663 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3664 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3665 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3670 /***********************************************************************
3671 * FD32_SendLbGetCurSel [internal]
3672 * retrieve selected listbox item
3674 static LRESULT CALLBACK
FD32_SendLbGetCurSel(const FD31_DATA
*lfs
)
3676 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3680 /************************************************************************
3681 * FD32_Destroy [internal]
3682 * called from the common 16/32 code to cleanup 32 bit data
3684 static void CALLBACK
FD32_Destroy(const FD31_DATA
*lfs
)
3686 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3688 /* if ofnW has been allocated, have to free everything in it */
3689 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3691 FD31_FreeOfnW(lfs
->ofnW
);
3692 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3696 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3698 callbacks
->Init
= FD32_Init
;
3699 callbacks
->CWP
= FD32_CallWindowProc
;
3700 callbacks
->UpdateResult
= FD32_UpdateResult
;
3701 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3702 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3703 callbacks
->Destroy
= FD32_Destroy
;
3706 /***********************************************************************
3707 * FD32_WMMeasureItem [internal]
3709 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3711 LPMEASUREITEMSTRUCT lpmeasure
;
3713 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3714 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3719 /***********************************************************************
3720 * FileOpenDlgProc [internal]
3721 * Used for open and save, in fact.
3723 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3724 WPARAM wParam
, LPARAM lParam
)
3726 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3728 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
3729 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3732 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3734 return lRet
; /* else continue message processing */
3739 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3741 case WM_MEASUREITEM
:
3742 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3745 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3748 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3751 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3752 switch (HIWORD(lParam
))
3755 SetTextColor((HDC16
)wParam
, 0x00000000);
3757 case CTLCOLOR_STATIC
:
3758 SetTextColor((HDC16
)wParam
, 0x00000000);
3768 /***********************************************************************
3769 * GetFileName31A [internal]
3771 * Creates a win31 style dialog box for the user to select a file to open/save.
3773 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
3774 UINT dlgType
/* type dialogue : open/save */
3780 FD31_CALLBACKS callbacks
;
3782 if (!lpofn
|| !FD31_Init()) return FALSE
;
3784 TRACE("ofn flags %08x\n", lpofn
->Flags
);
3785 FD32_SetupCallbacks(&callbacks
);
3786 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3789 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3790 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3791 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3792 FD31_DestroyPrivate(lfs
);
3795 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3799 /***********************************************************************
3800 * GetFileName31W [internal]
3802 * Creates a win31 style dialog box for the user to select a file to open/save
3804 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
3805 UINT dlgType
/* type dialogue : open/save */
3811 FD31_CALLBACKS callbacks
;
3813 if (!lpofn
|| !FD31_Init()) return FALSE
;
3815 FD32_SetupCallbacks(&callbacks
);
3816 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3819 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3820 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3821 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3822 FD31_DestroyPrivate(lfs
);
3825 TRACE("file %s, file offset %d, ext offset %d\n",
3826 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3830 /* ------------------ APIs ---------------------- */
3832 /***********************************************************************
3833 * GetOpenFileNameA (COMDLG32.@)
3835 * Creates a dialog box for the user to select a file to open.
3838 * TRUE on success: user enters a valid file
3839 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3842 BOOL WINAPI
GetOpenFileNameA(
3843 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3845 BOOL win16look
= FALSE
;
3847 TRACE("flags %08x\n", ofn
->Flags
);
3849 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3850 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3851 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3853 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3854 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3857 return GetFileName31A(ofn
, OPEN_DIALOG
);
3859 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3862 /***********************************************************************
3863 * GetOpenFileNameW (COMDLG32.@)
3865 * Creates a dialog box for the user to select a file to open.
3868 * TRUE on success: user enters a valid file
3869 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3872 BOOL WINAPI
GetOpenFileNameW(
3873 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3875 BOOL win16look
= FALSE
;
3877 TRACE("flags %08x\n", ofn
->Flags
);
3879 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3880 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3881 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3883 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3884 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3887 return GetFileName31W(ofn
, OPEN_DIALOG
);
3889 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3893 /***********************************************************************
3894 * GetSaveFileNameA (COMDLG32.@)
3896 * Creates a dialog box for the user to select a file to save.
3899 * TRUE on success: user enters a valid file
3900 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3903 BOOL WINAPI
GetSaveFileNameA(
3904 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3906 BOOL win16look
= FALSE
;
3908 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3909 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3912 return GetFileName31A(ofn
, SAVE_DIALOG
);
3914 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3917 /***********************************************************************
3918 * GetSaveFileNameW (COMDLG32.@)
3920 * Creates a dialog box for the user to select a file to save.
3923 * TRUE on success: user enters a valid file
3924 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3927 BOOL WINAPI
GetSaveFileNameW(
3928 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3930 BOOL win16look
= FALSE
;
3932 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3933 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3936 return GetFileName31W(ofn
, SAVE_DIALOG
);
3938 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
3941 /***********************************************************************
3942 * GetFileTitleA (COMDLG32.@)
3944 * See GetFileTitleW.
3946 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
3949 UNICODE_STRING strWFile
;
3952 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
3953 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
3954 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
3955 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
3956 RtlFreeUnicodeString( &strWFile
);
3957 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
3962 /***********************************************************************
3963 * GetFileTitleW (COMDLG32.@)
3965 * Get the name of a file.
3968 * lpFile [I] name and location of file
3969 * lpTitle [O] returned file name
3970 * cbBuf [I] buffer size of lpTitle
3974 * Failure: negative number.
3976 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
3979 static const WCHAR brkpoint
[] = {'*','[',']',0};
3980 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
3982 if(lpFile
== NULL
|| lpTitle
== NULL
)
3985 len
= lstrlenW(lpFile
);
3990 if(strpbrkW(lpFile
, brkpoint
))
3995 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
3998 for(i
= len
; i
>= 0; i
--)
4000 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4010 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4012 len
= lstrlenW(lpFile
+i
)+1;
4016 lstrcpyW(lpTitle
, &lpFile
[i
]);