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_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
73 #include "filedlg31.h"
77 #include "filedlgbrowser.h"
80 #include "wine/unicode.h"
81 #include "wine/debug.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex
; /* Index of picture in image list */
100 int m_iIndent
; /* Indentation index */
101 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
103 } SFOLDER
,*LPSFOLDER
;
105 typedef struct tagLookInInfo
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE
, *PFD32_PRIVATE
;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
145 #define CBInsertString(hwnd,str,pos) \
146 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
148 #define CBDeleteString(hwnd,pos) \
149 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
151 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
152 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
154 #define CBGetItemDataPtr(hwnd,iItemId) \
155 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
157 #define CBGetLBText(hwnd,iItemId,str) \
158 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
160 #define CBGetCurSel(hwnd) \
161 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
163 #define CBSetCurSel(hwnd,pos) \
164 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
166 #define CBGetCount(hwnd) \
167 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
168 #define CBShowDropDown(hwnd,show) \
169 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
170 #define CBSetItemHeight(hwnd,index,height) \
171 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
173 #define CBSetExtendedUI(hwnd,flag) \
174 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
176 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
177 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
179 /***********************************************************************
183 /* Internal functions used by the dialog */
184 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
185 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
186 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
187 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
188 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
189 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
190 static void FILEDLG95_Clean(HWND hwnd
);
192 /* Functions used by the shell navigation */
193 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
197 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
);
202 /* Functions used by the filetype combo box */
203 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
204 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
210 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
211 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
219 /* Miscellaneous tool functions */
220 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
221 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
222 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
223 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
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 WINAPI
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
,
294 (LPCDLGTEMPLATEA
) template,
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 BOOL WINAPI
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 BOOL WINAPI
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;
827 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
829 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
831 if(!fodInfos
) return 0;
833 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
835 TRACE("CALL NOTIFY for %x\n", uCode
);
836 if(fodInfos
->unicode
)
839 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
840 ofnNotify
.hdr
.idFrom
=0;
841 ofnNotify
.hdr
.code
= uCode
;
842 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
843 ofnNotify
.pszFile
= NULL
;
844 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
849 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
850 ofnNotify
.hdr
.idFrom
=0;
851 ofnNotify
.hdr
.code
= uCode
;
852 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
853 ofnNotify
.pszFile
= NULL
;
854 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
856 TRACE("RET NOTIFY\n");
858 TRACE("Retval: 0x%08lx\n", hook_result
);
862 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
864 UINT sizeUsed
= 0, n
, total
;
865 LPWSTR lpstrFileList
= NULL
;
866 WCHAR lpstrCurrentDir
[MAX_PATH
];
867 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
869 TRACE("CDM_GETFILEPATH:\n");
871 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
874 /* get path and filenames */
875 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrCurrentDir
);
876 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
878 TRACE("path >%s< filespec >%s< %d files\n",
879 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
881 if( fodInfos
->unicode
)
883 LPWSTR bufW
= buffer
;
884 total
= lstrlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
886 /* Prepend the current path */
887 n
= lstrlenW(lpstrCurrentDir
) + 1;
888 memcpy( bufW
, lpstrCurrentDir
, min(n
,size
) * sizeof(WCHAR
));
891 /* 'n' includes trailing \0 */
893 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
895 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
900 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
901 NULL
, 0, NULL
, NULL
);
902 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
903 NULL
, 0, NULL
, NULL
);
905 /* Prepend the current path */
906 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
907 bufA
, size
, NULL
, NULL
);
911 /* 'n' includes trailing \0 */
913 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
914 &bufA
[n
], size
-n
, NULL
, NULL
);
917 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
919 MemFree(lpstrFileList
);
924 static INT_PTR
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
927 LPWSTR lpstrFileList
= NULL
;
928 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
930 TRACE("CDM_GETSPEC:\n");
932 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
933 if( fodInfos
->unicode
)
935 LPWSTR bufW
= buffer
;
936 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
941 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
942 NULL
, 0, NULL
, NULL
);
943 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
944 bufA
, size
, NULL
, NULL
);
946 MemFree(lpstrFileList
);
951 /***********************************************************************
952 * FILEDLG95_HandleCustomDialogMessages
954 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
956 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
958 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
959 WCHAR lpstrPath
[MAX_PATH
];
962 if(!fodInfos
) return FALSE
;
966 case CDM_GETFILEPATH
:
967 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
970 case CDM_GETFOLDERPATH
:
971 TRACE("CDM_GETFOLDERPATH:\n");
972 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
975 if (fodInfos
->unicode
)
976 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
978 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
979 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
981 retval
= lstrlenW(lpstrPath
);
985 retval
= FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
988 case CDM_SETCONTROLTEXT
:
989 TRACE("CDM_SETCONTROLTEXT:\n");
992 if( fodInfos
->unicode
)
993 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
995 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
1000 case CDM_HIDECONTROL
:
1001 /* MSDN states that it should fail for not OFN_EXPLORER case */
1002 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1004 HWND control
= GetDlgItem( hwnd
, wParam
);
1005 if (control
) ShowWindow( control
, SW_HIDE
);
1008 else retval
= FALSE
;
1012 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1013 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
1016 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1020 /***********************************************************************
1023 * File open dialog procedure
1025 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1028 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
1035 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1037 /* Adds the FileOpenDlgInfos in the property list of the dialog
1038 so it will be easily accessible through a GetPropA(...) */
1039 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
1041 FILEDLG95_InitControls(hwnd
);
1043 fodInfos
->DlgInfos
.hwndCustomDlg
=
1044 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1046 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1047 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1049 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1050 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1051 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1055 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1058 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1061 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1067 case WM_GETISHELLBROWSER
:
1068 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1071 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1076 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1079 /* set up the button tooltips strings */
1080 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1082 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1083 switch(lpnmh
->idFrom
)
1085 /* Up folder button */
1086 case FCIDM_TB_UPFOLDER
:
1087 stringId
= IDS_UPFOLDER
;
1089 /* New folder button */
1090 case FCIDM_TB_NEWFOLDER
:
1091 stringId
= IDS_NEWFOLDER
;
1093 /* List option button */
1094 case FCIDM_TB_SMALLICON
:
1095 stringId
= IDS_LISTVIEW
;
1097 /* Details option button */
1098 case FCIDM_TB_REPORTVIEW
:
1099 stringId
= IDS_REPORTVIEW
;
1101 /* Desktop button */
1102 case FCIDM_TB_DESKTOP
:
1103 stringId
= IDS_TODESKTOP
;
1108 lpdi
->hinst
= COMDLG32_hInstance
;
1109 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1114 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1115 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1120 /***********************************************************************
1121 * FILEDLG95_InitControls
1123 * WM_INITDIALOG message handler (before hook notification)
1125 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1127 int win2000plus
= 0;
1129 int handledPath
= FALSE
;
1130 OSVERSIONINFOW osVi
;
1131 static const WCHAR szwSlash
[] = { '\\', 0 };
1132 static const WCHAR szwStar
[] = { '*',0 };
1134 static const TBBUTTON tbb
[] =
1136 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1137 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1138 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1139 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1140 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1141 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1142 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1143 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1144 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1149 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1151 tba
[0].hInst
= HINST_COMMCTRL
;
1152 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1153 tba
[1].hInst
= COMDLG32_hInstance
;
1156 TRACE("%p\n", fodInfos
);
1158 /* Get windows version emulating */
1159 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1160 GetVersionExW(&osVi
);
1161 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1162 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1163 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1164 win2000plus
= (osVi
.dwMajorVersion
> 4);
1165 if (win2000plus
) win98plus
= TRUE
;
1167 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1169 /* Get the hwnd of the controls */
1170 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1171 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1172 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1174 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1175 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1177 /* construct the toolbar */
1178 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1179 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1181 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1182 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1183 rectTB
.left
= rectlook
.right
;
1184 rectTB
.top
= rectlook
.top
-1;
1186 if (fodInfos
->unicode
)
1187 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1188 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1189 rectTB
.left
, rectTB
.top
,
1190 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1191 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1193 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1194 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1195 rectTB
.left
, rectTB
.top
,
1196 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1197 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1199 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1201 /* FIXME: use TB_LOADIMAGES when implemented */
1202 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1203 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
[0]);
1204 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 1, (LPARAM
) &tba
[1]);
1206 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) &tbb
);
1207 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1209 /* Set the window text with the text specified in the OPENFILENAME structure */
1212 SetWindowTextW(hwnd
,fodInfos
->title
);
1214 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1217 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1218 SetWindowTextW(hwnd
, buf
);
1221 /* Initialise the file name edit control */
1222 handledPath
= FALSE
;
1223 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1225 if(fodInfos
->filename
)
1227 /* 1. If win2000 or higher and filename contains a path, use it
1228 in preference over the lpstrInitialDir */
1229 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1230 WCHAR tmpBuf
[MAX_PATH
];
1234 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1237 /* nameBit is always shorter than the original filename */
1238 lstrcpyW(fodInfos
->filename
,nameBit
);
1241 if (fodInfos
->initdir
== NULL
)
1242 MemFree(fodInfos
->initdir
);
1243 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1244 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1246 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1247 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1249 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1252 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1256 /* 2. (All platforms) If initdir is not null, then use it */
1257 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1258 (*fodInfos
->initdir
!=0x00))
1260 /* Work out the proper path as supplied one might be relative */
1261 /* (Here because supplying '.' as dir browses to My Computer) */
1262 if (handledPath
==FALSE
) {
1263 WCHAR tmpBuf
[MAX_PATH
];
1264 WCHAR tmpBuf2
[MAX_PATH
];
1268 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1269 if( PathFileExistsW(tmpBuf
) ) {
1270 /* initdir does not have to be a directory. If a file is
1271 * specified, the dir part is taken */
1272 if( PathIsDirectoryW(tmpBuf
)) {
1273 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1274 lstrcatW(tmpBuf
, szwSlash
);
1276 lstrcatW(tmpBuf
, szwStar
);
1278 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1281 MemFree(fodInfos
->initdir
);
1282 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1283 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1285 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1288 else if (fodInfos
->initdir
)
1290 MemFree(fodInfos
->initdir
);
1291 fodInfos
->initdir
= NULL
;
1292 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1297 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1298 (*fodInfos
->initdir
==0x00)))
1300 /* 3. All except w2k+: if filename contains a path use it */
1301 if (!win2000plus
&& fodInfos
->filename
&&
1302 *fodInfos
->filename
&&
1303 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1304 WCHAR tmpBuf
[MAX_PATH
];
1308 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1313 /* nameBit is always shorter than the original filename */
1314 lstrcpyW(fodInfos
->filename
, nameBit
);
1317 len
= lstrlenW(tmpBuf
);
1318 MemFree(fodInfos
->initdir
);
1319 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1320 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1323 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1324 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1326 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1329 /* 4. win98+ and win2000+ if any files of specified filter types in
1330 current directory, use it */
1331 if ( win98plus
&& handledPath
== FALSE
&&
1332 fodInfos
->filter
&& *fodInfos
->filter
) {
1334 BOOL searchMore
= TRUE
;
1335 LPCWSTR lpstrPos
= fodInfos
->filter
;
1336 WIN32_FIND_DATAW FindFileData
;
1341 /* filter is a list... title\0ext\0......\0\0 */
1343 /* Skip the title */
1344 if(! *lpstrPos
) break; /* end */
1345 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1347 /* See if any files exist in the current dir with this extension */
1348 if(! *lpstrPos
) break; /* end */
1350 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1352 if (hFind
== INVALID_HANDLE_VALUE
) {
1353 /* None found - continue search */
1354 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1359 MemFree(fodInfos
->initdir
);
1360 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1361 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1364 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1365 debugstr_w(lpstrPos
));
1371 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1373 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1374 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1375 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1377 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1379 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1382 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1383 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1385 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1388 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1391 } else if (handledPath
==FALSE
) {
1392 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1393 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1395 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1398 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1399 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1401 /* Must the open as read only check box be checked ?*/
1402 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1404 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1407 /* Must the open as read only check box be hidden? */
1408 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1410 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1411 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1414 /* Must the help button be hidden? */
1415 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1417 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1418 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1421 /* change Open to Save */
1422 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1425 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1426 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1427 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1428 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1433 /***********************************************************************
1434 * FILEDLG95_ResizeControls
1436 * WM_INITDIALOG message handler (after hook notification)
1438 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1440 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1442 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1445 UINT flags
= SWP_NOACTIVATE
;
1447 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1448 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1450 /* resize the custom dialog to the parent size */
1451 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1452 GetClientRect(hwnd
, &rc
);
1455 /* our own fake template is zero sized and doesn't have children, so
1456 * there is no need to resize it. Picasa depends on it.
1458 flags
|= SWP_NOSIZE
;
1461 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1462 0, 0, rc
.right
, rc
.bottom
, flags
);
1466 /* Resize the height, if open as read only checkbox ad help button are
1467 * hidden and we are not using a custom template nor a customDialog
1469 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1470 (!(fodInfos
->ofnInfos
->Flags
&
1471 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1473 RECT rectDlg
, rectHelp
, rectCancel
;
1474 GetWindowRect(hwnd
, &rectDlg
);
1475 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1476 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1477 /* subtract the height of the help button plus the space between the help
1478 * button and the cancel button to the height of the dialog
1480 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1481 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1482 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1488 /***********************************************************************
1489 * FILEDLG95_FillControls
1491 * WM_INITDIALOG message handler (after hook notification)
1493 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1495 LPITEMIDLIST pidlItemId
= NULL
;
1497 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1499 TRACE("dir=%s file=%s\n",
1500 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1502 /* Get the initial directory pidl */
1504 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1506 WCHAR path
[MAX_PATH
];
1508 GetCurrentDirectoryW(MAX_PATH
,path
);
1509 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1512 /* Initialise shell objects */
1513 FILEDLG95_SHELL_Init(hwnd
);
1515 /* Initialize the Look In combo box */
1516 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1518 /* Initialize the filter combo box */
1519 FILEDLG95_FILETYPE_Init(hwnd
);
1521 /* Browse to the initial directory */
1522 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1524 /* Free pidlItem memory */
1525 COMDLG32_SHFree(pidlItemId
);
1529 /***********************************************************************
1532 * Regroups all the cleaning functions of the filedlg
1534 void FILEDLG95_Clean(HWND hwnd
)
1536 FILEDLG95_FILETYPE_Clean(hwnd
);
1537 FILEDLG95_LOOKIN_Clean(hwnd
);
1538 FILEDLG95_SHELL_Clean(hwnd
);
1540 /***********************************************************************
1541 * FILEDLG95_OnWMCommand
1543 * WM_COMMAND message handler
1545 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1547 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1548 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1549 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1555 FILEDLG95_OnOpen(hwnd
);
1559 FILEDLG95_Clean(hwnd
);
1560 EndDialog(hwnd
, FALSE
);
1562 /* Filetype combo box */
1564 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1566 /* LookIn combo box */
1568 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1571 /* --- toolbar --- */
1572 /* Up folder button */
1573 case FCIDM_TB_UPFOLDER
:
1574 FILEDLG95_SHELL_UpFolder(hwnd
);
1576 /* New folder button */
1577 case FCIDM_TB_NEWFOLDER
:
1578 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1580 /* List option button */
1581 case FCIDM_TB_SMALLICON
:
1582 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1584 /* Details option button */
1585 case FCIDM_TB_REPORTVIEW
:
1586 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1588 /* Details option button */
1589 case FCIDM_TB_DESKTOP
:
1590 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1597 /* Do not use the listview selection anymore */
1598 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1602 /***********************************************************************
1603 * FILEDLG95_OnWMGetIShellBrowser
1605 * WM_GETISHELLBROWSER message handler
1607 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1610 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1614 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1620 /***********************************************************************
1621 * FILEDLG95_SendFileOK
1623 * Sends the CDN_FILEOK notification if required
1626 * TRUE if the dialog should close
1627 * FALSE if the dialog should not be closed
1629 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1631 /* ask the hook if we can close */
1632 if(IsHooked(fodInfos
))
1637 /* First send CDN_FILEOK as MSDN doc says */
1638 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1639 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1641 TRACE("canceled\n");
1642 return (retval
== 0);
1645 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1646 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1647 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1648 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1650 TRACE("canceled\n");
1651 return (retval
== 0);
1657 /***********************************************************************
1658 * FILEDLG95_OnOpenMultipleFiles
1660 * Handles the opening of multiple files.
1663 * check destination buffer size
1665 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1667 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1668 UINT nCount
, nSizePath
;
1669 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1673 if(fodInfos
->unicode
)
1675 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1676 ofn
->lpstrFile
[0] = '\0';
1680 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1681 ofn
->lpstrFile
[0] = '\0';
1684 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1686 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1687 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1688 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1690 LPWSTR lpstrTemp
= lpstrFileList
;
1692 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1696 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1699 WCHAR lpstrNotFound
[100];
1700 WCHAR lpstrMsg
[100];
1702 static const WCHAR nl
[] = {'\n',0};
1704 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1705 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1707 lstrcpyW(tmp
, lpstrTemp
);
1709 lstrcatW(tmp
, lpstrNotFound
);
1711 lstrcatW(tmp
, lpstrMsg
);
1713 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1717 /* move to the next file in the list of files */
1718 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1719 COMDLG32_SHFree(pidl
);
1723 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1724 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1726 /* For "oldstyle" dialog the components have to
1727 be separated by blanks (not '\0'!) and short
1728 filenames have to be used! */
1729 FIXME("Components have to be separated by blanks\n");
1731 if(fodInfos
->unicode
)
1733 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1734 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1735 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1739 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1741 if (ofn
->lpstrFile
!= NULL
)
1743 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1744 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1745 if (ofn
->nMaxFile
> nSizePath
)
1747 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1748 ofn
->lpstrFile
+ nSizePath
,
1749 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1754 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1755 fodInfos
->ofnInfos
->nFileExtension
= 0;
1757 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1760 /* clean and exit */
1761 FILEDLG95_Clean(hwnd
);
1762 return EndDialog(hwnd
,TRUE
);
1765 /***********************************************************************
1768 * Ok button WM_COMMAND message handler
1770 * If the function succeeds, the return value is nonzero.
1772 #define ONOPEN_BROWSE 1
1773 #define ONOPEN_OPEN 2
1774 #define ONOPEN_SEARCH 3
1775 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1777 WCHAR strMsgTitle
[MAX_PATH
];
1778 WCHAR strMsgText
[MAX_PATH
];
1780 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1782 strMsgTitle
[0] = '\0';
1783 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1784 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1787 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1789 LPWSTR lpstrFileList
;
1790 UINT nFileCount
= 0;
1793 WCHAR lpstrPathAndFile
[MAX_PATH
];
1794 WCHAR lpstrTemp
[MAX_PATH
];
1795 LPSHELLFOLDER lpsf
= NULL
;
1797 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1799 TRACE("hwnd=%p\n", hwnd
);
1801 /* get the files from the edit control */
1802 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1804 /* try if the user selected a folder in the shellview */
1807 BrowseSelectedFolder(hwnd
);
1813 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1817 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1820 Step 1: Build a complete path name from the current folder and
1821 the filename or path in the edit box.
1823 - the path in the edit box is a root path
1824 (with or without drive letter)
1825 - the edit box contains ".." (or a path with ".." in it)
1828 /* Get the current directory name */
1829 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1832 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1834 PathAddBackslashW(lpstrPathAndFile
);
1836 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1838 /* if the user specifyed a fully qualified path use it */
1839 if(PathIsRelativeW(lpstrFileList
))
1841 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
1845 /* does the path have a drive letter? */
1846 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1847 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1849 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
1852 /* resolve "." and ".." */
1853 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1854 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
1855 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1857 MemFree(lpstrFileList
);
1860 Step 2: here we have a cleaned up path
1862 We have to parse the path step by step to see if we have to browse
1863 to a folder if the path points to a directory or the last
1864 valid element is a directory.
1867 lpstrPathAndFile: cleaned up path
1871 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1872 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
1873 nOpenAction
= ONOPEN_OPEN
;
1875 nOpenAction
= ONOPEN_BROWSE
;
1877 /* don't apply any checks with OFN_NOVALIDATE */
1879 LPWSTR lpszTemp
, lpszTemp1
;
1880 LPITEMIDLIST pidl
= NULL
;
1881 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1883 /* check for invalid chars */
1884 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1886 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1891 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1893 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1896 LPSHELLFOLDER lpsfChild
;
1897 WCHAR lpwstrTemp
[MAX_PATH
];
1898 DWORD dwEaten
, dwAttributes
;
1901 lstrcpyW(lpwstrTemp
, lpszTemp
);
1902 p
= PathFindNextComponentW(lpwstrTemp
);
1904 if (!p
) break; /* end of path */
1907 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
1909 /* There are no wildcards when OFN_NOVALIDATE is set */
1910 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1912 static const WCHAR wszWild
[] = { '*', '?', 0 };
1913 /* if the last element is a wildcard do a search */
1914 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1916 nOpenAction
= ONOPEN_SEARCH
;
1920 lpszTemp1
= lpszTemp
;
1922 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1924 /* append a backslash to drive letters */
1925 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1926 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1927 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1929 PathAddBackslashW(lpwstrTemp
);
1932 dwAttributes
= SFGAO_FOLDER
;
1933 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1935 /* the path component is valid, we have a pidl of the next path component */
1936 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
1937 if(dwAttributes
& SFGAO_FOLDER
)
1939 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1941 ERR("bind to failed\n"); /* should not fail */
1944 IShellFolder_Release(lpsf
);
1952 /* end dialog, return value */
1953 nOpenAction
= ONOPEN_OPEN
;
1956 COMDLG32_SHFree(pidl
);
1959 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1961 if(*lpszTemp
) /* points to trailing null for last path element */
1963 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1965 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1971 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1972 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1974 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1978 /* change to the current folder */
1979 nOpenAction
= ONOPEN_OPEN
;
1984 nOpenAction
= ONOPEN_OPEN
;
1988 if(pidl
) COMDLG32_SHFree(pidl
);
1992 Step 3: here we have a cleaned up and validated path
1995 lpsf: ShellFolder bound to the rightmost valid path component
1996 lpstrPathAndFile: cleaned up path
1997 nOpenAction: action to do
1999 TRACE("end validate sf=%p\n", lpsf
);
2003 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2004 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2007 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2010 /* replace the current filter */
2011 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2012 len
= lstrlenW(lpszTemp
)+1;
2013 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2014 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2016 /* set the filter cb to the extension when possible */
2017 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2018 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2021 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2022 TRACE("ONOPEN_BROWSE\n");
2024 IPersistFolder2
* ppf2
;
2025 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2027 LPITEMIDLIST pidlCurrent
;
2028 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2029 IPersistFolder2_Release(ppf2
);
2030 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2032 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
)))
2034 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2037 else if( nOpenAction
== ONOPEN_SEARCH
)
2039 if (fodInfos
->Shell
.FOIShellView
)
2040 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2042 COMDLG32_SHFree(pidlCurrent
);
2043 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2048 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2049 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2053 /* update READONLY check box flag */
2054 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2055 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2057 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2059 /* Attach the file extension with file name*/
2060 ext
= PathFindExtensionW(lpstrPathAndFile
);
2063 /* if no extension is specified with file name, then */
2064 /* attach the extension from file filter or default one */
2066 WCHAR
*filterExt
= NULL
;
2067 LPWSTR lpstrFilter
= NULL
;
2068 static const WCHAR szwDot
[] = {'.',0};
2069 int PathLength
= lstrlenW(lpstrPathAndFile
);
2072 lstrcatW(lpstrPathAndFile
, szwDot
);
2074 /*Get the file extension from file type filter*/
2075 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2076 fodInfos
->ofnInfos
->nFilterIndex
-1);
2078 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2079 filterExt
= PathFindExtensionW(lpstrFilter
);
2081 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2082 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2083 else if ( fodInfos
->defext
) /* attach the default file extension*/
2084 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2086 /* In Open dialog: if file does not exist try without extension */
2087 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2088 lpstrPathAndFile
[PathLength
] = '\0';
2091 if (fodInfos
->defext
) /* add default extension */
2093 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2096 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2097 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2099 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2102 /* In Save dialog: check if the file already exists */
2103 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2104 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2105 && PathFileExistsW(lpstrPathAndFile
))
2107 WCHAR lpstrOverwrite
[100];
2110 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2111 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2112 MB_YESNO
| MB_ICONEXCLAMATION
);
2120 /* Check that the size of the file does not exceed buffer size.
2121 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2122 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2123 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2127 /* fill destination buffer */
2128 if (fodInfos
->ofnInfos
->lpstrFile
)
2130 if(fodInfos
->unicode
)
2132 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2134 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2135 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2136 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2140 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2142 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2143 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2144 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2145 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2149 /* set filename offset */
2150 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2151 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2153 /* set extension offset */
2154 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2155 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2157 /* set the lpstrFileTitle */
2158 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2160 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2161 if(fodInfos
->unicode
)
2163 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2164 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2168 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2169 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2170 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2174 /* copy currently selected filter to lpstrCustomFilter */
2175 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2177 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2178 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2179 NULL
, 0, NULL
, NULL
);
2180 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2182 LPSTR s
= ofn
->lpstrCustomFilter
;
2183 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2184 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2185 s
, len
, NULL
, NULL
);
2190 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2194 FILEDLG95_Clean(hwnd
);
2195 ret
= EndDialog(hwnd
, TRUE
);
2201 size
= lstrlenW(lpstrPathAndFile
) + 1;
2202 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2204 /* return needed size in first two bytes of lpstrFile */
2205 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2206 FILEDLG95_Clean(hwnd
);
2207 ret
= EndDialog(hwnd
, FALSE
);
2208 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2216 if(lpsf
) IShellFolder_Release(lpsf
);
2220 /***********************************************************************
2221 * FILEDLG95_SHELL_Init
2223 * Initialisation of the shell objects
2225 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2227 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2232 * Initialisation of the FileOpenDialogInfos structure
2238 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2240 /* Disable multi-select if flag not set */
2241 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2243 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2245 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2246 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2248 /* Construct the IShellBrowser interface */
2249 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2254 /***********************************************************************
2255 * FILEDLG95_SHELL_ExecuteCommand
2257 * Change the folder option and refresh the view
2258 * If the function succeeds, the return value is nonzero.
2260 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2262 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2265 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2267 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2272 CMINVOKECOMMANDINFO ci
;
2273 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2274 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2278 IContextMenu_InvokeCommand(pcm
, &ci
);
2279 IContextMenu_Release(pcm
);
2285 /***********************************************************************
2286 * FILEDLG95_SHELL_UpFolder
2288 * Browse to the specified object
2289 * If the function succeeds, the return value is nonzero.
2291 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2293 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2297 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2301 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2307 /***********************************************************************
2308 * FILEDLG95_SHELL_BrowseToDesktop
2310 * Browse to the Desktop
2311 * If the function succeeds, the return value is nonzero.
2313 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2315 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2321 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2322 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2323 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2324 COMDLG32_SHFree(pidl
);
2325 return SUCCEEDED(hres
);
2327 /***********************************************************************
2328 * FILEDLG95_SHELL_Clean
2330 * Cleans the memory used by shell objects
2332 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2334 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2338 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2340 /* clean Shell interfaces */
2341 if (fodInfos
->Shell
.FOIShellView
)
2343 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2344 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2346 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2347 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2348 if (fodInfos
->Shell
.FOIDataObject
)
2349 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2352 /***********************************************************************
2353 * FILEDLG95_FILETYPE_Init
2355 * Initialisation of the file type combo box
2357 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2359 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2360 int nFilters
= 0; /* number of filters */
2365 if(fodInfos
->customfilter
)
2367 /* customfilter has one entry... title\0ext\0
2368 * Set first entry of combo box item with customfilter
2371 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2374 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2376 /* Copy the extensions */
2377 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2378 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2379 lstrcpyW(lpstrExt
,lpstrPos
);
2381 /* Add the item at the end of the combo */
2382 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2383 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2386 if(fodInfos
->filter
)
2388 LPCWSTR lpstrPos
= fodInfos
->filter
;
2392 /* filter is a list... title\0ext\0......\0\0
2393 * Set the combo item text to the title and the item data
2396 LPCWSTR lpstrDisplay
;
2400 if(! *lpstrPos
) break; /* end */
2401 lpstrDisplay
= lpstrPos
;
2402 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2404 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2408 /* Copy the extensions */
2409 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2410 lstrcpyW(lpstrExt
,lpstrPos
);
2411 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2413 /* Add the item at the end of the combo */
2414 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2416 /* malformed filters are added anyway... */
2417 if (!*lpstrExt
) break;
2422 * Set the current filter to the one specified
2423 * in the initialisation structure
2425 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2429 /* Check to make sure our index isn't out of bounds. */
2430 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2431 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2432 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2434 /* set default filter index */
2435 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2436 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2438 /* calculate index of Combo Box item */
2439 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2440 if (fodInfos
->customfilter
== NULL
)
2443 /* Set the current index selection. */
2444 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2446 /* Get the corresponding text string from the combo box. */
2447 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2450 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2456 CharLowerW(lpstrFilter
); /* lowercase */
2457 len
= lstrlenW(lpstrFilter
)+1;
2458 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2459 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2462 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2466 /***********************************************************************
2467 * FILEDLG95_FILETYPE_OnCommand
2469 * WM_COMMAND of the file type combo box
2470 * If the function succeeds, the return value is nonzero.
2472 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2474 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2482 /* Get the current item of the filetype combo box */
2483 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2485 /* set the current filter index */
2486 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2487 (fodInfos
->customfilter
== NULL
? 1 : 0);
2489 /* Set the current filter with the current selection */
2490 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2492 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2494 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2497 CharLowerW(lpstrFilter
); /* lowercase */
2498 len
= lstrlenW(lpstrFilter
)+1;
2499 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2500 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2501 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2504 /* Refresh the actual view to display the included items*/
2505 if (fodInfos
->Shell
.FOIShellView
)
2506 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2511 /***********************************************************************
2512 * FILEDLG95_FILETYPE_SearchExt
2514 * searches for an extension in the filetype box
2516 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2518 int i
, iCount
= CBGetCount(hwnd
);
2520 TRACE("%s\n", debugstr_w(lpstrExt
));
2522 if(iCount
!= CB_ERR
)
2524 for(i
=0;i
<iCount
;i
++)
2526 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2533 /***********************************************************************
2534 * FILEDLG95_FILETYPE_Clean
2536 * Clean the memory used by the filetype combo box
2538 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2540 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2542 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2546 /* Delete each string of the combo and their associated data */
2547 if(iCount
!= CB_ERR
)
2549 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2551 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2552 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2555 /* Current filter */
2556 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2560 /***********************************************************************
2561 * FILEDLG95_LOOKIN_Init
2563 * Initialisation of the look in combo box
2566 /* Small helper function, to determine if the unixfs shell extension is rooted
2567 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2569 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2571 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2572 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2573 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2574 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2575 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2576 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2577 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2579 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2586 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2588 IShellFolder
*psfRoot
, *psfDrives
;
2589 IEnumIDList
*lpeRoot
, *lpeDrives
;
2590 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2592 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2596 liInfos
->iMaxIndentation
= 0;
2598 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2600 /* set item height for both text field and listbox */
2601 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2602 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2604 /* Turn on the extended UI for the combo box like Windows does */
2605 CBSetExtendedUI(hwndCombo
, TRUE
);
2607 /* Initialise data of Desktop folder */
2608 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2609 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2610 COMDLG32_SHFree(pidlTmp
);
2612 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2614 SHGetDesktopFolder(&psfRoot
);
2618 /* enumerate the contents of the desktop */
2619 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2621 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2623 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2625 /* If the unixfs extension is rooted, we don't expand the drives by default */
2626 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2628 /* special handling for CSIDL_DRIVES */
2629 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2631 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2633 /* enumerate the drives */
2634 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2636 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2638 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2639 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2640 COMDLG32_SHFree(pidlAbsTmp
);
2641 COMDLG32_SHFree(pidlTmp1
);
2643 IEnumIDList_Release(lpeDrives
);
2645 IShellFolder_Release(psfDrives
);
2650 COMDLG32_SHFree(pidlTmp
);
2652 IEnumIDList_Release(lpeRoot
);
2654 IShellFolder_Release(psfRoot
);
2657 COMDLG32_SHFree(pidlDrives
);
2660 /***********************************************************************
2661 * FILEDLG95_LOOKIN_DrawItem
2663 * WM_DRAWITEM message handler
2665 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2667 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2668 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2669 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2673 HIMAGELIST ilItemImage
;
2676 LPSFOLDER tmpFolder
;
2679 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2683 if(pDIStruct
->itemID
== -1)
2686 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2687 pDIStruct
->itemID
)))
2691 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2693 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2697 SHGFI_PIDL
| SHGFI_SMALLICON
|
2698 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2699 SHGFI_DISPLAYNAME
);
2703 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2707 SHGFI_PIDL
| SHGFI_SMALLICON
|
2708 SHGFI_SYSICONINDEX
|
2712 /* Is this item selected ? */
2713 if(pDIStruct
->itemState
& ODS_SELECTED
)
2715 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2716 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2717 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2721 SetTextColor(pDIStruct
->hDC
,crText
);
2722 SetBkColor(pDIStruct
->hDC
,crWin
);
2723 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2726 /* Do not indent item if drawing in the edit of the combo */
2727 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2730 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2734 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2735 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2740 iIndentation
= tmpFolder
->m_iIndent
;
2742 /* Draw text and icon */
2744 /* Initialise the icon display area */
2745 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2746 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2747 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2748 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2750 /* Initialise the text display area */
2751 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2752 rectText
.left
= rectIcon
.right
;
2754 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2755 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2757 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2759 /* Draw the icon from the image list */
2760 ImageList_Draw(ilItemImage
,
2767 /* Draw the associated text */
2768 if(sfi
.szDisplayName
)
2769 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
2775 /***********************************************************************
2776 * FILEDLG95_LOOKIN_OnCommand
2778 * LookIn combo box WM_COMMAND message handler
2779 * If the function succeeds, the return value is nonzero.
2781 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2783 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2785 TRACE("%p\n", fodInfos
);
2791 LPSFOLDER tmpFolder
;
2794 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2796 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2801 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2802 tmpFolder
->pidlItem
,
2805 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2815 /***********************************************************************
2816 * FILEDLG95_LOOKIN_AddItem
2818 * Adds an absolute pidl item to the lookin combo box
2819 * returns the index of the inserted item
2821 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2823 LPITEMIDLIST pidlNext
;
2826 LookInInfos
*liInfos
;
2828 TRACE("%08x\n", iInsertId
);
2833 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2836 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2837 tmpFolder
->m_iIndent
= 0;
2839 /* Calculate the indentation of the item in the lookin*/
2841 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2843 tmpFolder
->m_iIndent
++;
2846 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2848 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2849 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2851 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2852 SHGetFileInfoW((LPCWSTR
)pidl
,
2856 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2857 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2859 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
2861 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2865 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
2867 /* Add the item at the end of the list */
2870 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2872 /* Insert the item at the iInsertId position*/
2875 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2878 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2882 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2883 MemFree( tmpFolder
);
2888 /***********************************************************************
2889 * FILEDLG95_LOOKIN_InsertItemAfterParent
2891 * Insert an item below its parent
2893 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2896 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2901 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2905 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2908 /* Free pidlParent memory */
2909 COMDLG32_SHFree((LPVOID
)pidlParent
);
2911 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2914 /***********************************************************************
2915 * FILEDLG95_LOOKIN_SelectItem
2917 * Adds an absolute pidl item to the lookin combo box
2918 * returns the index of the inserted item
2920 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2923 LookInInfos
*liInfos
;
2927 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2929 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2933 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2934 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2939 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2940 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2944 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2946 if(iRemovedItem
< iItemPos
)
2951 CBSetCurSel(hwnd
,iItemPos
);
2952 liInfos
->uSelectedItem
= iItemPos
;
2958 /***********************************************************************
2959 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2961 * Remove the item with an expansion level over iExpansionLevel
2963 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2967 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2971 if(liInfos
->iMaxIndentation
<= 2)
2974 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2976 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2977 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2979 CBDeleteString(hwnd
,iItemPos
);
2980 liInfos
->iMaxIndentation
--;
2988 /***********************************************************************
2989 * FILEDLG95_LOOKIN_SearchItem
2991 * Search for pidl in the lookin combo box
2992 * returns the index of the found item
2994 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2997 int iCount
= CBGetCount(hwnd
);
2999 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3001 if (iCount
!= CB_ERR
)
3005 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3007 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3009 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3017 /***********************************************************************
3018 * FILEDLG95_LOOKIN_Clean
3020 * Clean the memory used by the lookin combo box
3022 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3024 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3026 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3030 /* Delete each string of the combo and their associated data */
3031 if (iCount
!= CB_ERR
)
3033 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3035 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3036 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3038 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3042 /* LookInInfos structure */
3043 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3046 /***********************************************************************
3047 * FILEDLG95_FILENAME_FillFromSelection
3049 * fills the edit box from the cached DataObject
3051 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3053 FileOpenDlgInfos
*fodInfos
;
3055 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3056 WCHAR lpstrTemp
[MAX_PATH
];
3057 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3060 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3062 /* Count how many files we have */
3063 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3065 /* calculate the string length, count files */
3066 if (nFileSelected
>= 1)
3068 nLength
+= 3; /* first and last quotes, trailing \0 */
3069 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3071 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3075 /* get the total length of the selected file names */
3076 lpstrTemp
[0] = '\0';
3077 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3079 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3081 nLength
+= lstrlenW( lpstrTemp
) + 3;
3084 COMDLG32_SHFree( pidl
);
3089 /* allocate the buffer */
3090 if (nFiles
<= 1) nLength
= MAX_PATH
;
3091 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3093 /* Generate the string for the edit control */
3096 lpstrCurrFile
= lpstrAllFile
;
3097 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3099 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3103 /* get the file name */
3104 lpstrTemp
[0] = '\0';
3105 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3107 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3111 *lpstrCurrFile
++ = '\"';
3112 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3113 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3114 *lpstrCurrFile
++ = '\"';
3115 *lpstrCurrFile
++ = ' ';
3120 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3123 COMDLG32_SHFree( (LPVOID
) pidl
);
3126 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3128 /* Select the file name like Windows does */
3129 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3131 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3135 /* copied from shell32 to avoid linking to it
3136 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3137 * is dependent on whether emulated OS is unicode or not.
3139 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3144 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3145 COMDLG32_SHFree(src
->u
.pOleStr
);
3149 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3154 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3159 FIXME("unknown type %x!\n", src
->uType
);
3160 if (len
) *dest
= '\0';
3166 /***********************************************************************
3167 * FILEDLG95_FILENAME_GetFileNames
3169 * Copies the filenames to a delimited string list.
3170 * The delimiter is specified by the parameter 'separator',
3171 * usually either a space or a nul
3173 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3175 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3176 UINT nStrCharCount
= 0; /* index in src buffer */
3177 UINT nFileIndex
= 0; /* index in dest buffer */
3178 UINT nFileCount
= 0; /* number of files */
3179 UINT nStrLen
= 0; /* length of string in edit control */
3180 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3184 /* get the filenames from the edit control */
3185 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3186 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3187 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3189 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3191 /* we might get single filename without any '"',
3192 * so we need nStrLen + terminating \0 + end-of-list \0 */
3193 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3196 /* build delimited file list from filenames */
3197 while ( nStrCharCount
<= nStrLen
)
3199 if ( lpstrEdit
[nStrCharCount
]=='"' )
3202 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3204 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3208 (*lpstrFileList
)[nFileIndex
++] = separator
;
3215 /* single, unquoted string */
3216 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3218 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3219 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3220 (*sizeUsed
) = nFileIndex
;
3225 (*lpstrFileList
)[nFileIndex
] = '\0';
3232 #define SETDefFormatEtc(fe,cf,med) \
3234 (fe).cfFormat = cf;\
3235 (fe).dwAspect = DVASPECT_CONTENT; \
3242 * DATAOBJECT Helper functions
3245 /***********************************************************************
3246 * COMCTL32_ReleaseStgMedium
3248 * like ReleaseStgMedium from ole32
3250 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3252 if(medium
.pUnkForRelease
)
3254 IUnknown_Release(medium
.pUnkForRelease
);
3258 GlobalUnlock(medium
.u
.hGlobal
);
3259 GlobalFree(medium
.u
.hGlobal
);
3263 /***********************************************************************
3264 * GetPidlFromDataObject
3266 * Return pidl(s) by number from the cached DataObject
3268 * nPidlIndex=0 gets the fully qualified root path
3270 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3274 FORMATETC formatetc
;
3275 LPITEMIDLIST pidl
= NULL
;
3277 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3282 /* Set the FORMATETC structure*/
3283 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3285 /* Get the pidls from IDataObject */
3286 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3288 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3289 if(nPidlIndex
<= cida
->cidl
)
3291 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3293 COMCTL32_ReleaseStgMedium(medium
);
3298 /***********************************************************************
3301 * Return the number of selected items in the DataObject.
3304 UINT
GetNumSelected( IDataObject
*doSelected
)
3308 FORMATETC formatetc
;
3310 TRACE("sv=%p\n", doSelected
);
3312 if (!doSelected
) return 0;
3314 /* Set the FORMATETC structure*/
3315 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3317 /* Get the pidls from IDataObject */
3318 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3320 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3321 retVal
= cida
->cidl
;
3322 COMCTL32_ReleaseStgMedium(medium
);
3332 /***********************************************************************
3335 * Get the pidl's display name (relative to folder) and
3336 * put it in lpstrFileName.
3338 * Return NOERROR on success,
3342 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3347 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3351 SHGetDesktopFolder(&lpsf
);
3352 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3353 IShellFolder_Release(lpsf
);
3357 /* Get the display name of the pidl relative to the folder */
3358 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3360 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3365 /***********************************************************************
3366 * GetShellFolderFromPidl
3368 * pidlRel is the item pidl relative
3369 * Return the IShellFolder of the absolute pidl
3371 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3373 IShellFolder
*psf
= NULL
,*psfParent
;
3375 TRACE("%p\n", pidlAbs
);
3377 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3380 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3382 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3384 IShellFolder_Release(psfParent
);
3388 /* return the desktop */
3394 /***********************************************************************
3397 * Return the LPITEMIDLIST to the parent of the pidl in the list
3399 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3401 LPITEMIDLIST pidlParent
;
3403 TRACE("%p\n", pidl
);
3405 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3406 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3411 /***********************************************************************
3414 * returns the pidl of the file name relative to folder
3415 * NULL if an error occurred
3417 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3419 LPITEMIDLIST pidl
= NULL
;
3422 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3424 if(!lpcstrFileName
) return NULL
;
3425 if(!*lpcstrFileName
) return NULL
;
3429 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3430 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3431 IShellFolder_Release(lpsf
);
3436 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3443 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3445 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3448 TRACE("%p, %p\n", psf
, pidl
);
3450 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3452 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3453 /* see documentation shell 4.1*/
3454 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3457 /***********************************************************************
3458 * BrowseSelectedFolder
3460 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3462 BOOL bBrowseSelFolder
= FALSE
;
3463 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3467 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3469 LPITEMIDLIST pidlSelection
;
3471 /* get the file selected */
3472 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3473 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3475 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3476 pidlSelection
, SBSP_RELATIVE
) ) )
3478 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3479 ' ','n','o','t',' ','e','x','i','s','t',0};
3480 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3482 bBrowseSelFolder
= TRUE
;
3483 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3485 COMDLG32_SHFree( pidlSelection
);
3488 return bBrowseSelFolder
;
3492 * Memory allocation methods */
3493 static void *MemAlloc(UINT size
)
3495 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3498 static void MemFree(void *mem
)
3500 HeapFree(GetProcessHeap(),0,mem
);
3504 * Old-style (win3.1) dialogs */
3506 /***********************************************************************
3507 * FD32_GetTemplate [internal]
3509 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3510 * by a 32 bits application
3513 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3515 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3516 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3519 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3521 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3523 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3527 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3531 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3532 priv
->ofnA
->lpTemplateName
,
3535 hResInfo
= FindResourceW(ofnW
->hInstance
,
3536 ofnW
->lpTemplateName
,
3540 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3543 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3545 !(lfs
->template = LockResource(hDlgTmpl
)))
3547 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3550 } else { /* get it from internal Wine resource */
3552 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3553 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3555 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3558 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3559 !(lfs
->template = LockResource( hDlgTmpl
)))
3561 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3569 /************************************************************************
3570 * FD32_Init [internal]
3571 * called from the common 16/32 code to initialize 32 bit data
3573 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3575 BOOL IsUnicode
= (BOOL
) data
;
3578 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3579 lfs
->private1632
= priv
;
3580 if (NULL
== lfs
->private1632
) return FALSE
;
3583 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3584 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3585 if (lfs
->ofnW
->lpfnHook
)
3590 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3591 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3592 if (priv
->ofnA
->lpfnHook
)
3594 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3595 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3598 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3603 /***********************************************************************
3604 * FD32_CallWindowProc [internal]
3606 * called from the common 16/32 code to call the appropriate hook
3608 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3612 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3616 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3617 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3618 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3619 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3620 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3624 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3625 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3626 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3627 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3628 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3632 /***********************************************************************
3633 * FD32_UpdateResult [internal]
3634 * update the real client structures if any
3636 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3638 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3639 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3643 if (ofnW
->nMaxFile
&&
3644 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3645 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3646 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3647 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3648 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
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
, /* addess 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
, /* addess 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
]);