2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
79 #include "filedlgbrowser.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex
; /* Index of picture in image list */
99 int m_iIndent
; /* Indentation index */
100 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
102 } SFOLDER
,*LPSFOLDER
;
104 typedef struct tagLookInInfo
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE
, *PFD32_PRIVATE
;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
122 #define XTEXTOFFSET 3
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
184 /* Internal functions used by the dialog */
185 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
186 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
187 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
188 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
189 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
190 static void FILEDLG95_Clean(HWND hwnd
);
192 /* Functions used by the shell navigation */
193 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
197 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
199 /* Functions used by the filetype combo box */
200 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
201 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
205 /* Functions used by the Look In combo box */
206 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
207 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
208 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
216 /* Miscellaneous tool functions */
217 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
218 HRESULT
GetFileName(HWND hwnd
, LPITEMIDLIST pidl
, LPSTR lpstrFileName
);
219 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
220 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
221 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size
);
225 static void MemFree(void *mem
);
227 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
);
228 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
229 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
230 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
231 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
232 static BOOL
BrowseSelectedFolder(HWND hwnd
);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
252 /* test for missing functionality */
253 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
259 /* Create the dialog from a template */
261 if(!(hRes
= FindResourceA(COMDLG32_hInstance
,MAKEINTRESOURCEA(NEWFILEOPENORD
),(LPSTR
)RT_DIALOG
)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
266 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
267 !(template = LockResource( hDlgTmpl
)))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
273 /* old style hook messages */
274 if (IsHooked(fodInfos
))
276 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
277 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
278 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
279 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
282 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
283 (LPDLGTEMPLATEA
) template,
284 fodInfos
->ofnInfos
->hwndOwner
,
288 /* Unable to create the dialog */
295 /***********************************************************************
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
306 FileOpenDlgInfos fodInfos
;
307 LPSTR lpstrSavDir
= NULL
;
309 LPWSTR defext
= NULL
;
310 LPWSTR filter
= NULL
;
311 LPWSTR customfilter
= NULL
;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
316 /* Pass in the original ofn */
317 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
319 /* save current directory */
320 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
322 lpstrSavDir
= MemAlloc(MAX_PATH
);
323 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
326 fodInfos
.unicode
= FALSE
;
328 /* convert all the input strings to unicode */
329 if(ofn
->lpstrInitialDir
)
331 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
332 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
333 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
336 fodInfos
.initdir
= NULL
;
340 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
341 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
344 fodInfos
.filename
= NULL
;
348 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
349 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
350 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
352 fodInfos
.defext
= defext
;
356 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
357 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
358 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
360 fodInfos
.title
= title
;
362 if (ofn
->lpstrFilter
)
367 /* filter is a list... title\0ext\0......\0\0 */
368 s
= ofn
->lpstrFilter
;
369 while (*s
) s
= s
+strlen(s
)+1;
371 n
= s
- ofn
->lpstrFilter
;
372 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
373 filter
= MemAlloc(len
*sizeof(WCHAR
));
374 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
376 fodInfos
.filter
= filter
;
378 /* convert lpstrCustomFilter */
379 if (ofn
->lpstrCustomFilter
)
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s
= ofn
->lpstrCustomFilter
;
386 if (*s
) s
= s
+strlen(s
)+1;
387 if (*s
) s
= s
+strlen(s
)+1;
388 n
= s
- ofn
->lpstrCustomFilter
;
389 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
390 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
391 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
393 fodInfos
.customfilter
= customfilter
;
395 /* Initialize the dialog property */
396 fodInfos
.DlgInfos
.dwDlgProp
= 0;
397 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
402 ret
= GetFileName95(&fodInfos
);
405 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
406 ret
= GetFileName95(&fodInfos
);
414 SetCurrentDirectoryA(lpstrSavDir
);
415 MemFree(lpstrSavDir
);
425 MemFree(customfilter
);
427 MemFree(fodInfos
.initdir
);
429 if(fodInfos
.filename
)
430 MemFree(fodInfos
.filename
);
432 TRACE("selected file: %s\n",ofn
->lpstrFile
);
437 /***********************************************************************
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
447 FileOpenDlgInfos fodInfos
;
448 LPWSTR lpstrSavDir
= NULL
;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
453 /* Pass in the original ofn */
454 fodInfos
.ofnInfos
= ofn
;
456 fodInfos
.title
= ofn
->lpstrTitle
;
457 fodInfos
.defext
= ofn
->lpstrDefExt
;
458 fodInfos
.filter
= ofn
->lpstrFilter
;
459 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
461 /* convert string arguments, save others */
464 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
465 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
468 fodInfos
.filename
= NULL
;
470 if(ofn
->lpstrInitialDir
)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len
= strlenW(ofn
->lpstrInitialDir
)+1;
474 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
475 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
478 fodInfos
.initdir
= NULL
;
480 /* save current directory */
481 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
483 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
484 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
487 fodInfos
.unicode
= TRUE
;
492 ret
= GetFileName95(&fodInfos
);
495 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
496 ret
= GetFileName95(&fodInfos
);
504 SetCurrentDirectoryW(lpstrSavDir
);
505 MemFree(lpstrSavDir
);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos
.filename
);
510 MemFree(fodInfos
.initdir
);
514 /***********************************************************************
515 * ArrangeCtrlPositions [internal]
517 * NOTE: Do not change anything here without a lot of testing.
519 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
521 HWND hwndChild
, hwndStc32
;
522 RECT rectParent
, rectChild
, rectStc32
;
523 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
525 /* Take into account if open as read only checkbox and help button
530 RECT rectHelp
, rectCancel
;
531 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
532 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
533 /* subtract the height of the help button plus the space between
534 * the help button and the cancel button to the height of the dialog
536 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
540 There are two possibilities to add components to the default file dialog box.
542 By default, all the new components are added below the standard dialog box (the else case).
544 However, if there is a static text component with the stc32 id, a special case happens.
545 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
546 in the window and the cx and cy indicate how to size the window.
547 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
548 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
552 GetClientRect(hwndParentDlg
, &rectParent
);
554 /* when arranging controls we have to use fixed parent size */
555 rectParent
.bottom
-= help_fixup
;
557 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
560 GetWindowRect(hwndStc32
, &rectStc32
);
561 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
563 /* set the size of the stc32 control according to the size of
564 * client area of the parent dialog
566 SetWindowPos(hwndStc32
, 0,
568 rectParent
.right
, rectParent
.bottom
,
569 SWP_NOMOVE
| SWP_NOZORDER
);
572 SetRectEmpty(&rectStc32
);
574 /* this part moves controls of the child dialog */
575 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
578 if (hwndChild
!= hwndStc32
)
580 GetWindowRect(hwndChild
, &rectChild
);
581 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
583 /* move only if stc32 exist */
584 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
586 LONG old_left
= rectChild
.left
;
588 /* move to the right of visible controls of the parent dialog */
589 rectChild
.left
+= rectParent
.right
;
590 rectChild
.left
-= rectStc32
.right
;
592 child_width_fixup
= rectChild
.left
- old_left
;
594 /* move even if stc32 doesn't exist */
595 if (rectChild
.top
>= rectStc32
.bottom
)
597 LONG old_top
= rectChild
.top
;
599 /* move below visible controls of the parent dialog */
600 rectChild
.top
+= rectParent
.bottom
;
601 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
603 child_height_fixup
= rectChild
.top
- old_top
;
606 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
607 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
609 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
612 /* this part moves controls of the parent dialog */
613 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
616 if (hwndChild
!= hwndChildDlg
)
618 GetWindowRect(hwndChild
, &rectChild
);
619 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
621 /* left,top of stc32 marks the position of controls
622 * from the parent dialog
624 rectChild
.left
+= rectStc32
.left
;
625 rectChild
.top
+= rectStc32
.top
;
627 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
628 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
630 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
633 /* calculate the size of the resulting dialog */
635 /* here we have to use original parent size */
636 GetClientRect(hwndParentDlg
, &rectParent
);
637 GetClientRect(hwndChildDlg
, &rectChild
);
641 rectChild
.right
+= child_width_fixup
;
642 rectChild
.bottom
+= child_height_fixup
;
644 if (rectParent
.right
> rectChild
.right
)
646 rectParent
.right
+= rectChild
.right
;
647 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
651 rectParent
.right
= rectChild
.right
;
654 if (rectParent
.bottom
> rectChild
.bottom
)
656 rectParent
.bottom
+= rectChild
.bottom
;
657 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
661 /* child dialog is higher, unconditionally set new dialog
662 * height to its size (help_fixup will be subtracted below)
664 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
669 rectParent
.bottom
+= rectChild
.bottom
;
672 /* finally use fixed parent size */
673 rectParent
.bottom
-= help_fixup
;
675 /* save the size of the parent's client area */
676 rectChild
.right
= rectParent
.right
;
677 rectChild
.bottom
= rectParent
.bottom
;
679 /* set the size of the parent dialog */
680 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
681 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
682 SetWindowPos(hwndParentDlg
, 0,
684 rectParent
.right
- rectParent
.left
,
685 rectParent
.bottom
- rectParent
.top
,
686 SWP_NOMOVE
| SWP_NOZORDER
);
688 /* set the size of the child dialog */
689 SetWindowPos(hwndChildDlg
, HWND_BOTTOM
,
690 0, 0, rectChild
.right
, rectChild
.bottom
, SWP_NOACTIVATE
);
693 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
702 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
712 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
713 * structure's hInstance parameter is not a HINSTANCE, but
714 * instead a pointer to a template resource to use.
716 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
719 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
722 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
724 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
730 hinst
= fodInfos
->ofnInfos
->hInstance
;
731 if(fodInfos
->unicode
)
733 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
734 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
738 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
739 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
743 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
746 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
747 !(template = LockResource( hDlgTmpl
)))
749 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
753 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, template, hwnd
,
754 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
755 (LPARAM
)fodInfos
->ofnInfos
);
758 ShowWindow(hChildDlg
,SW_SHOW
);
762 else if( IsHooked(fodInfos
))
767 WORD menu
,class,title
;
769 GetClientRect(hwnd
,&rectHwnd
);
770 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
771 temp
.tmplate
.dwExtendedStyle
= 0;
772 temp
.tmplate
.cdit
= 0;
777 temp
.menu
= temp
.class = temp
.title
= 0;
779 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
780 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
787 /***********************************************************************
788 * SendCustomDlgNotificationMessage
790 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
793 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
795 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
797 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
799 if(!fodInfos
) return 0;
801 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
804 TRACE("CALL NOTIFY for %x\n", uCode
);
805 if(fodInfos
->unicode
)
808 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
809 ofnNotify
.hdr
.idFrom
=0;
810 ofnNotify
.hdr
.code
= uCode
;
811 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
812 ofnNotify
.pszFile
= NULL
;
813 ret
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
818 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
819 ofnNotify
.hdr
.idFrom
=0;
820 ofnNotify
.hdr
.code
= uCode
;
821 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
822 ofnNotify
.pszFile
= NULL
;
823 ret
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
825 TRACE("RET NOTIFY\n");
831 HRESULT
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID buffer
)
833 UINT sizeUsed
= 0, n
, total
;
834 LPWSTR lpstrFileList
= NULL
;
835 WCHAR lpstrCurrentDir
[MAX_PATH
];
836 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
838 TRACE("CDM_GETFILEPATH:\n");
840 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
843 /* get path and filenames */
844 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
845 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
847 TRACE("path >%s< filespec >%s< %d files\n",
848 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
850 if( fodInfos
->unicode
)
852 LPWSTR bufW
= buffer
;
853 total
= strlenW(lpstrCurrentDir
) + 1 + sizeUsed
;
855 /* Prepend the current path */
856 n
= strlenW(lpstrCurrentDir
) + 1;
857 memcpy( bufW
, lpstrCurrentDir
, min(n
,size
) * sizeof(WCHAR
));
860 /* 'n' includes trailing \0 */
862 memcpy( &bufW
[n
], lpstrFileList
, (size
-n
)*sizeof(WCHAR
) );
864 TRACE("returned -> %s\n",debugstr_wn(bufW
, total
));
869 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
870 NULL
, 0, NULL
, NULL
);
871 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
872 NULL
, 0, NULL
, NULL
);
874 /* Prepend the current path */
875 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
876 bufA
, size
, NULL
, NULL
);
880 /* 'n' includes trailing \0 */
882 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
883 &bufA
[n
], size
-n
, NULL
, NULL
);
886 TRACE("returned -> %s\n",debugstr_an(bufA
, total
));
888 MemFree(lpstrFileList
);
893 HRESULT
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPVOID buffer
)
896 LPWSTR lpstrFileList
= NULL
;
897 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
899 TRACE("CDM_GETSPEC:\n");
901 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, ' ');
902 if( fodInfos
->unicode
)
904 LPWSTR bufW
= buffer
;
905 memcpy( bufW
, lpstrFileList
, sizeof(WCHAR
)*sizeUsed
);
910 sizeUsed
= WideCharToMultiByte( CP_ACP
, 0, lpstrFileList
, sizeUsed
,
911 NULL
, 0, NULL
, NULL
);
912 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
913 bufA
, size
, NULL
, NULL
);
915 MemFree(lpstrFileList
);
920 /***********************************************************************
921 * FILEDLG95_HandleCustomDialogMessages
923 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
925 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
927 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
928 if(!fodInfos
) return -1;
932 case CDM_GETFILEPATH
:
933 return FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
935 case CDM_GETFOLDERPATH
:
936 TRACE("CDM_GETFOLDERPATH:\n");
937 if( fodInfos
->unicode
)
939 WCHAR lpstrPath
[MAX_PATH
], *bufW
= (LPWSTR
)lParam
;
940 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
942 lstrcpynW(bufW
,lpstrPath
,(int)wParam
);
943 return strlenW(lpstrPath
);
947 char lpstrPath
[MAX_PATH
], *bufA
= (LPSTR
)lParam
;
948 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
950 lstrcpynA(bufA
,lpstrPath
,(int)wParam
);
951 return strlen(lpstrPath
);
955 return FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
957 case CDM_SETCONTROLTEXT
:
958 TRACE("CDM_SETCONTROLTEXT:\n");
961 if( fodInfos
->unicode
)
962 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
964 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
968 case CDM_HIDECONTROL
:
970 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
976 /***********************************************************************
979 * File open dialog procedure
981 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
984 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
991 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
993 /* Adds the FileOpenDlgInfos in the property list of the dialog
994 so it will be easily accessible through a GetPropA(...) */
995 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
997 fodInfos
->DlgInfos
.hwndCustomDlg
=
998 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1000 FILEDLG95_InitControls(hwnd
);
1002 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1003 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1004 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1006 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1008 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1009 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1010 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1014 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1017 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1020 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1026 case WM_GETISHELLBROWSER
:
1027 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1030 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1035 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1038 /* set up the button tooltips strings */
1039 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1041 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1042 switch(lpnmh
->idFrom
)
1044 /* Up folder button */
1045 case FCIDM_TB_UPFOLDER
:
1046 stringId
= IDS_UPFOLDER
;
1048 /* New folder button */
1049 case FCIDM_TB_NEWFOLDER
:
1050 stringId
= IDS_NEWFOLDER
;
1052 /* List option button */
1053 case FCIDM_TB_SMALLICON
:
1054 stringId
= IDS_LISTVIEW
;
1056 /* Details option button */
1057 case FCIDM_TB_REPORTVIEW
:
1058 stringId
= IDS_REPORTVIEW
;
1060 /* Desktop button */
1061 case FCIDM_TB_DESKTOP
:
1062 stringId
= IDS_TODESKTOP
;
1067 lpdi
->hinst
= COMDLG32_hInstance
;
1068 lpdi
->lpszText
= (LPSTR
) stringId
;
1073 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1074 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1079 /***********************************************************************
1080 * FILEDLG95_InitControls
1082 * WM_INITDIALOG message handler (before hook notification)
1084 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1086 int win2000plus
= 0;
1088 int handledPath
= FALSE
;
1089 OSVERSIONINFOA osVi
;
1090 static const WCHAR szwSlash
[] = { '\\', 0 };
1091 static const WCHAR szwStar
[] = { '*',0 };
1095 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1096 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1097 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1098 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1099 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1100 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1101 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1102 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1103 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1108 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1110 tba
[0].hInst
= HINST_COMMCTRL
;
1111 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1112 tba
[1].hInst
= COMDLG32_hInstance
;
1115 TRACE("%p\n", fodInfos
);
1117 /* Get windows version emulating */
1118 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1119 GetVersionExA(&osVi
);
1120 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1121 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1122 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1123 win2000plus
= (osVi
.dwMajorVersion
> 4);
1124 if (win2000plus
) win98plus
= TRUE
;
1126 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1128 /* Get the hwnd of the controls */
1129 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1130 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1131 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1133 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1134 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1136 /* construct the toolbar */
1137 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1138 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1140 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1141 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1142 rectTB
.left
= rectlook
.right
;
1143 rectTB
.top
= rectlook
.top
-1;
1145 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1146 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1147 rectTB
.left
, rectTB
.top
,
1148 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1149 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1151 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1153 /* FIXME: use TB_LOADIMAGES when implemented */
1154 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1155 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1156 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1158 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1159 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1161 /* Set the window text with the text specified in the OPENFILENAME structure */
1164 SetWindowTextW(hwnd
,fodInfos
->title
);
1166 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1169 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1170 SetWindowTextW(hwnd
, buf
);
1173 /* Initialise the file name edit control */
1174 handledPath
= FALSE
;
1175 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1177 if(fodInfos
->filename
)
1179 /* 1. If win2000 or higher and filename contains a path, use it
1180 in preference over the lpstrInitialDir */
1181 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1182 WCHAR tmpBuf
[MAX_PATH
];
1186 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1189 /* nameBit is always shorter than the original filename */
1190 strcpyW(fodInfos
->filename
,nameBit
);
1193 if (fodInfos
->initdir
== NULL
)
1194 MemFree(fodInfos
->initdir
);
1195 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1196 strcpyW(fodInfos
->initdir
, tmpBuf
);
1198 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1199 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1201 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1204 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1208 /* 2. (All platforms) If initdir is not null, then use it */
1209 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1210 (*fodInfos
->initdir
!=0x00))
1212 /* Work out the proper path as supplied one might be relative */
1213 /* (Here because supplying '.' as dir browses to My Computer) */
1214 if (handledPath
==FALSE
) {
1215 WCHAR tmpBuf
[MAX_PATH
];
1216 WCHAR tmpBuf2
[MAX_PATH
];
1220 strcpyW(tmpBuf
, fodInfos
->initdir
);
1221 if( PathFileExistsW(tmpBuf
) ) {
1222 /* initdir does not have to be a directory. If a file is
1223 * specified, the dir part is taken */
1224 if( PathIsDirectoryW(tmpBuf
)) {
1225 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1226 strcatW(tmpBuf
, szwSlash
);
1228 strcatW(tmpBuf
, szwStar
);
1230 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1233 if (fodInfos
->initdir
)
1234 MemFree(fodInfos
->initdir
);
1235 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1236 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1238 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1241 else if (fodInfos
->initdir
)
1243 MemFree(fodInfos
->initdir
);
1244 fodInfos
->initdir
= NULL
;
1245 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1250 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1251 (*fodInfos
->initdir
==0x00)))
1253 /* 3. All except w2k+: if filename contains a path use it */
1254 if (!win2000plus
&& fodInfos
->filename
&&
1255 *fodInfos
->filename
&&
1256 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1257 WCHAR tmpBuf
[MAX_PATH
];
1261 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1266 /* nameBit is always shorter than the original filename */
1267 strcpyW(fodInfos
->filename
, nameBit
);
1270 len
= strlenW(tmpBuf
);
1271 if(fodInfos
->initdir
)
1272 MemFree(fodInfos
->initdir
);
1273 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1274 strcpyW(fodInfos
->initdir
, tmpBuf
);
1277 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1278 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1280 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1283 /* 4. win98+ and win2000+ if any files of specified filter types in
1284 current directory, use it */
1285 if ( win98plus
&& handledPath
== FALSE
&&
1286 fodInfos
->filter
&& *fodInfos
->filter
) {
1288 BOOL searchMore
= TRUE
;
1289 LPCWSTR lpstrPos
= fodInfos
->filter
;
1290 WIN32_FIND_DATAW FindFileData
;
1295 /* filter is a list... title\0ext\0......\0\0 */
1297 /* Skip the title */
1298 if(! *lpstrPos
) break; /* end */
1299 lpstrPos
+= strlenW(lpstrPos
) + 1;
1301 /* See if any files exist in the current dir with this extension */
1302 if(! *lpstrPos
) break; /* end */
1304 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1306 if (hFind
== INVALID_HANDLE_VALUE
) {
1307 /* None found - continue search */
1308 lpstrPos
+= strlenW(lpstrPos
) + 1;
1313 if(fodInfos
->initdir
)
1314 MemFree(fodInfos
->initdir
);
1315 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1316 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1319 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1320 debugstr_w(lpstrPos
));
1326 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1328 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1329 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1330 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1332 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1334 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1337 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1338 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1340 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1343 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1346 } else if (handledPath
==FALSE
) {
1347 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1348 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1350 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1353 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1354 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1356 /* Must the open as read only check box be checked ?*/
1357 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1359 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1362 /* Must the open as read only check box be hidden? */
1363 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1365 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1366 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1369 /* Must the help button be hidden? */
1370 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1372 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1373 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1376 /* Resize the height, if open as read only checkbox ad help button
1377 are hidden and we are not using a custom template nor a customDialog
1379 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1380 (!(fodInfos
->ofnInfos
->Flags
&
1381 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))) &&
1382 (!fodInfos
->DlgInfos
.hwndCustomDlg
))
1384 RECT rectDlg
, rectHelp
, rectCancel
;
1385 GetWindowRect(hwnd
, &rectDlg
);
1386 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1387 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1388 /* subtract the height of the help button plus the space between
1389 the help button and the cancel button to the height of the dialog */
1390 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1391 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1392 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1394 /* change Open to Save */
1395 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1398 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1399 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1400 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1401 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1406 /***********************************************************************
1407 * FILEDLG95_FillControls
1409 * WM_INITDIALOG message handler (after hook notification)
1411 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1413 LPITEMIDLIST pidlItemId
= NULL
;
1415 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1417 TRACE("dir=%s file=%s\n",
1418 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1420 /* Get the initial directory pidl */
1422 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1424 WCHAR path
[MAX_PATH
];
1426 GetCurrentDirectoryW(MAX_PATH
,path
);
1427 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1430 /* Initialise shell objects */
1431 FILEDLG95_SHELL_Init(hwnd
);
1433 /* Initialize the Look In combo box */
1434 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1436 /* Initialize the filter combo box */
1437 FILEDLG95_FILETYPE_Init(hwnd
);
1439 /* Browse to the initial directory */
1440 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1442 /* Free pidlItem memory */
1443 COMDLG32_SHFree(pidlItemId
);
1447 /***********************************************************************
1450 * Regroups all the cleaning functions of the filedlg
1452 void FILEDLG95_Clean(HWND hwnd
)
1454 FILEDLG95_FILETYPE_Clean(hwnd
);
1455 FILEDLG95_LOOKIN_Clean(hwnd
);
1456 FILEDLG95_SHELL_Clean(hwnd
);
1458 /***********************************************************************
1459 * FILEDLG95_OnWMCommand
1461 * WM_COMMAND message handler
1463 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1465 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1466 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1467 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1473 FILEDLG95_OnOpen(hwnd
);
1477 FILEDLG95_Clean(hwnd
);
1478 EndDialog(hwnd
, FALSE
);
1480 /* Filetype combo box */
1482 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1484 /* LookIn combo box */
1486 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1489 /* --- toolbar --- */
1490 /* Up folder button */
1491 case FCIDM_TB_UPFOLDER
:
1492 FILEDLG95_SHELL_UpFolder(hwnd
);
1494 /* New folder button */
1495 case FCIDM_TB_NEWFOLDER
:
1496 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1498 /* List option button */
1499 case FCIDM_TB_SMALLICON
:
1500 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1502 /* Details option button */
1503 case FCIDM_TB_REPORTVIEW
:
1504 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1506 /* Details option button */
1507 case FCIDM_TB_DESKTOP
:
1508 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1515 /* Do not use the listview selection anymore */
1516 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1520 /***********************************************************************
1521 * FILEDLG95_OnWMGetIShellBrowser
1523 * WM_GETISHELLBROWSER message handler
1525 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1528 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1532 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1538 /***********************************************************************
1539 * FILEDLG95_SendFileOK
1541 * Sends the CDN_FILEOK notification if required
1544 * TRUE if the dialog should close
1545 * FALSE if the dialog should not be closed
1547 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1549 /* ask the hook if we can close */
1550 if(IsHooked(fodInfos
))
1553 /* First send CDN_FILEOK as MSDN doc says */
1554 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1555 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1557 TRACE("canceled\n");
1561 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1562 SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1563 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1564 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1566 TRACE("canceled\n");
1573 /***********************************************************************
1574 * FILEDLG95_OnOpenMultipleFiles
1576 * Handles the opening of multiple files.
1579 * check destination buffer size
1581 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1583 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1584 UINT nCount
, nSizePath
;
1585 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1589 if(fodInfos
->unicode
)
1591 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1592 ofn
->lpstrFile
[0] = '\0';
1596 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1597 ofn
->lpstrFile
[0] = '\0';
1600 SHGetPathFromIDListW( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1602 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1603 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1604 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1606 LPWSTR lpstrTemp
= lpstrFileList
;
1608 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1612 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1615 WCHAR lpstrNotFound
[100];
1616 WCHAR lpstrMsg
[100];
1618 static const WCHAR nl
[] = {'\n',0};
1620 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1621 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1623 strcpyW(tmp
, lpstrTemp
);
1625 strcatW(tmp
, lpstrNotFound
);
1627 strcatW(tmp
, lpstrMsg
);
1629 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1633 /* move to the next file in the list of files */
1634 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1635 COMDLG32_SHFree(pidl
);
1639 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1640 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1642 /* For "oldstyle" dialog the components have to
1643 be separated by blanks (not '\0'!) and short
1644 filenames have to be used! */
1645 FIXME("Components have to be separated by blanks\n");
1647 if(fodInfos
->unicode
)
1649 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1650 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1651 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1655 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1657 if (ofn
->lpstrFile
!= NULL
)
1659 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1660 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1661 if (ofn
->nMaxFile
> nSizePath
)
1663 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1664 ofn
->lpstrFile
+ nSizePath
,
1665 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1670 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1671 fodInfos
->ofnInfos
->nFileExtension
= 0;
1673 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1676 /* clean and exit */
1677 FILEDLG95_Clean(hwnd
);
1678 return EndDialog(hwnd
,TRUE
);
1681 /***********************************************************************
1684 * Ok button WM_COMMAND message handler
1686 * If the function succeeds, the return value is nonzero.
1688 #define ONOPEN_BROWSE 1
1689 #define ONOPEN_OPEN 2
1690 #define ONOPEN_SEARCH 3
1691 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1693 WCHAR strMsgTitle
[MAX_PATH
];
1694 WCHAR strMsgText
[MAX_PATH
];
1696 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1698 strMsgTitle
[0] = '\0';
1699 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1700 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1703 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1705 LPWSTR lpstrFileList
;
1706 UINT nFileCount
= 0;
1709 WCHAR lpstrPathAndFile
[MAX_PATH
];
1710 WCHAR lpstrTemp
[MAX_PATH
];
1711 LPSHELLFOLDER lpsf
= NULL
;
1713 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1715 TRACE("hwnd=%p\n", hwnd
);
1717 /* get the files from the edit control */
1718 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
, '\0');
1720 /* try if the user selected a folder in the shellview */
1723 BrowseSelectedFolder(hwnd
);
1729 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1733 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1736 Step 1: Build a complete path name from the current folder and
1737 the filename or path in the edit box.
1739 - the path in the edit box is a root path
1740 (with or without drive letter)
1741 - the edit box contains ".." (or a path with ".." in it)
1744 /* Get the current directory name */
1745 if (!SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1747 /* we are in a special folder, default to desktop */
1748 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, lpstrPathAndFile
)))
1751 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1754 PathAddBackslashW(lpstrPathAndFile
);
1756 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1758 /* if the user specifyed a fully qualified path use it */
1759 if(PathIsRelativeW(lpstrFileList
))
1761 strcatW(lpstrPathAndFile
, lpstrFileList
);
1765 /* does the path have a drive letter? */
1766 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1767 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1769 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1772 /* resolve "." and ".." */
1773 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1774 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1775 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1777 MemFree(lpstrFileList
);
1780 Step 2: here we have a cleaned up path
1782 We have to parse the path step by step to see if we have to browse
1783 to a folder if the path points to a directory or the last
1784 valid element is a directory.
1787 lpstrPathAndFile: cleaned up path
1790 nOpenAction
= ONOPEN_BROWSE
;
1792 /* don't apply any checks with OFN_NOVALIDATE */
1794 LPWSTR lpszTemp
, lpszTemp1
;
1795 LPITEMIDLIST pidl
= NULL
;
1796 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1798 /* check for invalid chars */
1799 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1801 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1806 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1808 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1811 LPSHELLFOLDER lpsfChild
;
1812 WCHAR lpwstrTemp
[MAX_PATH
];
1813 DWORD dwEaten
, dwAttributes
;
1816 strcpyW(lpwstrTemp
, lpszTemp
);
1817 p
= PathFindNextComponentW(lpwstrTemp
);
1819 if (!p
) break; /* end of path */
1822 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1826 static const WCHAR wszWild
[] = { '*', '?', 0 };
1827 /* if the last element is a wildcard do a search */
1828 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1830 nOpenAction
= ONOPEN_SEARCH
;
1834 lpszTemp1
= lpszTemp
;
1836 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1838 /* append a backslash to drive letters */
1839 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
1840 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
1841 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
1843 PathAddBackslashW(lpwstrTemp
);
1846 dwAttributes
= SFGAO_FOLDER
;
1847 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1849 /* the path component is valid, we have a pidl of the next path component */
1850 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1851 if(dwAttributes
& SFGAO_FOLDER
)
1853 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1855 ERR("bind to failed\n"); /* should not fail */
1858 IShellFolder_Release(lpsf
);
1866 /* end dialog, return value */
1867 nOpenAction
= ONOPEN_OPEN
;
1870 COMDLG32_SHFree(pidl
);
1873 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1875 if(*lpszTemp
) /* points to trailing null for last path element */
1877 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1879 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1885 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1886 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1888 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1892 /* change to the current folder */
1893 nOpenAction
= ONOPEN_OPEN
;
1898 nOpenAction
= ONOPEN_OPEN
;
1902 if(pidl
) COMDLG32_SHFree(pidl
);
1906 Step 3: here we have a cleaned up and validated path
1909 lpsf: ShellFolder bound to the rightmost valid path component
1910 lpstrPathAndFile: cleaned up path
1911 nOpenAction: action to do
1913 TRACE("end validate sf=%p\n", lpsf
);
1917 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1918 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1921 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1924 /* replace the current filter */
1925 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1926 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1927 len
= strlenW(lpszTemp
)+1;
1928 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1929 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1931 /* set the filter cb to the extension when possible */
1932 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1933 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1936 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1937 TRACE("ONOPEN_BROWSE\n");
1939 IPersistFolder2
* ppf2
;
1940 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1942 LPITEMIDLIST pidlCurrent
;
1943 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1944 IPersistFolder2_Release(ppf2
);
1945 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1947 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1949 else if( nOpenAction
== ONOPEN_SEARCH
)
1951 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1953 COMDLG32_SHFree(pidlCurrent
);
1958 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1959 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1963 /* update READONLY check box flag */
1964 if ((SendMessageA(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
1965 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
1967 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
1969 /* Attach the file extension with file name*/
1970 ext
= PathFindExtensionW(lpstrPathAndFile
);
1973 /* if no extension is specified with file name, then */
1974 /* attach the extension from file filter or default one */
1976 WCHAR
*filterExt
= NULL
;
1977 LPWSTR lpstrFilter
= NULL
;
1978 static const WCHAR szwDot
[] = {'.',0};
1979 int PathLength
= strlenW(lpstrPathAndFile
);
1982 strcatW(lpstrPathAndFile
, szwDot
);
1984 /*Get the file extension from file type filter*/
1985 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
1986 fodInfos
->ofnInfos
->nFilterIndex
-1);
1988 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
1989 filterExt
= PathFindExtensionW(lpstrFilter
);
1991 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
1992 strcatW(lpstrPathAndFile
, filterExt
+ 1);
1993 else if ( fodInfos
->defext
) /* attach the default file extension*/
1994 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
1996 /* In Open dialog: if file does not exist try without extension */
1997 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
1998 lpstrPathAndFile
[PathLength
] = '\0';
2001 if (fodInfos
->defext
) /* add default extension */
2003 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2006 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2007 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2009 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2012 /* In Save dialog: check if the file already exists */
2013 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2014 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2015 && PathFileExistsW(lpstrPathAndFile
))
2017 WCHAR lpstrOverwrite
[100];
2020 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2021 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2022 MB_YESNO
| MB_ICONEXCLAMATION
);
2030 /* Check that the size of the file does not exceed buffer size.
2031 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2032 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2033 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2037 /* fill destination buffer */
2038 if (fodInfos
->ofnInfos
->lpstrFile
)
2040 if(fodInfos
->unicode
)
2042 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2044 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2045 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2046 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2050 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2052 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2053 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2054 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2055 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2059 /* set filename offset */
2060 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2061 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2063 /* set extension offset */
2064 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2065 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2067 /* set the lpstrFileTitle */
2068 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2070 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2071 if(fodInfos
->unicode
)
2073 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2074 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2078 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2079 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2080 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2084 /* copy currently selected filter to lpstrCustomFilter */
2085 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2087 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2088 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2089 NULL
, 0, NULL
, NULL
);
2090 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2092 LPSTR s
= ofn
->lpstrCustomFilter
;
2093 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2094 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2095 s
, len
, NULL
, NULL
);
2100 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2104 FILEDLG95_Clean(hwnd
);
2105 ret
= EndDialog(hwnd
, TRUE
);
2111 size
= strlenW(lpstrPathAndFile
) + 1;
2112 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2114 /* return needed size in first two bytes of lpstrFile */
2115 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2116 FILEDLG95_Clean(hwnd
);
2117 ret
= EndDialog(hwnd
, FALSE
);
2118 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2126 if(lpsf
) IShellFolder_Release(lpsf
);
2130 /***********************************************************************
2131 * FILEDLG95_SHELL_Init
2133 * Initialisation of the shell objects
2135 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2137 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2142 * Initialisation of the FileOpenDialogInfos structure
2148 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2150 /* Disable multi-select if flag not set */
2151 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2153 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2155 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2156 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2158 /* Construct the IShellBrowser interface */
2159 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2164 /***********************************************************************
2165 * FILEDLG95_SHELL_ExecuteCommand
2167 * Change the folder option and refresh the view
2168 * If the function succeeds, the return value is nonzero.
2170 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2172 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2175 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2177 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2182 CMINVOKECOMMANDINFO ci
;
2183 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2184 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2188 IContextMenu_InvokeCommand(pcm
, &ci
);
2189 IContextMenu_Release(pcm
);
2195 /***********************************************************************
2196 * FILEDLG95_SHELL_UpFolder
2198 * Browse to the specified object
2199 * If the function succeeds, the return value is nonzero.
2201 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2203 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2207 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_BrowseToDesktop
2219 * Browse to the Desktop
2220 * If the function succeeds, the return value is nonzero.
2222 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2224 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2230 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2231 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2232 COMDLG32_SHFree(pidl
);
2233 return SUCCEEDED(hres
);
2235 /***********************************************************************
2236 * FILEDLG95_SHELL_Clean
2238 * Cleans the memory used by shell objects
2240 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2242 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2246 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2248 /* clean Shell interfaces */
2249 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2250 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2251 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2252 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2253 if (fodInfos
->Shell
.FOIDataObject
)
2254 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2257 /***********************************************************************
2258 * FILEDLG95_FILETYPE_Init
2260 * Initialisation of the file type combo box
2262 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2264 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2265 int nFilters
= 0; /* number of filters */
2270 if(fodInfos
->customfilter
)
2272 /* customfilter has one entry... title\0ext\0
2273 * Set first entry of combo box item with customfilter
2276 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2279 lpstrPos
+= strlenW(fodInfos
->customfilter
) + 1;
2281 /* Copy the extensions */
2282 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2283 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2284 strcpyW(lpstrExt
,lpstrPos
);
2286 /* Add the item at the end of the combo */
2287 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2288 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2291 if(fodInfos
->filter
)
2293 LPCWSTR lpstrPos
= fodInfos
->filter
;
2297 /* filter is a list... title\0ext\0......\0\0
2298 * Set the combo item text to the title and the item data
2301 LPCWSTR lpstrDisplay
;
2305 if(! *lpstrPos
) break; /* end */
2306 lpstrDisplay
= lpstrPos
;
2307 lpstrPos
+= strlenW(lpstrPos
) + 1;
2309 /* Copy the extensions */
2310 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2311 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2312 strcpyW(lpstrExt
,lpstrPos
);
2313 lpstrPos
+= strlenW(lpstrPos
) + 1;
2315 /* Add the item at the end of the combo */
2316 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2317 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2323 * Set the current filter to the one specified
2324 * in the initialisation structure
2326 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2330 /* Check to make sure our index isn't out of bounds. */
2331 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2332 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2333 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2335 /* set default filter index */
2336 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2337 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2339 /* calculate index of Combo Box item */
2340 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2341 if (fodInfos
->customfilter
== NULL
)
2344 /* Set the current index selection. */
2345 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2347 /* Get the corresponding text string from the combo box. */
2348 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2351 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2357 CharLowerW(lpstrFilter
); /* lowercase */
2358 len
= strlenW(lpstrFilter
)+1;
2359 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2360 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2363 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2368 /***********************************************************************
2369 * FILEDLG95_FILETYPE_OnCommand
2371 * WM_COMMAND of the file type combo box
2372 * If the function succeeds, the return value is nonzero.
2374 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2376 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2384 /* Get the current item of the filetype combo box */
2385 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2387 /* set the current filter index */
2388 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2389 (fodInfos
->customfilter
== NULL
? 1 : 0);
2391 /* Set the current filter with the current selection */
2392 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2393 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2395 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2397 if((int)lpstrFilter
!= CB_ERR
)
2400 CharLowerW(lpstrFilter
); /* lowercase */
2401 len
= strlenW(lpstrFilter
)+1;
2402 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2403 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2404 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2407 /* Refresh the actual view to display the included items*/
2408 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2413 /***********************************************************************
2414 * FILEDLG95_FILETYPE_SearchExt
2416 * searches for an extension in the filetype box
2418 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2420 int i
, iCount
= CBGetCount(hwnd
);
2422 TRACE("%s\n", debugstr_w(lpstrExt
));
2424 if(iCount
!= CB_ERR
)
2426 for(i
=0;i
<iCount
;i
++)
2428 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2435 /***********************************************************************
2436 * FILEDLG95_FILETYPE_Clean
2438 * Clean the memory used by the filetype combo box
2440 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2442 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2444 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2448 /* Delete each string of the combo and their associated data */
2449 if(iCount
!= CB_ERR
)
2451 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2453 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2454 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2457 /* Current filter */
2458 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2459 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2463 /***********************************************************************
2464 * FILEDLG95_LOOKIN_Init
2466 * Initialisation of the look in combo box
2468 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2470 IShellFolder
*psfRoot
, *psfDrives
;
2471 IEnumIDList
*lpeRoot
, *lpeDrives
;
2472 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2474 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2478 liInfos
->iMaxIndentation
= 0;
2480 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2482 /* set item height for both text field and listbox */
2483 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2484 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2486 /* Turn on the extended UI for the combo box like Windows does */
2487 CBSetExtendedUI(hwndCombo
, TRUE
);
2489 /* Initialise data of Desktop folder */
2490 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2491 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2492 COMDLG32_SHFree(pidlTmp
);
2494 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2496 SHGetDesktopFolder(&psfRoot
);
2500 /* enumerate the contents of the desktop */
2501 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2503 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2505 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2507 /* special handling for CSIDL_DRIVES */
2508 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2510 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2512 /* enumerate the drives */
2513 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2515 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2517 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2518 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2519 COMDLG32_SHFree(pidlAbsTmp
);
2520 COMDLG32_SHFree(pidlTmp1
);
2522 IEnumIDList_Release(lpeDrives
);
2524 IShellFolder_Release(psfDrives
);
2527 COMDLG32_SHFree(pidlTmp
);
2529 IEnumIDList_Release(lpeRoot
);
2531 IShellFolder_Release(psfRoot
);
2534 COMDLG32_SHFree(pidlDrives
);
2538 /***********************************************************************
2539 * FILEDLG95_LOOKIN_DrawItem
2541 * WM_DRAWITEM message handler
2543 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2545 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2546 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2547 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2551 HIMAGELIST ilItemImage
;
2554 LPSFOLDER tmpFolder
;
2557 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2561 if(pDIStruct
->itemID
== -1)
2564 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2565 pDIStruct
->itemID
)))
2569 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2571 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2574 sizeof (SHFILEINFOA
),
2575 SHGFI_PIDL
| SHGFI_SMALLICON
|
2576 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2577 SHGFI_DISPLAYNAME
);
2581 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2584 sizeof (SHFILEINFOA
),
2585 SHGFI_PIDL
| SHGFI_SMALLICON
|
2586 SHGFI_SYSICONINDEX
|
2590 /* Is this item selected ? */
2591 if(pDIStruct
->itemState
& ODS_SELECTED
)
2593 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2594 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2595 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2599 SetTextColor(pDIStruct
->hDC
,crText
);
2600 SetBkColor(pDIStruct
->hDC
,crWin
);
2601 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2604 /* Do not indent item if drawing in the edit of the combo */
2605 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2608 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2611 sizeof (SHFILEINFOA
),
2612 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2613 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2618 iIndentation
= tmpFolder
->m_iIndent
;
2620 /* Draw text and icon */
2622 /* Initialise the icon display area */
2623 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2624 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2625 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2626 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2628 /* Initialise the text display area */
2629 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2630 rectText
.left
= rectIcon
.right
;
2632 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2633 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2635 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2637 /* Draw the icon from the image list */
2638 ImageList_Draw(ilItemImage
,
2645 /* Draw the associated text */
2646 if(sfi
.szDisplayName
)
2647 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2653 /***********************************************************************
2654 * FILEDLG95_LOOKIN_OnCommand
2656 * LookIn combo box WM_COMMAND message handler
2657 * If the function succeeds, the return value is nonzero.
2659 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2661 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2663 TRACE("%p\n", fodInfos
);
2669 LPSFOLDER tmpFolder
;
2672 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2674 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2679 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2680 tmpFolder
->pidlItem
,
2692 /***********************************************************************
2693 * FILEDLG95_LOOKIN_AddItem
2695 * Adds an absolute pidl item to the lookin combo box
2696 * returns the index of the inserted item
2698 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2700 LPITEMIDLIST pidlNext
;
2703 LookInInfos
*liInfos
;
2705 TRACE("%08x\n", iInsertId
);
2710 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2713 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2714 tmpFolder
->m_iIndent
= 0;
2716 /* Calculate the indentation of the item in the lookin*/
2718 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2720 tmpFolder
->m_iIndent
++;
2723 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2725 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2726 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2728 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2729 SHGetFileInfoA((LPSTR
)pidl
,
2733 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2734 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2736 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2738 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2742 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2744 /* Add the item at the end of the list */
2747 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2749 /* Insert the item at the iInsertId position*/
2752 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2755 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2759 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2760 MemFree( tmpFolder
);
2765 /***********************************************************************
2766 * FILEDLG95_LOOKIN_InsertItemAfterParent
2768 * Insert an item below its parent
2770 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2773 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2778 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2782 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2785 /* Free pidlParent memory */
2786 COMDLG32_SHFree((LPVOID
)pidlParent
);
2788 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2791 /***********************************************************************
2792 * FILEDLG95_LOOKIN_SelectItem
2794 * Adds an absolute pidl item to the lookin combo box
2795 * returns the index of the inserted item
2797 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2800 LookInInfos
*liInfos
;
2804 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2806 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2810 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2811 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2816 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2817 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2821 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2823 if(iRemovedItem
< iItemPos
)
2828 CBSetCurSel(hwnd
,iItemPos
);
2829 liInfos
->uSelectedItem
= iItemPos
;
2835 /***********************************************************************
2836 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2838 * Remove the item with an expansion level over iExpansionLevel
2840 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2844 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2848 if(liInfos
->iMaxIndentation
<= 2)
2851 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2853 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2854 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2856 CBDeleteString(hwnd
,iItemPos
);
2857 liInfos
->iMaxIndentation
--;
2865 /***********************************************************************
2866 * FILEDLG95_LOOKIN_SearchItem
2868 * Search for pidl in the lookin combo box
2869 * returns the index of the found item
2871 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2874 int iCount
= CBGetCount(hwnd
);
2876 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2878 if (iCount
!= CB_ERR
)
2882 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2884 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2886 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2894 /***********************************************************************
2895 * FILEDLG95_LOOKIN_Clean
2897 * Clean the memory used by the lookin combo box
2899 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2901 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2903 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2907 /* Delete each string of the combo and their associated data */
2908 if (iCount
!= CB_ERR
)
2910 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2912 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2913 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2915 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2919 /* LookInInfos structure */
2920 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2923 /***********************************************************************
2924 * FILEDLG95_FILENAME_FillFromSelection
2926 * fills the edit box from the cached DataObject
2928 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2930 FileOpenDlgInfos
*fodInfos
;
2932 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2933 char lpstrTemp
[MAX_PATH
];
2934 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2937 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2939 /* Count how many files we have */
2940 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2942 /* calculate the string length, count files */
2943 if (nFileSelected
>= 1)
2945 nLength
+= 3; /* first and last quotes, trailing \0 */
2946 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2948 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2952 /* get the total length of the selected file names */
2953 lpstrTemp
[0] = '\0';
2954 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2956 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2958 nLength
+= strlen( lpstrTemp
) + 3;
2961 COMDLG32_SHFree( pidl
);
2966 /* allocate the buffer */
2967 if (nFiles
<= 1) nLength
= MAX_PATH
;
2968 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2969 lpstrAllFile
[0] = '\0';
2971 /* Generate the string for the edit control */
2974 lpstrCurrFile
= lpstrAllFile
;
2975 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2977 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2981 /* get the file name */
2982 lpstrTemp
[0] = '\0';
2983 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2985 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2989 *lpstrCurrFile
++ = '\"';
2990 strcpy( lpstrCurrFile
, lpstrTemp
);
2991 lpstrCurrFile
+= strlen( lpstrTemp
);
2992 strcpy( lpstrCurrFile
, "\" " );
2997 strcpy( lpstrAllFile
, lpstrTemp
);
3000 COMDLG32_SHFree( (LPVOID
) pidl
);
3003 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3005 /* Select the file name like Windows does */
3006 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)-1);
3008 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3012 /* copied from shell32 to avoid linking to it */
3013 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3018 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
3019 COMDLG32_SHFree(src
->u
.pOleStr
);
3023 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
3027 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
3031 FIXME("unknown type!\n");
3034 *(LPSTR
)dest
= '\0';
3041 /***********************************************************************
3042 * FILEDLG95_FILENAME_GetFileNames
3044 * Copies the filenames to a delimited string list.
3045 * The delimiter is specified by the parameter 'separator',
3046 * usually either a space or a nul
3048 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
, char separator
)
3050 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3051 UINT nStrCharCount
= 0; /* index in src buffer */
3052 UINT nFileIndex
= 0; /* index in dest buffer */
3053 UINT nFileCount
= 0; /* number of files */
3054 UINT nStrLen
= 0; /* length of string in edit control */
3055 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3059 /* get the filenames from the edit control */
3060 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3061 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3062 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3064 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3066 /* we might get single filename without any '"',
3067 * so we need nStrLen + terminating \0 + end-of-list \0 */
3068 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3071 /* build delimited file list from filenames */
3072 while ( nStrCharCount
<= nStrLen
)
3074 if ( lpstrEdit
[nStrCharCount
]=='"' )
3077 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3079 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3083 (*lpstrFileList
)[nFileIndex
++] = separator
;
3090 /* single, unquoted string */
3091 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
3093 strcpyW(*lpstrFileList
, lpstrEdit
);
3094 nFileIndex
= strlenW(lpstrEdit
) + 1;
3095 (*sizeUsed
) = nFileIndex
;
3100 (*lpstrFileList
)[nFileIndex
] = '\0';
3107 #define SETDefFormatEtc(fe,cf,med) \
3109 (fe).cfFormat = cf;\
3110 (fe).dwAspect = DVASPECT_CONTENT; \
3117 * DATAOBJECT Helper functions
3120 /***********************************************************************
3121 * COMCTL32_ReleaseStgMedium
3123 * like ReleaseStgMedium from ole32
3125 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3127 if(medium
.pUnkForRelease
)
3129 IUnknown_Release(medium
.pUnkForRelease
);
3133 GlobalUnlock(medium
.u
.hGlobal
);
3134 GlobalFree(medium
.u
.hGlobal
);
3138 /***********************************************************************
3139 * GetPidlFromDataObject
3141 * Return pidl(s) by number from the cached DataObject
3143 * nPidlIndex=0 gets the fully qualified root path
3145 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3149 FORMATETC formatetc
;
3150 LPITEMIDLIST pidl
= NULL
;
3152 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3154 /* Set the FORMATETC structure*/
3155 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3157 /* Get the pidls from IDataObject */
3158 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3160 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3161 if(nPidlIndex
<= cida
->cidl
)
3163 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3165 COMCTL32_ReleaseStgMedium(medium
);
3170 /***********************************************************************
3173 * Return the number of selected items in the DataObject.
3176 UINT
GetNumSelected( IDataObject
*doSelected
)
3180 FORMATETC formatetc
;
3182 TRACE("sv=%p\n", doSelected
);
3184 if (!doSelected
) return 0;
3186 /* Set the FORMATETC structure*/
3187 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
3189 /* Get the pidls from IDataObject */
3190 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3192 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3193 retVal
= cida
->cidl
;
3194 COMCTL32_ReleaseStgMedium(medium
);
3204 /***********************************************************************
3207 * Get the pidl's display name (relative to folder) and
3208 * put it in lpstrFileName.
3210 * Return NOERROR on success,
3214 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
3219 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3223 SHGetDesktopFolder(&lpsf
);
3224 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3225 IShellFolder_Release(lpsf
);
3229 /* Get the display name of the pidl relative to the folder */
3230 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3232 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3237 /***********************************************************************
3238 * GetShellFolderFromPidl
3240 * pidlRel is the item pidl relative
3241 * Return the IShellFolder of the absolute pidl
3243 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3245 IShellFolder
*psf
= NULL
,*psfParent
;
3247 TRACE("%p\n", pidlAbs
);
3249 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3252 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3254 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3256 IShellFolder_Release(psfParent
);
3260 /* return the desktop */
3266 /***********************************************************************
3269 * Return the LPITEMIDLIST to the parent of the pidl in the list
3271 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3273 LPITEMIDLIST pidlParent
;
3275 TRACE("%p\n", pidl
);
3277 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3278 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3283 /***********************************************************************
3286 * returns the pidl of the file name relative to folder
3287 * NULL if an error occurred
3289 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3291 LPITEMIDLIST pidl
= NULL
;
3294 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3296 if(!lpcstrFileName
) return NULL
;
3297 if(!*lpcstrFileName
) return NULL
;
3301 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3302 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3303 IShellFolder_Release(lpsf
);
3308 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3315 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3317 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3320 TRACE("%p, %p\n", psf
, pidl
);
3322 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3324 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3325 /* see documentation shell 4.1*/
3326 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3329 /***********************************************************************
3330 * BrowseSelectedFolder
3332 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3334 BOOL bBrowseSelFolder
= FALSE
;
3335 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3339 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3341 LPITEMIDLIST pidlSelection
;
3343 /* get the file selected */
3344 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3345 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3347 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3348 pidlSelection
, SBSP_RELATIVE
) ) )
3350 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3351 ' ','n','o','t',' ','e','x','i','s','t',0};
3352 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3355 bBrowseSelFolder
= TRUE
;
3357 COMDLG32_SHFree( pidlSelection
);
3360 return bBrowseSelFolder
;
3364 * Memory allocation methods */
3365 static void *MemAlloc(UINT size
)
3367 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3370 static void MemFree(void *mem
)
3372 HeapFree(GetProcessHeap(),0,mem
);
3376 * Old-style (win3.1) dialogs */
3378 /***********************************************************************
3379 * FD32_GetTemplate [internal]
3381 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3382 * by a 32 bits application
3385 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3387 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3388 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3391 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3393 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3395 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3399 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3403 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3404 priv
->ofnA
->lpTemplateName
,
3407 hResInfo
= FindResourceW(ofnW
->hInstance
,
3408 ofnW
->lpTemplateName
,
3412 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3415 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3417 !(lfs
->template = LockResource(hDlgTmpl
)))
3419 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3422 } else { /* get it from internal Wine resource */
3424 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3425 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3427 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3430 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3431 !(lfs
->template = LockResource( hDlgTmpl
)))
3433 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3441 /************************************************************************
3442 * FD32_Init [internal]
3443 * called from the common 16/32 code to initialize 32 bit data
3445 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3447 BOOL IsUnicode
= (BOOL
) data
;
3450 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3451 lfs
->private1632
= priv
;
3452 if (NULL
== lfs
->private1632
) return FALSE
;
3455 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3456 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3457 if (lfs
->ofnW
->lpfnHook
)
3462 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3463 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3464 if (priv
->ofnA
->lpfnHook
)
3466 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3467 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3470 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3475 /***********************************************************************
3476 * FD32_CallWindowProc [internal]
3478 * called from the common 16/32 code to call the appropriate hook
3480 BOOL CALLBACK
FD32_CallWindowProc(PFD31_DATA lfs
, UINT wMsg
, WPARAM wParam
,
3484 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3488 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3489 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3490 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3491 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3492 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3496 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3497 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3498 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3499 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3500 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3504 /***********************************************************************
3505 * FD32_UpdateResult [internal]
3506 * update the real client structures if any
3508 static void CALLBACK
FD32_UpdateResult(PFD31_DATA lfs
)
3510 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3511 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3515 if (ofnW
->nMaxFile
&&
3516 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3517 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3518 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3519 priv
->ofnA
->nFileOffset
= ofnW
->nFileOffset
;
3520 priv
->ofnA
->nFileExtension
= ofnW
->nFileExtension
;
3524 /***********************************************************************
3525 * FD32_UpdateFileTitle [internal]
3526 * update the real client structures if any
3528 static void CALLBACK
FD32_UpdateFileTitle(PFD31_DATA lfs
)
3530 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3531 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3535 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3536 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3537 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3542 /***********************************************************************
3543 * FD32_SendLbGetCurSel [internal]
3544 * retrieve selected listbox item
3546 static LRESULT CALLBACK
FD32_SendLbGetCurSel(PFD31_DATA lfs
)
3548 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3552 /************************************************************************
3553 * FD32_Destroy [internal]
3554 * called from the common 16/32 code to cleanup 32 bit data
3556 static void CALLBACK
FD32_Destroy(PFD31_DATA lfs
)
3558 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3560 /* if ofnW has been allocated, have to free everything in it */
3561 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3563 FD31_FreeOfnW(lfs
->ofnW
);
3564 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3568 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3570 callbacks
->Init
= FD32_Init
;
3571 callbacks
->CWP
= FD32_CallWindowProc
;
3572 callbacks
->UpdateResult
= FD32_UpdateResult
;
3573 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3574 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3575 callbacks
->Destroy
= FD32_Destroy
;
3578 /***********************************************************************
3579 * FD32_WMMeasureItem [internal]
3581 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3583 LPMEASUREITEMSTRUCT lpmeasure
;
3585 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3586 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3591 /***********************************************************************
3592 * FileOpenDlgProc [internal]
3593 * Used for open and save, in fact.
3595 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3596 WPARAM wParam
, LPARAM lParam
)
3598 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3600 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg
, wParam
, lParam
);
3601 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3604 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3606 return lRet
; /* else continue message processing */
3611 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3613 case WM_MEASUREITEM
:
3614 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3617 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3620 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3623 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3624 switch (HIWORD(lParam
))
3627 SetTextColor((HDC16
)wParam
, 0x00000000);
3629 case CTLCOLOR_STATIC
:
3630 SetTextColor((HDC16
)wParam
, 0x00000000);
3640 /***********************************************************************
3641 * GetFileName31A [internal]
3643 * Creates a win31 style dialog box for the user to select a file to open/save.
3645 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* addess of structure with data*/
3646 UINT dlgType
/* type dialogue : open/save */
3652 FD31_CALLBACKS callbacks
;
3654 if (!lpofn
|| !FD31_Init()) return FALSE
;
3656 TRACE("ofn flags %08lx\n", lpofn
->Flags
);
3657 FD32_SetupCallbacks(&callbacks
);
3658 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3661 hInst
= (HINSTANCE
)GetWindowLongPtrA( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3662 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3663 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3664 FD31_DestroyPrivate(lfs
);
3667 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3671 /***********************************************************************
3672 * GetFileName31W [internal]
3674 * Creates a win31 style dialog box for the user to select a file to open/save
3676 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* addess of structure with data*/
3677 UINT dlgType
/* type dialogue : open/save */
3683 FD31_CALLBACKS callbacks
;
3685 if (!lpofn
|| !FD31_Init()) return FALSE
;
3687 FD32_SetupCallbacks(&callbacks
);
3688 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3691 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3692 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3693 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3694 FD31_DestroyPrivate(lfs
);
3697 TRACE("file %s, file offset %d, ext offset %d\n",
3698 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3702 /* ------------------ APIs ---------------------- */
3704 /***********************************************************************
3705 * GetOpenFileNameA (COMDLG32.@)
3707 * Creates a dialog box for the user to select a file to open.
3710 * TRUE on success: user enters a valid file
3711 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3714 BOOL WINAPI
GetOpenFileNameA(
3715 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3717 BOOL win16look
= FALSE
;
3719 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3720 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
3721 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
3723 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3724 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3727 return GetFileName31A(ofn
, OPEN_DIALOG
);
3729 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
3732 /***********************************************************************
3733 * GetOpenFileNameW (COMDLG32.@)
3735 * Creates a dialog box for the user to select a file to open.
3738 * TRUE on success: user enters a valid file
3739 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3742 BOOL WINAPI
GetOpenFileNameW(
3743 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3745 BOOL win16look
= FALSE
;
3747 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3748 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3751 return GetFileName31W(ofn
, OPEN_DIALOG
);
3753 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
3757 /***********************************************************************
3758 * GetSaveFileNameA (COMDLG32.@)
3760 * Creates a dialog box for the user to select a file to save.
3763 * TRUE on success: user enters a valid file
3764 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3767 BOOL WINAPI
GetSaveFileNameA(
3768 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
3770 BOOL win16look
= FALSE
;
3772 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3773 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3776 return GetFileName31A(ofn
, SAVE_DIALOG
);
3778 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
3781 /***********************************************************************
3782 * GetSaveFileNameW (COMDLG32.@)
3784 * Creates a dialog box for the user to select a file to save.
3787 * TRUE on success: user enters a valid file
3788 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3791 BOOL WINAPI
GetSaveFileNameW(
3792 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
3794 BOOL win16look
= FALSE
;
3796 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
3797 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
3800 return GetFileName31W(ofn
, SAVE_DIALOG
);
3802 return GetFileDialog95W(ofn
, SAVE_DIALOG
);