2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
79 #include "filedlgbrowser.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | 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 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
184 /* Internal functions used by the dialog */
185 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
186 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
187 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
188 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
189 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
190 static void FILEDLG95_Clean(HWND hwnd
);
192 /* Functions used by the shell navigation */
193 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
197 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
);
202 /* Functions used by the filetype combo box */
203 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
204 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
210 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
211 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
219 /* Miscellaneous tool functions */
220 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
221 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
222 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
223 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size
);
227 static void MemFree(void *mem
);
229 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 void SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
231 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
232 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
233 static BOOL
BrowseSelectedFolder(HWND hwnd
);
235 /***********************************************************************
238 * Creates an Open common dialog box that lets the user select
239 * the drive, directory, and the name of a file or set of files to open.
241 * IN : The FileOpenDlgInfos structure associated with the dialog
242 * OUT : TRUE on success
243 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
245 static BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
253 /* test for missing functionality */
254 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
256 FIXME("Flags 0x%08lx not yet implemented\n",
257 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
260 /* Create the dialog from a template */
262 if(!(hRes
= FindResourceA(COMDLG32_hInstance
,MAKEINTRESOURCEA(NEWFILEOPENORD
),(LPSTR
)RT_DIALOG
)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
267 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
268 !(template = LockResource( hDlgTmpl
)))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
274 /* old style hook messages */
275 if (IsHooked(fodInfos
))
277 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
278 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
279 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
280 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
283 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
284 (LPDLGTEMPLATEA
) template,
285 fodInfos
->ofnInfos
->hwndOwner
,
289 /* Unable to create the dialog */
296 /***********************************************************************
299 * Call GetFileName95 with this structure and clean the memory.
301 * IN : The OPENFILENAMEA initialisation structure passed to
302 * GetOpenFileNameA win api function (see filedlg.c)
304 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
307 FileOpenDlgInfos fodInfos
;
308 LPSTR lpstrSavDir
= NULL
;
310 LPWSTR defext
= NULL
;
311 LPWSTR filter
= NULL
;
312 LPWSTR customfilter
= NULL
;
314 /* Initialize FileOpenDlgInfos structure */
315 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
317 /* Pass in the original ofn */
318 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
320 /* save current directory */
321 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
323 lpstrSavDir
= MemAlloc(MAX_PATH
);
324 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
327 fodInfos
.unicode
= FALSE
;
329 /* convert all the input strings to unicode */
330 if(ofn
->lpstrInitialDir
)
332 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
333 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
334 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
337 fodInfos
.initdir
= NULL
;
341 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
342 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
345 fodInfos
.filename
= NULL
;
349 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
350 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
351 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
353 fodInfos
.defext
= defext
;
357 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
358 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
359 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
361 fodInfos
.title
= title
;
363 if (ofn
->lpstrFilter
)
368 /* filter is a list... title\0ext\0......\0\0 */
369 s
= ofn
->lpstrFilter
;
370 while (*s
) s
= s
+strlen(s
)+1;
372 n
= s
- ofn
->lpstrFilter
;
373 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
374 filter
= MemAlloc(len
*sizeof(WCHAR
));
375 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
377 fodInfos
.filter
= filter
;
379 /* convert lpstrCustomFilter */
380 if (ofn
->lpstrCustomFilter
)
385 /* customfilter contains a pair of strings... title\0ext\0 */
386 s
= ofn
->lpstrCustomFilter
;
387 if (*s
) s
= s
+strlen(s
)+1;
388 if (*s
) s
= s
+strlen(s
)+1;
389 n
= s
- ofn
->lpstrCustomFilter
;
390 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
391 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
392 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
394 fodInfos
.customfilter
= customfilter
;
396 /* Initialize the dialog property */
397 fodInfos
.DlgInfos
.dwDlgProp
= 0;
398 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
403 ret
= GetFileName95(&fodInfos
);
406 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
407 ret
= GetFileName95(&fodInfos
);
415 SetCurrentDirectoryA(lpstrSavDir
);
416 MemFree(lpstrSavDir
);
426 MemFree(customfilter
);
428 MemFree(fodInfos
.initdir
);
430 if(fodInfos
.filename
)
431 MemFree(fodInfos
.filename
);
433 TRACE("selected file: %s\n",ofn
->lpstrFile
);
438 /***********************************************************************
441 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
442 * Call GetFileName95 with this structure and clean the memory.
445 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
448 FileOpenDlgInfos fodInfos
;
449 LPWSTR lpstrSavDir
= NULL
;
451 /* Initialize FileOpenDlgInfos structure */
452 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
454 /* Pass in the original ofn */
455 fodInfos
.ofnInfos
= ofn
;
457 fodInfos
.title
= ofn
->lpstrTitle
;
458 fodInfos
.defext
= ofn
->lpstrDefExt
;
459 fodInfos
.filter
= ofn
->lpstrFilter
;
460 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
462 /* convert string arguments, save others */
465 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
466 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
469 fodInfos
.filename
= NULL
;
471 if(ofn
->lpstrInitialDir
)
473 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
474 DWORD len
= strlenW(ofn
->lpstrInitialDir
)+1;
475 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
476 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
479 fodInfos
.initdir
= NULL
;
481 /* save current directory */
482 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
484 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
485 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
488 fodInfos
.unicode
= TRUE
;
493 ret
= GetFileName95(&fodInfos
);
496 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
497 ret
= GetFileName95(&fodInfos
);
505 SetCurrentDirectoryW(lpstrSavDir
);
506 MemFree(lpstrSavDir
);
509 /* restore saved IN arguments and convert OUT arguments back */
510 MemFree(fodInfos
.filename
);
511 MemFree(fodInfos
.initdir
);
515 /******************************************************************************
516 * COMDLG32_GetDisplayNameOf [internal]
518 * Helper function to get the display name for a pidl.
520 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
521 LPSHELLFOLDER psfDesktop
;
524 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
527 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
528 IShellFolder_Release(psfDesktop
);
532 IShellFolder_Release(psfDesktop
);
533 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
536 /***********************************************************************
537 * ArrangeCtrlPositions [internal]
539 * NOTE: Do not change anything here without a lot of testing.
541 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
543 HWND hwndChild
, hwndStc32
;
544 RECT rectParent
, rectChild
, rectStc32
;
545 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
547 /* Take into account if open as read only checkbox and help button
552 RECT rectHelp
, rectCancel
;
553 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
554 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
555 /* subtract the height of the help button plus the space between
556 * the help button and the cancel button to the height of the dialog
558 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
562 There are two possibilities to add components to the default file dialog box.
564 By default, all the new components are added below the standard dialog box (the else case).
566 However, if there is a static text component with the stc32 id, a special case happens.
567 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
568 in the window and the cx and cy indicate how to size the window.
569 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
570 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
574 GetClientRect(hwndParentDlg
, &rectParent
);
576 /* when arranging controls we have to use fixed parent size */
577 rectParent
.bottom
-= help_fixup
;
579 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
582 GetWindowRect(hwndStc32
, &rectStc32
);
583 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
585 /* set the size of the stc32 control according to the size of
586 * client area of the parent dialog
588 SetWindowPos(hwndStc32
, 0,
590 rectParent
.right
, rectParent
.bottom
,
591 SWP_NOMOVE
| SWP_NOZORDER
);
594 SetRectEmpty(&rectStc32
);
596 /* this part moves controls of the child dialog */
597 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
600 if (hwndChild
!= hwndStc32
)
602 GetWindowRect(hwndChild
, &rectChild
);
603 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
605 /* move only if stc32 exist */
606 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
608 LONG old_left
= rectChild
.left
;
610 /* move to the right of visible controls of the parent dialog */
611 rectChild
.left
+= rectParent
.right
;
612 rectChild
.left
-= rectStc32
.right
;
614 child_width_fixup
= rectChild
.left
- old_left
;
616 /* move even if stc32 doesn't exist */
617 if (rectChild
.top
>= rectStc32
.bottom
)
619 LONG old_top
= rectChild
.top
;
621 /* move below visible controls of the parent dialog */
622 rectChild
.top
+= rectParent
.bottom
;
623 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
625 child_height_fixup
= rectChild
.top
- old_top
;
628 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
629 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
631 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
634 /* this part moves controls of the parent dialog */
635 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
638 if (hwndChild
!= hwndChildDlg
)
640 GetWindowRect(hwndChild
, &rectChild
);
641 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
643 /* left,top of stc32 marks the position of controls
644 * from the parent dialog
646 rectChild
.left
+= rectStc32
.left
;
647 rectChild
.top
+= rectStc32
.top
;
649 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
650 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
652 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
655 /* calculate the size of the resulting dialog */
657 /* here we have to use original parent size */
658 GetClientRect(hwndParentDlg
, &rectParent
);
659 GetClientRect(hwndChildDlg
, &rectChild
);
663 rectChild
.right
+= child_width_fixup
;
664 rectChild
.bottom
+= child_height_fixup
;
666 if (rectParent
.right
> rectChild
.right
)
668 rectParent
.right
+= rectChild
.right
;
669 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
673 rectParent
.right
= rectChild
.right
;
676 if (rectParent
.bottom
> rectChild
.bottom
)
678 rectParent
.bottom
+= rectChild
.bottom
;
679 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
683 /* child dialog is higher, unconditionally set new dialog
684 * height to its size (help_fixup will be subtracted below)
686 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
691 rectParent
.bottom
+= rectChild
.bottom
;
694 /* finally use fixed parent size */
695 rectParent
.bottom
-= help_fixup
;
697 /* save the size of the parent's client area */
698 rectChild
.right
= rectParent
.right
;
699 rectChild
.bottom
= rectParent
.bottom
;
701 /* set the size of the parent dialog */
702 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
703 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
704 SetWindowPos(hwndParentDlg
, 0,
706 rectParent
.right
- rectParent
.left
,
707 rectParent
.bottom
- rectParent
.top
,
708 SWP_NOMOVE
| SWP_NOZORDER
);
710 /* set the size of the child dialog */
711 SetWindowPos(hwndChildDlg
, HWND_BOTTOM
,
712 0, 0, rectChild
.right
, rectChild
.bottom
, SWP_NOACTIVATE
);
715 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
724 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
734 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
735 * structure's hInstance parameter is not a HINSTANCE, but
736 * instead a pointer to a template resource to use.
738 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
741 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
744 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
746 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
752 hinst
= fodInfos
->ofnInfos
->hInstance
;
753 if(fodInfos
->unicode
)
755 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
756 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
760 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
761 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
765 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
768 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
769 !(template = LockResource( hDlgTmpl
)))
771 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
775 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, template, hwnd
,
776 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
777 (LPARAM
)fodInfos
->ofnInfos
);
780 ShowWindow(hChildDlg
,SW_SHOW
);
784 else if( IsHooked(fodInfos
))
789 WORD menu
,class,title
;
791 GetClientRect(hwnd
,&rectHwnd
);
792 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
793 temp
.tmplate
.dwExtendedStyle
= 0;
794 temp
.tmplate
.cdit
= 0;
799 temp
.menu
= temp
.class = temp
.title
= 0;
801 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
802 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
809 /***********************************************************************
810 * SendCustomDlgNotificationMessage
812 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
815 void SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
817 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
819 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
821 if(!fodInfos
) return;
823 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
825 TRACE("CALL NOTIFY for %x\n", uCode
);
826 if(fodInfos
->unicode
)
829 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
830 ofnNotify
.hdr
.idFrom
=0;
831 ofnNotify
.hdr
.code
= uCode
;
832 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
833 ofnNotify
.pszFile
= NULL
;
834 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
839 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
840 ofnNotify
.hdr
.idFrom
=0;
841 ofnNotify
.hdr
.code
= uCode
;
842 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
843 ofnNotify
.pszFile
= NULL
;
844 SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
846 TRACE("RET NOTIFY\n");
850 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
852 INT_PTR sizeUsed
= 0, n
, total
;
853 LPWSTR lpstrFileList
= NULL
;
854 WCHAR lpstrCurrentDir
[MAX_PATH
];
855 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
857 TRACE("CDM_GETFILEPATH:\n");
859 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
862 /* get path and filenames */
863 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrCurrentDir
);
864 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
866 TRACE("path >%s< filespec >%s< %d files\n",
867 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
869 if( fodInfos
->unicode
)
871 LPWSTR bufW
= buffer
;
872 total
= strlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
874 /* Prepend the current path */
875 n
= strlenW(lpstrCurrentDir
) + 1;
876 memcpy( bufW
, lpstrCurrentDir
, min(n
,size
) * sizeof(WCHAR
));
879 /* 'n' includes trailing \0 */
881 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
883 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
888 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
889 NULL
, 0, NULL
, NULL
);
890 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
891 NULL
, 0, NULL
, NULL
);
893 /* Prepend the current path */
894 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
895 bufA
, size
, NULL
, NULL
);
899 /* 'n' includes trailing \0 */
901 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
902 &bufA
[n
], size
-n
, NULL
, NULL
);
905 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
907 MemFree(lpstrFileList
);
912 static INT_PTR
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
914 INT_PTR sizeUsed
= 0;
915 LPWSTR lpstrFileList
= NULL
;
916 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
918 TRACE("CDM_GETSPEC:\n");
920 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
921 if( fodInfos
->unicode
)
923 LPWSTR bufW
= buffer
;
924 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
929 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
930 NULL
, 0, NULL
, NULL
);
931 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
932 bufA
, size
, NULL
, NULL
);
934 MemFree(lpstrFileList
);
939 /***********************************************************************
940 * FILEDLG95_HandleCustomDialogMessages
942 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
944 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
946 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
947 WCHAR lpstrPath
[MAX_PATH
];
950 if(!fodInfos
) return FALSE
;
954 case CDM_GETFILEPATH
:
955 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
958 case CDM_GETFOLDERPATH
:
959 TRACE("CDM_GETFOLDERPATH:\n");
960 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
963 if (fodInfos
->unicode
)
964 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
966 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
967 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
969 retval
= strlenW(lpstrPath
);
973 retval
= FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
976 case CDM_SETCONTROLTEXT
:
977 TRACE("CDM_SETCONTROLTEXT:\n");
980 if( fodInfos
->unicode
)
981 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
983 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
988 case CDM_HIDECONTROL
:
990 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
997 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
1001 /***********************************************************************
1004 * File open dialog procedure
1006 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1009 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
1016 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1018 /* Adds the FileOpenDlgInfos in the property list of the dialog
1019 so it will be easily accessible through a GetPropA(...) */
1020 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
1022 fodInfos
->DlgInfos
.hwndCustomDlg
=
1023 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1025 FILEDLG95_InitControls(hwnd
);
1027 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1028 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1029 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1031 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1033 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1034 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1035 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1039 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1042 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1045 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1051 case WM_GETISHELLBROWSER
:
1052 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1055 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1060 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1063 /* set up the button tooltips strings */
1064 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1066 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1067 switch(lpnmh
->idFrom
)
1069 /* Up folder button */
1070 case FCIDM_TB_UPFOLDER
:
1071 stringId
= IDS_UPFOLDER
;
1073 /* New folder button */
1074 case FCIDM_TB_NEWFOLDER
:
1075 stringId
= IDS_NEWFOLDER
;
1077 /* List option button */
1078 case FCIDM_TB_SMALLICON
:
1079 stringId
= IDS_LISTVIEW
;
1081 /* Details option button */
1082 case FCIDM_TB_REPORTVIEW
:
1083 stringId
= IDS_REPORTVIEW
;
1085 /* Desktop button */
1086 case FCIDM_TB_DESKTOP
:
1087 stringId
= IDS_TODESKTOP
;
1092 lpdi
->hinst
= COMDLG32_hInstance
;
1093 lpdi
->lpszText
= (LPSTR
) stringId
;
1098 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1099 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1104 /***********************************************************************
1105 * FILEDLG95_InitControls
1107 * WM_INITDIALOG message handler (before hook notification)
1109 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1111 int win2000plus
= 0;
1113 int handledPath
= FALSE
;
1114 OSVERSIONINFOA osVi
;
1115 static const WCHAR szwSlash
[] = { '\\', 0 };
1116 static const WCHAR szwStar
[] = { '*',0 };
1120 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1121 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1122 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1123 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1124 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1125 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1126 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1127 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1128 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1133 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1135 tba
[0].hInst
= HINST_COMMCTRL
;
1136 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1137 tba
[1].hInst
= COMDLG32_hInstance
;
1140 TRACE("%p\n", fodInfos
);
1142 /* Get windows version emulating */
1143 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1144 GetVersionExA(&osVi
);
1145 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1146 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1147 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1148 win2000plus
= (osVi
.dwMajorVersion
> 4);
1149 if (win2000plus
) win98plus
= TRUE
;
1151 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1153 /* Get the hwnd of the controls */
1154 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1155 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1156 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1158 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1159 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1161 /* construct the toolbar */
1162 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1163 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1165 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1166 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1167 rectTB
.left
= rectlook
.right
;
1168 rectTB
.top
= rectlook
.top
-1;
1170 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1171 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1172 rectTB
.left
, rectTB
.top
,
1173 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1174 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1176 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1178 /* FIXME: use TB_LOADIMAGES when implemented */
1179 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1180 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1181 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1183 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1184 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1186 /* Set the window text with the text specified in the OPENFILENAME structure */
1189 SetWindowTextW(hwnd
,fodInfos
->title
);
1191 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1194 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1195 SetWindowTextW(hwnd
, buf
);
1198 /* Initialise the file name edit control */
1199 handledPath
= FALSE
;
1200 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1202 if(fodInfos
->filename
)
1204 /* 1. If win2000 or higher and filename contains a path, use it
1205 in preference over the lpstrInitialDir */
1206 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1207 WCHAR tmpBuf
[MAX_PATH
];
1211 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1214 /* nameBit is always shorter than the original filename */
1215 strcpyW(fodInfos
->filename
,nameBit
);
1218 if (fodInfos
->initdir
== NULL
)
1219 MemFree(fodInfos
->initdir
);
1220 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1221 strcpyW(fodInfos
->initdir
, tmpBuf
);
1223 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1224 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1226 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1229 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1233 /* 2. (All platforms) If initdir is not null, then use it */
1234 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1235 (*fodInfos
->initdir
!=0x00))
1237 /* Work out the proper path as supplied one might be relative */
1238 /* (Here because supplying '.' as dir browses to My Computer) */
1239 if (handledPath
==FALSE
) {
1240 WCHAR tmpBuf
[MAX_PATH
];
1241 WCHAR tmpBuf2
[MAX_PATH
];
1245 strcpyW(tmpBuf
, fodInfos
->initdir
);
1246 if( PathFileExistsW(tmpBuf
) ) {
1247 /* initdir does not have to be a directory. If a file is
1248 * specified, the dir part is taken */
1249 if( PathIsDirectoryW(tmpBuf
)) {
1250 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1251 strcatW(tmpBuf
, szwSlash
);
1253 strcatW(tmpBuf
, szwStar
);
1255 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1258 if (fodInfos
->initdir
)
1259 MemFree(fodInfos
->initdir
);
1260 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1261 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1263 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1266 else if (fodInfos
->initdir
)
1268 MemFree(fodInfos
->initdir
);
1269 fodInfos
->initdir
= NULL
;
1270 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1275 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1276 (*fodInfos
->initdir
==0x00)))
1278 /* 3. All except w2k+: if filename contains a path use it */
1279 if (!win2000plus
&& fodInfos
->filename
&&
1280 *fodInfos
->filename
&&
1281 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1282 WCHAR tmpBuf
[MAX_PATH
];
1286 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1291 /* nameBit is always shorter than the original filename */
1292 strcpyW(fodInfos
->filename
, nameBit
);
1295 len
= strlenW(tmpBuf
);
1296 if(fodInfos
->initdir
)
1297 MemFree(fodInfos
->initdir
);
1298 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1299 strcpyW(fodInfos
->initdir
, tmpBuf
);
1302 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1303 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1305 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1308 /* 4. win98+ and win2000+ if any files of specified filter types in
1309 current directory, use it */
1310 if ( win98plus
&& handledPath
== FALSE
&&
1311 fodInfos
->filter
&& *fodInfos
->filter
) {
1313 BOOL searchMore
= TRUE
;
1314 LPCWSTR lpstrPos
= fodInfos
->filter
;
1315 WIN32_FIND_DATAW FindFileData
;
1320 /* filter is a list... title\0ext\0......\0\0 */
1322 /* Skip the title */
1323 if(! *lpstrPos
) break; /* end */
1324 lpstrPos
+= strlenW(lpstrPos
) + 1;
1326 /* See if any files exist in the current dir with this extension */
1327 if(! *lpstrPos
) break; /* end */
1329 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1331 if (hFind
== INVALID_HANDLE_VALUE
) {
1332 /* None found - continue search */
1333 lpstrPos
+= strlenW(lpstrPos
) + 1;
1338 if(fodInfos
->initdir
)
1339 MemFree(fodInfos
->initdir
);
1340 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1341 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1344 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1345 debugstr_w(lpstrPos
));
1351 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1353 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1354 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1355 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1357 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1359 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1362 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1363 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1365 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1368 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1371 } else if (handledPath
==FALSE
) {
1372 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1373 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1375 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1378 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1379 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1381 /* Must the open as read only check box be checked ?*/
1382 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1384 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1387 /* Must the open as read only check box be hidden? */
1388 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1390 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1391 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1394 /* Must the help button be hidden? */
1395 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1397 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1398 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1401 /* Resize the height, if open as read only checkbox ad help button
1402 are hidden and we are not using a custom template nor a customDialog
1404 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1405 (!(fodInfos
->ofnInfos
->Flags
&
1406 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))) &&
1407 (!fodInfos
->DlgInfos
.hwndCustomDlg
))
1409 RECT rectDlg
, rectHelp
, rectCancel
;
1410 GetWindowRect(hwnd
, &rectDlg
);
1411 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1412 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1413 /* subtract the height of the help button plus the space between
1414 the help button and the cancel button to the height of the dialog */
1415 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1416 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1417 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1419 /* change Open to Save */
1420 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1423 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1424 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1425 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1426 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1431 /***********************************************************************
1432 * FILEDLG95_FillControls
1434 * WM_INITDIALOG message handler (after hook notification)
1436 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1438 LPITEMIDLIST pidlItemId
= NULL
;
1440 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1442 TRACE("dir=%s file=%s\n",
1443 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1445 /* Get the initial directory pidl */
1447 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1449 WCHAR path
[MAX_PATH
];
1451 GetCurrentDirectoryW(MAX_PATH
,path
);
1452 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1455 /* Initialise shell objects */
1456 FILEDLG95_SHELL_Init(hwnd
);
1458 /* Initialize the Look In combo box */
1459 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1461 /* Initialize the filter combo box */
1462 FILEDLG95_FILETYPE_Init(hwnd
);
1464 /* Browse to the initial directory */
1465 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1467 /* Free pidlItem memory */
1468 COMDLG32_SHFree(pidlItemId
);
1472 /***********************************************************************
1475 * Regroups all the cleaning functions of the filedlg
1477 void FILEDLG95_Clean(HWND hwnd
)
1479 FILEDLG95_FILETYPE_Clean(hwnd
);
1480 FILEDLG95_LOOKIN_Clean(hwnd
);
1481 FILEDLG95_SHELL_Clean(hwnd
);
1483 /***********************************************************************
1484 * FILEDLG95_OnWMCommand
1486 * WM_COMMAND message handler
1488 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1490 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1491 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1492 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1498 FILEDLG95_OnOpen(hwnd
);
1502 FILEDLG95_Clean(hwnd
);
1503 EndDialog(hwnd
, FALSE
);
1505 /* Filetype combo box */
1507 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1509 /* LookIn combo box */
1511 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1514 /* --- toolbar --- */
1515 /* Up folder button */
1516 case FCIDM_TB_UPFOLDER
:
1517 FILEDLG95_SHELL_UpFolder(hwnd
);
1519 /* New folder button */
1520 case FCIDM_TB_NEWFOLDER
:
1521 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1523 /* List option button */
1524 case FCIDM_TB_SMALLICON
:
1525 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1527 /* Details option button */
1528 case FCIDM_TB_REPORTVIEW
:
1529 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1531 /* Details option button */
1532 case FCIDM_TB_DESKTOP
:
1533 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1540 /* Do not use the listview selection anymore */
1541 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1545 /***********************************************************************
1546 * FILEDLG95_OnWMGetIShellBrowser
1548 * WM_GETISHELLBROWSER message handler
1550 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1553 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1557 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1563 /***********************************************************************
1564 * FILEDLG95_SendFileOK
1566 * Sends the CDN_FILEOK notification if required
1569 * TRUE if the dialog should close
1570 * FALSE if the dialog should not be closed
1572 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1574 /* ask the hook if we can close */
1575 if(IsHooked(fodInfos
))
1578 /* First send CDN_FILEOK as MSDN doc says */
1579 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1580 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1582 TRACE("canceled\n");
1586 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1587 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1588 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1589 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1591 TRACE("canceled\n");
1598 /***********************************************************************
1599 * FILEDLG95_OnOpenMultipleFiles
1601 * Handles the opening of multiple files.
1604 * check destination buffer size
1606 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1608 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1609 UINT nCount
, nSizePath
;
1610 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1614 if(fodInfos
->unicode
)
1616 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1617 ofn
->lpstrFile
[0] = '\0';
1621 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1622 ofn
->lpstrFile
[0] = '\0';
1625 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1627 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1628 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1629 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1631 LPWSTR lpstrTemp
= lpstrFileList
;
1633 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1637 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1640 WCHAR lpstrNotFound
[100];
1641 WCHAR lpstrMsg
[100];
1643 static const WCHAR nl
[] = {'\n',0};
1645 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1646 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1648 strcpyW(tmp
, lpstrTemp
);
1650 strcatW(tmp
, lpstrNotFound
);
1652 strcatW(tmp
, lpstrMsg
);
1654 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1658 /* move to the next file in the list of files */
1659 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1660 COMDLG32_SHFree(pidl
);
1664 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1665 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1667 /* For "oldstyle" dialog the components have to
1668 be separated by blanks (not '\0'!) and short
1669 filenames have to be used! */
1670 FIXME("Components have to be separated by blanks\n");
1672 if(fodInfos
->unicode
)
1674 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1675 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1676 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1680 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1682 if (ofn
->lpstrFile
!= NULL
)
1684 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1685 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1686 if (ofn
->nMaxFile
> nSizePath
)
1688 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1689 ofn
->lpstrFile
+ nSizePath
,
1690 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1695 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1696 fodInfos
->ofnInfos
->nFileExtension
= 0;
1698 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1701 /* clean and exit */
1702 FILEDLG95_Clean(hwnd
);
1703 return EndDialog(hwnd
,TRUE
);
1706 /***********************************************************************
1709 * Ok button WM_COMMAND message handler
1711 * If the function succeeds, the return value is nonzero.
1713 #define ONOPEN_OPEN 1
1714 #define ONOPEN_SEARCH 2
1715 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1717 WCHAR strMsgTitle
[MAX_PATH
];
1718 WCHAR strMsgText
[MAX_PATH
];
1720 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1722 strMsgTitle
[0] = '\0';
1723 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1724 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1727 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1729 LPWSTR lpstrFileList
;
1730 UINT nFileCount
= 0;
1733 WCHAR lpstrPathAndFile
[MAX_PATH
];
1734 WCHAR lpstrTemp
[MAX_PATH
];
1735 LPSHELLFOLDER lpsf
= NULL
;
1737 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1739 TRACE("hwnd=%p\n", hwnd
);
1741 if(BrowseSelectedFolder(hwnd
))
1744 /* get the files from the edit control */
1745 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1747 /* try if the user selected a folder in the shellview */
1753 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1757 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1760 Step 1: Build a complete path name from the current folder and
1761 the filename or path in the edit box.
1763 - the path in the edit box is a root path
1764 (with or without drive letter)
1765 - the edit box contains ".." (or a path with ".." in it)
1768 /* Get the current directory name */
1769 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1772 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1774 PathAddBackslashW(lpstrPathAndFile
);
1776 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1778 /* if the user specifyed a fully qualified path use it */
1779 if(PathIsRelativeW(lpstrFileList
))
1781 strcatW(lpstrPathAndFile
, lpstrFileList
);
1785 /* does the path have a drive letter? */
1786 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1787 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1789 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1792 /* resolve "." and ".." */
1793 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1794 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1795 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1797 MemFree(lpstrFileList
);
1800 Step 2: here we have a cleaned up path
1802 We have to parse the path step by step to see if we have to browse
1803 to a folder if the path points to a directory or the last
1804 valid element is a directory.
1807 lpstrPathAndFile: cleaned up path
1810 nOpenAction
= ONOPEN_OPEN
;
1812 /* don't apply any checks with OFN_NOVALIDATE */
1814 LPWSTR lpszTemp
, lpszTemp1
;
1815 LPITEMIDLIST pidl
= NULL
;
1816 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1818 /* check for invalid chars */
1819 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1821 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1826 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1828 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1831 LPSHELLFOLDER lpsfChild
;
1832 WCHAR lpwstrTemp
[MAX_PATH
];
1833 DWORD dwEaten
, dwAttributes
;
1836 strcpyW(lpwstrTemp
, lpszTemp
);
1837 p
= PathFindNextComponentW(lpwstrTemp
);
1839 if (!p
) break; /* end of path */
1842 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1846 static const WCHAR wszWild
[] = { '*', '?', 0 };
1847 /* if the last element is a wildcard do a search */
1848 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1850 nOpenAction
= ONOPEN_SEARCH
;
1854 lpszTemp1
= lpszTemp
;
1856 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1858 /* append a backslash to drive letters */
1859 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1860 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1861 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1863 PathAddBackslashW(lpwstrTemp
);
1866 dwAttributes
= SFGAO_FOLDER
;
1867 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1869 /* the path component is valid, we have a pidl of the next path component */
1870 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1871 if(dwAttributes
& SFGAO_FOLDER
)
1873 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1875 ERR("bind to failed\n"); /* should not fail */
1878 IShellFolder_Release(lpsf
);
1886 /* end dialog, return value */
1887 nOpenAction
= ONOPEN_OPEN
;
1890 COMDLG32_SHFree(pidl
);
1893 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1895 if(*lpszTemp
) /* points to trailing null for last path element */
1897 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1899 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1905 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1906 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1908 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1912 /* change to the current folder */
1913 nOpenAction
= ONOPEN_OPEN
;
1918 nOpenAction
= ONOPEN_OPEN
;
1922 if(pidl
) COMDLG32_SHFree(pidl
);
1926 Step 3: here we have a cleaned up and validated path
1929 lpsf: ShellFolder bound to the rightmost valid path component
1930 lpstrPathAndFile: cleaned up path
1931 nOpenAction: action to do
1933 TRACE("end validate sf=%p\n", lpsf
);
1937 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1938 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1941 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1943 IPersistFolder2
* ppf2
;
1945 /* replace the current filter */
1946 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1947 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1948 len
= strlenW(lpszTemp
)+1;
1949 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1950 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1952 /* set the filter cb to the extension when possible */
1953 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1954 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1956 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1958 LPITEMIDLIST pidlCurrent
;
1959 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1960 IPersistFolder2_Release(ppf2
);
1961 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1963 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1967 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1969 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
1970 COMDLG32_SHFree(pidlCurrent
);
1975 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1976 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1980 /* update READONLY check box flag */
1981 if ((SendMessageA(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
1982 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
1984 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
1986 /* Attach the file extension with file name*/
1988 if(!PathIsDirectoryW(lpstrPathAndFile
))
1990 if((ext
= PathFindExtensionW(lpstrPathAndFile
)) == NULL
)
1992 /* if no extension is specified with file name, then */
1993 /* attach the extension from file filter or default one */
1995 WCHAR
*filterExt
= NULL
;
1996 LPWSTR lpstrFilter
= NULL
;
1997 static const WCHAR szwDot
[] = {'.',0};
1998 int PathLength
= strlenW(lpstrPathAndFile
);
2001 strcatW(lpstrPathAndFile
, szwDot
);
2003 /*Get the file extension from file type filter*/
2004 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2005 fodInfos
->ofnInfos
->nFilterIndex
-1);
2007 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2008 filterExt
= PathFindExtensionW(lpstrFilter
);
2010 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2011 strcatW(lpstrPathAndFile
, filterExt
+ 1);
2012 else if ( fodInfos
->defext
) /* attach the default file extension*/
2013 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
2015 /* In Open dialog: if file does not exist try without extension */
2016 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2017 lpstrPathAndFile
[PathLength
] = '\0';
2020 if (fodInfos
->defext
) /* add default extension */
2022 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2025 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2026 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2028 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2032 /* In Save dialog: check if the file already exists */
2033 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2034 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2035 && PathFileExistsW(lpstrPathAndFile
))
2037 WCHAR lpstrOverwrite
[100];
2040 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2041 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2042 MB_YESNO
| MB_ICONEXCLAMATION
);
2050 /* Check that the size of the file does not exceed buffer size.
2051 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2052 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2053 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2057 /* fill destination buffer */
2058 if (fodInfos
->ofnInfos
->lpstrFile
)
2060 if(fodInfos
->unicode
)
2062 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2064 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2065 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2066 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2070 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2072 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2073 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2074 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2075 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2079 /* set filename offset */
2080 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2081 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2083 /* set extension offset */
2084 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2085 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2087 /* set the lpstrFileTitle */
2088 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2090 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2091 if(fodInfos
->unicode
)
2093 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2094 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2098 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2099 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2100 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2104 /* copy currently selected filter to lpstrCustomFilter */
2105 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2107 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2108 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2109 NULL
, 0, NULL
, NULL
);
2110 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2112 LPSTR s
= ofn
->lpstrCustomFilter
;
2113 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2114 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2115 s
, len
, NULL
, NULL
);
2120 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2124 FILEDLG95_Clean(hwnd
);
2125 ret
= EndDialog(hwnd
, TRUE
);
2131 size
= strlenW(lpstrPathAndFile
) + 1;
2132 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2134 /* return needed size in first two bytes of lpstrFile */
2135 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2136 FILEDLG95_Clean(hwnd
);
2137 ret
= EndDialog(hwnd
, FALSE
);
2138 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2146 if(lpsf
) IShellFolder_Release(lpsf
);
2150 /***********************************************************************
2151 * FILEDLG95_SHELL_Init
2153 * Initialisation of the shell objects
2155 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2157 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2162 * Initialisation of the FileOpenDialogInfos structure
2168 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2170 /* Disable multi-select if flag not set */
2171 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2173 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2175 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2176 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2178 /* Construct the IShellBrowser interface */
2179 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2184 /***********************************************************************
2185 * FILEDLG95_SHELL_ExecuteCommand
2187 * Change the folder option and refresh the view
2188 * If the function succeeds, the return value is nonzero.
2190 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2192 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2195 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2197 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2202 CMINVOKECOMMANDINFO ci
;
2203 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2204 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2208 IContextMenu_InvokeCommand(pcm
, &ci
);
2209 IContextMenu_Release(pcm
);
2215 /***********************************************************************
2216 * FILEDLG95_SHELL_UpFolder
2218 * Browse to the specified object
2219 * If the function succeeds, the return value is nonzero.
2221 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2223 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2227 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2231 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2237 /***********************************************************************
2238 * FILEDLG95_SHELL_BrowseToDesktop
2240 * Browse to the Desktop
2241 * If the function succeeds, the return value is nonzero.
2243 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2245 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2251 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2252 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2253 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2254 COMDLG32_SHFree(pidl
);
2255 return SUCCEEDED(hres
);
2257 /***********************************************************************
2258 * FILEDLG95_SHELL_Clean
2260 * Cleans the memory used by shell objects
2262 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2264 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2268 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2270 /* clean Shell interfaces */
2271 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2272 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2273 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2274 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2275 if (fodInfos
->Shell
.FOIDataObject
)
2276 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2279 /***********************************************************************
2280 * FILEDLG95_FILETYPE_Init
2282 * Initialisation of the file type combo box
2284 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2286 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2287 int nFilters
= 0; /* number of filters */
2292 if(fodInfos
->customfilter
)
2294 /* customfilter has one entry... title\0ext\0
2295 * Set first entry of combo box item with customfilter
2298 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2301 lpstrPos
+= strlenW(fodInfos
->customfilter
) + 1;
2303 /* Copy the extensions */
2304 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2305 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2306 strcpyW(lpstrExt
,lpstrPos
);
2308 /* Add the item at the end of the combo */
2309 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2310 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2313 if(fodInfos
->filter
)
2315 LPCWSTR lpstrPos
= fodInfos
->filter
;
2319 /* filter is a list... title\0ext\0......\0\0
2320 * Set the combo item text to the title and the item data
2323 LPCWSTR lpstrDisplay
;
2327 if(! *lpstrPos
) break; /* end */
2328 lpstrDisplay
= lpstrPos
;
2329 lpstrPos
+= strlenW(lpstrPos
) + 1;
2331 /* Copy the extensions */
2332 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2333 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2334 strcpyW(lpstrExt
,lpstrPos
);
2335 lpstrPos
+= strlenW(lpstrPos
) + 1;
2337 /* Add the item at the end of the combo */
2338 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2339 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2345 * Set the current filter to the one specified
2346 * in the initialisation structure
2348 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2352 /* Check to make sure our index isn't out of bounds. */
2353 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2354 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2355 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2357 /* set default filter index */
2358 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2359 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2361 /* calculate index of Combo Box item */
2362 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2363 if (fodInfos
->customfilter
== NULL
)
2366 /* Set the current index selection. */
2367 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2369 /* Get the corresponding text string from the combo box. */
2370 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2373 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2379 CharLowerW(lpstrFilter
); /* lowercase */
2380 len
= strlenW(lpstrFilter
)+1;
2381 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2382 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2385 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2389 /***********************************************************************
2390 * FILEDLG95_FILETYPE_OnCommand
2392 * WM_COMMAND of the file type combo box
2393 * If the function succeeds, the return value is nonzero.
2395 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2397 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2405 /* Get the current item of the filetype combo box */
2406 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2408 /* set the current filter index */
2409 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2410 (fodInfos
->customfilter
== NULL
? 1 : 0);
2412 /* Set the current filter with the current selection */
2413 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2414 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2416 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2418 if((int)lpstrFilter
!= CB_ERR
)
2421 CharLowerW(lpstrFilter
); /* lowercase */
2422 len
= strlenW(lpstrFilter
)+1;
2423 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2424 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2425 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2428 /* Refresh the actual view to display the included items*/
2429 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2434 /***********************************************************************
2435 * FILEDLG95_FILETYPE_SearchExt
2437 * searches for an extension in the filetype box
2439 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2441 int i
, iCount
= CBGetCount(hwnd
);
2443 TRACE("%s\n", debugstr_w(lpstrExt
));
2445 if(iCount
!= CB_ERR
)
2447 for(i
=0;i
<iCount
;i
++)
2449 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2456 /***********************************************************************
2457 * FILEDLG95_FILETYPE_Clean
2459 * Clean the memory used by the filetype combo box
2461 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2463 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2465 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2469 /* Delete each string of the combo and their associated data */
2470 if(iCount
!= CB_ERR
)
2472 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2474 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2475 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2478 /* Current filter */
2479 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2480 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2484 /***********************************************************************
2485 * FILEDLG95_LOOKIN_Init
2487 * Initialisation of the look in combo box
2489 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2491 IShellFolder
*psfRoot
, *psfDrives
;
2492 IEnumIDList
*lpeRoot
, *lpeDrives
;
2493 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2495 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2499 liInfos
->iMaxIndentation
= 0;
2501 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2503 /* set item height for both text field and listbox */
2504 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2505 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2507 /* Turn on the extended UI for the combo box like Windows does */
2508 CBSetExtendedUI(hwndCombo
, TRUE
);
2510 /* Initialise data of Desktop folder */
2511 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2512 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2513 COMDLG32_SHFree(pidlTmp
);
2515 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2517 SHGetDesktopFolder(&psfRoot
);
2521 /* enumerate the contents of the desktop */
2522 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2524 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2526 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2528 /* special handling for CSIDL_DRIVES */
2529 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2531 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2533 /* enumerate the drives */
2534 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2536 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2538 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2539 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2540 COMDLG32_SHFree(pidlAbsTmp
);
2541 COMDLG32_SHFree(pidlTmp1
);
2543 IEnumIDList_Release(lpeDrives
);
2545 IShellFolder_Release(psfDrives
);
2548 COMDLG32_SHFree(pidlTmp
);
2550 IEnumIDList_Release(lpeRoot
);
2552 IShellFolder_Release(psfRoot
);
2555 COMDLG32_SHFree(pidlDrives
);
2558 /***********************************************************************
2559 * FILEDLG95_LOOKIN_DrawItem
2561 * WM_DRAWITEM message handler
2563 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2565 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2566 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2567 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2571 HIMAGELIST ilItemImage
;
2574 LPSFOLDER tmpFolder
;
2577 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2581 if(pDIStruct
->itemID
== -1)
2584 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2585 pDIStruct
->itemID
)))
2589 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2591 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2594 sizeof (SHFILEINFOA
),
2595 SHGFI_PIDL
| SHGFI_SMALLICON
|
2596 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2597 SHGFI_DISPLAYNAME
);
2601 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2604 sizeof (SHFILEINFOA
),
2605 SHGFI_PIDL
| SHGFI_SMALLICON
|
2606 SHGFI_SYSICONINDEX
|
2610 /* Is this item selected ? */
2611 if(pDIStruct
->itemState
& ODS_SELECTED
)
2613 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2614 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2615 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2619 SetTextColor(pDIStruct
->hDC
,crText
);
2620 SetBkColor(pDIStruct
->hDC
,crWin
);
2621 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2624 /* Do not indent item if drawing in the edit of the combo */
2625 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2628 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2631 sizeof (SHFILEINFOA
),
2632 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2633 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2638 iIndentation
= tmpFolder
->m_iIndent
;
2640 /* Draw text and icon */
2642 /* Initialise the icon display area */
2643 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2644 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2645 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2646 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2648 /* Initialise the text display area */
2649 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2650 rectText
.left
= rectIcon
.right
;
2652 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2653 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2655 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2657 /* Draw the icon from the image list */
2658 ImageList_Draw(ilItemImage
,
2665 /* Draw the associated text */
2666 if(sfi
.szDisplayName
)
2667 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2673 /***********************************************************************
2674 * FILEDLG95_LOOKIN_OnCommand
2676 * LookIn combo box WM_COMMAND message handler
2677 * If the function succeeds, the return value is nonzero.
2679 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2681 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2683 TRACE("%p\n", fodInfos
);
2689 LPSFOLDER tmpFolder
;
2692 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2694 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2699 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2700 tmpFolder
->pidlItem
,
2703 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2713 /***********************************************************************
2714 * FILEDLG95_LOOKIN_AddItem
2716 * Adds an absolute pidl item to the lookin combo box
2717 * returns the index of the inserted item
2719 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2721 LPITEMIDLIST pidlNext
;
2724 LookInInfos
*liInfos
;
2726 TRACE("%08x\n", iInsertId
);
2731 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2734 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2735 tmpFolder
->m_iIndent
= 0;
2737 /* Calculate the indentation of the item in the lookin*/
2739 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2741 tmpFolder
->m_iIndent
++;
2744 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2746 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2747 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2749 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2750 SHGetFileInfoA((LPSTR
)pidl
,
2754 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2755 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2757 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2759 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2763 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2765 /* Add the item at the end of the list */
2768 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2770 /* Insert the item at the iInsertId position*/
2773 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2776 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2780 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2781 MemFree( tmpFolder
);
2786 /***********************************************************************
2787 * FILEDLG95_LOOKIN_InsertItemAfterParent
2789 * Insert an item below its parent
2791 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2794 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2799 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2803 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2806 /* Free pidlParent memory */
2807 COMDLG32_SHFree((LPVOID
)pidlParent
);
2809 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2812 /***********************************************************************
2813 * FILEDLG95_LOOKIN_SelectItem
2815 * Adds an absolute pidl item to the lookin combo box
2816 * returns the index of the inserted item
2818 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2821 LookInInfos
*liInfos
;
2825 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2827 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2831 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2832 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2837 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2838 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2842 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2844 if(iRemovedItem
< iItemPos
)
2849 CBSetCurSel(hwnd
,iItemPos
);
2850 liInfos
->uSelectedItem
= iItemPos
;
2856 /***********************************************************************
2857 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2859 * Remove the item with an expansion level over iExpansionLevel
2861 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2865 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2869 if(liInfos
->iMaxIndentation
<= 2)
2872 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2874 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2875 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2877 CBDeleteString(hwnd
,iItemPos
);
2878 liInfos
->iMaxIndentation
--;
2886 /***********************************************************************
2887 * FILEDLG95_LOOKIN_SearchItem
2889 * Search for pidl in the lookin combo box
2890 * returns the index of the found item
2892 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2895 int iCount
= CBGetCount(hwnd
);
2897 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2899 if (iCount
!= CB_ERR
)
2903 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2905 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2907 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2915 /***********************************************************************
2916 * FILEDLG95_LOOKIN_Clean
2918 * Clean the memory used by the lookin combo box
2920 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2922 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2924 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2928 /* Delete each string of the combo and their associated data */
2929 if (iCount
!= CB_ERR
)
2931 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2933 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2934 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2936 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2940 /* LookInInfos structure */
2941 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2944 /***********************************************************************
2945 * FILEDLG95_FILENAME_FillFromSelection
2947 * fills the edit box from the cached DataObject
2949 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2951 FileOpenDlgInfos
*fodInfos
;
2953 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2954 char lpstrTemp
[MAX_PATH
];
2955 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2958 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2960 /* Count how many files we have */
2961 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2963 /* calculate the string length, count files */
2964 if (nFileSelected
>= 1)
2966 nLength
+= 3; /* first and last quotes, trailing \0 */
2967 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2969 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2973 /* get the total length of the selected file names */
2974 lpstrTemp
[0] = '\0';
2975 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2977 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2979 nLength
+= strlen( lpstrTemp
) + 3;
2982 COMDLG32_SHFree( pidl
);
2987 /* allocate the buffer */
2988 if (nFiles
<= 1) nLength
= MAX_PATH
;
2989 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2990 lpstrAllFile
[0] = '\0';
2992 /* Generate the string for the edit control */
2995 lpstrCurrFile
= lpstrAllFile
;
2996 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2998 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3002 /* get the file name */
3003 lpstrTemp
[0] = '\0';
3004 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3006 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3010 *lpstrCurrFile
++ = '\"';
3011 strcpy( lpstrCurrFile
, lpstrTemp
);
3012 lpstrCurrFile
+= strlen( lpstrTemp
);
3013 strcpy( lpstrCurrFile
, "\" " );
3018 strcpy( lpstrAllFile
, lpstrTemp
);
3021 COMDLG32_SHFree( (LPVOID
) pidl
);
3024 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3026 /* Select the file name like Windows does */
3027 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)-1);
3029 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3033 /* copied from shell32 to avoid linking to it
3034 * FIXME: why? shell32 is already linked
3036 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3041 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
3042 COMDLG32_SHFree(src
->u
.pOleStr
);
3046 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
3050 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
3054 FIXME("unknown type!\n");
3057 *(LPSTR
)dest
= '\0';
3064 /***********************************************************************
3065 * FILEDLG95_FILENAME_GetFileNames
3067 * Copies the filenames to a delimited string list.
3068 * The delimiter is specified by the parameter 'separator',
3069 * usually either a space or a nul
3071 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3073 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3074 UINT nStrCharCount
= 0; /* index in src buffer */
3075 UINT nFileIndex
= 0; /* index in dest buffer */
3076 UINT nFileCount
= 0; /* number of files */
3077 UINT nStrLen
= 0; /* length of string in edit control */
3078 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3082 /* get the filenames from the edit control */
3083 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3084 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3085 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3087 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3089 /* we might get single filename without any '"',
3090 * so we need nStrLen + terminating \0 + end-of-list \0 */
3091 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3094 /* build delimited file list from filenames */
3095 while ( nStrCharCount
<= nStrLen
)
3097 if ( lpstrEdit
[nStrCharCount
]=='"' )
3100 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3102 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3106 (*lpstrFileList
)[nFileIndex
++] = separator
;
3113 /* single, unquoted string */
3114 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3116 strcpyW(*lpstrFileList
, lpstrEdit
);
3117 nFileIndex
= strlenW(lpstrEdit
) + 1;
3118 (*sizeUsed
) = nFileIndex
;
3123 (*lpstrFileList
)[nFileIndex
] = '\0';
3130 #define SETDefFormatEtc(fe,cf,med) \
3132 (fe).cfFormat = cf;\
3133 (fe).dwAspect = DVASPECT_CONTENT; \
3140 * DATAOBJECT Helper functions
3143 /***********************************************************************
3144 * COMCTL32_ReleaseStgMedium
3146 * like ReleaseStgMedium from ole32
3148 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3150 if(medium
.pUnkForRelease
)
3152 IUnknown_Release(medium
.pUnkForRelease
);
3156 GlobalUnlock(medium
.u
.hGlobal
);
3157 GlobalFree(medium
.u
.hGlobal
);
3161 /***********************************************************************
3162 * GetPidlFromDataObject
3164 * Return pidl(s) by number from the cached DataObject
3166 * nPidlIndex=0 gets the fully qualified root path
3168 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3172 FORMATETC formatetc
;
3173 LPITEMIDLIST pidl
= NULL
;
3175 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3177 /* Set the FORMATETC structure*/
3178 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3180 /* Get the pidls from IDataObject */
3181 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3183 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3184 if(nPidlIndex
<= cida
->cidl
)
3186 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3188 COMCTL32_ReleaseStgMedium(medium
);
3193 /***********************************************************************
3196 * Return the number of selected items in the DataObject.
3199 UINT
GetNumSelected( IDataObject
*doSelected
)
3203 FORMATETC formatetc
;
3205 TRACE("sv=%p\n", doSelected
);
3207 if (!doSelected
) return 0;
3209 /* Set the FORMATETC structure*/
3210 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3212 /* Get the pidls from IDataObject */
3213 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3215 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3216 retVal
= cida
->cidl
;
3217 COMCTL32_ReleaseStgMedium(medium
);
3227 /***********************************************************************
3230 * Get the pidl's display name (relative to folder) and
3231 * put it in lpstrFileName.
3233 * Return NOERROR on success,
3237 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
3242 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3246 SHGetDesktopFolder(&lpsf
);
3247 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3248 IShellFolder_Release(lpsf
);
3252 /* Get the display name of the pidl relative to the folder */
3253 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3255 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3260 /***********************************************************************
3261 * GetShellFolderFromPidl
3263 * pidlRel is the item pidl relative
3264 * Return the IShellFolder of the absolute pidl
3266 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3268 IShellFolder
*psf
= NULL
,*psfParent
;
3270 TRACE("%p\n", pidlAbs
);
3272 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3275 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3277 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3279 IShellFolder_Release(psfParent
);
3283 /* return the desktop */
3289 /***********************************************************************
3292 * Return the LPITEMIDLIST to the parent of the pidl in the list
3294 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3296 LPITEMIDLIST pidlParent
;
3298 TRACE("%p\n", pidl
);
3300 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3301 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3306 /***********************************************************************
3309 * returns the pidl of the file name relative to folder
3310 * NULL if an error occurred
3312 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3314 LPITEMIDLIST pidl
= NULL
;
3317 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3319 if(!lpcstrFileName
) return NULL
;
3320 if(!*lpcstrFileName
) return NULL
;
3324 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3325 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3326 IShellFolder_Release(lpsf
);
3331 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3338 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3340 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3343 TRACE("%p, %p\n", psf
, pidl
);
3345 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3347 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3348 /* see documentation shell 4.1*/
3349 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3352 /***********************************************************************
3353 * BrowseSelectedFolder
3355 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3357 BOOL bBrowseSelFolder
= FALSE
;
3358 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3362 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3364 LPITEMIDLIST pidlSelection
;
3366 /* get the file selected */
3367 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3368 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3370 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3371 pidlSelection
, SBSP_RELATIVE
) ) )
3373 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3374 ' ','n','o','t',' ','e','x','i','s','t',0};
3375 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3377 bBrowseSelFolder
= TRUE
;
3378 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3380 COMDLG32_SHFree( pidlSelection
);
3383 return bBrowseSelFolder
;
3387 * Memory allocation methods */
3388 static void *MemAlloc(UINT size
)
3390 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3393 static void MemFree(void *mem
)
3395 HeapFree(GetProcessHeap(),0,mem
);
3399 * Old-style (win3.1) dialogs */
3401 /***********************************************************************
3402 * FD32_GetTemplate [internal]
3404 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3405 * by a 32 bits application
3408 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3410 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3411 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3414 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3416 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3418 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3422 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3426 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3427 priv
->ofnA
->lpTemplateName
,
3430 hResInfo
= FindResourceW(ofnW
->hInstance
,
3431 ofnW
->lpTemplateName
,
3435 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3438 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3440 !(lfs
->template = LockResource(hDlgTmpl
)))
3442 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3445 } else { /* get it from internal Wine resource */
3447 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3448 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3450 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3453 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3454 !(lfs
->template = LockResource( hDlgTmpl
)))
3456 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3464 /************************************************************************
3465 * FD32_Init [internal]
3466 * called from the common 16/32 code to initialize 32 bit data
3468 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3470 BOOL IsUnicode
= (BOOL
) data
;
3473 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3474 lfs
->private1632
= priv
;
3475 if (NULL
== lfs
->private1632
) return FALSE
;
3478 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3479 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3480 if (lfs
->ofnW
->lpfnHook
)
3485 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3486 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3487 if (priv
->ofnA
->lpfnHook
)
3489 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3490 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3493 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3498 /***********************************************************************
3499 * FD32_CallWindowProc [internal]
3501 * called from the common 16/32 code to call the appropriate hook
3503 BOOL CALLBACK
FD32_CallWindowProc(PFD31_DATA lfs
, UINT wMsg
, WPARAM wParam
,
3507 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3511 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3512 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3513 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3514 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3515 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3519 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3520 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3521 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3522 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3523 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3527 /***********************************************************************
3528 * FD32_UpdateResult [internal]
3529 * update the real client structures if any
3531 static void CALLBACK
FD32_UpdateResult(PFD31_DATA lfs
)
3533 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3534 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3538 if (ofnW
->nMaxFile
&&
3539 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3540 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3541 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3542 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3543 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
3547 /***********************************************************************
3548 * FD32_UpdateFileTitle [internal]
3549 * update the real client structures if any
3551 static void CALLBACK
FD32_UpdateFileTitle(PFD31_DATA lfs
)
3553 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3554 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3558 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3559 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3560 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3565 /***********************************************************************
3566 * FD32_SendLbGetCurSel [internal]
3567 * retrieve selected listbox item
3569 static LRESULT CALLBACK
FD32_SendLbGetCurSel(PFD31_DATA lfs
)
3571 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3575 /************************************************************************
3576 * FD32_Destroy [internal]
3577 * called from the common 16/32 code to cleanup 32 bit data
3579 static void CALLBACK
FD32_Destroy(PFD31_DATA lfs
)
3581 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3583 /* if ofnW has been allocated, have to free everything in it */
3584 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3586 FD31_FreeOfnW(lfs
->ofnW
);
3587 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3591 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3593 callbacks
->Init
= FD32_Init
;
3594 callbacks
->CWP
= FD32_CallWindowProc
;
3595 callbacks
->UpdateResult
= FD32_UpdateResult
;
3596 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3597 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3598 callbacks
->Destroy
= FD32_Destroy
;
3601 /***********************************************************************
3602 * FD32_WMMeasureItem [internal]
3604 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3606 LPMEASUREITEMSTRUCT lpmeasure
;
3608 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3609 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3614 /***********************************************************************
3615 * FileOpenDlgProc [internal]
3616 * Used for open and save, in fact.
3618 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3619 WPARAM wParam
, LPARAM lParam
)
3621 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3623 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg
, wParam
, lParam
);
3624 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3627 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3629 return lRet
; /* else continue message processing */
3634 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3636 case WM_MEASUREITEM
:
3637 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3640 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3643 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3646 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3647 switch (HIWORD(lParam
))
3650 SetTextColor((HDC16
)wParam
, 0x00000000);
3652 case CTLCOLOR_STATIC
:
3653 SetTextColor((HDC16
)wParam
, 0x00000000);
3663 /***********************************************************************
3664 * GetFileName31A [internal]
3666 * Creates a win31 style dialog box for the user to select a file to open/save.
3668 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* addess of structure with data*/
3669 UINT dlgType
/* type dialogue : open/save */
3675 FD31_CALLBACKS callbacks
;
3677 if (!lpofn
|| !FD31_Init()) return FALSE
;
3679 TRACE("ofn flags %08lx\n", lpofn
->Flags
);
3680 FD32_SetupCallbacks(&callbacks
);
3681 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3684 hInst
= (HINSTANCE
)GetWindowLongPtrA( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3685 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3686 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3687 FD31_DestroyPrivate(lfs
);
3690 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3694 /***********************************************************************
3695 * GetFileName31W [internal]
3697 * Creates a win31 style dialog box for the user to select a file to open/save
3699 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* addess of structure with data*/
3700 UINT dlgType
/* type dialogue : open/save */
3706 FD31_CALLBACKS callbacks
;
3708 if (!lpofn
|| !FD31_Init()) return FALSE
;
3710 FD32_SetupCallbacks(&callbacks
);
3711 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3714 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3715 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3716 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3717 FD31_DestroyPrivate(lfs
);
3720 TRACE("file %s, file offset %d, ext offset %d\n",
3721 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3725 /* ------------------ APIs ---------------------- */
3727 /***********************************************************************
3728 * GetOpenFileNameA (COMDLG32.@)
3730 * Creates a dialog box for the user to select a file to open.
3733 * TRUE on success: user enters a valid file
3734 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3737 BOOL WINAPI
GetOpenFileNameA(
3738 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3740 BOOL win16look
= FALSE
;
3742 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3743 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3744 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3746 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3747 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3750 return GetFileName31A(ofn
, OPEN_DIALOG
);
3752 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3755 /***********************************************************************
3756 * GetOpenFileNameW (COMDLG32.@)
3758 * Creates a dialog box for the user to select a file to open.
3761 * TRUE on success: user enters a valid file
3762 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3765 BOOL WINAPI
GetOpenFileNameW(
3766 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3768 BOOL win16look
= FALSE
;
3770 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3771 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3774 return GetFileName31W(ofn
, OPEN_DIALOG
);
3776 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3780 /***********************************************************************
3781 * GetSaveFileNameA (COMDLG32.@)
3783 * Creates a dialog box for the user to select a file to save.
3786 * TRUE on success: user enters a valid file
3787 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3790 BOOL WINAPI
GetSaveFileNameA(
3791 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3793 BOOL win16look
= FALSE
;
3795 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3796 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3799 return GetFileName31A(ofn
, SAVE_DIALOG
);
3801 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3804 /***********************************************************************
3805 * GetSaveFileNameW (COMDLG32.@)
3807 * Creates a dialog box for the user to select a file to save.
3810 * TRUE on success: user enters a valid file
3811 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3814 BOOL WINAPI
GetSaveFileNameW(
3815 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3817 BOOL win16look
= FALSE
;
3819 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3820 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3823 return GetFileName31W(ofn
, SAVE_DIALOG
);
3825 return GetFileDialog95W(ofn
, SAVE_DIALOG
);