2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_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
72 #include "filedlg31.h"
76 #include "filedlgbrowser.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex
; /* Index of picture in image list */
99 int m_iIndent
; /* Indentation index */
100 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
102 } SFOLDER
,*LPSFOLDER
;
104 typedef struct tagLookInInfo
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE
, *PFD32_PRIVATE
;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
122 #define XTEXTOFFSET 3
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
175 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
182 /* Internal functions used by the dialog */
183 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
184 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
185 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
186 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
187 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
188 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
189 static void FILEDLG95_Clean(HWND hwnd
);
191 /* Functions used by the shell navigation */
192 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
193 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
196 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
201 /* Functions used by the filetype combo box */
202 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
203 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
209 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
210 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
218 /* Miscellaneous tool functions */
219 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
220 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
221 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
222 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size
);
226 static void MemFree(void *mem
);
228 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
229 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
231 static BOOL
BrowseSelectedFolder(HWND hwnd
);
233 /***********************************************************************
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
252 /* test for missing functionality */
253 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
259 /* Create the dialog from a template */
261 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
266 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
267 !(template = LockResource( hDlgTmpl
)))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
273 /* old style hook messages */
274 if (IsHooked(fodInfos
))
276 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
277 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
278 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
279 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr
= OleInitialize(NULL
);
285 if (fodInfos
->unicode
)
286 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
288 fodInfos
->ofnInfos
->hwndOwner
,
292 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
293 (LPCDLGTEMPLATEA
) template,
294 fodInfos
->ofnInfos
->hwndOwner
,
300 /* Unable to create the dialog */
307 /***********************************************************************
310 * Call GetFileName95 with this structure and clean the memory.
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
315 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
318 FileOpenDlgInfos fodInfos
;
319 LPSTR lpstrSavDir
= NULL
;
321 LPWSTR defext
= NULL
;
322 LPWSTR filter
= NULL
;
323 LPWSTR customfilter
= NULL
;
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
331 /* Pass in the original ofn */
332 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
334 /* save current directory */
335 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
337 lpstrSavDir
= MemAlloc(MAX_PATH
);
338 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
341 fodInfos
.unicode
= FALSE
;
343 /* convert all the input strings to unicode */
344 if(ofn
->lpstrInitialDir
)
346 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
347 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
348 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
351 fodInfos
.initdir
= NULL
;
355 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
356 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
359 fodInfos
.filename
= NULL
;
363 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
364 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
365 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
367 fodInfos
.defext
= defext
;
371 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
372 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
373 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
375 fodInfos
.title
= title
;
377 if (ofn
->lpstrFilter
)
382 /* filter is a list... title\0ext\0......\0\0 */
383 s
= ofn
->lpstrFilter
;
384 while (*s
) s
= s
+strlen(s
)+1;
386 n
= s
- ofn
->lpstrFilter
;
387 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
388 filter
= MemAlloc(len
*sizeof(WCHAR
));
389 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
391 fodInfos
.filter
= filter
;
393 /* convert lpstrCustomFilter */
394 if (ofn
->lpstrCustomFilter
)
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s
= ofn
->lpstrCustomFilter
;
401 if (*s
) s
= s
+strlen(s
)+1;
402 if (*s
) s
= s
+strlen(s
)+1;
403 n
= s
- ofn
->lpstrCustomFilter
;
404 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
405 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
406 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
408 fodInfos
.customfilter
= customfilter
;
410 /* Initialize the dialog property */
411 fodInfos
.DlgInfos
.dwDlgProp
= 0;
412 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
417 ret
= GetFileName95(&fodInfos
);
420 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
421 ret
= GetFileName95(&fodInfos
);
429 SetCurrentDirectoryA(lpstrSavDir
);
430 MemFree(lpstrSavDir
);
436 MemFree(customfilter
);
437 MemFree(fodInfos
.initdir
);
438 MemFree(fodInfos
.filename
);
440 TRACE("selected file: %s\n",ofn
->lpstrFile
);
445 /***********************************************************************
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
455 FileOpenDlgInfos fodInfos
;
456 LPWSTR lpstrSavDir
= NULL
;
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
464 /* Pass in the original ofn */
465 fodInfos
.ofnInfos
= ofn
;
467 fodInfos
.title
= ofn
->lpstrTitle
;
468 fodInfos
.defext
= ofn
->lpstrDefExt
;
469 fodInfos
.filter
= ofn
->lpstrFilter
;
470 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
472 /* convert string arguments, save others */
475 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
476 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
479 fodInfos
.filename
= NULL
;
481 if(ofn
->lpstrInitialDir
)
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
485 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
486 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
489 fodInfos
.initdir
= NULL
;
491 /* save current directory */
492 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
494 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
495 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
498 fodInfos
.unicode
= TRUE
;
503 ret
= GetFileName95(&fodInfos
);
506 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
507 ret
= GetFileName95(&fodInfos
);
515 SetCurrentDirectoryW(lpstrSavDir
);
516 MemFree(lpstrSavDir
);
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos
.filename
);
521 MemFree(fodInfos
.initdir
);
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
528 * Helper function to get the display name for a pidl.
530 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
531 LPSHELLFOLDER psfDesktop
;
534 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
538 IShellFolder_Release(psfDesktop
);
542 IShellFolder_Release(psfDesktop
);
543 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
549 * NOTE: Do not change anything here without a lot of testing.
551 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
553 HWND hwndChild
, hwndStc32
;
554 RECT rectParent
, rectChild
, rectStc32
;
555 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
557 /* Take into account if open as read only checkbox and help button
562 RECT rectHelp
, rectCancel
;
563 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
564 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
568 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
572 There are two possibilities to add components to the default file dialog box.
574 By default, all the new components are added below the standard dialog box (the else case).
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
584 GetClientRect(hwndParentDlg
, &rectParent
);
586 /* when arranging controls we have to use fixed parent size */
587 rectParent
.bottom
-= help_fixup
;
589 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
592 GetWindowRect(hwndStc32
, &rectStc32
);
593 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
598 SetWindowPos(hwndStc32
, 0,
600 rectParent
.right
, rectParent
.bottom
,
601 SWP_NOMOVE
| SWP_NOZORDER
);
604 SetRectEmpty(&rectStc32
);
606 /* this part moves controls of the child dialog */
607 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
610 if (hwndChild
!= hwndStc32
)
612 GetWindowRect(hwndChild
, &rectChild
);
613 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
615 /* move only if stc32 exist */
616 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
618 LONG old_left
= rectChild
.left
;
620 /* move to the right of visible controls of the parent dialog */
621 rectChild
.left
+= rectParent
.right
;
622 rectChild
.left
-= rectStc32
.right
;
624 child_width_fixup
= rectChild
.left
- old_left
;
626 /* move even if stc32 doesn't exist */
627 if (rectChild
.top
>= rectStc32
.bottom
)
629 LONG old_top
= rectChild
.top
;
631 /* move below visible controls of the parent dialog */
632 rectChild
.top
+= rectParent
.bottom
;
633 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
635 child_height_fixup
= rectChild
.top
- old_top
;
638 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
639 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
641 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
644 /* this part moves controls of the parent dialog */
645 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
648 if (hwndChild
!= hwndChildDlg
)
650 GetWindowRect(hwndChild
, &rectChild
);
651 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
656 rectChild
.left
+= rectStc32
.left
;
657 rectChild
.top
+= rectStc32
.top
;
659 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
660 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
662 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
665 /* calculate the size of the resulting dialog */
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg
, &rectParent
);
669 GetClientRect(hwndChildDlg
, &rectChild
);
673 rectChild
.right
+= child_width_fixup
;
674 rectChild
.bottom
+= child_height_fixup
;
676 if (rectParent
.right
> rectChild
.right
)
678 rectParent
.right
+= rectChild
.right
;
679 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
683 rectParent
.right
= rectChild
.right
;
686 if (rectParent
.bottom
> rectChild
.bottom
)
688 rectParent
.bottom
+= rectChild
.bottom
;
689 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
696 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
701 rectParent
.bottom
+= rectChild
.bottom
;
704 /* finally use fixed parent size */
705 rectParent
.bottom
-= help_fixup
;
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
709 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
710 SetWindowPos(hwndParentDlg
, 0,
712 rectParent
.right
- rectParent
.left
,
713 rectParent
.bottom
- rectParent
.top
,
714 SWP_NOMOVE
| SWP_NOZORDER
);
717 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
726 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
740 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
743 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
745 hinst
= COMDLG32_hInstance
;
746 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
754 hinst
= fodInfos
->ofnInfos
->hInstance
;
755 if(fodInfos
->unicode
)
757 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
758 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
762 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
763 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
770 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
771 !(template = LockResource( hDlgTmpl
)))
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
777 if (fodInfos
->unicode
)
778 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
779 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
780 (LPARAM
)fodInfos
->ofnInfos
);
782 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
783 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
784 (LPARAM
)fodInfos
->ofnInfos
);
787 ShowWindow(hChildDlg
,SW_SHOW
);
791 else if( IsHooked(fodInfos
))
796 WORD menu
,class,title
;
798 GetClientRect(hwnd
,&rectHwnd
);
799 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
800 temp
.tmplate
.dwExtendedStyle
= 0;
801 temp
.tmplate
.cdit
= 0;
806 temp
.menu
= temp
.class = temp
.title
= 0;
808 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
809 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
824 LRESULT hook_result
= 0;
825 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
827 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
829 if(!fodInfos
) return 0;
831 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
833 TRACE("CALL NOTIFY for %x\n", uCode
);
834 if(fodInfos
->unicode
)
837 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
838 ofnNotify
.hdr
.idFrom
=0;
839 ofnNotify
.hdr
.code
= uCode
;
840 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
841 ofnNotify
.pszFile
= NULL
;
842 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
847 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
848 ofnNotify
.hdr
.idFrom
=0;
849 ofnNotify
.hdr
.code
= uCode
;
850 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
851 ofnNotify
.pszFile
= NULL
;
852 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
854 TRACE("RET NOTIFY\n");
856 TRACE("Retval: 0x%08lx\n", hook_result
);
860 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
864 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
866 TRACE("CDM_GETFILEPATH:\n");
868 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
871 /* get path and filenames */
872 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
873 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
874 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
877 p
= buffer
+ strlenW(buffer
);
879 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
881 if (fodInfos
->unicode
)
883 total
= strlenW( buffer
) + 1;
884 if (result
) lstrcpynW( result
, buffer
, size
);
885 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
889 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
890 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
891 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
893 HeapFree( GetProcessHeap(), 0, buffer
);
897 /***********************************************************************
898 * FILEDLG95_HandleCustomDialogMessages
900 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
902 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
904 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
905 WCHAR lpstrPath
[MAX_PATH
];
908 if(!fodInfos
) return FALSE
;
912 case CDM_GETFILEPATH
:
913 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
916 case CDM_GETFOLDERPATH
:
917 TRACE("CDM_GETFOLDERPATH:\n");
918 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
921 if (fodInfos
->unicode
)
922 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
924 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
925 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
927 retval
= lstrlenW(lpstrPath
);
930 case CDM_GETFOLDERIDLIST
:
931 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
932 if (retval
<= wParam
)
933 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
937 TRACE("CDM_GETSPEC:\n");
938 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
941 if (fodInfos
->unicode
)
942 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
944 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
948 case CDM_SETCONTROLTEXT
:
949 TRACE("CDM_SETCONTROLTEXT:\n");
952 if( fodInfos
->unicode
)
953 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
955 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
960 case CDM_HIDECONTROL
:
961 /* MSDN states that it should fail for not OFN_EXPLORER case */
962 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
964 HWND control
= GetDlgItem( hwnd
, wParam
);
965 if (control
) ShowWindow( control
, SW_HIDE
);
972 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
973 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
976 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
980 /***********************************************************************
983 * File open dialog procedure
985 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
988 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
995 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
997 /* Adds the FileOpenDlgInfos in the property list of the dialog
998 so it will be easily accessible through a GetPropA(...) */
999 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
1001 FILEDLG95_InitControls(hwnd
);
1003 fodInfos
->DlgInfos
.hwndCustomDlg
=
1004 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1006 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1007 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1009 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1010 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1011 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1015 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1018 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1021 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1027 case WM_GETISHELLBROWSER
:
1028 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1031 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1036 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1039 /* set up the button tooltips strings */
1040 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1042 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1043 switch(lpnmh
->idFrom
)
1045 /* Up folder button */
1046 case FCIDM_TB_UPFOLDER
:
1047 stringId
= IDS_UPFOLDER
;
1049 /* New folder button */
1050 case FCIDM_TB_NEWFOLDER
:
1051 stringId
= IDS_NEWFOLDER
;
1053 /* List option button */
1054 case FCIDM_TB_SMALLICON
:
1055 stringId
= IDS_LISTVIEW
;
1057 /* Details option button */
1058 case FCIDM_TB_REPORTVIEW
:
1059 stringId
= IDS_REPORTVIEW
;
1061 /* Desktop button */
1062 case FCIDM_TB_DESKTOP
:
1063 stringId
= IDS_TODESKTOP
;
1068 lpdi
->hinst
= COMDLG32_hInstance
;
1069 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1074 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1075 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1080 /***********************************************************************
1081 * FILEDLG95_InitControls
1083 * WM_INITDIALOG message handler (before hook notification)
1085 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1087 int win2000plus
= 0;
1089 int handledPath
= FALSE
;
1090 OSVERSIONINFOW osVi
;
1091 static const WCHAR szwSlash
[] = { '\\', 0 };
1092 static const WCHAR szwStar
[] = { '*',0 };
1094 static const TBBUTTON tbb
[] =
1096 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1097 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1098 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1099 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1101 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1102 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1103 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1104 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1109 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1111 tba
[0].hInst
= HINST_COMMCTRL
;
1112 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1113 tba
[1].hInst
= COMDLG32_hInstance
;
1116 TRACE("%p\n", fodInfos
);
1118 /* Get windows version emulating */
1119 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1120 GetVersionExW(&osVi
);
1121 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1122 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1123 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1124 win2000plus
= (osVi
.dwMajorVersion
> 4);
1125 if (win2000plus
) win98plus
= TRUE
;
1127 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1129 /* Get the hwnd of the controls */
1130 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1131 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1132 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1134 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1135 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1137 /* construct the toolbar */
1138 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1139 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1141 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1142 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1143 rectTB
.left
= rectlook
.right
;
1144 rectTB
.top
= rectlook
.top
-1;
1146 if (fodInfos
->unicode
)
1147 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1148 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1149 rectTB
.left
, rectTB
.top
,
1150 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1151 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1153 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1154 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1155 rectTB
.left
, rectTB
.top
,
1156 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1157 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1159 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1161 /* FIXME: use TB_LOADIMAGES when implemented */
1162 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1163 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
[0]);
1164 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 1, (LPARAM
) &tba
[1]);
1166 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1167 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1169 /* Set the window text with the text specified in the OPENFILENAME structure */
1172 SetWindowTextW(hwnd
,fodInfos
->title
);
1174 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1177 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1178 SetWindowTextW(hwnd
, buf
);
1181 /* Initialise the file name edit control */
1182 handledPath
= FALSE
;
1183 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1185 if(fodInfos
->filename
)
1187 /* 1. If win2000 or higher and filename contains a path, use it
1188 in preference over the lpstrInitialDir */
1189 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1190 WCHAR tmpBuf
[MAX_PATH
];
1194 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1197 /* nameBit is always shorter than the original filename */
1198 lstrcpyW(fodInfos
->filename
,nameBit
);
1201 if (fodInfos
->initdir
== NULL
)
1202 MemFree(fodInfos
->initdir
);
1203 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1204 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1206 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1207 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1209 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1212 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1216 /* 2. (All platforms) If initdir is not null, then use it */
1217 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1218 (*fodInfos
->initdir
!=0x00))
1220 /* Work out the proper path as supplied one might be relative */
1221 /* (Here because supplying '.' as dir browses to My Computer) */
1222 if (handledPath
==FALSE
) {
1223 WCHAR tmpBuf
[MAX_PATH
];
1224 WCHAR tmpBuf2
[MAX_PATH
];
1228 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1229 if( PathFileExistsW(tmpBuf
) ) {
1230 /* initdir does not have to be a directory. If a file is
1231 * specified, the dir part is taken */
1232 if( PathIsDirectoryW(tmpBuf
)) {
1233 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1234 lstrcatW(tmpBuf
, szwSlash
);
1236 lstrcatW(tmpBuf
, szwStar
);
1238 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1241 MemFree(fodInfos
->initdir
);
1242 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1243 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1245 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1248 else if (fodInfos
->initdir
)
1250 MemFree(fodInfos
->initdir
);
1251 fodInfos
->initdir
= NULL
;
1252 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1257 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1258 (*fodInfos
->initdir
==0x00)))
1260 /* 3. All except w2k+: if filename contains a path use it */
1261 if (!win2000plus
&& fodInfos
->filename
&&
1262 *fodInfos
->filename
&&
1263 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1264 WCHAR tmpBuf
[MAX_PATH
];
1268 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1273 /* nameBit is always shorter than the original filename */
1274 lstrcpyW(fodInfos
->filename
, nameBit
);
1277 len
= lstrlenW(tmpBuf
);
1278 MemFree(fodInfos
->initdir
);
1279 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1280 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1283 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1284 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1286 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1289 /* 4. win98+ and win2000+ if any files of specified filter types in
1290 current directory, use it */
1291 if ( win98plus
&& handledPath
== FALSE
&&
1292 fodInfos
->filter
&& *fodInfos
->filter
) {
1294 BOOL searchMore
= TRUE
;
1295 LPCWSTR lpstrPos
= fodInfos
->filter
;
1296 WIN32_FIND_DATAW FindFileData
;
1301 /* filter is a list... title\0ext\0......\0\0 */
1303 /* Skip the title */
1304 if(! *lpstrPos
) break; /* end */
1305 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1307 /* See if any files exist in the current dir with this extension */
1308 if(! *lpstrPos
) break; /* end */
1310 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1312 if (hFind
== INVALID_HANDLE_VALUE
) {
1313 /* None found - continue search */
1314 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1319 MemFree(fodInfos
->initdir
);
1320 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1321 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1324 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1325 debugstr_w(lpstrPos
));
1331 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1333 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1334 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1335 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1337 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1339 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1342 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1343 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1345 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1348 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1351 } else if (handledPath
==FALSE
) {
1352 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1353 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1355 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1358 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1359 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1361 /* Must the open as read only check box be checked ?*/
1362 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1364 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1367 /* Must the open as read only check box be hidden? */
1368 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1370 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1371 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1374 /* Must the help button be hidden? */
1375 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1377 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1378 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1381 /* change Open to Save */
1382 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1385 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1386 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1387 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1388 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1391 /* Initialize the filter combo box */
1392 FILEDLG95_FILETYPE_Init(hwnd
);
1397 /***********************************************************************
1398 * FILEDLG95_ResizeControls
1400 * WM_INITDIALOG message handler (after hook notification)
1402 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1404 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1406 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1409 UINT flags
= SWP_NOACTIVATE
;
1411 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1412 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1414 /* resize the custom dialog to the parent size */
1415 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1416 GetClientRect(hwnd
, &rc
);
1419 /* our own fake template is zero sized and doesn't have children, so
1420 * there is no need to resize it. Picasa depends on it.
1422 flags
|= SWP_NOSIZE
;
1425 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1426 0, 0, rc
.right
, rc
.bottom
, flags
);
1430 /* Resize the height, if open as read only checkbox ad help button are
1431 * hidden and we are not using a custom template nor a customDialog
1433 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1434 (!(fodInfos
->ofnInfos
->Flags
&
1435 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1437 RECT rectDlg
, rectHelp
, rectCancel
;
1438 GetWindowRect(hwnd
, &rectDlg
);
1439 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1440 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1441 /* subtract the height of the help button plus the space between the help
1442 * button and the cancel button to the height of the dialog
1444 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1445 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1446 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1452 /***********************************************************************
1453 * FILEDLG95_FillControls
1455 * WM_INITDIALOG message handler (after hook notification)
1457 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1459 LPITEMIDLIST pidlItemId
= NULL
;
1461 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1463 TRACE("dir=%s file=%s\n",
1464 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1466 /* Get the initial directory pidl */
1468 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1470 WCHAR path
[MAX_PATH
];
1472 GetCurrentDirectoryW(MAX_PATH
,path
);
1473 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1476 /* Initialise shell objects */
1477 FILEDLG95_SHELL_Init(hwnd
);
1479 /* Initialize the Look In combo box */
1480 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1482 /* Browse to the initial directory */
1483 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1485 /* Free pidlItem memory */
1486 COMDLG32_SHFree(pidlItemId
);
1490 /***********************************************************************
1493 * Regroups all the cleaning functions of the filedlg
1495 void FILEDLG95_Clean(HWND hwnd
)
1497 FILEDLG95_FILETYPE_Clean(hwnd
);
1498 FILEDLG95_LOOKIN_Clean(hwnd
);
1499 FILEDLG95_SHELL_Clean(hwnd
);
1501 /***********************************************************************
1502 * FILEDLG95_OnWMCommand
1504 * WM_COMMAND message handler
1506 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1508 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1509 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1510 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1516 FILEDLG95_OnOpen(hwnd
);
1520 FILEDLG95_Clean(hwnd
);
1521 EndDialog(hwnd
, FALSE
);
1523 /* Filetype combo box */
1525 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1527 /* LookIn combo box */
1529 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1532 /* --- toolbar --- */
1533 /* Up folder button */
1534 case FCIDM_TB_UPFOLDER
:
1535 FILEDLG95_SHELL_UpFolder(hwnd
);
1537 /* New folder button */
1538 case FCIDM_TB_NEWFOLDER
:
1539 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1541 /* List option button */
1542 case FCIDM_TB_SMALLICON
:
1543 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1545 /* Details option button */
1546 case FCIDM_TB_REPORTVIEW
:
1547 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1549 /* Details option button */
1550 case FCIDM_TB_DESKTOP
:
1551 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1558 /* Do not use the listview selection anymore */
1559 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1563 /***********************************************************************
1564 * FILEDLG95_OnWMGetIShellBrowser
1566 * WM_GETISHELLBROWSER message handler
1568 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1570 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1574 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1580 /***********************************************************************
1581 * FILEDLG95_SendFileOK
1583 * Sends the CDN_FILEOK notification if required
1586 * TRUE if the dialog should close
1587 * FALSE if the dialog should not be closed
1589 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1591 /* ask the hook if we can close */
1592 if(IsHooked(fodInfos
))
1597 /* First send CDN_FILEOK as MSDN doc says */
1598 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1599 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1601 TRACE("canceled\n");
1602 return (retval
== 0);
1605 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1606 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1607 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1608 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1610 TRACE("canceled\n");
1611 return (retval
== 0);
1617 /***********************************************************************
1618 * FILEDLG95_OnOpenMultipleFiles
1620 * Handles the opening of multiple files.
1623 * check destination buffer size
1625 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1627 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1628 UINT nCount
, nSizePath
;
1629 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1633 if(fodInfos
->unicode
)
1635 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1636 ofn
->lpstrFile
[0] = '\0';
1640 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1641 ofn
->lpstrFile
[0] = '\0';
1644 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1646 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1647 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1648 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1650 LPWSTR lpstrTemp
= lpstrFileList
;
1652 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1656 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1659 WCHAR lpstrNotFound
[100];
1660 WCHAR lpstrMsg
[100];
1662 static const WCHAR nl
[] = {'\n',0};
1664 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1665 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1667 lstrcpyW(tmp
, lpstrTemp
);
1669 lstrcatW(tmp
, lpstrNotFound
);
1671 lstrcatW(tmp
, lpstrMsg
);
1673 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1677 /* move to the next file in the list of files */
1678 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1679 COMDLG32_SHFree(pidl
);
1683 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1684 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1686 /* For "oldstyle" dialog the components have to
1687 be separated by blanks (not '\0'!) and short
1688 filenames have to be used! */
1689 FIXME("Components have to be separated by blanks\n");
1691 if(fodInfos
->unicode
)
1693 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1694 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1695 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1699 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1701 if (ofn
->lpstrFile
!= NULL
)
1703 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1704 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1705 if (ofn
->nMaxFile
> nSizePath
)
1707 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1708 ofn
->lpstrFile
+ nSizePath
,
1709 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1714 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1715 fodInfos
->ofnInfos
->nFileExtension
= 0;
1717 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1720 /* clean and exit */
1721 FILEDLG95_Clean(hwnd
);
1722 return EndDialog(hwnd
,TRUE
);
1725 /***********************************************************************
1728 * Ok button WM_COMMAND message handler
1730 * If the function succeeds, the return value is nonzero.
1732 #define ONOPEN_BROWSE 1
1733 #define ONOPEN_OPEN 2
1734 #define ONOPEN_SEARCH 3
1735 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1737 WCHAR strMsgTitle
[MAX_PATH
];
1738 WCHAR strMsgText
[MAX_PATH
];
1740 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1742 strMsgTitle
[0] = '\0';
1743 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1744 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1747 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1749 LPWSTR lpstrFileList
;
1750 UINT nFileCount
= 0;
1753 WCHAR lpstrPathAndFile
[MAX_PATH
];
1754 WCHAR lpstrTemp
[MAX_PATH
];
1755 LPSHELLFOLDER lpsf
= NULL
;
1757 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1759 TRACE("hwnd=%p\n", hwnd
);
1761 /* get the files from the edit control */
1762 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1764 /* try if the user selected a folder in the shellview */
1767 BrowseSelectedFolder(hwnd
);
1773 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1777 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1780 Step 1: Build a complete path name from the current folder and
1781 the filename or path in the edit box.
1783 - the path in the edit box is a root path
1784 (with or without drive letter)
1785 - the edit box contains ".." (or a path with ".." in it)
1788 /* Get the current directory name */
1789 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1792 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1794 PathAddBackslashW(lpstrPathAndFile
);
1796 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1798 /* if the user specified a fully qualified path use it */
1799 if(PathIsRelativeW(lpstrFileList
))
1801 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
1805 /* does the path have a drive letter? */
1806 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1807 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1809 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
1812 /* resolve "." and ".." */
1813 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1814 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
1815 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1817 MemFree(lpstrFileList
);
1820 Step 2: here we have a cleaned up path
1822 We have to parse the path step by step to see if we have to browse
1823 to a folder if the path points to a directory or the last
1824 valid element is a directory.
1827 lpstrPathAndFile: cleaned up path
1831 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1832 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
1833 nOpenAction
= ONOPEN_OPEN
;
1835 nOpenAction
= ONOPEN_BROWSE
;
1837 /* don't apply any checks with OFN_NOVALIDATE */
1839 LPWSTR lpszTemp
, lpszTemp1
;
1840 LPITEMIDLIST pidl
= NULL
;
1841 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1843 /* check for invalid chars */
1844 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1846 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1851 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1853 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1856 LPSHELLFOLDER lpsfChild
;
1857 WCHAR lpwstrTemp
[MAX_PATH
];
1858 DWORD dwEaten
, dwAttributes
;
1861 lstrcpyW(lpwstrTemp
, lpszTemp
);
1862 p
= PathFindNextComponentW(lpwstrTemp
);
1864 if (!p
) break; /* end of path */
1867 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
1869 /* There are no wildcards when OFN_NOVALIDATE is set */
1870 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1872 static const WCHAR wszWild
[] = { '*', '?', 0 };
1873 /* if the last element is a wildcard do a search */
1874 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1876 nOpenAction
= ONOPEN_SEARCH
;
1880 lpszTemp1
= lpszTemp
;
1882 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1884 /* append a backslash to drive letters */
1885 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1886 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1887 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1889 PathAddBackslashW(lpwstrTemp
);
1892 dwAttributes
= SFGAO_FOLDER
;
1893 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1895 /* the path component is valid, we have a pidl of the next path component */
1896 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
1897 if(dwAttributes
& SFGAO_FOLDER
)
1899 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1901 ERR("bind to failed\n"); /* should not fail */
1904 IShellFolder_Release(lpsf
);
1912 /* end dialog, return value */
1913 nOpenAction
= ONOPEN_OPEN
;
1916 COMDLG32_SHFree(pidl
);
1919 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1921 if(*lpszTemp
|| /* points to trailing null for last path element */
1922 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
1924 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1926 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1932 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1933 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1935 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1939 /* change to the current folder */
1940 nOpenAction
= ONOPEN_OPEN
;
1945 nOpenAction
= ONOPEN_OPEN
;
1949 if(pidl
) COMDLG32_SHFree(pidl
);
1953 Step 3: here we have a cleaned up and validated path
1956 lpsf: ShellFolder bound to the rightmost valid path component
1957 lpstrPathAndFile: cleaned up path
1958 nOpenAction: action to do
1960 TRACE("end validate sf=%p\n", lpsf
);
1964 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1965 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1968 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1971 /* replace the current filter */
1972 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1973 len
= lstrlenW(lpszTemp
)+1;
1974 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1975 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1977 /* set the filter cb to the extension when possible */
1978 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1979 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1982 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1983 TRACE("ONOPEN_BROWSE\n");
1985 IPersistFolder2
* ppf2
;
1986 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1988 LPITEMIDLIST pidlCurrent
;
1989 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1990 IPersistFolder2_Release(ppf2
);
1991 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1993 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
)))
1995 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
1998 else if( nOpenAction
== ONOPEN_SEARCH
)
2000 if (fodInfos
->Shell
.FOIShellView
)
2001 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2003 COMDLG32_SHFree(pidlCurrent
);
2004 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2009 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2010 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2014 /* update READONLY check box flag */
2015 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2016 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2018 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2020 /* Attach the file extension with file name*/
2021 ext
= PathFindExtensionW(lpstrPathAndFile
);
2024 /* if no extension is specified with file name, then */
2025 /* attach the extension from file filter or default one */
2027 WCHAR
*filterExt
= NULL
;
2028 LPWSTR lpstrFilter
= NULL
;
2029 static const WCHAR szwDot
[] = {'.',0};
2030 int PathLength
= lstrlenW(lpstrPathAndFile
);
2033 lstrcatW(lpstrPathAndFile
, szwDot
);
2035 /*Get the file extension from file type filter*/
2036 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2037 fodInfos
->ofnInfos
->nFilterIndex
-1);
2039 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2040 filterExt
= PathFindExtensionW(lpstrFilter
);
2042 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2043 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2044 else if ( fodInfos
->defext
) /* attach the default file extension*/
2045 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2047 /* In Open dialog: if file does not exist try without extension */
2048 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2049 lpstrPathAndFile
[PathLength
] = '\0';
2052 if (fodInfos
->defext
) /* add default extension */
2054 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2057 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2058 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2060 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2063 /* In Save dialog: check if the file already exists */
2064 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2065 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2066 && PathFileExistsW(lpstrPathAndFile
))
2068 WCHAR lpstrOverwrite
[100];
2071 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2072 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2073 MB_YESNO
| MB_ICONEXCLAMATION
);
2081 /* In Open dialog: check if it should be created if it doesn't exist */
2082 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2083 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2084 && !PathFileExistsW(lpstrPathAndFile
))
2086 WCHAR lpstrCreate
[100];
2089 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2090 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2091 MB_YESNO
| MB_ICONEXCLAMATION
);
2099 /* Check that the size of the file does not exceed buffer size.
2100 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2101 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2102 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2105 /* fill destination buffer */
2106 if (fodInfos
->ofnInfos
->lpstrFile
)
2108 if(fodInfos
->unicode
)
2110 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2112 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2113 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2114 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2118 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2120 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2121 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2122 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2123 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2127 if(fodInfos
->unicode
)
2131 /* set filename offset */
2132 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2133 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2135 /* set extension offset */
2136 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2137 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2142 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2144 /* set filename offset */
2145 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2146 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2148 /* set extension offset */
2149 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2150 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2153 /* set the lpstrFileTitle */
2154 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2156 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2157 if(fodInfos
->unicode
)
2159 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2160 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2164 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2165 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2166 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2170 /* copy currently selected filter to lpstrCustomFilter */
2171 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2173 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2174 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2175 NULL
, 0, NULL
, NULL
);
2176 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2178 LPSTR s
= ofn
->lpstrCustomFilter
;
2179 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2180 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2181 s
, len
, NULL
, NULL
);
2186 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2190 FILEDLG95_Clean(hwnd
);
2191 ret
= EndDialog(hwnd
, TRUE
);
2197 size
= lstrlenW(lpstrPathAndFile
) + 1;
2198 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2200 /* return needed size in first two bytes of lpstrFile */
2201 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2202 FILEDLG95_Clean(hwnd
);
2203 ret
= EndDialog(hwnd
, FALSE
);
2204 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2212 if(lpsf
) IShellFolder_Release(lpsf
);
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_Init
2219 * Initialisation of the shell objects
2221 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2223 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2228 * Initialisation of the FileOpenDialogInfos structure
2234 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2236 /* Disable multi-select if flag not set */
2237 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2239 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2241 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2242 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2244 /* Construct the IShellBrowser interface */
2245 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2250 /***********************************************************************
2251 * FILEDLG95_SHELL_ExecuteCommand
2253 * Change the folder option and refresh the view
2254 * If the function succeeds, the return value is nonzero.
2256 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2258 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2261 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2263 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2268 CMINVOKECOMMANDINFO ci
;
2269 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2270 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2274 IContextMenu_InvokeCommand(pcm
, &ci
);
2275 IContextMenu_Release(pcm
);
2281 /***********************************************************************
2282 * FILEDLG95_SHELL_UpFolder
2284 * Browse to the specified object
2285 * If the function succeeds, the return value is nonzero.
2287 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2289 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2293 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2297 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2303 /***********************************************************************
2304 * FILEDLG95_SHELL_BrowseToDesktop
2306 * Browse to the Desktop
2307 * If the function succeeds, the return value is nonzero.
2309 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2311 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2317 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2318 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2319 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2320 COMDLG32_SHFree(pidl
);
2321 return SUCCEEDED(hres
);
2323 /***********************************************************************
2324 * FILEDLG95_SHELL_Clean
2326 * Cleans the memory used by shell objects
2328 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2330 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2334 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2336 /* clean Shell interfaces */
2337 if (fodInfos
->Shell
.FOIShellView
)
2339 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2340 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2342 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2343 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2344 if (fodInfos
->Shell
.FOIDataObject
)
2345 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2348 /***********************************************************************
2349 * FILEDLG95_FILETYPE_Init
2351 * Initialisation of the file type combo box
2353 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2355 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2356 int nFilters
= 0; /* number of filters */
2361 if(fodInfos
->customfilter
)
2363 /* customfilter has one entry... title\0ext\0
2364 * Set first entry of combo box item with customfilter
2367 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2370 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2372 /* Copy the extensions */
2373 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2374 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2375 lstrcpyW(lpstrExt
,lpstrPos
);
2377 /* Add the item at the end of the combo */
2378 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2379 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2382 if(fodInfos
->filter
)
2384 LPCWSTR lpstrPos
= fodInfos
->filter
;
2388 /* filter is a list... title\0ext\0......\0\0
2389 * Set the combo item text to the title and the item data
2392 LPCWSTR lpstrDisplay
;
2396 if(! *lpstrPos
) break; /* end */
2397 lpstrDisplay
= lpstrPos
;
2398 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2400 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2404 /* Copy the extensions */
2405 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2406 lstrcpyW(lpstrExt
,lpstrPos
);
2407 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2409 /* Add the item at the end of the combo */
2410 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2412 /* malformed filters are added anyway... */
2413 if (!*lpstrExt
) break;
2418 * Set the current filter to the one specified
2419 * in the initialisation structure
2421 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2425 /* Check to make sure our index isn't out of bounds. */
2426 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2427 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2428 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2430 /* set default filter index */
2431 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2432 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2434 /* calculate index of Combo Box item */
2435 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2436 if (fodInfos
->customfilter
== NULL
)
2439 /* Set the current index selection. */
2440 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2442 /* Get the corresponding text string from the combo box. */
2443 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2446 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2452 CharLowerW(lpstrFilter
); /* lowercase */
2453 len
= lstrlenW(lpstrFilter
)+1;
2454 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2455 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2458 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2462 /***********************************************************************
2463 * FILEDLG95_FILETYPE_OnCommand
2465 * WM_COMMAND of the file type combo box
2466 * If the function succeeds, the return value is nonzero.
2468 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2470 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2478 /* Get the current item of the filetype combo box */
2479 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2481 /* set the current filter index */
2482 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2483 (fodInfos
->customfilter
== NULL
? 1 : 0);
2485 /* Set the current filter with the current selection */
2486 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2488 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2490 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2493 CharLowerW(lpstrFilter
); /* lowercase */
2494 len
= lstrlenW(lpstrFilter
)+1;
2495 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2496 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2497 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2500 /* Refresh the actual view to display the included items*/
2501 if (fodInfos
->Shell
.FOIShellView
)
2502 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2507 /***********************************************************************
2508 * FILEDLG95_FILETYPE_SearchExt
2510 * searches for an extension in the filetype box
2512 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2514 int i
, iCount
= CBGetCount(hwnd
);
2516 TRACE("%s\n", debugstr_w(lpstrExt
));
2518 if(iCount
!= CB_ERR
)
2520 for(i
=0;i
<iCount
;i
++)
2522 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2529 /***********************************************************************
2530 * FILEDLG95_FILETYPE_Clean
2532 * Clean the memory used by the filetype combo box
2534 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2536 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2538 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2542 /* Delete each string of the combo and their associated data */
2543 if(iCount
!= CB_ERR
)
2545 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2547 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2548 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2551 /* Current filter */
2552 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2556 /***********************************************************************
2557 * FILEDLG95_LOOKIN_Init
2559 * Initialisation of the look in combo box
2562 /* Small helper function, to determine if the unixfs shell extension is rooted
2563 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2565 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2567 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2568 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2569 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2570 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2571 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2572 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2573 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2575 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2582 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2584 IShellFolder
*psfRoot
, *psfDrives
;
2585 IEnumIDList
*lpeRoot
, *lpeDrives
;
2586 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2588 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2592 liInfos
->iMaxIndentation
= 0;
2594 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2596 /* set item height for both text field and listbox */
2597 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2598 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2600 /* Turn on the extended UI for the combo box like Windows does */
2601 CBSetExtendedUI(hwndCombo
, TRUE
);
2603 /* Initialise data of Desktop folder */
2604 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2605 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2606 COMDLG32_SHFree(pidlTmp
);
2608 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2610 SHGetDesktopFolder(&psfRoot
);
2614 /* enumerate the contents of the desktop */
2615 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2617 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2619 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2621 /* If the unixfs extension is rooted, we don't expand the drives by default */
2622 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2624 /* special handling for CSIDL_DRIVES */
2625 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2627 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2629 /* enumerate the drives */
2630 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2632 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2634 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2635 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2636 COMDLG32_SHFree(pidlAbsTmp
);
2637 COMDLG32_SHFree(pidlTmp1
);
2639 IEnumIDList_Release(lpeDrives
);
2641 IShellFolder_Release(psfDrives
);
2646 COMDLG32_SHFree(pidlTmp
);
2648 IEnumIDList_Release(lpeRoot
);
2650 IShellFolder_Release(psfRoot
);
2653 COMDLG32_SHFree(pidlDrives
);
2656 /***********************************************************************
2657 * FILEDLG95_LOOKIN_DrawItem
2659 * WM_DRAWITEM message handler
2661 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2663 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2664 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2665 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2669 HIMAGELIST ilItemImage
;
2672 LPSFOLDER tmpFolder
;
2673 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2677 if(pDIStruct
->itemID
== -1)
2680 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2681 pDIStruct
->itemID
)))
2685 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2687 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2691 SHGFI_PIDL
| SHGFI_SMALLICON
|
2692 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2693 SHGFI_DISPLAYNAME
);
2697 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2701 SHGFI_PIDL
| SHGFI_SMALLICON
|
2702 SHGFI_SYSICONINDEX
|
2706 /* Is this item selected ? */
2707 if(pDIStruct
->itemState
& ODS_SELECTED
)
2709 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2710 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2711 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2715 SetTextColor(pDIStruct
->hDC
,crText
);
2716 SetBkColor(pDIStruct
->hDC
,crWin
);
2717 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2720 /* Do not indent item if drawing in the edit of the combo */
2721 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2724 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2728 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2729 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2734 iIndentation
= tmpFolder
->m_iIndent
;
2736 /* Draw text and icon */
2738 /* Initialise the icon display area */
2739 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2740 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2741 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2742 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2744 /* Initialise the text display area */
2745 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2746 rectText
.left
= rectIcon
.right
;
2748 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2749 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2751 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2753 /* Draw the icon from the image list */
2754 ImageList_Draw(ilItemImage
,
2761 /* Draw the associated text */
2762 if(sfi
.szDisplayName
)
2763 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
2769 /***********************************************************************
2770 * FILEDLG95_LOOKIN_OnCommand
2772 * LookIn combo box WM_COMMAND message handler
2773 * If the function succeeds, the return value is nonzero.
2775 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2777 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2779 TRACE("%p\n", fodInfos
);
2785 LPSFOLDER tmpFolder
;
2788 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2790 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2795 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2796 tmpFolder
->pidlItem
,
2799 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2809 /***********************************************************************
2810 * FILEDLG95_LOOKIN_AddItem
2812 * Adds an absolute pidl item to the lookin combo box
2813 * returns the index of the inserted item
2815 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2817 LPITEMIDLIST pidlNext
;
2820 LookInInfos
*liInfos
;
2822 TRACE("%08x\n", iInsertId
);
2827 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
2830 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2831 tmpFolder
->m_iIndent
= 0;
2833 /* Calculate the indentation of the item in the lookin*/
2835 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2837 tmpFolder
->m_iIndent
++;
2840 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2842 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2843 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2845 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2846 SHGetFileInfoW((LPCWSTR
)pidl
,
2850 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2851 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2853 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
2855 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2859 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
2861 /* Add the item at the end of the list */
2864 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2866 /* Insert the item at the iInsertId position*/
2869 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2872 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2876 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2877 MemFree( tmpFolder
);
2882 /***********************************************************************
2883 * FILEDLG95_LOOKIN_InsertItemAfterParent
2885 * Insert an item below its parent
2887 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2890 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2895 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2899 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2902 /* Free pidlParent memory */
2903 COMDLG32_SHFree((LPVOID
)pidlParent
);
2905 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2908 /***********************************************************************
2909 * FILEDLG95_LOOKIN_SelectItem
2911 * Adds an absolute pidl item to the lookin combo box
2912 * returns the index of the inserted item
2914 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2917 LookInInfos
*liInfos
;
2921 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2923 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
2927 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2928 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2933 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2934 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2938 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2940 if(iRemovedItem
< iItemPos
)
2945 CBSetCurSel(hwnd
,iItemPos
);
2946 liInfos
->uSelectedItem
= iItemPos
;
2952 /***********************************************************************
2953 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2955 * Remove the item with an expansion level over iExpansionLevel
2957 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2960 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
2964 if(liInfos
->iMaxIndentation
<= 2)
2967 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2969 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2970 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2972 CBDeleteString(hwnd
,iItemPos
);
2973 liInfos
->iMaxIndentation
--;
2981 /***********************************************************************
2982 * FILEDLG95_LOOKIN_SearchItem
2984 * Search for pidl in the lookin combo box
2985 * returns the index of the found item
2987 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2990 int iCount
= CBGetCount(hwnd
);
2992 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
2994 if (iCount
!= CB_ERR
)
2998 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3000 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3002 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3010 /***********************************************************************
3011 * FILEDLG95_LOOKIN_Clean
3013 * Clean the memory used by the lookin combo box
3015 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3017 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3019 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3023 /* Delete each string of the combo and their associated data */
3024 if (iCount
!= CB_ERR
)
3026 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3028 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3029 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3031 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3035 /* LookInInfos structure */
3036 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3039 /***********************************************************************
3040 * FILEDLG95_FILENAME_FillFromSelection
3042 * fills the edit box from the cached DataObject
3044 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3046 FileOpenDlgInfos
*fodInfos
;
3048 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3049 WCHAR lpstrTemp
[MAX_PATH
];
3050 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3053 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3055 /* Count how many files we have */
3056 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3058 /* calculate the string length, count files */
3059 if (nFileSelected
>= 1)
3061 nLength
+= 3; /* first and last quotes, trailing \0 */
3062 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3064 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3068 /* get the total length of the selected file names */
3069 lpstrTemp
[0] = '\0';
3070 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3072 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3074 nLength
+= lstrlenW( lpstrTemp
) + 3;
3077 COMDLG32_SHFree( pidl
);
3082 /* allocate the buffer */
3083 if (nFiles
<= 1) nLength
= MAX_PATH
;
3084 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3086 /* Generate the string for the edit control */
3089 lpstrCurrFile
= lpstrAllFile
;
3090 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3092 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3096 /* get the file name */
3097 lpstrTemp
[0] = '\0';
3098 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3100 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3104 *lpstrCurrFile
++ = '\"';
3105 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3106 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3107 *lpstrCurrFile
++ = '\"';
3108 *lpstrCurrFile
++ = ' ';
3113 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3116 COMDLG32_SHFree( (LPVOID
) pidl
);
3119 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3121 /* Select the file name like Windows does */
3122 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3124 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3128 /* copied from shell32 to avoid linking to it
3129 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3130 * is dependent on whether emulated OS is unicode or not.
3132 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3137 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3138 COMDLG32_SHFree(src
->u
.pOleStr
);
3142 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3147 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3152 FIXME("unknown type %x!\n", src
->uType
);
3153 if (len
) *dest
= '\0';
3159 /***********************************************************************
3160 * FILEDLG95_FILENAME_GetFileNames
3162 * Copies the filenames to a delimited string list.
3163 * The delimiter is specified by the parameter 'separator',
3164 * usually either a space or a nul
3166 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3168 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3169 UINT nStrCharCount
= 0; /* index in src buffer */
3170 UINT nFileIndex
= 0; /* index in dest buffer */
3171 UINT nFileCount
= 0; /* number of files */
3172 UINT nStrLen
= 0; /* length of string in edit control */
3173 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3177 /* get the filenames from the edit control */
3178 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3179 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3180 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3182 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3184 /* we might get single filename without any '"',
3185 * so we need nStrLen + terminating \0 + end-of-list \0 */
3186 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3189 /* build delimited file list from filenames */
3190 while ( nStrCharCount
<= nStrLen
)
3192 if ( lpstrEdit
[nStrCharCount
]=='"' )
3195 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3197 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3200 (*lpstrFileList
)[nFileIndex
++] = 0;
3206 /* single, unquoted string */
3207 if ((nStrLen
> 0) && (nFileIndex
== 0) )
3209 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3210 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3215 (*lpstrFileList
)[nFileIndex
++] = '\0';
3217 *sizeUsed
= nFileIndex
;
3222 #define SETDefFormatEtc(fe,cf,med) \
3224 (fe).cfFormat = cf;\
3225 (fe).dwAspect = DVASPECT_CONTENT; \
3232 * DATAOBJECT Helper functions
3235 /***********************************************************************
3236 * COMCTL32_ReleaseStgMedium
3238 * like ReleaseStgMedium from ole32
3240 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3242 if(medium
.pUnkForRelease
)
3244 IUnknown_Release(medium
.pUnkForRelease
);
3248 GlobalUnlock(medium
.u
.hGlobal
);
3249 GlobalFree(medium
.u
.hGlobal
);
3253 /***********************************************************************
3254 * GetPidlFromDataObject
3256 * Return pidl(s) by number from the cached DataObject
3258 * nPidlIndex=0 gets the fully qualified root path
3260 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3264 FORMATETC formatetc
;
3265 LPITEMIDLIST pidl
= NULL
;
3267 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3272 /* Set the FORMATETC structure*/
3273 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3275 /* Get the pidls from IDataObject */
3276 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3278 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3279 if(nPidlIndex
<= cida
->cidl
)
3281 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3283 COMCTL32_ReleaseStgMedium(medium
);
3288 /***********************************************************************
3291 * Return the number of selected items in the DataObject.
3294 UINT
GetNumSelected( IDataObject
*doSelected
)
3298 FORMATETC formatetc
;
3300 TRACE("sv=%p\n", doSelected
);
3302 if (!doSelected
) return 0;
3304 /* Set the FORMATETC structure*/
3305 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3307 /* Get the pidls from IDataObject */
3308 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3310 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3311 retVal
= cida
->cidl
;
3312 COMCTL32_ReleaseStgMedium(medium
);
3322 /***********************************************************************
3325 * Get the pidl's display name (relative to folder) and
3326 * put it in lpstrFileName.
3328 * Return NOERROR on success,
3332 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3337 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3341 SHGetDesktopFolder(&lpsf
);
3342 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3343 IShellFolder_Release(lpsf
);
3347 /* Get the display name of the pidl relative to the folder */
3348 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3350 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3355 /***********************************************************************
3356 * GetShellFolderFromPidl
3358 * pidlRel is the item pidl relative
3359 * Return the IShellFolder of the absolute pidl
3361 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3363 IShellFolder
*psf
= NULL
,*psfParent
;
3365 TRACE("%p\n", pidlAbs
);
3367 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3370 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3372 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3374 IShellFolder_Release(psfParent
);
3378 /* return the desktop */
3384 /***********************************************************************
3387 * Return the LPITEMIDLIST to the parent of the pidl in the list
3389 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3391 LPITEMIDLIST pidlParent
;
3393 TRACE("%p\n", pidl
);
3395 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3396 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3401 /***********************************************************************
3404 * returns the pidl of the file name relative to folder
3405 * NULL if an error occurred
3407 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3409 LPITEMIDLIST pidl
= NULL
;
3412 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3414 if(!lpcstrFileName
) return NULL
;
3415 if(!*lpcstrFileName
) return NULL
;
3419 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3420 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3421 IShellFolder_Release(lpsf
);
3426 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3433 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3435 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3438 TRACE("%p, %p\n", psf
, pidl
);
3440 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3442 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3443 /* see documentation shell 4.1*/
3444 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3447 /***********************************************************************
3448 * BrowseSelectedFolder
3450 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3452 BOOL bBrowseSelFolder
= FALSE
;
3453 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3457 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3459 LPITEMIDLIST pidlSelection
;
3461 /* get the file selected */
3462 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3463 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3465 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3466 pidlSelection
, SBSP_RELATIVE
) ) )
3468 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3469 ' ','n','o','t',' ','e','x','i','s','t',0};
3470 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3472 bBrowseSelFolder
= TRUE
;
3473 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3475 COMDLG32_SHFree( pidlSelection
);
3478 return bBrowseSelFolder
;
3482 * Memory allocation methods */
3483 static void *MemAlloc(UINT size
)
3485 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3488 static void MemFree(void *mem
)
3490 HeapFree(GetProcessHeap(),0,mem
);
3494 * Old-style (win3.1) dialogs */
3496 /***********************************************************************
3497 * FD32_GetTemplate [internal]
3499 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3500 * by a 32 bits application
3503 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3505 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3506 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3509 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3511 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3513 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3517 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3521 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3522 priv
->ofnA
->lpTemplateName
,
3525 hResInfo
= FindResourceW(ofnW
->hInstance
,
3526 ofnW
->lpTemplateName
,
3530 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3533 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3535 !(lfs
->template = LockResource(hDlgTmpl
)))
3537 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3540 } else { /* get it from internal Wine resource */
3542 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3543 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3545 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3548 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3549 !(lfs
->template = LockResource( hDlgTmpl
)))
3551 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3559 /************************************************************************
3560 * FD32_Init [internal]
3561 * called from the common 16/32 code to initialize 32 bit data
3563 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3565 BOOL IsUnicode
= (BOOL
) data
;
3568 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3569 lfs
->private1632
= priv
;
3570 if (NULL
== lfs
->private1632
) return FALSE
;
3573 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3574 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3575 if (lfs
->ofnW
->lpfnHook
)
3580 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3581 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3582 if (priv
->ofnA
->lpfnHook
)
3584 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3585 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3588 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3593 /***********************************************************************
3594 * FD32_CallWindowProc [internal]
3596 * called from the common 16/32 code to call the appropriate hook
3598 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3602 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3606 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3607 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3608 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3609 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3610 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3614 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3615 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3616 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3617 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3618 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3622 /***********************************************************************
3623 * FD32_UpdateResult [internal]
3624 * update the real client structures if any
3626 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3628 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3629 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3634 if (ofnW
->nMaxFile
&&
3635 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3636 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3637 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3639 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3640 /* set filename offset */
3641 lpszTemp
= PathFindFileNameA(priv
->ofnA
->lpstrFile
);
3642 priv
->ofnA
->nFileOffset
= (lpszTemp
- priv
->ofnA
->lpstrFile
);
3644 /* set extension offset */
3645 lpszTemp
= PathFindExtensionA(priv
->ofnA
->lpstrFile
);
3646 priv
->ofnA
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- priv
->ofnA
->lpstrFile
) + 1 : 0;
3650 /***********************************************************************
3651 * FD32_UpdateFileTitle [internal]
3652 * update the real client structures if any
3654 static void CALLBACK
FD32_UpdateFileTitle(const FD31_DATA
*lfs
)
3656 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3657 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3661 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3662 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3663 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3668 /***********************************************************************
3669 * FD32_SendLbGetCurSel [internal]
3670 * retrieve selected listbox item
3672 static LRESULT CALLBACK
FD32_SendLbGetCurSel(const FD31_DATA
*lfs
)
3674 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3678 /************************************************************************
3679 * FD32_Destroy [internal]
3680 * called from the common 16/32 code to cleanup 32 bit data
3682 static void CALLBACK
FD32_Destroy(const FD31_DATA
*lfs
)
3684 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3686 /* if ofnW has been allocated, have to free everything in it */
3687 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3689 FD31_FreeOfnW(lfs
->ofnW
);
3690 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3694 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3696 callbacks
->Init
= FD32_Init
;
3697 callbacks
->CWP
= FD32_CallWindowProc
;
3698 callbacks
->UpdateResult
= FD32_UpdateResult
;
3699 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3700 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3701 callbacks
->Destroy
= FD32_Destroy
;
3704 /***********************************************************************
3705 * FD32_WMMeasureItem [internal]
3707 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3709 LPMEASUREITEMSTRUCT lpmeasure
;
3711 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3712 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3717 /***********************************************************************
3718 * FileOpenDlgProc [internal]
3719 * Used for open and save, in fact.
3721 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3722 WPARAM wParam
, LPARAM lParam
)
3724 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3726 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
3727 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3730 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3732 return lRet
; /* else continue message processing */
3737 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3739 case WM_MEASUREITEM
:
3740 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3743 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3746 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3749 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3750 switch (HIWORD(lParam
))
3753 SetTextColor((HDC16
)wParam
, 0x00000000);
3755 case CTLCOLOR_STATIC
:
3756 SetTextColor((HDC16
)wParam
, 0x00000000);
3766 /***********************************************************************
3767 * GetFileName31A [internal]
3769 * Creates a win31 style dialog box for the user to select a file to open/save.
3771 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
3772 UINT dlgType
/* type dialogue : open/save */
3778 FD31_CALLBACKS callbacks
;
3780 if (!lpofn
|| !FD31_Init()) return FALSE
;
3782 TRACE("ofn flags %08x\n", lpofn
->Flags
);
3783 FD32_SetupCallbacks(&callbacks
);
3784 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3787 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3788 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3789 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3790 FD31_DestroyPrivate(lfs
);
3793 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3797 /***********************************************************************
3798 * GetFileName31W [internal]
3800 * Creates a win31 style dialog box for the user to select a file to open/save
3802 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
3803 UINT dlgType
/* type dialogue : open/save */
3809 FD31_CALLBACKS callbacks
;
3811 if (!lpofn
|| !FD31_Init()) return FALSE
;
3813 FD32_SetupCallbacks(&callbacks
);
3814 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3817 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3818 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3819 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3820 FD31_DestroyPrivate(lfs
);
3823 TRACE("file %s, file offset %d, ext offset %d\n",
3824 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3828 /* ------------------ APIs ---------------------- */
3830 /***********************************************************************
3831 * GetOpenFileNameA (COMDLG32.@)
3833 * Creates a dialog box for the user to select a file to open.
3836 * TRUE on success: user enters a valid file
3837 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3840 BOOL WINAPI
GetOpenFileNameA(
3841 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3843 BOOL win16look
= FALSE
;
3845 TRACE("flags %08x\n", ofn
->Flags
);
3847 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3848 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3849 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3851 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3852 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3855 return GetFileName31A(ofn
, OPEN_DIALOG
);
3857 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3860 /***********************************************************************
3861 * GetOpenFileNameW (COMDLG32.@)
3863 * Creates a dialog box for the user to select a file to open.
3866 * TRUE on success: user enters a valid file
3867 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3870 BOOL WINAPI
GetOpenFileNameW(
3871 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3873 BOOL win16look
= FALSE
;
3875 TRACE("flags %08x\n", ofn
->Flags
);
3877 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3878 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3879 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3881 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3882 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3885 return GetFileName31W(ofn
, OPEN_DIALOG
);
3887 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3891 /***********************************************************************
3892 * GetSaveFileNameA (COMDLG32.@)
3894 * Creates a dialog box for the user to select a file to save.
3897 * TRUE on success: user enters a valid file
3898 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3901 BOOL WINAPI
GetSaveFileNameA(
3902 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3904 BOOL win16look
= FALSE
;
3906 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3907 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3910 return GetFileName31A(ofn
, SAVE_DIALOG
);
3912 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3915 /***********************************************************************
3916 * GetSaveFileNameW (COMDLG32.@)
3918 * Creates a dialog box for the user to select a file to save.
3921 * TRUE on success: user enters a valid file
3922 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3925 BOOL WINAPI
GetSaveFileNameW(
3926 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3928 BOOL win16look
= FALSE
;
3930 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3931 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3934 return GetFileName31W(ofn
, SAVE_DIALOG
);
3936 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
3939 /***********************************************************************
3940 * GetFileTitleA (COMDLG32.@)
3942 * See GetFileTitleW.
3944 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
3947 UNICODE_STRING strWFile
;
3950 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
3951 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
3952 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
3953 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
3954 RtlFreeUnicodeString( &strWFile
);
3955 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
3960 /***********************************************************************
3961 * GetFileTitleW (COMDLG32.@)
3963 * Get the name of a file.
3966 * lpFile [I] name and location of file
3967 * lpTitle [O] returned file name
3968 * cbBuf [I] buffer size of lpTitle
3972 * Failure: negative number.
3974 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
3977 static const WCHAR brkpoint
[] = {'*','[',']',0};
3978 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
3980 if(lpFile
== NULL
|| lpTitle
== NULL
)
3983 len
= lstrlenW(lpFile
);
3988 if(strpbrkW(lpFile
, brkpoint
))
3993 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
3996 for(i
= len
; i
>= 0; i
--)
3998 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4008 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4010 len
= lstrlenW(lpFile
+i
)+1;
4014 lstrcpyW(lpTitle
, &lpFile
[i
]);