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
= 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 LPSTR lpstrSavDir
= NULL
;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
453 /* Pass in the original ofn */
454 fodInfos
.ofnInfos
= (LPOPENFILENAMEA
) 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 strncpyW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
468 fodInfos
.filename
= NULL
;
470 if(ofn
->lpstrInitialDir
)
472 DWORD len
= strlenW(ofn
->lpstrInitialDir
);
473 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
474 strcpyW(fodInfos
.initdir
,ofn
->lpstrInitialDir
);
477 fodInfos
.initdir
= NULL
;
479 /* save current directory */
480 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
482 lpstrSavDir
= MemAlloc(MAX_PATH
);
483 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
486 fodInfos
.unicode
= TRUE
;
491 ret
= GetFileName95(&fodInfos
);
494 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
495 ret
= GetFileName95(&fodInfos
);
503 SetCurrentDirectoryA(lpstrSavDir
);
504 MemFree(lpstrSavDir
);
507 /* restore saved IN arguments and convert OUT arguments back */
508 MemFree(fodInfos
.filename
);
509 MemFree(fodInfos
.initdir
);
513 /***********************************************************************
514 * ArrangeCtrlPositions [internal]
516 * NOTE: Do not change anything here without a lot of testing.
518 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
520 HWND hwndChild
, hwndStc32
;
521 RECT rectParent
, rectChild
, rectStc32
;
522 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
524 /* Take into account if open as read only checkbox and help button
529 RECT rectHelp
, rectCancel
;
530 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
531 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
532 /* subtract the height of the help button plus the space between
533 * the help button and the cancel button to the height of the dialog
535 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
539 There are two possibilities to add components to the default file dialog box.
541 By default, all the new components are added below the standard dialog box (the else case).
543 However, if there is a static text component with the stc32 id, a special case happens.
544 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
545 in the window and the cx and cy indicate how to size the window.
546 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
547 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
551 GetClientRect(hwndParentDlg
, &rectParent
);
553 /* when arranging controls we have to use fixed parent size */
554 rectParent
.bottom
-= help_fixup
;
556 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
559 GetWindowRect(hwndStc32
, &rectStc32
);
560 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
562 /* set the size of the stc32 control according to the size of
563 * client area of the parent dialog
565 SetWindowPos(hwndStc32
, 0,
567 rectParent
.right
, rectParent
.bottom
,
568 SWP_NOMOVE
| SWP_NOZORDER
);
571 SetRectEmpty(&rectStc32
);
573 /* this part moves controls of the child dialog */
574 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
577 if (hwndChild
!= hwndStc32
)
579 GetWindowRect(hwndChild
, &rectChild
);
580 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
582 /* move only if stc32 exist */
583 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
585 LONG old_left
= rectChild
.left
;
587 /* move to the right of visible controls of the parent dialog */
588 rectChild
.left
+= rectParent
.right
;
589 rectChild
.left
-= rectStc32
.right
;
591 child_width_fixup
= rectChild
.left
- old_left
;
593 /* move even if stc32 doesn't exist */
594 if (rectChild
.top
>= rectStc32
.bottom
)
596 LONG old_top
= rectChild
.top
;
598 /* move below visible controls of the parent dialog */
599 rectChild
.top
+= rectParent
.bottom
;
600 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
602 child_height_fixup
= rectChild
.top
- old_top
;
605 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
606 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
608 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
611 /* this part moves controls of the parent dialog */
612 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
615 if (hwndChild
!= hwndChildDlg
)
617 GetWindowRect(hwndChild
, &rectChild
);
618 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
620 /* left,top of stc32 marks the position of controls
621 * from the parent dialog
623 rectChild
.left
+= rectStc32
.left
;
624 rectChild
.top
+= rectStc32
.top
;
626 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
627 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
629 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
632 /* calculate the size of the resulting dialog */
634 /* here we have to use original parent size */
635 GetClientRect(hwndParentDlg
, &rectParent
);
636 GetClientRect(hwndChildDlg
, &rectChild
);
640 rectChild
.right
+= child_width_fixup
;
641 rectChild
.bottom
+= child_height_fixup
;
643 if (rectParent
.right
> rectChild
.right
)
645 rectParent
.right
+= rectChild
.right
;
646 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
650 rectParent
.right
= rectChild
.right
;
653 if (rectParent
.bottom
> rectChild
.bottom
)
655 rectParent
.bottom
+= rectChild
.bottom
;
656 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
660 /* child dialog is higher, unconditionally set new dialog
661 * height to its size (help_fixup will be subtracted below)
663 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
668 rectParent
.bottom
+= rectChild
.bottom
;
671 /* finally use fixed parent size */
672 rectParent
.bottom
-= help_fixup
;
674 /* save the size of the parent's client area */
675 rectChild
.right
= rectParent
.right
;
676 rectChild
.bottom
= rectParent
.bottom
;
678 /* set the size of the parent dialog */
679 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
680 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
681 SetWindowPos(hwndParentDlg
, 0,
683 rectParent
.right
- rectParent
.left
,
684 rectParent
.bottom
- rectParent
.top
,
685 SWP_NOMOVE
| SWP_NOZORDER
);
687 /* set the size of the child dialog */
688 SetWindowPos(hwndChildDlg
, HWND_BOTTOM
,
689 0, 0, rectChild
.right
, rectChild
.bottom
, SWP_NOACTIVATE
);
692 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
701 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
711 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
712 * structure's hInstance parameter is not a HINSTANCE, but
713 * instead a pointer to a template resource to use.
715 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
718 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
721 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
723 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
729 hinst
= fodInfos
->ofnInfos
->hInstance
;
730 if(fodInfos
->unicode
)
732 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
733 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
737 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
738 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
742 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
745 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
746 !(template = LockResource( hDlgTmpl
)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
752 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, template, hwnd
,
753 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
754 (LPARAM
)fodInfos
->ofnInfos
);
757 ShowWindow(hChildDlg
,SW_SHOW
);
761 else if( IsHooked(fodInfos
))
766 WORD menu
,class,title
;
768 GetClientRect(hwnd
,&rectHwnd
);
769 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
770 temp
.tmplate
.dwExtendedStyle
= 0;
771 temp
.tmplate
.cdit
= 0;
776 temp
.menu
= temp
.class = temp
.title
= 0;
778 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
779 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
786 /***********************************************************************
787 * SendCustomDlgNotificationMessage
789 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
792 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
794 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
796 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
798 if(!fodInfos
) return 0;
800 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
803 TRACE("CALL NOTIFY for %x\n", uCode
);
804 if(fodInfos
->unicode
)
807 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
808 ofnNotify
.hdr
.idFrom
=0;
809 ofnNotify
.hdr
.code
= uCode
;
810 ofnNotify
.lpOFN
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
811 ofnNotify
.pszFile
= NULL
;
812 ret
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
817 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
818 ofnNotify
.hdr
.idFrom
=0;
819 ofnNotify
.hdr
.code
= uCode
;
820 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
821 ofnNotify
.pszFile
= NULL
;
822 ret
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
824 TRACE("RET NOTIFY\n");
830 HRESULT
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
832 UINT sizeUsed
= 0, n
, total
;
833 LPWSTR lpstrFileList
= NULL
;
834 WCHAR lpstrCurrentDir
[MAX_PATH
];
835 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
837 TRACE("CDM_GETFILEPATH:\n");
839 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
842 /* get path and filenames */
843 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
844 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
846 TRACE("path >%s< filespec >%s< %d files\n",
847 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
849 if( fodInfos
->unicode
)
851 LPWSTR bufW
= buffer
;
852 total
= strlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
854 /* Prepend the current path */
855 n
= strlenW(lpstrCurrentDir
) + 1;
856 strncpyW( bufW
, lpstrCurrentDir
, size
);
859 /* 'n' includes trailing \0 */
861 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
863 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
868 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
869 NULL
, 0, NULL
, NULL
);
870 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
871 NULL
, 0, NULL
, NULL
);
873 /* Prepend the current path */
874 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
875 bufA
, size
, NULL
, NULL
);
879 /* 'n' includes trailing \0 */
881 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
882 &bufA
[n
], size
-n
, NULL
, NULL
);
885 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
887 MemFree(lpstrFileList
);
892 HRESULT
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
895 LPWSTR lpstrFileList
= NULL
;
896 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
898 TRACE("CDM_GETSPEC:\n");
900 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
901 if( fodInfos
->unicode
)
903 LPWSTR bufW
= buffer
;
904 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
909 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
910 NULL
, 0, NULL
, NULL
);
911 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
912 bufA
, size
, NULL
, NULL
);
914 MemFree(lpstrFileList
);
919 /***********************************************************************
920 * FILEDLG95_HandleCustomDialogMessages
922 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
924 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
926 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
927 if(!fodInfos
) return -1;
931 case CDM_GETFILEPATH
:
932 return FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
934 case CDM_GETFOLDERPATH
:
935 TRACE("CDM_GETFOLDERPATH:\n");
936 if( fodInfos
->unicode
)
938 WCHAR lpstrPath
[MAX_PATH
], *bufW
= (LPWSTR
)lParam
;
939 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
941 lstrcpynW(bufW
,lpstrPath
,(int)wParam
);
942 return strlenW(lpstrPath
);
946 char lpstrPath
[MAX_PATH
], *bufA
= (LPSTR
)lParam
;
947 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
949 lstrcpynA(bufA
,lpstrPath
,(int)wParam
);
950 return strlen(lpstrPath
);
954 return FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
956 case CDM_SETCONTROLTEXT
:
957 TRACE("CDM_SETCONTROLTEXT:\n");
960 if( fodInfos
->unicode
)
961 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
963 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
967 case CDM_HIDECONTROL
:
969 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
975 /***********************************************************************
978 * File open dialog procedure
980 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
983 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
990 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
992 /* Adds the FileOpenDlgInfos in the property list of the dialog
993 so it will be easily accessible through a GetPropA(...) */
994 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
996 fodInfos
->DlgInfos
.hwndCustomDlg
=
997 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
999 FILEDLG95_InitControls(hwnd
);
1001 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1002 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1003 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1005 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1007 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1008 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1009 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1013 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1016 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1019 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1025 case WM_GETISHELLBROWSER
:
1026 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1029 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1034 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1037 /* set up the button tooltips strings */
1038 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1040 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1041 switch(lpnmh
->idFrom
)
1043 /* Up folder button */
1044 case FCIDM_TB_UPFOLDER
:
1045 stringId
= IDS_UPFOLDER
;
1047 /* New folder button */
1048 case FCIDM_TB_NEWFOLDER
:
1049 stringId
= IDS_NEWFOLDER
;
1051 /* List option button */
1052 case FCIDM_TB_SMALLICON
:
1053 stringId
= IDS_LISTVIEW
;
1055 /* Details option button */
1056 case FCIDM_TB_REPORTVIEW
:
1057 stringId
= IDS_REPORTVIEW
;
1059 /* Desktop button */
1060 case FCIDM_TB_DESKTOP
:
1061 stringId
= IDS_TODESKTOP
;
1066 lpdi
->hinst
= COMDLG32_hInstance
;
1067 lpdi
->lpszText
= (LPSTR
) stringId
;
1072 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1073 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1078 /***********************************************************************
1079 * FILEDLG95_InitControls
1081 * WM_INITDIALOG message handler (before hook notification)
1083 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1085 int win2000plus
= 0;
1087 int handledPath
= FALSE
;
1088 OSVERSIONINFOA osVi
;
1089 static const WCHAR szwSlash
[] = { '\\', 0 };
1090 static const WCHAR szwStar
[] = { '*',0 };
1094 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1095 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1096 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1097 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1098 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1099 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1101 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1102 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1107 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1109 tba
[0].hInst
= HINST_COMMCTRL
;
1110 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1111 tba
[1].hInst
= COMDLG32_hInstance
;
1114 TRACE("%p\n", fodInfos
);
1116 /* Get windows version emulating */
1117 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1118 GetVersionExA(&osVi
);
1119 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1120 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1121 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1122 win2000plus
= (osVi
.dwMajorVersion
> 4);
1123 if (win2000plus
) win98plus
= TRUE
;
1125 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1127 /* Get the hwnd of the controls */
1128 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1129 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1130 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1132 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1133 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1135 /* construct the toolbar */
1136 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1137 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1139 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1140 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1141 rectTB
.left
= rectlook
.right
;
1142 rectTB
.top
= rectlook
.top
-1;
1144 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1145 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1146 rectTB
.left
, rectTB
.top
,
1147 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1148 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1150 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1152 /* FIXME: use TB_LOADIMAGES when implemented */
1153 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1154 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1155 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1157 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1158 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1160 /* Set the window text with the text specified in the OPENFILENAME structure */
1163 SetWindowTextW(hwnd
,fodInfos
->title
);
1165 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1167 SetWindowTextA(hwnd
,"Save");
1170 /* Initialise the file name edit control */
1171 handledPath
= FALSE
;
1172 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1174 if(fodInfos
->filename
)
1176 /* 1. If win2000 or higher and filename contains a path, use it
1177 in preference over the lpstrInitialDir */
1178 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1179 WCHAR tmpBuf
[MAX_PATH
];
1183 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1186 /* nameBit is always shorter than the original filename */
1187 strcpyW(fodInfos
->filename
,nameBit
);
1190 if (fodInfos
->initdir
== NULL
)
1191 MemFree(fodInfos
->initdir
);
1192 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1193 strcpyW(fodInfos
->initdir
, tmpBuf
);
1195 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1196 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1198 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1201 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1205 /* 2. (All platforms) If initdir is not null, then use it */
1206 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1207 (*fodInfos
->initdir
!=0x00))
1209 /* Work out the proper path as supplied one might be relative */
1210 /* (Here because supplying '.' as dir browses to My Computer) */
1211 if (handledPath
==FALSE
) {
1212 WCHAR tmpBuf
[MAX_PATH
];
1213 WCHAR tmpBuf2
[MAX_PATH
];
1217 strcpyW(tmpBuf
, fodInfos
->initdir
);
1218 if( PathFileExistsW(tmpBuf
) ) {
1219 /* initdir does not have to be a directory. If a file is
1220 * specified, the dir part is taken */
1221 if( PathIsDirectoryW(tmpBuf
)) {
1222 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1223 strcatW(tmpBuf
, szwSlash
);
1225 strcatW(tmpBuf
, szwStar
);
1227 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1230 if (fodInfos
->initdir
)
1231 MemFree(fodInfos
->initdir
);
1232 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1233 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1235 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1238 else if (fodInfos
->initdir
)
1240 MemFree(fodInfos
->initdir
);
1241 fodInfos
->initdir
= NULL
;
1242 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1247 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1248 (*fodInfos
->initdir
==0x00)))
1250 /* 3. All except w2k+: if filename contains a path use it */
1251 if (!win2000plus
&& fodInfos
->filename
&&
1252 *fodInfos
->filename
&&
1253 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1254 WCHAR tmpBuf
[MAX_PATH
];
1258 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1263 /* nameBit is always shorter than the original filename */
1264 strcpyW(fodInfos
->filename
, nameBit
);
1267 len
= strlenW(tmpBuf
);
1268 if(fodInfos
->initdir
)
1269 MemFree(fodInfos
->initdir
);
1270 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1271 strcpyW(fodInfos
->initdir
, tmpBuf
);
1274 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1275 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1277 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1280 /* 4. win98+ and win2000+ if any files of specified filter types in
1281 current directory, use it */
1282 if ( win98plus
&& handledPath
== FALSE
&&
1283 fodInfos
->filter
&& *fodInfos
->filter
) {
1285 BOOL searchMore
= TRUE
;
1286 LPCWSTR lpstrPos
= fodInfos
->filter
;
1287 WIN32_FIND_DATAW FindFileData
;
1292 /* filter is a list... title\0ext\0......\0\0 */
1294 /* Skip the title */
1295 if(! *lpstrPos
) break; /* end */
1296 lpstrPos
+= strlenW(lpstrPos
) + 1;
1298 /* See if any files exist in the current dir with this extension */
1299 if(! *lpstrPos
) break; /* end */
1301 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1303 if (hFind
== INVALID_HANDLE_VALUE
) {
1304 /* None found - continue search */
1305 lpstrPos
+= strlenW(lpstrPos
) + 1;
1310 if(fodInfos
->initdir
)
1311 MemFree(fodInfos
->initdir
);
1312 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1313 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1316 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1317 debugstr_w(lpstrPos
));
1323 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1325 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1326 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1327 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1329 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1331 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1334 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1335 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1337 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1340 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1343 } else if (handledPath
==FALSE
) {
1344 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1345 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1347 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1350 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1351 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1353 /* Must the open as read only check box be checked ?*/
1354 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1356 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1359 /* Must the open as read only check box be hidden? */
1360 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1362 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1363 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1366 /* Must the help button be hidden? */
1367 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1369 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1370 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1373 /* Resize the height, if open as read only checkbox ad help button
1374 are hidden and we are not using a custom template nor a customDialog
1376 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1377 (!(fodInfos
->ofnInfos
->Flags
&
1378 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))) &&
1379 (!fodInfos
->DlgInfos
.hwndCustomDlg
))
1381 RECT rectDlg
, rectHelp
, rectCancel
;
1382 GetWindowRect(hwnd
, &rectDlg
);
1383 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1384 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1385 /* subtract the height of the help button plus the space between
1386 the help button and the cancel button to the height of the dialog */
1387 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1388 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1389 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1391 /* change Open to Save FIXME: use resources */
1392 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1394 SetDlgItemTextA(hwnd
,IDOK
,"&Save");
1395 SetDlgItemTextA(hwnd
,IDC_LOOKINSTATIC
,"Save &in");
1400 /***********************************************************************
1401 * FILEDLG95_FillControls
1403 * WM_INITDIALOG message handler (after hook notification)
1405 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1407 LPITEMIDLIST pidlItemId
= NULL
;
1409 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1411 TRACE("dir=%s file=%s\n",
1412 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1414 /* Get the initial directory pidl */
1416 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1418 WCHAR path
[MAX_PATH
];
1420 GetCurrentDirectoryW(MAX_PATH
,path
);
1421 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1424 /* Initialise shell objects */
1425 FILEDLG95_SHELL_Init(hwnd
);
1427 /* Initialize the Look In combo box */
1428 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1430 /* Initialize the filter combo box */
1431 FILEDLG95_FILETYPE_Init(hwnd
);
1433 /* Browse to the initial directory */
1434 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1436 /* Free pidlItem memory */
1437 COMDLG32_SHFree(pidlItemId
);
1441 /***********************************************************************
1444 * Regroups all the cleaning functions of the filedlg
1446 void FILEDLG95_Clean(HWND hwnd
)
1448 FILEDLG95_FILETYPE_Clean(hwnd
);
1449 FILEDLG95_LOOKIN_Clean(hwnd
);
1450 FILEDLG95_SHELL_Clean(hwnd
);
1452 /***********************************************************************
1453 * FILEDLG95_OnWMCommand
1455 * WM_COMMAND message handler
1457 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1459 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1460 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1461 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1467 FILEDLG95_OnOpen(hwnd
);
1471 FILEDLG95_Clean(hwnd
);
1472 EndDialog(hwnd
, FALSE
);
1474 /* Filetype combo box */
1476 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1478 /* LookIn combo box */
1480 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1483 /* --- toolbar --- */
1484 /* Up folder button */
1485 case FCIDM_TB_UPFOLDER
:
1486 FILEDLG95_SHELL_UpFolder(hwnd
);
1488 /* New folder button */
1489 case FCIDM_TB_NEWFOLDER
:
1490 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1492 /* List option button */
1493 case FCIDM_TB_SMALLICON
:
1494 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1496 /* Details option button */
1497 case FCIDM_TB_REPORTVIEW
:
1498 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1500 /* Details option button */
1501 case FCIDM_TB_DESKTOP
:
1502 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1509 /* Do not use the listview selection anymore */
1510 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1514 /***********************************************************************
1515 * FILEDLG95_OnWMGetIShellBrowser
1517 * WM_GETISHELLBROWSER message handler
1519 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1522 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1526 SetWindowLongA(hwnd
,DWL_MSGRESULT
,(LONG
)fodInfos
->Shell
.FOIShellBrowser
);
1532 /***********************************************************************
1533 * FILEDLG95_SendFileOK
1535 * Sends the CDN_FILEOK notification if required
1538 * TRUE if the dialog should close
1539 * FALSE if the dialog should not be closed
1541 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1543 /* ask the hook if we can close */
1544 if(IsHooked(fodInfos
))
1547 /* First send CDN_FILEOK as MSDN doc says */
1548 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1549 if (GetWindowLongW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWL_MSGRESULT
))
1551 TRACE("canceled\n");
1555 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1556 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1557 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1558 if (GetWindowLongW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWL_MSGRESULT
))
1560 TRACE("canceled\n");
1567 /***********************************************************************
1568 * FILEDLG95_OnOpenMultipleFiles
1570 * Handles the opening of multiple files.
1573 * check destination buffer size
1575 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1577 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1578 UINT nCount
, nSizePath
;
1579 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1583 if(fodInfos
->unicode
)
1585 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1586 ofn
->lpstrFile
[0] = '\0';
1590 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1591 ofn
->lpstrFile
[0] = '\0';
1594 SHGetPathFromIDListW( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1596 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1597 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1598 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1600 LPWSTR lpstrTemp
= lpstrFileList
;
1602 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1606 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1609 WCHAR lpstrNotFound
[100];
1610 WCHAR lpstrMsg
[100];
1612 static const WCHAR nl
[] = {'\n',0};
1614 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1615 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1617 strcpyW(tmp
, lpstrTemp
);
1619 strcatW(tmp
, lpstrNotFound
);
1621 strcatW(tmp
, lpstrMsg
);
1623 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1627 /* move to the next file in the list of files */
1628 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1629 COMDLG32_SHFree(pidl
);
1633 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1634 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1636 /* For "oldstyle" dialog the components have to
1637 be separated by blanks (not '\0'!) and short
1638 filenames have to be used! */
1639 FIXME("Components have to be separated by blanks\n");
1641 if(fodInfos
->unicode
)
1643 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1644 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1645 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1649 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1651 if (ofn
->lpstrFile
!= NULL
)
1653 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1654 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1655 if (ofn
->nMaxFile
> nSizePath
)
1657 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1658 ofn
->lpstrFile
+ nSizePath
,
1659 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1664 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1665 fodInfos
->ofnInfos
->nFileExtension
= 0;
1667 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1670 /* clean and exit */
1671 FILEDLG95_Clean(hwnd
);
1672 return EndDialog(hwnd
,TRUE
);
1675 /***********************************************************************
1678 * Ok button WM_COMMAND message handler
1680 * If the function succeeds, the return value is nonzero.
1682 #define ONOPEN_BROWSE 1
1683 #define ONOPEN_OPEN 2
1684 #define ONOPEN_SEARCH 3
1685 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1687 char strMsgTitle
[MAX_PATH
];
1688 char strMsgText
[MAX_PATH
];
1690 LoadStringA(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
));
1692 strMsgTitle
[0] = '\0';
1693 LoadStringA(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
));
1694 MessageBoxA(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1697 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1699 LPWSTR lpstrFileList
;
1700 UINT nFileCount
= 0;
1703 WCHAR lpstrPathAndFile
[MAX_PATH
];
1704 WCHAR lpstrTemp
[MAX_PATH
];
1705 LPSHELLFOLDER lpsf
= NULL
;
1707 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1709 TRACE("hwnd=%p\n", hwnd
);
1711 /* get the files from the edit control */
1712 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1714 /* try if the user selected a folder in the shellview */
1717 BrowseSelectedFolder(hwnd
);
1723 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1727 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1730 Step 1: Build a complete path name from the current folder and
1731 the filename or path in the edit box.
1733 - the path in the edit box is a root path
1734 (with or without drive letter)
1735 - the edit box contains ".." (or a path with ".." in it)
1738 /* Get the current directory name */
1739 if (!SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1741 /* we are in a special folder, default to desktop */
1742 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, lpstrPathAndFile
)))
1745 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1748 PathAddBackslashW(lpstrPathAndFile
);
1750 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1752 /* if the user specifyed a fully qualified path use it */
1753 if(PathIsRelativeW(lpstrFileList
))
1755 strcatW(lpstrPathAndFile
, lpstrFileList
);
1759 /* does the path have a drive letter? */
1760 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1761 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1763 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1766 /* resolve "." and ".." */
1767 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1768 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1769 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1771 MemFree(lpstrFileList
);
1774 Step 2: here we have a cleaned up path
1776 We have to parse the path step by step to see if we have to browse
1777 to a folder if the path points to a directory or the last
1778 valid element is a directory.
1781 lpstrPathAndFile: cleaned up path
1784 nOpenAction
= ONOPEN_BROWSE
;
1786 /* don't apply any checks with OFN_NOVALIDATE */
1788 LPWSTR lpszTemp
, lpszTemp1
;
1789 LPITEMIDLIST pidl
= NULL
;
1790 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1792 /* check for invalid chars */
1793 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1795 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1800 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1802 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1805 LPSHELLFOLDER lpsfChild
;
1806 WCHAR lpwstrTemp
[MAX_PATH
];
1807 DWORD dwEaten
, dwAttributes
;
1810 strcpyW(lpwstrTemp
, lpszTemp
);
1811 p
= PathFindNextComponentW(lpwstrTemp
);
1813 if (!p
) break; /* end of path */
1816 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1820 static const WCHAR wszWild
[] = { '*', '?', 0 };
1821 /* if the last element is a wildcard do a search */
1822 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1824 nOpenAction
= ONOPEN_SEARCH
;
1828 lpszTemp1
= lpszTemp
;
1830 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1832 if(lstrlenW(lpwstrTemp
)==2) PathAddBackslashW(lpwstrTemp
);
1834 dwAttributes
= SFGAO_FOLDER
;
1835 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1837 /* the path component is valid, we have a pidl of the next path component */
1838 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1839 if(dwAttributes
& SFGAO_FOLDER
)
1841 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1843 ERR("bind to failed\n"); /* should not fail */
1846 IShellFolder_Release(lpsf
);
1854 /* end dialog, return value */
1855 nOpenAction
= ONOPEN_OPEN
;
1858 COMDLG32_SHFree(pidl
);
1861 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1863 if(*lpszTemp
) /* points to trailing null for last path element */
1865 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1867 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1873 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1874 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1876 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1880 /* change to the current folder */
1881 nOpenAction
= ONOPEN_OPEN
;
1886 nOpenAction
= ONOPEN_OPEN
;
1890 if(pidl
) COMDLG32_SHFree(pidl
);
1894 Step 3: here we have a cleaned up and validated path
1897 lpsf: ShellFolder bound to the rightmost valid path component
1898 lpstrPathAndFile: cleaned up path
1899 nOpenAction: action to do
1901 TRACE("end validate sf=%p\n", lpsf
);
1905 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1906 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1909 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1912 /* replace the current filter */
1913 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1914 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1915 len
= strlenW(lpszTemp
)+1;
1916 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1917 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1919 /* set the filter cb to the extension when possible */
1920 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1921 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1924 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1925 TRACE("ONOPEN_BROWSE\n");
1927 IPersistFolder2
* ppf2
;
1928 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1930 LPITEMIDLIST pidlCurrent
;
1931 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1932 IPersistFolder2_Release(ppf2
);
1933 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1935 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1937 else if( nOpenAction
== ONOPEN_SEARCH
)
1939 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1941 COMDLG32_SHFree(pidlCurrent
);
1946 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1947 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1951 /* update READONLY check box flag */
1952 if ((SendMessageA(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
1953 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
1955 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
1957 /* Attach the file extension with file name*/
1958 ext
= PathFindExtensionW(lpstrPathAndFile
);
1961 /* if no extension is specified with file name, then */
1962 /* attach the extension from file filter or default one */
1964 WCHAR
*filterExt
= NULL
;
1965 LPWSTR lpstrFilter
= NULL
;
1966 static const WCHAR szwDot
[] = {'.',0};
1967 int PathLength
= strlenW(lpstrPathAndFile
);
1970 strcatW(lpstrPathAndFile
, szwDot
);
1972 /*Get the file extension from file type filter*/
1973 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
1974 fodInfos
->ofnInfos
->nFilterIndex
-1);
1976 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
1977 filterExt
= PathFindExtensionW(lpstrFilter
);
1979 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
1980 strcatW(lpstrPathAndFile
, filterExt
+ 1);
1981 else if ( fodInfos
->defext
) /* attach the default file extension*/
1982 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
1984 /* In Open dialog: if file does not exist try without extension */
1985 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
1986 lpstrPathAndFile
[PathLength
] = '\0';
1989 if (fodInfos
->defext
) /* add default extension */
1991 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1994 if (!lstrcmpiW(fodInfos
->defext
, ext
))
1995 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
1997 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2000 /* In Save dialog: check if the file already exists */
2001 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2002 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2003 && PathFileExistsW(lpstrPathAndFile
))
2005 WCHAR lpstrOverwrite
[100];
2008 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2009 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2010 MB_YESNO
| MB_ICONEXCLAMATION
);
2018 /* Check that the size of the file does not exceed buffer size.
2019 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2020 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2021 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2025 /* fill destination buffer */
2026 if (fodInfos
->ofnInfos
->lpstrFile
)
2028 if(fodInfos
->unicode
)
2030 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
2032 strncpyW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2033 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2034 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2038 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
2040 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2041 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2042 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2043 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2047 /* set filename offset */
2048 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2049 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2051 /* set extension offset */
2052 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2053 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2055 /* set the lpstrFileTitle */
2056 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2058 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2059 if(fodInfos
->unicode
)
2061 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
2062 strncpyW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2066 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
2067 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2068 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2072 /* copy currently selected filter to lpstrCustomFilter */
2073 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2075 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
2076 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2077 NULL
, 0, NULL
, NULL
);
2078 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2080 LPSTR s
= ofn
->lpstrCustomFilter
;
2081 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2082 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2083 s
, len
, NULL
, NULL
);
2088 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2092 FILEDLG95_Clean(hwnd
);
2093 ret
= EndDialog(hwnd
, TRUE
);
2099 size
= strlenW(lpstrPathAndFile
) + 1;
2100 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2102 /* return needed size in first two bytes of lpstrFile */
2103 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2104 FILEDLG95_Clean(hwnd
);
2105 ret
= EndDialog(hwnd
, FALSE
);
2106 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2114 if(lpsf
) IShellFolder_Release(lpsf
);
2118 /***********************************************************************
2119 * FILEDLG95_SHELL_Init
2121 * Initialisation of the shell objects
2123 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2125 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2130 * Initialisation of the FileOpenDialogInfos structure
2136 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2138 /* Disable multi-select if flag not set */
2139 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2141 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2143 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2144 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2146 /* Construct the IShellBrowser interface */
2147 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2152 /***********************************************************************
2153 * FILEDLG95_SHELL_ExecuteCommand
2155 * Change the folder option and refresh the view
2156 * If the function succeeds, the return value is nonzero.
2158 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2160 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2163 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2165 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2170 CMINVOKECOMMANDINFO ci
;
2171 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2172 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2176 IContextMenu_InvokeCommand(pcm
, &ci
);
2177 IContextMenu_Release(pcm
);
2183 /***********************************************************************
2184 * FILEDLG95_SHELL_UpFolder
2186 * Browse to the specified object
2187 * If the function succeeds, the return value is nonzero.
2189 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2191 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2195 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2204 /***********************************************************************
2205 * FILEDLG95_SHELL_BrowseToDesktop
2207 * Browse to the Desktop
2208 * If the function succeeds, the return value is nonzero.
2210 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2212 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2218 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2219 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2220 COMDLG32_SHFree(pidl
);
2221 return SUCCEEDED(hres
);
2223 /***********************************************************************
2224 * FILEDLG95_SHELL_Clean
2226 * Cleans the memory used by shell objects
2228 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2230 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2234 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2236 /* clean Shell interfaces */
2237 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2238 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2239 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2240 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2241 if (fodInfos
->Shell
.FOIDataObject
)
2242 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2245 /***********************************************************************
2246 * FILEDLG95_FILETYPE_Init
2248 * Initialisation of the file type combo box
2250 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2252 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2253 int nFilters
= 0; /* number of filters */
2258 if(fodInfos
->customfilter
)
2260 /* customfilter has one entry... title\0ext\0
2261 * Set first entry of combo box item with customfilter
2264 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2267 lpstrPos
+= strlenW(fodInfos
->customfilter
) + 1;
2269 /* Copy the extensions */
2270 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2271 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2272 strcpyW(lpstrExt
,lpstrPos
);
2274 /* Add the item at the end of the combo */
2275 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2276 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2279 if(fodInfos
->filter
)
2281 LPCWSTR lpstrPos
= fodInfos
->filter
;
2285 /* filter is a list... title\0ext\0......\0\0
2286 * Set the combo item text to the title and the item data
2289 LPCWSTR lpstrDisplay
;
2293 if(! *lpstrPos
) break; /* end */
2294 lpstrDisplay
= lpstrPos
;
2295 lpstrPos
+= strlenW(lpstrPos
) + 1;
2297 /* Copy the extensions */
2298 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2299 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2300 strcpyW(lpstrExt
,lpstrPos
);
2301 lpstrPos
+= strlenW(lpstrPos
) + 1;
2303 /* Add the item at the end of the combo */
2304 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2305 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2311 * Set the current filter to the one specified
2312 * in the initialisation structure
2314 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2318 /* Check to make sure our index isn't out of bounds. */
2319 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2320 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2321 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2323 /* set default filter index */
2324 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2325 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2327 /* calculate index of Combo Box item */
2328 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2329 if (fodInfos
->customfilter
== NULL
)
2332 /* Set the current index selection. */
2333 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2335 /* Get the corresponding text string from the combo box. */
2336 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2339 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2345 CharLowerW(lpstrFilter
); /* lowercase */
2346 len
= strlenW(lpstrFilter
)+1;
2347 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2348 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2351 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2356 /***********************************************************************
2357 * FILEDLG95_FILETYPE_OnCommand
2359 * WM_COMMAND of the file type combo box
2360 * If the function succeeds, the return value is nonzero.
2362 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2364 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2372 /* Get the current item of the filetype combo box */
2373 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2375 /* set the current filter index */
2376 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2377 (fodInfos
->customfilter
== NULL
? 1 : 0);
2379 /* Set the current filter with the current selection */
2380 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2381 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2383 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2385 if((int)lpstrFilter
!= CB_ERR
)
2388 CharLowerW(lpstrFilter
); /* lowercase */
2389 len
= strlenW(lpstrFilter
)+1;
2390 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2391 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2392 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2395 /* Refresh the actual view to display the included items*/
2396 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2401 /***********************************************************************
2402 * FILEDLG95_FILETYPE_SearchExt
2404 * searches for a extension in the filetype box
2406 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2408 int i
, iCount
= CBGetCount(hwnd
);
2410 TRACE("%s\n", debugstr_w(lpstrExt
));
2412 if(iCount
!= CB_ERR
)
2414 for(i
=0;i
<iCount
;i
++)
2416 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2423 /***********************************************************************
2424 * FILEDLG95_FILETYPE_Clean
2426 * Clean the memory used by the filetype combo box
2428 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2430 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2432 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2436 /* Delete each string of the combo and their associated data */
2437 if(iCount
!= CB_ERR
)
2439 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2441 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2442 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2445 /* Current filter */
2446 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2447 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2451 /***********************************************************************
2452 * FILEDLG95_LOOKIN_Init
2454 * Initialisation of the look in combo box
2456 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2458 IShellFolder
*psfRoot
, *psfDrives
;
2459 IEnumIDList
*lpeRoot
, *lpeDrives
;
2460 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2462 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2466 liInfos
->iMaxIndentation
= 0;
2468 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2470 /* set item height for both text field and listbox */
2471 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2472 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2474 /* Turn on the extended UI for the combo box like Windows does */
2475 CBSetExtendedUI(hwndCombo
, TRUE
);
2477 /* Initialise data of Desktop folder */
2478 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2479 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2480 COMDLG32_SHFree(pidlTmp
);
2482 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2484 SHGetDesktopFolder(&psfRoot
);
2488 /* enumerate the contents of the desktop */
2489 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2491 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2493 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2495 /* special handling for CSIDL_DRIVES */
2496 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2498 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2500 /* enumerate the drives */
2501 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2503 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2505 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2506 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2507 COMDLG32_SHFree(pidlAbsTmp
);
2508 COMDLG32_SHFree(pidlTmp1
);
2510 IEnumIDList_Release(lpeDrives
);
2512 IShellFolder_Release(psfDrives
);
2515 COMDLG32_SHFree(pidlTmp
);
2517 IEnumIDList_Release(lpeRoot
);
2519 IShellFolder_Release(psfRoot
);
2522 COMDLG32_SHFree(pidlDrives
);
2526 /***********************************************************************
2527 * FILEDLG95_LOOKIN_DrawItem
2529 * WM_DRAWITEM message handler
2531 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2533 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2534 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2535 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2539 HIMAGELIST ilItemImage
;
2542 LPSFOLDER tmpFolder
;
2545 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2549 if(pDIStruct
->itemID
== -1)
2552 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2553 pDIStruct
->itemID
)))
2557 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2559 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2562 sizeof (SHFILEINFOA
),
2563 SHGFI_PIDL
| SHGFI_SMALLICON
|
2564 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2565 SHGFI_DISPLAYNAME
);
2569 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2572 sizeof (SHFILEINFOA
),
2573 SHGFI_PIDL
| SHGFI_SMALLICON
|
2574 SHGFI_SYSICONINDEX
|
2578 /* Is this item selected ? */
2579 if(pDIStruct
->itemState
& ODS_SELECTED
)
2581 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2582 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2583 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2587 SetTextColor(pDIStruct
->hDC
,crText
);
2588 SetBkColor(pDIStruct
->hDC
,crWin
);
2589 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2592 /* Do not indent item if drawing in the edit of the combo */
2593 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2596 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2599 sizeof (SHFILEINFOA
),
2600 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2601 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2606 iIndentation
= tmpFolder
->m_iIndent
;
2608 /* Draw text and icon */
2610 /* Initialise the icon display area */
2611 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2612 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2613 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2614 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2616 /* Initialise the text display area */
2617 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2618 rectText
.left
= rectIcon
.right
;
2620 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2621 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2623 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2625 /* Draw the icon from the image list */
2626 ImageList_Draw(ilItemImage
,
2633 /* Draw the associated text */
2634 if(sfi
.szDisplayName
)
2635 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2641 /***********************************************************************
2642 * FILEDLG95_LOOKIN_OnCommand
2644 * LookIn combo box WM_COMMAND message handler
2645 * If the function succeeds, the return value is nonzero.
2647 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2649 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2651 TRACE("%p\n", fodInfos
);
2657 LPSFOLDER tmpFolder
;
2660 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2662 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2667 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2668 tmpFolder
->pidlItem
,
2680 /***********************************************************************
2681 * FILEDLG95_LOOKIN_AddItem
2683 * Adds an absolute pidl item to the lookin combo box
2684 * returns the index of the inserted item
2686 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2688 LPITEMIDLIST pidlNext
;
2691 LookInInfos
*liInfos
;
2693 TRACE("%08x\n", iInsertId
);
2698 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2701 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2702 tmpFolder
->m_iIndent
= 0;
2704 /* Calculate the indentation of the item in the lookin*/
2706 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2708 tmpFolder
->m_iIndent
++;
2711 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2713 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2714 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2716 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2717 SHGetFileInfoA((LPSTR
)pidl
,
2721 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2722 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2724 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2726 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2730 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2732 /* Add the item at the end of the list */
2735 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2737 /* Insert the item at the iInsertId position*/
2740 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2743 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2747 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2748 MemFree( tmpFolder
);
2753 /***********************************************************************
2754 * FILEDLG95_LOOKIN_InsertItemAfterParent
2756 * Insert an item below its parent
2758 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2761 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2766 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2770 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2773 /* Free pidlParent memory */
2774 COMDLG32_SHFree((LPVOID
)pidlParent
);
2776 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2779 /***********************************************************************
2780 * FILEDLG95_LOOKIN_SelectItem
2782 * Adds an absolute pidl item to the lookin combo box
2783 * returns the index of the inserted item
2785 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2788 LookInInfos
*liInfos
;
2792 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2794 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2798 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2799 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2804 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2805 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2809 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2811 if(iRemovedItem
< iItemPos
)
2816 CBSetCurSel(hwnd
,iItemPos
);
2817 liInfos
->uSelectedItem
= iItemPos
;
2823 /***********************************************************************
2824 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2826 * Remove the item with an expansion level over iExpansionLevel
2828 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2832 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2836 if(liInfos
->iMaxIndentation
<= 2)
2839 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2841 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2842 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2844 CBDeleteString(hwnd
,iItemPos
);
2845 liInfos
->iMaxIndentation
--;
2853 /***********************************************************************
2854 * FILEDLG95_LOOKIN_SearchItem
2856 * Search for pidl in the lookin combo box
2857 * returns the index of the found item
2859 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2862 int iCount
= CBGetCount(hwnd
);
2864 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2866 if (iCount
!= CB_ERR
)
2870 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2872 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2874 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2882 /***********************************************************************
2883 * FILEDLG95_LOOKIN_Clean
2885 * Clean the memory used by the lookin combo box
2887 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2889 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2891 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2895 /* Delete each string of the combo and their associated data */
2896 if (iCount
!= CB_ERR
)
2898 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2900 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2901 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2903 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2907 /* LookInInfos structure */
2908 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2911 /***********************************************************************
2912 * FILEDLG95_FILENAME_FillFromSelection
2914 * fills the edit box from the cached DataObject
2916 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2918 FileOpenDlgInfos
*fodInfos
;
2920 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2921 char lpstrTemp
[MAX_PATH
];
2922 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2925 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2927 /* Count how many files we have */
2928 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2930 /* calculate the string length, count files */
2931 if (nFileSelected
>= 1)
2933 nLength
+= 3; /* first and last quotes, trailing \0 */
2934 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2936 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2940 /* get the total length of the selected file names */
2941 lpstrTemp
[0] = '\0';
2942 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2944 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2946 nLength
+= strlen( lpstrTemp
) + 3;
2949 COMDLG32_SHFree( pidl
);
2954 /* allocate the buffer */
2955 if (nFiles
<= 1) nLength
= MAX_PATH
;
2956 lpstrAllFile
= (LPSTR
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2957 lpstrAllFile
[0] = '\0';
2959 /* Generate the string for the edit control */
2962 lpstrCurrFile
= lpstrAllFile
;
2963 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2965 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2969 /* get the file name */
2970 lpstrTemp
[0] = '\0';
2971 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2973 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2977 *lpstrCurrFile
++ = '\"';
2978 strcpy( lpstrCurrFile
, lpstrTemp
);
2979 lpstrCurrFile
+= strlen( lpstrTemp
);
2980 strcpy( lpstrCurrFile
, "\" " );
2985 strcpy( lpstrAllFile
, lpstrTemp
);
2988 COMDLG32_SHFree( (LPVOID
) pidl
);
2991 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
2993 /* Select the file name like Windows does */
2994 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)-1);
2996 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3000 /* copied from shell32 to avoid linking to it */
3001 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3006 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
3007 COMDLG32_SHFree(src
->u
.pOleStr
);
3011 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
3015 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
3019 FIXME("unknown type!\n");
3022 *(LPSTR
)dest
= '\0';
3029 /***********************************************************************
3030 * FILEDLG95_FILENAME_GetFileNames
3032 * Copies the filenames to a delimited string list.
3033 * The delimiter is specified by the parameter 'separator',
3034 * usually either a space or a nul
3036 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3038 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3039 UINT nStrCharCount
= 0; /* index in src buffer */
3040 UINT nFileIndex
= 0; /* index in dest buffer */
3041 UINT nFileCount
= 0; /* number of files */
3042 UINT nStrLen
= 0; /* length of string in edit control */
3043 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3047 /* get the filenames from the edit control */
3048 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3049 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3050 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3052 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3054 /* we might get single filename without any '"',
3055 * so we need nStrLen + terminating \0 + end-of-list \0 */
3056 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3059 /* build delimited file list from filenames */
3060 while ( nStrCharCount
<= nStrLen
)
3062 if ( lpstrEdit
[nStrCharCount
]=='"' )
3065 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3067 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3071 (*lpstrFileList
)[nFileIndex
++] = separator
;
3078 /* single, unquoted string */
3079 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3081 strcpyW(*lpstrFileList
, lpstrEdit
);
3082 nFileIndex
= strlenW(lpstrEdit
) + 1;
3083 (*sizeUsed
) = nFileIndex
;
3088 (*lpstrFileList
)[nFileIndex
] = '\0';
3095 #define SETDefFormatEtc(fe,cf,med) \
3097 (fe).cfFormat = cf;\
3098 (fe).dwAspect = DVASPECT_CONTENT; \
3105 * DATAOBJECT Helper functions
3108 /***********************************************************************
3109 * COMCTL32_ReleaseStgMedium
3111 * like ReleaseStgMedium from ole32
3113 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3115 if(medium
.pUnkForRelease
)
3117 IUnknown_Release(medium
.pUnkForRelease
);
3121 GlobalUnlock(medium
.u
.hGlobal
);
3122 GlobalFree(medium
.u
.hGlobal
);
3126 /***********************************************************************
3127 * GetPidlFromDataObject
3129 * Return pidl(s) by number from the cached DataObject
3131 * nPidlIndex=0 gets the fully qualified root path
3133 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3137 FORMATETC formatetc
;
3138 LPITEMIDLIST pidl
= NULL
;
3140 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3142 /* Set the FORMATETC structure*/
3143 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3145 /* Get the pidls from IDataObject */
3146 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3148 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3149 if(nPidlIndex
<= cida
->cidl
)
3151 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3153 COMCTL32_ReleaseStgMedium(medium
);
3158 /***********************************************************************
3161 * Return the number of selected items in the DataObject.
3164 UINT
GetNumSelected( IDataObject
*doSelected
)
3168 FORMATETC formatetc
;
3170 TRACE("sv=%p\n", doSelected
);
3172 if (!doSelected
) return 0;
3174 /* Set the FORMATETC structure*/
3175 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3177 /* Get the pidls from IDataObject */
3178 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3180 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3181 retVal
= cida
->cidl
;
3182 COMCTL32_ReleaseStgMedium(medium
);
3192 /***********************************************************************
3195 * Get the pidl's display name (relative to folder) and
3196 * put it in lpstrFileName.
3198 * Return NOERROR on success,
3202 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
3207 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3212 SHGetDesktopFolder(&lpsf
);
3213 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3214 IShellFolder_Release(lpsf
);
3218 /* Get the display name of the pidl relative to the folder */
3219 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3221 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3226 /***********************************************************************
3227 * GetShellFolderFromPidl
3229 * pidlRel is the item pidl relative
3230 * Return the IShellFolder of the absolute pidl
3232 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3234 IShellFolder
*psf
= NULL
,*psfParent
;
3236 TRACE("%p\n", pidlAbs
);
3238 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3241 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3243 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3245 IShellFolder_Release(psfParent
);
3249 /* return the desktop */
3255 /***********************************************************************
3258 * Return the LPITEMIDLIST to the parent of the pidl in the list
3260 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3262 LPITEMIDLIST pidlParent
;
3264 TRACE("%p\n", pidl
);
3266 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3267 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3272 /***********************************************************************
3275 * returns the pidl of the file name relative to folder
3276 * NULL if an error occurred
3278 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3280 LPITEMIDLIST pidl
= NULL
;
3283 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3285 if(!lpcstrFileName
) return NULL
;
3286 if(!*lpcstrFileName
) return NULL
;
3290 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3291 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3292 IShellFolder_Release(lpsf
);
3297 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3304 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3306 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3309 TRACE("%p, %p\n", psf
, pidl
);
3311 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3313 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3314 /* see documentation shell 4.1*/
3315 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3318 /***********************************************************************
3319 * BrowseSelectedFolder
3321 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3323 BOOL bBrowseSelFolder
= FALSE
;
3324 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3328 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3330 LPITEMIDLIST pidlSelection
;
3332 /* get the file selected */
3333 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3334 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3336 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3337 pidlSelection
, SBSP_RELATIVE
) ) )
3339 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3340 ' ','n','o','t',' ','e','x','i','s','t',0};
3341 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3344 bBrowseSelFolder
= TRUE
;
3346 COMDLG32_SHFree( pidlSelection
);
3349 return bBrowseSelFolder
;
3353 * Memory allocation methods */
3354 static void *MemAlloc(UINT size
)
3356 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3359 static void MemFree(void *mem
)
3361 HeapFree(GetProcessHeap(),0,mem
);
3365 * Old-style (win3.1) dialogs */
3367 /***********************************************************************
3368 * FD32_GetTemplate [internal]
3370 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3371 * by a 32 bits application
3374 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3376 LPOPENFILENAMEW ofnW
= &lfs
->ofnW
;
3377 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3380 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3382 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3384 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3388 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3392 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3393 priv
->ofnA
->lpTemplateName
,
3396 hResInfo
= FindResourceW(ofnW
->hInstance
,
3397 ofnW
->lpTemplateName
,
3401 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3404 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3406 !(lfs
->template = LockResource(hDlgTmpl
)))
3408 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3411 } else { /* get it from internal Wine resource */
3413 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3414 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3416 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3419 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3420 !(lfs
->template = LockResource( hDlgTmpl
)))
3422 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3430 /************************************************************************
3431 * FD32_Init [internal]
3432 * called from the common 16/32 code to initialize 32 bit data
3434 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3436 BOOL IsUnicode
= (BOOL
) data
;
3439 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3440 lfs
->private1632
= priv
;
3441 if (NULL
== lfs
->private1632
) return FALSE
;
3444 lfs
->ofnW
= *((LPOPENFILENAMEW
) lParam
);
3445 if (lfs
->ofnW
.Flags
& OFN_ENABLEHOOK
)
3446 if (lfs
->ofnW
.lpfnHook
)
3451 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3452 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3453 if (priv
->ofnA
->lpfnHook
)
3455 FD31_MapOfnStructA(priv
->ofnA
, &lfs
->ofnW
, lfs
->open
);
3458 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3463 /***********************************************************************
3464 * FD32_CallWindowProc [internal]
3466 * called from the common 16/32 code to call the appropriate hook
3468 BOOL CALLBACK
FD32_CallWindowProc(PFD31_DATA lfs
, UINT wMsg
, WPARAM wParam
,
3471 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3475 return (BOOL
) CallWindowProcA(
3476 (WNDPROC
)priv
->ofnA
->lpfnHook
, lfs
->hwnd
,
3477 wMsg
, wParam
, lParam
);
3480 return (BOOL
) CallWindowProcW(
3481 (WNDPROC
)lfs
->ofnW
.lpfnHook
, lfs
->hwnd
,
3482 wMsg
, wParam
, lParam
);
3485 /***********************************************************************
3486 * FD32_UpdateResult [internal]
3487 * update the real client structures if any
3489 static void CALLBACK
FD32_UpdateResult(PFD31_DATA lfs
)
3491 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3492 LPOPENFILENAMEW ofnW
= &lfs
->ofnW
;
3496 if (ofnW
->nMaxFile
&&
3497 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3498 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3499 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3500 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3501 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
3505 /***********************************************************************
3506 * FD32_UpdateFileTitle [internal]
3507 * update the real client structures if any
3509 static void CALLBACK
FD32_UpdateFileTitle(PFD31_DATA lfs
)
3511 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3512 LPOPENFILENAMEW ofnW
= &lfs
->ofnW
;
3516 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3517 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3518 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3523 /***********************************************************************
3524 * FD32_SendLbGetCurSel [internal]
3525 * retrieve selected listbox item
3527 static LRESULT CALLBACK
FD32_SendLbGetCurSel(PFD31_DATA lfs
)
3529 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3533 /************************************************************************
3534 * FD32_Destroy [internal]
3535 * called from the common 16/32 code to cleanup 32 bit data
3537 static void CALLBACK
FD32_Destroy(PFD31_DATA lfs
)
3539 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3541 /* if ofnW has been allocated, have to free everything in it */
3542 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3543 FD31_FreeOfnW(&lfs
->ofnW
);
3546 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3548 callbacks
->Init
= FD32_Init
;
3549 callbacks
->CWP
= FD32_CallWindowProc
;
3550 callbacks
->UpdateResult
= FD32_UpdateResult
;
3551 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3552 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3553 callbacks
->Destroy
= FD32_Destroy
;
3556 /***********************************************************************
3557 * FD32_WMMeasureItem [internal]
3559 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3561 LPMEASUREITEMSTRUCT lpmeasure
;
3563 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3564 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3569 /***********************************************************************
3570 * FileOpenDlgProc [internal]
3571 * Used for open and save, in fact.
3573 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3574 WPARAM wParam
, LPARAM lParam
)
3576 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3578 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg
, wParam
, lParam
);
3579 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3582 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3584 return lRet
; /* else continue message processing */
3589 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3591 case WM_MEASUREITEM
:
3592 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3595 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3598 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3601 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3602 switch (HIWORD(lParam
))
3605 SetTextColor((HDC16
)wParam
, 0x00000000);
3607 case CTLCOLOR_STATIC
:
3608 SetTextColor((HDC16
)wParam
, 0x00000000);
3618 /***********************************************************************
3619 * GetFileName31A [internal]
3621 * Creates a win31 style dialog box for the user to select a file to open/save.
3623 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* addess of structure with data*/
3624 UINT dlgType
/* type dialogue : open/save */
3630 FD31_CALLBACKS callbacks
;
3632 if (!lpofn
|| !FD31_Init()) return FALSE
;
3634 TRACE("ofn flags %08lx\n", lpofn
->Flags
);
3635 FD32_SetupCallbacks(&callbacks
);
3636 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3639 hInst
= (HINSTANCE
)GetWindowLongPtrA( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3640 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3641 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3642 FD31_DestroyPrivate(lfs
);
3645 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3649 /***********************************************************************
3650 * GetFileName31W [internal]
3652 * Creates a win31 style dialog box for the user to select a file to open/save
3654 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* addess of structure with data*/
3655 UINT dlgType
/* type dialogue : open/save */
3661 FD31_CALLBACKS callbacks
;
3663 if (!lpofn
|| !FD31_Init()) return FALSE
;
3665 FD32_SetupCallbacks(&callbacks
);
3666 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3669 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3670 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3671 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3672 FD31_DestroyPrivate(lfs
);
3675 TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn
->lpstrFile
));
3679 /* ------------------ APIs ---------------------- */
3681 /***********************************************************************
3682 * GetOpenFileNameA (COMDLG32.@)
3684 * Creates a dialog box for the user to select a file to open.
3687 * TRUE on success: user enters a valid file
3688 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3691 BOOL WINAPI
GetOpenFileNameA(
3692 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3694 BOOL win16look
= FALSE
;
3696 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3697 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3700 return GetFileName31A(ofn
, OPEN_DIALOG
);
3702 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3705 /***********************************************************************
3706 * GetOpenFileNameW (COMDLG32.@)
3708 * Creates a dialog box for the user to select a file to open.
3711 * TRUE on success: user enters a valid file
3712 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3715 BOOL WINAPI
GetOpenFileNameW(
3716 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3718 BOOL win16look
= FALSE
;
3720 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3721 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3724 return GetFileName31W(ofn
, OPEN_DIALOG
);
3726 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3730 /***********************************************************************
3731 * GetSaveFileNameA (COMDLG32.@)
3733 * Creates a dialog box for the user to select a file to save.
3736 * TRUE on success: user enters a valid file
3737 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3740 BOOL WINAPI
GetSaveFileNameA(
3741 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3743 BOOL win16look
= FALSE
;
3745 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3746 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3749 return GetFileName31A(ofn
, SAVE_DIALOG
);
3751 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3754 /***********************************************************************
3755 * GetSaveFileNameW (COMDLG32.@)
3757 * Creates a dialog box for the user to select a file to save.
3760 * TRUE on success: user enters a valid file
3761 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3764 BOOL WINAPI
GetSaveFileNameW(
3765 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3767 BOOL win16look
= FALSE
;
3769 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3770 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3773 return GetFileName31W(ofn
, SAVE_DIALOG
);
3775 return GetFileDialog95W(ofn
, SAVE_DIALOG
);