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 filetype combo box */
200 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
201 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
205 /* Functions used by the Look In combo box */
206 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
207 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
208 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
216 /* Miscellaneous tool functions */
217 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
218 HRESULT
GetFileName(HWND hwnd
, LPITEMIDLIST pidl
, LPSTR lpstrFileName
);
219 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
220 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
221 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size
);
225 static void MemFree(void *mem
);
227 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
);
228 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
229 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
230 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
231 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
232 static BOOL
BrowseSelectedFolder(HWND hwnd
);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
252 /* test for missing functionality */
253 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
259 /* Create the dialog from a template */
261 if(!(hRes
= FindResourceA(COMDLG32_hInstance
,MAKEINTRESOURCEA(NEWFILEOPENORD
),(LPSTR
)RT_DIALOG
)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
266 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
267 !(template = LockResource( hDlgTmpl
)))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
273 /* old style hook messages */
274 if (IsHooked(fodInfos
))
276 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
277 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
278 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
279 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
282 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
283 (LPDLGTEMPLATEA
) template,
284 fodInfos
->ofnInfos
->hwndOwner
,
288 /* Unable to create the dialog */
295 /***********************************************************************
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
306 FileOpenDlgInfos fodInfos
;
307 LPSTR lpstrSavDir
= NULL
;
309 LPWSTR defext
= NULL
;
310 LPWSTR filter
= NULL
;
311 LPWSTR customfilter
= NULL
;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
316 /* Pass in the original ofn */
317 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
319 /* save current directory */
320 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
322 lpstrSavDir
= MemAlloc(MAX_PATH
);
323 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
326 fodInfos
.unicode
= FALSE
;
328 /* convert all the input strings to unicode */
329 if(ofn
->lpstrInitialDir
)
331 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
332 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
333 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
336 fodInfos
.initdir
= NULL
;
340 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
341 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
344 fodInfos
.filename
= NULL
;
348 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
349 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
350 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
352 fodInfos
.defext
= defext
;
356 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
357 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
358 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
360 fodInfos
.title
= title
;
362 if (ofn
->lpstrFilter
)
367 /* filter is a list... title\0ext\0......\0\0 */
368 s
= ofn
->lpstrFilter
;
369 while (*s
) s
= s
+strlen(s
)+1;
371 n
= s
- ofn
->lpstrFilter
;
372 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
373 filter
= MemAlloc(len
*sizeof(WCHAR
));
374 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
376 fodInfos
.filter
= filter
;
378 /* convert lpstrCustomFilter */
379 if (ofn
->lpstrCustomFilter
)
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s
= ofn
->lpstrCustomFilter
;
386 if (*s
) s
= s
+strlen(s
)+1;
387 if (*s
) s
= s
+strlen(s
)+1;
388 n
= s
- ofn
->lpstrCustomFilter
;
389 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
390 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
391 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
393 fodInfos
.customfilter
= customfilter
;
395 /* Initialize the dialog property */
396 fodInfos
.DlgInfos
.dwDlgProp
= 0;
397 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
402 ret
= GetFileName95(&fodInfos
);
405 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
406 ret
= GetFileName95(&fodInfos
);
414 SetCurrentDirectoryA(lpstrSavDir
);
415 MemFree(lpstrSavDir
);
425 MemFree(customfilter
);
427 MemFree(fodInfos
.initdir
);
429 if(fodInfos
.filename
)
430 MemFree(fodInfos
.filename
);
432 TRACE("selected file: %s\n",ofn
->lpstrFile
);
437 /***********************************************************************
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
447 FileOpenDlgInfos fodInfos
;
448 LPWSTR lpstrSavDir
= NULL
;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
453 /* Pass in the original ofn */
454 fodInfos
.ofnInfos
= ofn
;
456 fodInfos
.title
= ofn
->lpstrTitle
;
457 fodInfos
.defext
= ofn
->lpstrDefExt
;
458 fodInfos
.filter
= ofn
->lpstrFilter
;
459 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
461 /* convert string arguments, save others */
464 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
465 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
468 fodInfos
.filename
= NULL
;
470 if(ofn
->lpstrInitialDir
)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len
= strlenW(ofn
->lpstrInitialDir
)+1;
474 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
475 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
478 fodInfos
.initdir
= NULL
;
480 /* save current directory */
481 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
483 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
484 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
487 fodInfos
.unicode
= TRUE
;
492 ret
= GetFileName95(&fodInfos
);
495 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
496 ret
= GetFileName95(&fodInfos
);
504 SetCurrentDirectoryW(lpstrSavDir
);
505 MemFree(lpstrSavDir
);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos
.filename
);
510 MemFree(fodInfos
.initdir
);
514 /******************************************************************************
515 * COMDLG32_GetDisplayNameOf [internal]
517 * Helper function to get the display name for a pidl.
519 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
520 LPSHELLFOLDER psfDesktop
;
523 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
526 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
527 IShellFolder_Release(psfDesktop
);
531 IShellFolder_Release(psfDesktop
);
532 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
535 /***********************************************************************
536 * ArrangeCtrlPositions [internal]
538 * NOTE: Do not change anything here without a lot of testing.
540 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
542 HWND hwndChild
, hwndStc32
;
543 RECT rectParent
, rectChild
, rectStc32
;
544 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
546 /* Take into account if open as read only checkbox and help button
551 RECT rectHelp
, rectCancel
;
552 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
553 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
554 /* subtract the height of the help button plus the space between
555 * the help button and the cancel button to the height of the dialog
557 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
561 There are two possibilities to add components to the default file dialog box.
563 By default, all the new components are added below the standard dialog box (the else case).
565 However, if there is a static text component with the stc32 id, a special case happens.
566 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
567 in the window and the cx and cy indicate how to size the window.
568 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
569 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
573 GetClientRect(hwndParentDlg
, &rectParent
);
575 /* when arranging controls we have to use fixed parent size */
576 rectParent
.bottom
-= help_fixup
;
578 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
581 GetWindowRect(hwndStc32
, &rectStc32
);
582 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
584 /* set the size of the stc32 control according to the size of
585 * client area of the parent dialog
587 SetWindowPos(hwndStc32
, 0,
589 rectParent
.right
, rectParent
.bottom
,
590 SWP_NOMOVE
| SWP_NOZORDER
);
593 SetRectEmpty(&rectStc32
);
595 /* this part moves controls of the child dialog */
596 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
599 if (hwndChild
!= hwndStc32
)
601 GetWindowRect(hwndChild
, &rectChild
);
602 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
604 /* move only if stc32 exist */
605 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
607 LONG old_left
= rectChild
.left
;
609 /* move to the right of visible controls of the parent dialog */
610 rectChild
.left
+= rectParent
.right
;
611 rectChild
.left
-= rectStc32
.right
;
613 child_width_fixup
= rectChild
.left
- old_left
;
615 /* move even if stc32 doesn't exist */
616 if (rectChild
.top
>= rectStc32
.bottom
)
618 LONG old_top
= rectChild
.top
;
620 /* move below visible controls of the parent dialog */
621 rectChild
.top
+= rectParent
.bottom
;
622 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
624 child_height_fixup
= rectChild
.top
- old_top
;
627 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
628 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
630 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
633 /* this part moves controls of the parent dialog */
634 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
637 if (hwndChild
!= hwndChildDlg
)
639 GetWindowRect(hwndChild
, &rectChild
);
640 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
642 /* left,top of stc32 marks the position of controls
643 * from the parent dialog
645 rectChild
.left
+= rectStc32
.left
;
646 rectChild
.top
+= rectStc32
.top
;
648 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
649 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
651 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
654 /* calculate the size of the resulting dialog */
656 /* here we have to use original parent size */
657 GetClientRect(hwndParentDlg
, &rectParent
);
658 GetClientRect(hwndChildDlg
, &rectChild
);
662 rectChild
.right
+= child_width_fixup
;
663 rectChild
.bottom
+= child_height_fixup
;
665 if (rectParent
.right
> rectChild
.right
)
667 rectParent
.right
+= rectChild
.right
;
668 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
672 rectParent
.right
= rectChild
.right
;
675 if (rectParent
.bottom
> rectChild
.bottom
)
677 rectParent
.bottom
+= rectChild
.bottom
;
678 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
682 /* child dialog is higher, unconditionally set new dialog
683 * height to its size (help_fixup will be subtracted below)
685 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
690 rectParent
.bottom
+= rectChild
.bottom
;
693 /* finally use fixed parent size */
694 rectParent
.bottom
-= help_fixup
;
696 /* save the size of the parent's client area */
697 rectChild
.right
= rectParent
.right
;
698 rectChild
.bottom
= rectParent
.bottom
;
700 /* set the size of the parent dialog */
701 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
702 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
703 SetWindowPos(hwndParentDlg
, 0,
705 rectParent
.right
- rectParent
.left
,
706 rectParent
.bottom
- rectParent
.top
,
707 SWP_NOMOVE
| SWP_NOZORDER
);
709 /* set the size of the child dialog */
710 SetWindowPos(hwndChildDlg
, HWND_BOTTOM
,
711 0, 0, rectChild
.right
, rectChild
.bottom
, SWP_NOACTIVATE
);
714 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
723 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
740 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
743 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
751 hinst
= fodInfos
->ofnInfos
->hInstance
;
752 if(fodInfos
->unicode
)
754 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
755 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
759 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
760 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
767 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
768 !(template = LockResource( hDlgTmpl
)))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
774 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, template, hwnd
,
775 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
776 (LPARAM
)fodInfos
->ofnInfos
);
779 ShowWindow(hChildDlg
,SW_SHOW
);
783 else if( IsHooked(fodInfos
))
788 WORD menu
,class,title
;
790 GetClientRect(hwnd
,&rectHwnd
);
791 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
792 temp
.tmplate
.dwExtendedStyle
= 0;
793 temp
.tmplate
.cdit
= 0;
798 temp
.menu
= temp
.class = temp
.title
= 0;
800 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
801 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
808 /***********************************************************************
809 * SendCustomDlgNotificationMessage
811 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
814 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
816 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
818 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
820 if(!fodInfos
) return 0;
822 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 ret
= 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 ret
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
846 TRACE("RET NOTIFY\n");
852 HRESULT
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
854 UINT sizeUsed
= 0, n
, total
;
855 LPWSTR lpstrFileList
= NULL
;
856 WCHAR lpstrCurrentDir
[MAX_PATH
];
857 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
864 /* get path and filenames */
865 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrCurrentDir
);
866 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
868 TRACE("path >%s< filespec >%s< %d files\n",
869 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
871 if( fodInfos
->unicode
)
873 LPWSTR bufW
= buffer
;
874 total
= strlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
876 /* Prepend the current path */
877 n
= strlenW(lpstrCurrentDir
) + 1;
878 memcpy( bufW
, lpstrCurrentDir
, min(n
,size
) * sizeof(WCHAR
));
881 /* 'n' includes trailing \0 */
883 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
885 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
890 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
891 NULL
, 0, NULL
, NULL
);
892 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
893 NULL
, 0, NULL
, NULL
);
895 /* Prepend the current path */
896 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
897 bufA
, size
, NULL
, NULL
);
901 /* 'n' includes trailing \0 */
903 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
904 &bufA
[n
], size
-n
, NULL
, NULL
);
907 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
909 MemFree(lpstrFileList
);
914 HRESULT
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
917 LPWSTR lpstrFileList
= NULL
;
918 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
920 TRACE("CDM_GETSPEC:\n");
922 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
923 if( fodInfos
->unicode
)
925 LPWSTR bufW
= buffer
;
926 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
931 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
932 NULL
, 0, NULL
, NULL
);
933 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
934 bufA
, size
, NULL
, NULL
);
936 MemFree(lpstrFileList
);
941 /***********************************************************************
942 * FILEDLG95_HandleCustomDialogMessages
944 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
946 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
948 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
949 WCHAR lpstrPath
[MAX_PATH
];
950 if(!fodInfos
) return -1;
954 case CDM_GETFILEPATH
:
955 return FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
957 case CDM_GETFOLDERPATH
:
958 TRACE("CDM_GETFOLDERPATH:\n");
959 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
962 if (fodInfos
->unicode
)
963 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
965 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
966 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
968 return strlenW(lpstrPath
);
971 return FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
973 case CDM_SETCONTROLTEXT
:
974 TRACE("CDM_SETCONTROLTEXT:\n");
977 if( fodInfos
->unicode
)
978 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
980 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
984 case CDM_HIDECONTROL
:
986 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
992 /***********************************************************************
995 * File open dialog procedure
997 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1000 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
1007 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1009 /* Adds the FileOpenDlgInfos in the property list of the dialog
1010 so it will be easily accessible through a GetPropA(...) */
1011 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
1013 fodInfos
->DlgInfos
.hwndCustomDlg
=
1014 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1016 FILEDLG95_InitControls(hwnd
);
1018 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1019 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1020 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1022 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1024 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1025 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1026 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1030 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1033 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1036 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1042 case WM_GETISHELLBROWSER
:
1043 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1046 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1051 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1054 /* set up the button tooltips strings */
1055 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1057 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1058 switch(lpnmh
->idFrom
)
1060 /* Up folder button */
1061 case FCIDM_TB_UPFOLDER
:
1062 stringId
= IDS_UPFOLDER
;
1064 /* New folder button */
1065 case FCIDM_TB_NEWFOLDER
:
1066 stringId
= IDS_NEWFOLDER
;
1068 /* List option button */
1069 case FCIDM_TB_SMALLICON
:
1070 stringId
= IDS_LISTVIEW
;
1072 /* Details option button */
1073 case FCIDM_TB_REPORTVIEW
:
1074 stringId
= IDS_REPORTVIEW
;
1076 /* Desktop button */
1077 case FCIDM_TB_DESKTOP
:
1078 stringId
= IDS_TODESKTOP
;
1083 lpdi
->hinst
= COMDLG32_hInstance
;
1084 lpdi
->lpszText
= (LPSTR
) stringId
;
1089 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1090 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1095 /***********************************************************************
1096 * FILEDLG95_InitControls
1098 * WM_INITDIALOG message handler (before hook notification)
1100 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1102 int win2000plus
= 0;
1104 int handledPath
= FALSE
;
1105 OSVERSIONINFOA osVi
;
1106 static const WCHAR szwSlash
[] = { '\\', 0 };
1107 static const WCHAR szwStar
[] = { '*',0 };
1111 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1112 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1113 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1114 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1115 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1116 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1117 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1118 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1119 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1124 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1126 tba
[0].hInst
= HINST_COMMCTRL
;
1127 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1128 tba
[1].hInst
= COMDLG32_hInstance
;
1131 TRACE("%p\n", fodInfos
);
1133 /* Get windows version emulating */
1134 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1135 GetVersionExA(&osVi
);
1136 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1137 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1138 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1139 win2000plus
= (osVi
.dwMajorVersion
> 4);
1140 if (win2000plus
) win98plus
= TRUE
;
1142 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1144 /* Get the hwnd of the controls */
1145 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1146 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1147 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1149 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1150 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1152 /* construct the toolbar */
1153 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1154 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1156 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1157 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1158 rectTB
.left
= rectlook
.right
;
1159 rectTB
.top
= rectlook
.top
-1;
1161 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1162 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1163 rectTB
.left
, rectTB
.top
,
1164 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1165 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1167 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1169 /* FIXME: use TB_LOADIMAGES when implemented */
1170 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1171 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1172 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1174 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1175 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1177 /* Set the window text with the text specified in the OPENFILENAME structure */
1180 SetWindowTextW(hwnd
,fodInfos
->title
);
1182 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1185 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1186 SetWindowTextW(hwnd
, buf
);
1189 /* Initialise the file name edit control */
1190 handledPath
= FALSE
;
1191 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1193 if(fodInfos
->filename
)
1195 /* 1. If win2000 or higher and filename contains a path, use it
1196 in preference over the lpstrInitialDir */
1197 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1198 WCHAR tmpBuf
[MAX_PATH
];
1202 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1205 /* nameBit is always shorter than the original filename */
1206 strcpyW(fodInfos
->filename
,nameBit
);
1209 if (fodInfos
->initdir
== NULL
)
1210 MemFree(fodInfos
->initdir
);
1211 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1212 strcpyW(fodInfos
->initdir
, tmpBuf
);
1214 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1215 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1217 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1220 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1224 /* 2. (All platforms) If initdir is not null, then use it */
1225 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1226 (*fodInfos
->initdir
!=0x00))
1228 /* Work out the proper path as supplied one might be relative */
1229 /* (Here because supplying '.' as dir browses to My Computer) */
1230 if (handledPath
==FALSE
) {
1231 WCHAR tmpBuf
[MAX_PATH
];
1232 WCHAR tmpBuf2
[MAX_PATH
];
1236 strcpyW(tmpBuf
, fodInfos
->initdir
);
1237 if( PathFileExistsW(tmpBuf
) ) {
1238 /* initdir does not have to be a directory. If a file is
1239 * specified, the dir part is taken */
1240 if( PathIsDirectoryW(tmpBuf
)) {
1241 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1242 strcatW(tmpBuf
, szwSlash
);
1244 strcatW(tmpBuf
, szwStar
);
1246 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1249 if (fodInfos
->initdir
)
1250 MemFree(fodInfos
->initdir
);
1251 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1252 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1254 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1257 else if (fodInfos
->initdir
)
1259 MemFree(fodInfos
->initdir
);
1260 fodInfos
->initdir
= NULL
;
1261 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1266 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1267 (*fodInfos
->initdir
==0x00)))
1269 /* 3. All except w2k+: if filename contains a path use it */
1270 if (!win2000plus
&& fodInfos
->filename
&&
1271 *fodInfos
->filename
&&
1272 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1273 WCHAR tmpBuf
[MAX_PATH
];
1277 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1282 /* nameBit is always shorter than the original filename */
1283 strcpyW(fodInfos
->filename
, nameBit
);
1286 len
= strlenW(tmpBuf
);
1287 if(fodInfos
->initdir
)
1288 MemFree(fodInfos
->initdir
);
1289 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1290 strcpyW(fodInfos
->initdir
, tmpBuf
);
1293 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1294 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1296 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1299 /* 4. win98+ and win2000+ if any files of specified filter types in
1300 current directory, use it */
1301 if ( win98plus
&& handledPath
== FALSE
&&
1302 fodInfos
->filter
&& *fodInfos
->filter
) {
1304 BOOL searchMore
= TRUE
;
1305 LPCWSTR lpstrPos
= fodInfos
->filter
;
1306 WIN32_FIND_DATAW FindFileData
;
1311 /* filter is a list... title\0ext\0......\0\0 */
1313 /* Skip the title */
1314 if(! *lpstrPos
) break; /* end */
1315 lpstrPos
+= strlenW(lpstrPos
) + 1;
1317 /* See if any files exist in the current dir with this extension */
1318 if(! *lpstrPos
) break; /* end */
1320 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1322 if (hFind
== INVALID_HANDLE_VALUE
) {
1323 /* None found - continue search */
1324 lpstrPos
+= strlenW(lpstrPos
) + 1;
1329 if(fodInfos
->initdir
)
1330 MemFree(fodInfos
->initdir
);
1331 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1332 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1335 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1336 debugstr_w(lpstrPos
));
1342 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1344 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1345 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1346 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1348 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1350 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1353 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1354 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1356 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1359 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1362 } else if (handledPath
==FALSE
) {
1363 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1364 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1366 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1369 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1370 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1372 /* Must the open as read only check box be checked ?*/
1373 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1375 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1378 /* Must the open as read only check box be hidden? */
1379 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1381 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1382 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1385 /* Must the help button be hidden? */
1386 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1388 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1389 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1392 /* Resize the height, if open as read only checkbox ad help button
1393 are hidden and we are not using a custom template nor a customDialog
1395 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1396 (!(fodInfos
->ofnInfos
->Flags
&
1397 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))) &&
1398 (!fodInfos
->DlgInfos
.hwndCustomDlg
))
1400 RECT rectDlg
, rectHelp
, rectCancel
;
1401 GetWindowRect(hwnd
, &rectDlg
);
1402 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1403 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1404 /* subtract the height of the help button plus the space between
1405 the help button and the cancel button to the height of the dialog */
1406 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1407 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1408 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1410 /* change Open to Save */
1411 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1414 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1415 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1416 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1417 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1422 /***********************************************************************
1423 * FILEDLG95_FillControls
1425 * WM_INITDIALOG message handler (after hook notification)
1427 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1429 LPITEMIDLIST pidlItemId
= NULL
;
1431 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1433 TRACE("dir=%s file=%s\n",
1434 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1436 /* Get the initial directory pidl */
1438 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1440 WCHAR path
[MAX_PATH
];
1442 GetCurrentDirectoryW(MAX_PATH
,path
);
1443 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1446 /* Initialise shell objects */
1447 FILEDLG95_SHELL_Init(hwnd
);
1449 /* Initialize the Look In combo box */
1450 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1452 /* Initialize the filter combo box */
1453 FILEDLG95_FILETYPE_Init(hwnd
);
1455 /* Browse to the initial directory */
1456 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1458 /* Free pidlItem memory */
1459 COMDLG32_SHFree(pidlItemId
);
1463 /***********************************************************************
1466 * Regroups all the cleaning functions of the filedlg
1468 void FILEDLG95_Clean(HWND hwnd
)
1470 FILEDLG95_FILETYPE_Clean(hwnd
);
1471 FILEDLG95_LOOKIN_Clean(hwnd
);
1472 FILEDLG95_SHELL_Clean(hwnd
);
1474 /***********************************************************************
1475 * FILEDLG95_OnWMCommand
1477 * WM_COMMAND message handler
1479 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1481 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1482 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1483 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1489 FILEDLG95_OnOpen(hwnd
);
1493 FILEDLG95_Clean(hwnd
);
1494 EndDialog(hwnd
, FALSE
);
1496 /* Filetype combo box */
1498 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1500 /* LookIn combo box */
1502 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1505 /* --- toolbar --- */
1506 /* Up folder button */
1507 case FCIDM_TB_UPFOLDER
:
1508 FILEDLG95_SHELL_UpFolder(hwnd
);
1510 /* New folder button */
1511 case FCIDM_TB_NEWFOLDER
:
1512 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1514 /* List option button */
1515 case FCIDM_TB_SMALLICON
:
1516 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1518 /* Details option button */
1519 case FCIDM_TB_REPORTVIEW
:
1520 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1522 /* Details option button */
1523 case FCIDM_TB_DESKTOP
:
1524 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1531 /* Do not use the listview selection anymore */
1532 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1536 /***********************************************************************
1537 * FILEDLG95_OnWMGetIShellBrowser
1539 * WM_GETISHELLBROWSER message handler
1541 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1544 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1548 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1554 /***********************************************************************
1555 * FILEDLG95_SendFileOK
1557 * Sends the CDN_FILEOK notification if required
1560 * TRUE if the dialog should close
1561 * FALSE if the dialog should not be closed
1563 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1565 /* ask the hook if we can close */
1566 if(IsHooked(fodInfos
))
1569 /* First send CDN_FILEOK as MSDN doc says */
1570 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1571 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1573 TRACE("canceled\n");
1577 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1578 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1579 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1580 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1582 TRACE("canceled\n");
1589 /***********************************************************************
1590 * FILEDLG95_OnOpenMultipleFiles
1592 * Handles the opening of multiple files.
1595 * check destination buffer size
1597 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1599 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1600 UINT nCount
, nSizePath
;
1601 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1605 if(fodInfos
->unicode
)
1607 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1608 ofn
->lpstrFile
[0] = '\0';
1612 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1613 ofn
->lpstrFile
[0] = '\0';
1616 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1618 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1619 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1620 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1622 LPWSTR lpstrTemp
= lpstrFileList
;
1624 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1628 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1631 WCHAR lpstrNotFound
[100];
1632 WCHAR lpstrMsg
[100];
1634 static const WCHAR nl
[] = {'\n',0};
1636 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1637 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1639 strcpyW(tmp
, lpstrTemp
);
1641 strcatW(tmp
, lpstrNotFound
);
1643 strcatW(tmp
, lpstrMsg
);
1645 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1649 /* move to the next file in the list of files */
1650 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1651 COMDLG32_SHFree(pidl
);
1655 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1656 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1658 /* For "oldstyle" dialog the components have to
1659 be separated by blanks (not '\0'!) and short
1660 filenames have to be used! */
1661 FIXME("Components have to be separated by blanks\n");
1663 if(fodInfos
->unicode
)
1665 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1666 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1667 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1671 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1673 if (ofn
->lpstrFile
!= NULL
)
1675 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1676 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1677 if (ofn
->nMaxFile
> nSizePath
)
1679 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1680 ofn
->lpstrFile
+ nSizePath
,
1681 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1686 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1687 fodInfos
->ofnInfos
->nFileExtension
= 0;
1689 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1692 /* clean and exit */
1693 FILEDLG95_Clean(hwnd
);
1694 return EndDialog(hwnd
,TRUE
);
1697 /***********************************************************************
1700 * Ok button WM_COMMAND message handler
1702 * If the function succeeds, the return value is nonzero.
1704 #define ONOPEN_BROWSE 1
1705 #define ONOPEN_OPEN 2
1706 #define ONOPEN_SEARCH 3
1707 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1709 WCHAR strMsgTitle
[MAX_PATH
];
1710 WCHAR strMsgText
[MAX_PATH
];
1712 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1714 strMsgTitle
[0] = '\0';
1715 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1716 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1719 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1721 LPWSTR lpstrFileList
;
1722 UINT nFileCount
= 0;
1725 WCHAR lpstrPathAndFile
[MAX_PATH
];
1726 WCHAR lpstrTemp
[MAX_PATH
];
1727 LPSHELLFOLDER lpsf
= NULL
;
1729 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1731 TRACE("hwnd=%p\n", hwnd
);
1733 /* get the files from the edit control */
1734 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1736 /* try if the user selected a folder in the shellview */
1739 BrowseSelectedFolder(hwnd
);
1745 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1749 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1752 Step 1: Build a complete path name from the current folder and
1753 the filename or path in the edit box.
1755 - the path in the edit box is a root path
1756 (with or without drive letter)
1757 - the edit box contains ".." (or a path with ".." in it)
1760 /* Get the current directory name */
1761 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1764 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1766 PathAddBackslashW(lpstrPathAndFile
);
1768 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1770 /* if the user specifyed a fully qualified path use it */
1771 if(PathIsRelativeW(lpstrFileList
))
1773 strcatW(lpstrPathAndFile
, lpstrFileList
);
1777 /* does the path have a drive letter? */
1778 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1779 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1781 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1784 /* resolve "." and ".." */
1785 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1786 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1787 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1789 MemFree(lpstrFileList
);
1792 Step 2: here we have a cleaned up path
1794 We have to parse the path step by step to see if we have to browse
1795 to a folder if the path points to a directory or the last
1796 valid element is a directory.
1799 lpstrPathAndFile: cleaned up path
1802 nOpenAction
= ONOPEN_BROWSE
;
1804 /* don't apply any checks with OFN_NOVALIDATE */
1806 LPWSTR lpszTemp
, lpszTemp1
;
1807 LPITEMIDLIST pidl
= NULL
;
1808 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1810 /* check for invalid chars */
1811 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1813 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1818 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1820 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1823 LPSHELLFOLDER lpsfChild
;
1824 WCHAR lpwstrTemp
[MAX_PATH
];
1825 DWORD dwEaten
, dwAttributes
;
1828 strcpyW(lpwstrTemp
, lpszTemp
);
1829 p
= PathFindNextComponentW(lpwstrTemp
);
1831 if (!p
) break; /* end of path */
1834 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1838 static const WCHAR wszWild
[] = { '*', '?', 0 };
1839 /* if the last element is a wildcard do a search */
1840 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1842 nOpenAction
= ONOPEN_SEARCH
;
1846 lpszTemp1
= lpszTemp
;
1848 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1850 /* append a backslash to drive letters */
1851 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1852 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1853 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1855 PathAddBackslashW(lpwstrTemp
);
1858 dwAttributes
= SFGAO_FOLDER
;
1859 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1861 /* the path component is valid, we have a pidl of the next path component */
1862 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1863 if(dwAttributes
& SFGAO_FOLDER
)
1865 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1867 ERR("bind to failed\n"); /* should not fail */
1870 IShellFolder_Release(lpsf
);
1878 /* end dialog, return value */
1879 nOpenAction
= ONOPEN_OPEN
;
1882 COMDLG32_SHFree(pidl
);
1885 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1887 if(*lpszTemp
) /* points to trailing null for last path element */
1889 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1891 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1897 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1898 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1900 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1904 /* change to the current folder */
1905 nOpenAction
= ONOPEN_OPEN
;
1910 nOpenAction
= ONOPEN_OPEN
;
1914 if(pidl
) COMDLG32_SHFree(pidl
);
1918 Step 3: here we have a cleaned up and validated path
1921 lpsf: ShellFolder bound to the rightmost valid path component
1922 lpstrPathAndFile: cleaned up path
1923 nOpenAction: action to do
1925 TRACE("end validate sf=%p\n", lpsf
);
1929 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1930 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1933 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1936 /* replace the current filter */
1937 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1938 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1939 len
= strlenW(lpszTemp
)+1;
1940 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1941 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1943 /* set the filter cb to the extension when possible */
1944 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1945 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1948 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1949 TRACE("ONOPEN_BROWSE\n");
1951 IPersistFolder2
* ppf2
;
1952 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1954 LPITEMIDLIST pidlCurrent
;
1955 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1956 IPersistFolder2_Release(ppf2
);
1957 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1959 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1961 else if( nOpenAction
== ONOPEN_SEARCH
)
1963 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1965 COMDLG32_SHFree(pidlCurrent
);
1970 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1971 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1975 /* update READONLY check box flag */
1976 if ((SendMessageA(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
1977 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
1979 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
1981 /* Attach the file extension with file name*/
1982 ext
= PathFindExtensionW(lpstrPathAndFile
);
1985 /* if no extension is specified with file name, then */
1986 /* attach the extension from file filter or default one */
1988 WCHAR
*filterExt
= NULL
;
1989 LPWSTR lpstrFilter
= NULL
;
1990 static const WCHAR szwDot
[] = {'.',0};
1991 int PathLength
= strlenW(lpstrPathAndFile
);
1994 strcatW(lpstrPathAndFile
, szwDot
);
1996 /*Get the file extension from file type filter*/
1997 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
1998 fodInfos
->ofnInfos
->nFilterIndex
-1);
2000 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2001 filterExt
= PathFindExtensionW(lpstrFilter
);
2003 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2004 strcatW(lpstrPathAndFile
, filterExt
+ 1);
2005 else if ( fodInfos
->defext
) /* attach the default file extension*/
2006 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
2008 /* In Open dialog: if file does not exist try without extension */
2009 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2010 lpstrPathAndFile
[PathLength
] = '\0';
2013 if (fodInfos
->defext
) /* add default extension */
2015 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2018 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2019 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2021 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2024 /* In Save dialog: check if the file already exists */
2025 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2026 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2027 && PathFileExistsW(lpstrPathAndFile
))
2029 WCHAR lpstrOverwrite
[100];
2032 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2033 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2034 MB_YESNO
| MB_ICONEXCLAMATION
);
2042 /* Check that the size of the file does not exceed buffer size.
2043 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2044 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2045 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2049 /* fill destination buffer */
2050 if (fodInfos
->ofnInfos
->lpstrFile
)
2052 if(fodInfos
->unicode
)
2054 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2056 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2057 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2058 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2062 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2064 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2065 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2066 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2067 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2071 /* set filename offset */
2072 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2073 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2075 /* set extension offset */
2076 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2077 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2079 /* set the lpstrFileTitle */
2080 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2082 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2083 if(fodInfos
->unicode
)
2085 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2086 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2090 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2091 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2092 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2096 /* copy currently selected filter to lpstrCustomFilter */
2097 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2099 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2100 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2101 NULL
, 0, NULL
, NULL
);
2102 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2104 LPSTR s
= ofn
->lpstrCustomFilter
;
2105 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2106 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2107 s
, len
, NULL
, NULL
);
2112 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2116 FILEDLG95_Clean(hwnd
);
2117 ret
= EndDialog(hwnd
, TRUE
);
2123 size
= strlenW(lpstrPathAndFile
) + 1;
2124 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2126 /* return needed size in first two bytes of lpstrFile */
2127 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2128 FILEDLG95_Clean(hwnd
);
2129 ret
= EndDialog(hwnd
, FALSE
);
2130 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2138 if(lpsf
) IShellFolder_Release(lpsf
);
2142 /***********************************************************************
2143 * FILEDLG95_SHELL_Init
2145 * Initialisation of the shell objects
2147 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2149 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2154 * Initialisation of the FileOpenDialogInfos structure
2160 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2162 /* Disable multi-select if flag not set */
2163 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2165 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2167 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2168 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2170 /* Construct the IShellBrowser interface */
2171 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2176 /***********************************************************************
2177 * FILEDLG95_SHELL_ExecuteCommand
2179 * Change the folder option and refresh the view
2180 * If the function succeeds, the return value is nonzero.
2182 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2184 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2187 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2189 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2194 CMINVOKECOMMANDINFO ci
;
2195 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2196 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2200 IContextMenu_InvokeCommand(pcm
, &ci
);
2201 IContextMenu_Release(pcm
);
2207 /***********************************************************************
2208 * FILEDLG95_SHELL_UpFolder
2210 * Browse to the specified object
2211 * If the function succeeds, the return value is nonzero.
2213 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2215 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2219 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2228 /***********************************************************************
2229 * FILEDLG95_SHELL_BrowseToDesktop
2231 * Browse to the Desktop
2232 * If the function succeeds, the return value is nonzero.
2234 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2236 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2242 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2243 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2244 COMDLG32_SHFree(pidl
);
2245 return SUCCEEDED(hres
);
2247 /***********************************************************************
2248 * FILEDLG95_SHELL_Clean
2250 * Cleans the memory used by shell objects
2252 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2254 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2258 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2260 /* clean Shell interfaces */
2261 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2262 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2263 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2264 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2265 if (fodInfos
->Shell
.FOIDataObject
)
2266 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2269 /***********************************************************************
2270 * FILEDLG95_FILETYPE_Init
2272 * Initialisation of the file type combo box
2274 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2276 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2277 int nFilters
= 0; /* number of filters */
2282 if(fodInfos
->customfilter
)
2284 /* customfilter has one entry... title\0ext\0
2285 * Set first entry of combo box item with customfilter
2288 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2291 lpstrPos
+= strlenW(fodInfos
->customfilter
) + 1;
2293 /* Copy the extensions */
2294 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2295 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2296 strcpyW(lpstrExt
,lpstrPos
);
2298 /* Add the item at the end of the combo */
2299 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2300 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2303 if(fodInfos
->filter
)
2305 LPCWSTR lpstrPos
= fodInfos
->filter
;
2309 /* filter is a list... title\0ext\0......\0\0
2310 * Set the combo item text to the title and the item data
2313 LPCWSTR lpstrDisplay
;
2317 if(! *lpstrPos
) break; /* end */
2318 lpstrDisplay
= lpstrPos
;
2319 lpstrPos
+= strlenW(lpstrPos
) + 1;
2321 /* Copy the extensions */
2322 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2323 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2324 strcpyW(lpstrExt
,lpstrPos
);
2325 lpstrPos
+= strlenW(lpstrPos
) + 1;
2327 /* Add the item at the end of the combo */
2328 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2329 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2335 * Set the current filter to the one specified
2336 * in the initialisation structure
2338 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2342 /* Check to make sure our index isn't out of bounds. */
2343 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2344 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2345 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2347 /* set default filter index */
2348 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2349 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2351 /* calculate index of Combo Box item */
2352 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2353 if (fodInfos
->customfilter
== NULL
)
2356 /* Set the current index selection. */
2357 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2359 /* Get the corresponding text string from the combo box. */
2360 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2363 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2369 CharLowerW(lpstrFilter
); /* lowercase */
2370 len
= strlenW(lpstrFilter
)+1;
2371 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2372 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2375 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2380 /***********************************************************************
2381 * FILEDLG95_FILETYPE_OnCommand
2383 * WM_COMMAND of the file type combo box
2384 * If the function succeeds, the return value is nonzero.
2386 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2388 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2396 /* Get the current item of the filetype combo box */
2397 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2399 /* set the current filter index */
2400 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2401 (fodInfos
->customfilter
== NULL
? 1 : 0);
2403 /* Set the current filter with the current selection */
2404 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2405 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2407 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2409 if((int)lpstrFilter
!= CB_ERR
)
2412 CharLowerW(lpstrFilter
); /* lowercase */
2413 len
= strlenW(lpstrFilter
)+1;
2414 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2415 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2416 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2419 /* Refresh the actual view to display the included items*/
2420 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2425 /***********************************************************************
2426 * FILEDLG95_FILETYPE_SearchExt
2428 * searches for an extension in the filetype box
2430 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2432 int i
, iCount
= CBGetCount(hwnd
);
2434 TRACE("%s\n", debugstr_w(lpstrExt
));
2436 if(iCount
!= CB_ERR
)
2438 for(i
=0;i
<iCount
;i
++)
2440 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2447 /***********************************************************************
2448 * FILEDLG95_FILETYPE_Clean
2450 * Clean the memory used by the filetype combo box
2452 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2454 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2456 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2460 /* Delete each string of the combo and their associated data */
2461 if(iCount
!= CB_ERR
)
2463 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2465 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2466 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2469 /* Current filter */
2470 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2471 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2475 /***********************************************************************
2476 * FILEDLG95_LOOKIN_Init
2478 * Initialisation of the look in combo box
2480 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2482 IShellFolder
*psfRoot
, *psfDrives
;
2483 IEnumIDList
*lpeRoot
, *lpeDrives
;
2484 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2486 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2490 liInfos
->iMaxIndentation
= 0;
2492 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2494 /* set item height for both text field and listbox */
2495 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2496 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2498 /* Turn on the extended UI for the combo box like Windows does */
2499 CBSetExtendedUI(hwndCombo
, TRUE
);
2501 /* Initialise data of Desktop folder */
2502 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2503 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2504 COMDLG32_SHFree(pidlTmp
);
2506 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2508 SHGetDesktopFolder(&psfRoot
);
2512 /* enumerate the contents of the desktop */
2513 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2515 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2517 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2519 /* special handling for CSIDL_DRIVES */
2520 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2522 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2524 /* enumerate the drives */
2525 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2527 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2529 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2530 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2531 COMDLG32_SHFree(pidlAbsTmp
);
2532 COMDLG32_SHFree(pidlTmp1
);
2534 IEnumIDList_Release(lpeDrives
);
2536 IShellFolder_Release(psfDrives
);
2539 COMDLG32_SHFree(pidlTmp
);
2541 IEnumIDList_Release(lpeRoot
);
2543 IShellFolder_Release(psfRoot
);
2546 COMDLG32_SHFree(pidlDrives
);
2550 /***********************************************************************
2551 * FILEDLG95_LOOKIN_DrawItem
2553 * WM_DRAWITEM message handler
2555 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2557 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2558 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2559 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2563 HIMAGELIST ilItemImage
;
2566 LPSFOLDER tmpFolder
;
2569 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2573 if(pDIStruct
->itemID
== -1)
2576 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2577 pDIStruct
->itemID
)))
2581 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2583 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2586 sizeof (SHFILEINFOA
),
2587 SHGFI_PIDL
| SHGFI_SMALLICON
|
2588 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2589 SHGFI_DISPLAYNAME
);
2593 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2596 sizeof (SHFILEINFOA
),
2597 SHGFI_PIDL
| SHGFI_SMALLICON
|
2598 SHGFI_SYSICONINDEX
|
2602 /* Is this item selected ? */
2603 if(pDIStruct
->itemState
& ODS_SELECTED
)
2605 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2606 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2607 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2611 SetTextColor(pDIStruct
->hDC
,crText
);
2612 SetBkColor(pDIStruct
->hDC
,crWin
);
2613 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2616 /* Do not indent item if drawing in the edit of the combo */
2617 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2620 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2623 sizeof (SHFILEINFOA
),
2624 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2625 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2630 iIndentation
= tmpFolder
->m_iIndent
;
2632 /* Draw text and icon */
2634 /* Initialise the icon display area */
2635 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2636 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2637 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2638 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2640 /* Initialise the text display area */
2641 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2642 rectText
.left
= rectIcon
.right
;
2644 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2645 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2647 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2649 /* Draw the icon from the image list */
2650 ImageList_Draw(ilItemImage
,
2657 /* Draw the associated text */
2658 if(sfi
.szDisplayName
)
2659 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2665 /***********************************************************************
2666 * FILEDLG95_LOOKIN_OnCommand
2668 * LookIn combo box WM_COMMAND message handler
2669 * If the function succeeds, the return value is nonzero.
2671 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2673 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2675 TRACE("%p\n", fodInfos
);
2681 LPSFOLDER tmpFolder
;
2684 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2686 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2691 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2692 tmpFolder
->pidlItem
,
2704 /***********************************************************************
2705 * FILEDLG95_LOOKIN_AddItem
2707 * Adds an absolute pidl item to the lookin combo box
2708 * returns the index of the inserted item
2710 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2712 LPITEMIDLIST pidlNext
;
2715 LookInInfos
*liInfos
;
2717 TRACE("%08x\n", iInsertId
);
2722 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2725 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2726 tmpFolder
->m_iIndent
= 0;
2728 /* Calculate the indentation of the item in the lookin*/
2730 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2732 tmpFolder
->m_iIndent
++;
2735 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2737 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2738 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2740 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2741 SHGetFileInfoA((LPSTR
)pidl
,
2745 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2746 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2748 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2750 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2754 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2756 /* Add the item at the end of the list */
2759 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2761 /* Insert the item at the iInsertId position*/
2764 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2767 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2771 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2772 MemFree( tmpFolder
);
2777 /***********************************************************************
2778 * FILEDLG95_LOOKIN_InsertItemAfterParent
2780 * Insert an item below its parent
2782 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2785 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2790 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2794 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2797 /* Free pidlParent memory */
2798 COMDLG32_SHFree((LPVOID
)pidlParent
);
2800 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2803 /***********************************************************************
2804 * FILEDLG95_LOOKIN_SelectItem
2806 * Adds an absolute pidl item to the lookin combo box
2807 * returns the index of the inserted item
2809 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2812 LookInInfos
*liInfos
;
2816 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2818 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2822 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2823 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2828 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2829 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2833 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2835 if(iRemovedItem
< iItemPos
)
2840 CBSetCurSel(hwnd
,iItemPos
);
2841 liInfos
->uSelectedItem
= iItemPos
;
2847 /***********************************************************************
2848 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2850 * Remove the item with an expansion level over iExpansionLevel
2852 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2856 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2860 if(liInfos
->iMaxIndentation
<= 2)
2863 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2865 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2866 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2868 CBDeleteString(hwnd
,iItemPos
);
2869 liInfos
->iMaxIndentation
--;
2877 /***********************************************************************
2878 * FILEDLG95_LOOKIN_SearchItem
2880 * Search for pidl in the lookin combo box
2881 * returns the index of the found item
2883 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2886 int iCount
= CBGetCount(hwnd
);
2888 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2890 if (iCount
!= CB_ERR
)
2894 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2896 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2898 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2906 /***********************************************************************
2907 * FILEDLG95_LOOKIN_Clean
2909 * Clean the memory used by the lookin combo box
2911 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2913 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2915 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2919 /* Delete each string of the combo and their associated data */
2920 if (iCount
!= CB_ERR
)
2922 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2924 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2925 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2927 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2931 /* LookInInfos structure */
2932 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2935 /***********************************************************************
2936 * FILEDLG95_FILENAME_FillFromSelection
2938 * fills the edit box from the cached DataObject
2940 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2942 FileOpenDlgInfos
*fodInfos
;
2944 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2945 char lpstrTemp
[MAX_PATH
];
2946 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2949 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2951 /* Count how many files we have */
2952 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2954 /* calculate the string length, count files */
2955 if (nFileSelected
>= 1)
2957 nLength
+= 3; /* first and last quotes, trailing \0 */
2958 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2960 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2964 /* get the total length of the selected file names */
2965 lpstrTemp
[0] = '\0';
2966 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2968 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2970 nLength
+= strlen( lpstrTemp
) + 3;
2973 COMDLG32_SHFree( pidl
);
2978 /* allocate the buffer */
2979 if (nFiles
<= 1) nLength
= MAX_PATH
;
2980 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2981 lpstrAllFile
[0] = '\0';
2983 /* Generate the string for the edit control */
2986 lpstrCurrFile
= lpstrAllFile
;
2987 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2989 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2993 /* get the file name */
2994 lpstrTemp
[0] = '\0';
2995 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2997 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3001 *lpstrCurrFile
++ = '\"';
3002 strcpy( lpstrCurrFile
, lpstrTemp
);
3003 lpstrCurrFile
+= strlen( lpstrTemp
);
3004 strcpy( lpstrCurrFile
, "\" " );
3009 strcpy( lpstrAllFile
, lpstrTemp
);
3012 COMDLG32_SHFree( (LPVOID
) pidl
);
3015 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3017 /* Select the file name like Windows does */
3018 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)-1);
3020 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3024 /* copied from shell32 to avoid linking to it */
3025 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3030 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
3031 COMDLG32_SHFree(src
->u
.pOleStr
);
3035 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
3039 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
3043 FIXME("unknown type!\n");
3046 *(LPSTR
)dest
= '\0';
3053 /***********************************************************************
3054 * FILEDLG95_FILENAME_GetFileNames
3056 * Copies the filenames to a delimited string list.
3057 * The delimiter is specified by the parameter 'separator',
3058 * usually either a space or a nul
3060 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3062 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3063 UINT nStrCharCount
= 0; /* index in src buffer */
3064 UINT nFileIndex
= 0; /* index in dest buffer */
3065 UINT nFileCount
= 0; /* number of files */
3066 UINT nStrLen
= 0; /* length of string in edit control */
3067 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3071 /* get the filenames from the edit control */
3072 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3073 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3074 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3076 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3078 /* we might get single filename without any '"',
3079 * so we need nStrLen + terminating \0 + end-of-list \0 */
3080 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3083 /* build delimited file list from filenames */
3084 while ( nStrCharCount
<= nStrLen
)
3086 if ( lpstrEdit
[nStrCharCount
]=='"' )
3089 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3091 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3095 (*lpstrFileList
)[nFileIndex
++] = separator
;
3102 /* single, unquoted string */
3103 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3105 strcpyW(*lpstrFileList
, lpstrEdit
);
3106 nFileIndex
= strlenW(lpstrEdit
) + 1;
3107 (*sizeUsed
) = nFileIndex
;
3112 (*lpstrFileList
)[nFileIndex
] = '\0';
3119 #define SETDefFormatEtc(fe,cf,med) \
3121 (fe).cfFormat = cf;\
3122 (fe).dwAspect = DVASPECT_CONTENT; \
3129 * DATAOBJECT Helper functions
3132 /***********************************************************************
3133 * COMCTL32_ReleaseStgMedium
3135 * like ReleaseStgMedium from ole32
3137 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3139 if(medium
.pUnkForRelease
)
3141 IUnknown_Release(medium
.pUnkForRelease
);
3145 GlobalUnlock(medium
.u
.hGlobal
);
3146 GlobalFree(medium
.u
.hGlobal
);
3150 /***********************************************************************
3151 * GetPidlFromDataObject
3153 * Return pidl(s) by number from the cached DataObject
3155 * nPidlIndex=0 gets the fully qualified root path
3157 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3161 FORMATETC formatetc
;
3162 LPITEMIDLIST pidl
= NULL
;
3164 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3166 /* Set the FORMATETC structure*/
3167 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3169 /* Get the pidls from IDataObject */
3170 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3172 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3173 if(nPidlIndex
<= cida
->cidl
)
3175 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3177 COMCTL32_ReleaseStgMedium(medium
);
3182 /***********************************************************************
3185 * Return the number of selected items in the DataObject.
3188 UINT
GetNumSelected( IDataObject
*doSelected
)
3192 FORMATETC formatetc
;
3194 TRACE("sv=%p\n", doSelected
);
3196 if (!doSelected
) return 0;
3198 /* Set the FORMATETC structure*/
3199 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3201 /* Get the pidls from IDataObject */
3202 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3204 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3205 retVal
= cida
->cidl
;
3206 COMCTL32_ReleaseStgMedium(medium
);
3216 /***********************************************************************
3219 * Get the pidl's display name (relative to folder) and
3220 * put it in lpstrFileName.
3222 * Return NOERROR on success,
3226 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
3231 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3235 SHGetDesktopFolder(&lpsf
);
3236 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3237 IShellFolder_Release(lpsf
);
3241 /* Get the display name of the pidl relative to the folder */
3242 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3244 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3249 /***********************************************************************
3250 * GetShellFolderFromPidl
3252 * pidlRel is the item pidl relative
3253 * Return the IShellFolder of the absolute pidl
3255 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3257 IShellFolder
*psf
= NULL
,*psfParent
;
3259 TRACE("%p\n", pidlAbs
);
3261 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3264 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3266 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3268 IShellFolder_Release(psfParent
);
3272 /* return the desktop */
3278 /***********************************************************************
3281 * Return the LPITEMIDLIST to the parent of the pidl in the list
3283 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3285 LPITEMIDLIST pidlParent
;
3287 TRACE("%p\n", pidl
);
3289 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3290 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3295 /***********************************************************************
3298 * returns the pidl of the file name relative to folder
3299 * NULL if an error occurred
3301 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3303 LPITEMIDLIST pidl
= NULL
;
3306 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3308 if(!lpcstrFileName
) return NULL
;
3309 if(!*lpcstrFileName
) return NULL
;
3313 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3314 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3315 IShellFolder_Release(lpsf
);
3320 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3327 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3329 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3332 TRACE("%p, %p\n", psf
, pidl
);
3334 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3336 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3337 /* see documentation shell 4.1*/
3338 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3341 /***********************************************************************
3342 * BrowseSelectedFolder
3344 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3346 BOOL bBrowseSelFolder
= FALSE
;
3347 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3351 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3353 LPITEMIDLIST pidlSelection
;
3355 /* get the file selected */
3356 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3357 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3359 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3360 pidlSelection
, SBSP_RELATIVE
) ) )
3362 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3363 ' ','n','o','t',' ','e','x','i','s','t',0};
3364 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3367 bBrowseSelFolder
= TRUE
;
3369 COMDLG32_SHFree( pidlSelection
);
3372 return bBrowseSelFolder
;
3376 * Memory allocation methods */
3377 static void *MemAlloc(UINT size
)
3379 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3382 static void MemFree(void *mem
)
3384 HeapFree(GetProcessHeap(),0,mem
);
3388 * Old-style (win3.1) dialogs */
3390 /***********************************************************************
3391 * FD32_GetTemplate [internal]
3393 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3394 * by a 32 bits application
3397 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3399 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3400 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3403 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3405 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3407 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3411 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3415 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3416 priv
->ofnA
->lpTemplateName
,
3419 hResInfo
= FindResourceW(ofnW
->hInstance
,
3420 ofnW
->lpTemplateName
,
3424 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3427 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3429 !(lfs
->template = LockResource(hDlgTmpl
)))
3431 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3434 } else { /* get it from internal Wine resource */
3436 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3437 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3439 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3442 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3443 !(lfs
->template = LockResource( hDlgTmpl
)))
3445 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3453 /************************************************************************
3454 * FD32_Init [internal]
3455 * called from the common 16/32 code to initialize 32 bit data
3457 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3459 BOOL IsUnicode
= (BOOL
) data
;
3462 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3463 lfs
->private1632
= priv
;
3464 if (NULL
== lfs
->private1632
) return FALSE
;
3467 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3468 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3469 if (lfs
->ofnW
->lpfnHook
)
3474 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3475 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3476 if (priv
->ofnA
->lpfnHook
)
3478 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3479 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3482 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3487 /***********************************************************************
3488 * FD32_CallWindowProc [internal]
3490 * called from the common 16/32 code to call the appropriate hook
3492 BOOL CALLBACK
FD32_CallWindowProc(PFD31_DATA lfs
, UINT wMsg
, WPARAM wParam
,
3496 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3500 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3501 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3502 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3503 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3504 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3508 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3509 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3510 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3511 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3512 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3516 /***********************************************************************
3517 * FD32_UpdateResult [internal]
3518 * update the real client structures if any
3520 static void CALLBACK
FD32_UpdateResult(PFD31_DATA lfs
)
3522 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3523 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3527 if (ofnW
->nMaxFile
&&
3528 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3529 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3530 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3531 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3532 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
3536 /***********************************************************************
3537 * FD32_UpdateFileTitle [internal]
3538 * update the real client structures if any
3540 static void CALLBACK
FD32_UpdateFileTitle(PFD31_DATA lfs
)
3542 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3543 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3547 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3548 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3549 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3554 /***********************************************************************
3555 * FD32_SendLbGetCurSel [internal]
3556 * retrieve selected listbox item
3558 static LRESULT CALLBACK
FD32_SendLbGetCurSel(PFD31_DATA lfs
)
3560 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3564 /************************************************************************
3565 * FD32_Destroy [internal]
3566 * called from the common 16/32 code to cleanup 32 bit data
3568 static void CALLBACK
FD32_Destroy(PFD31_DATA lfs
)
3570 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3572 /* if ofnW has been allocated, have to free everything in it */
3573 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3575 FD31_FreeOfnW(lfs
->ofnW
);
3576 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3580 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3582 callbacks
->Init
= FD32_Init
;
3583 callbacks
->CWP
= FD32_CallWindowProc
;
3584 callbacks
->UpdateResult
= FD32_UpdateResult
;
3585 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3586 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3587 callbacks
->Destroy
= FD32_Destroy
;
3590 /***********************************************************************
3591 * FD32_WMMeasureItem [internal]
3593 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3595 LPMEASUREITEMSTRUCT lpmeasure
;
3597 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3598 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3603 /***********************************************************************
3604 * FileOpenDlgProc [internal]
3605 * Used for open and save, in fact.
3607 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3608 WPARAM wParam
, LPARAM lParam
)
3610 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3612 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg
, wParam
, lParam
);
3613 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3616 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3618 return lRet
; /* else continue message processing */
3623 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3625 case WM_MEASUREITEM
:
3626 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3629 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3632 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3635 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3636 switch (HIWORD(lParam
))
3639 SetTextColor((HDC16
)wParam
, 0x00000000);
3641 case CTLCOLOR_STATIC
:
3642 SetTextColor((HDC16
)wParam
, 0x00000000);
3652 /***********************************************************************
3653 * GetFileName31A [internal]
3655 * Creates a win31 style dialog box for the user to select a file to open/save.
3657 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* addess of structure with data*/
3658 UINT dlgType
/* type dialogue : open/save */
3664 FD31_CALLBACKS callbacks
;
3666 if (!lpofn
|| !FD31_Init()) return FALSE
;
3668 TRACE("ofn flags %08lx\n", lpofn
->Flags
);
3669 FD32_SetupCallbacks(&callbacks
);
3670 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3673 hInst
= (HINSTANCE
)GetWindowLongPtrA( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3674 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3675 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3676 FD31_DestroyPrivate(lfs
);
3679 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3683 /***********************************************************************
3684 * GetFileName31W [internal]
3686 * Creates a win31 style dialog box for the user to select a file to open/save
3688 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* addess of structure with data*/
3689 UINT dlgType
/* type dialogue : open/save */
3695 FD31_CALLBACKS callbacks
;
3697 if (!lpofn
|| !FD31_Init()) return FALSE
;
3699 FD32_SetupCallbacks(&callbacks
);
3700 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3703 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3704 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3705 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3706 FD31_DestroyPrivate(lfs
);
3709 TRACE("file %s, file offset %d, ext offset %d\n",
3710 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3714 /* ------------------ APIs ---------------------- */
3716 /***********************************************************************
3717 * GetOpenFileNameA (COMDLG32.@)
3719 * Creates a dialog box for the user to select a file to open.
3722 * TRUE on success: user enters a valid file
3723 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3726 BOOL WINAPI
GetOpenFileNameA(
3727 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3729 BOOL win16look
= FALSE
;
3731 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3732 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3733 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3735 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3736 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3739 return GetFileName31A(ofn
, OPEN_DIALOG
);
3741 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3744 /***********************************************************************
3745 * GetOpenFileNameW (COMDLG32.@)
3747 * Creates a dialog box for the user to select a file to open.
3750 * TRUE on success: user enters a valid file
3751 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3754 BOOL WINAPI
GetOpenFileNameW(
3755 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3757 BOOL win16look
= FALSE
;
3759 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3760 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3763 return GetFileName31W(ofn
, OPEN_DIALOG
);
3765 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3769 /***********************************************************************
3770 * GetSaveFileNameA (COMDLG32.@)
3772 * Creates a dialog box for the user to select a file to save.
3775 * TRUE on success: user enters a valid file
3776 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3779 BOOL WINAPI
GetSaveFileNameA(
3780 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3782 BOOL win16look
= FALSE
;
3784 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3785 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3788 return GetFileName31A(ofn
, SAVE_DIALOG
);
3790 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3793 /***********************************************************************
3794 * GetSaveFileNameW (COMDLG32.@)
3796 * Creates a dialog box for the user to select a file to save.
3799 * TRUE on success: user enters a valid file
3800 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3803 BOOL WINAPI
GetSaveFileNameW(
3804 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3806 BOOL win16look
= FALSE
;
3808 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3809 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3812 return GetFileName31W(ofn
, SAVE_DIALOG
);
3814 return GetFileDialog95W(ofn
, SAVE_DIALOG
);