2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
71 #include "filedlg31.h"
75 #include "filedlgbrowser.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex
; /* Index of picture in image list */
97 int m_iIndent
; /* Indentation index */
98 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
100 } SFOLDER
,*LPSFOLDER
;
102 typedef struct tagLookInInfo
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA
*ofnA
; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE
, *PFD32_PRIVATE
;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
120 #define XTEXTOFFSET 3
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 #define CBInsertString(hwnd,str,pos) \
143 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 #define CBDeleteString(hwnd,pos) \
146 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
149 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 #define CBGetItemDataPtr(hwnd,iItemId) \
152 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 #define CBGetLBText(hwnd,iItemId,str) \
155 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 #define CBGetCurSel(hwnd) \
158 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 #define CBSetCurSel(hwnd,pos) \
161 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 #define CBGetCount(hwnd) \
164 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
165 #define CBShowDropDown(hwnd,show) \
166 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
167 #define CBSetItemHeight(hwnd,index,height) \
168 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 #define CBSetExtendedUI(hwnd,flag) \
171 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 const char FileOpenDlgInfosStr
[] = "FileOpenDlgInfos"; /* windows property description string */
174 static const char LookInInfosStr
[] = "LookInInfos"; /* LOOKIN combo box property */
176 /***********************************************************************
180 /* Internal functions used by the dialog */
181 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
182 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
183 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
184 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
185 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
186 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
187 static void FILEDLG95_Clean(HWND hwnd
);
189 /* Functions used by the shell navigation */
190 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
191 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
192 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
194 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
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 void 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 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
218 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
219 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
220 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
221 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
222 static UINT
GetNumSelected( IDataObject
*doSelected
);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size
);
226 static void MemFree(void *mem
);
228 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
229 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
231 static BOOL
BrowseSelectedFolder(HWND hwnd
);
233 /***********************************************************************
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
252 /* test for missing functionality */
253 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
259 /* Create the dialog from a template */
261 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
266 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
267 !(template = LockResource( hDlgTmpl
)))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
273 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
275 ((LPDLGTEMPLATEW
)template)->style
|= WS_SIZEBOX
;
276 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
277 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
280 /* old style hook messages */
281 if (IsHooked(fodInfos
))
283 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
284 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
285 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
286 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
289 /* Some shell namespace extensions depend on COM being initialized. */
290 hr
= OleInitialize(NULL
);
292 if (fodInfos
->unicode
)
293 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
295 fodInfos
->ofnInfos
->hwndOwner
,
299 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
301 fodInfos
->ofnInfos
->hwndOwner
,
307 /* Unable to create the dialog */
314 /***********************************************************************
317 * Call GetFileName95 with this structure and clean the memory.
319 * IN : The OPENFILENAMEA initialisation structure passed to
320 * GetOpenFileNameA win api function (see filedlg.c)
322 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
325 FileOpenDlgInfos fodInfos
;
326 LPSTR lpstrSavDir
= NULL
;
328 LPWSTR defext
= NULL
;
329 LPWSTR filter
= NULL
;
330 LPWSTR customfilter
= NULL
;
332 /* Initialize CommDlgExtendedError() */
333 COMDLG32_SetCommDlgExtendedError(0);
335 /* Initialize FileOpenDlgInfos structure */
336 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
338 /* Pass in the original ofn */
339 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
341 /* save current directory */
342 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
344 lpstrSavDir
= MemAlloc(MAX_PATH
);
345 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
348 fodInfos
.unicode
= FALSE
;
350 /* convert all the input strings to unicode */
351 if(ofn
->lpstrInitialDir
)
353 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
354 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
355 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
358 fodInfos
.initdir
= NULL
;
362 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
363 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
366 fodInfos
.filename
= NULL
;
370 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
371 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
372 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
374 fodInfos
.defext
= defext
;
378 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
379 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
380 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
382 fodInfos
.title
= title
;
384 if (ofn
->lpstrFilter
)
389 /* filter is a list... title\0ext\0......\0\0 */
390 s
= ofn
->lpstrFilter
;
391 while (*s
) s
= s
+strlen(s
)+1;
393 n
= s
- ofn
->lpstrFilter
;
394 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
395 filter
= MemAlloc(len
*sizeof(WCHAR
));
396 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
398 fodInfos
.filter
= filter
;
400 /* convert lpstrCustomFilter */
401 if (ofn
->lpstrCustomFilter
)
406 /* customfilter contains a pair of strings... title\0ext\0 */
407 s
= ofn
->lpstrCustomFilter
;
408 if (*s
) s
= s
+strlen(s
)+1;
409 if (*s
) s
= s
+strlen(s
)+1;
410 n
= s
- ofn
->lpstrCustomFilter
;
411 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
412 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
413 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
415 fodInfos
.customfilter
= customfilter
;
417 /* Initialize the dialog property */
418 fodInfos
.DlgInfos
.dwDlgProp
= 0;
419 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
424 ret
= GetFileName95(&fodInfos
);
427 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
428 ret
= GetFileName95(&fodInfos
);
436 SetCurrentDirectoryA(lpstrSavDir
);
437 MemFree(lpstrSavDir
);
443 MemFree(customfilter
);
444 MemFree(fodInfos
.initdir
);
445 MemFree(fodInfos
.filename
);
447 TRACE("selected file: %s\n",ofn
->lpstrFile
);
452 /***********************************************************************
455 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
456 * Call GetFileName95 with this structure and clean the memory.
459 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
462 FileOpenDlgInfos fodInfos
;
463 LPWSTR lpstrSavDir
= NULL
;
465 /* Initialize CommDlgExtendedError() */
466 COMDLG32_SetCommDlgExtendedError(0);
468 /* Initialize FileOpenDlgInfos structure */
469 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
471 /* Pass in the original ofn */
472 fodInfos
.ofnInfos
= ofn
;
474 fodInfos
.title
= ofn
->lpstrTitle
;
475 fodInfos
.defext
= ofn
->lpstrDefExt
;
476 fodInfos
.filter
= ofn
->lpstrFilter
;
477 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
479 /* convert string arguments, save others */
482 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
483 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
486 fodInfos
.filename
= NULL
;
488 if(ofn
->lpstrInitialDir
)
490 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
491 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
492 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
493 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
496 fodInfos
.initdir
= NULL
;
498 /* save current directory */
499 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
501 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
502 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
505 fodInfos
.unicode
= TRUE
;
510 ret
= GetFileName95(&fodInfos
);
513 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
514 ret
= GetFileName95(&fodInfos
);
522 SetCurrentDirectoryW(lpstrSavDir
);
523 MemFree(lpstrSavDir
);
526 /* restore saved IN arguments and convert OUT arguments back */
527 MemFree(fodInfos
.filename
);
528 MemFree(fodInfos
.initdir
);
532 /******************************************************************************
533 * COMDLG32_GetDisplayNameOf [internal]
535 * Helper function to get the display name for a pidl.
537 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
538 LPSHELLFOLDER psfDesktop
;
541 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
544 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
545 IShellFolder_Release(psfDesktop
);
549 IShellFolder_Release(psfDesktop
);
550 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
553 /***********************************************************************
554 * ArrangeCtrlPositions [internal]
556 * NOTE: Do not change anything here without a lot of testing.
558 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
560 HWND hwndChild
, hwndStc32
;
561 RECT rectParent
, rectChild
, rectStc32
;
562 INT help_fixup
= 0, child_height_fixup
= 0, child_width_fixup
= 0;
564 /* Take into account if open as read only checkbox and help button
569 RECT rectHelp
, rectCancel
;
570 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
571 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
572 /* subtract the height of the help button plus the space between
573 * the help button and the cancel button to the height of the dialog
575 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
579 There are two possibilities to add components to the default file dialog box.
581 By default, all the new components are added below the standard dialog box (the else case).
583 However, if there is a static text component with the stc32 id, a special case happens.
584 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
585 in the window and the cx and cy indicate how to size the window.
586 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
587 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
591 GetClientRect(hwndParentDlg
, &rectParent
);
593 /* when arranging controls we have to use fixed parent size */
594 rectParent
.bottom
-= help_fixup
;
596 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
599 GetWindowRect(hwndStc32
, &rectStc32
);
600 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
602 /* set the size of the stc32 control according to the size of
603 * client area of the parent dialog
605 SetWindowPos(hwndStc32
, 0,
607 rectParent
.right
, rectParent
.bottom
,
608 SWP_NOMOVE
| SWP_NOZORDER
);
611 SetRectEmpty(&rectStc32
);
613 /* this part moves controls of the child dialog */
614 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
617 if (hwndChild
!= hwndStc32
)
619 GetWindowRect(hwndChild
, &rectChild
);
620 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
622 /* move only if stc32 exist */
623 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
625 LONG old_left
= rectChild
.left
;
627 /* move to the right of visible controls of the parent dialog */
628 rectChild
.left
+= rectParent
.right
;
629 rectChild
.left
-= rectStc32
.right
;
631 child_width_fixup
= rectChild
.left
- old_left
;
633 /* move even if stc32 doesn't exist */
634 if (rectChild
.top
>= rectStc32
.bottom
)
636 LONG old_top
= rectChild
.top
;
638 /* move below visible controls of the parent dialog */
639 rectChild
.top
+= rectParent
.bottom
;
640 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
642 child_height_fixup
= rectChild
.top
- old_top
;
645 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
646 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
648 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
651 /* this part moves controls of the parent dialog */
652 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
655 if (hwndChild
!= hwndChildDlg
)
657 GetWindowRect(hwndChild
, &rectChild
);
658 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
660 /* left,top of stc32 marks the position of controls
661 * from the parent dialog
663 rectChild
.left
+= rectStc32
.left
;
664 rectChild
.top
+= rectStc32
.top
;
666 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
667 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
669 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
672 /* calculate the size of the resulting dialog */
674 /* here we have to use original parent size */
675 GetClientRect(hwndParentDlg
, &rectParent
);
676 GetClientRect(hwndChildDlg
, &rectChild
);
680 rectChild
.right
+= child_width_fixup
;
681 rectChild
.bottom
+= child_height_fixup
;
683 if (rectParent
.right
> rectChild
.right
)
685 rectParent
.right
+= rectChild
.right
;
686 rectParent
.right
-= rectStc32
.right
- rectStc32
.left
;
690 rectParent
.right
= rectChild
.right
;
693 if (rectParent
.bottom
> rectChild
.bottom
)
695 rectParent
.bottom
+= rectChild
.bottom
;
696 rectParent
.bottom
-= rectStc32
.bottom
- rectStc32
.top
;
700 /* child dialog is higher, unconditionally set new dialog
701 * height to its size (help_fixup will be subtracted below)
703 rectParent
.bottom
= rectChild
.bottom
+ help_fixup
;
708 rectParent
.bottom
+= rectChild
.bottom
;
711 /* finally use fixed parent size */
712 rectParent
.bottom
-= help_fixup
;
714 /* set the size of the parent dialog */
715 AdjustWindowRectEx(&rectParent
, GetWindowLongW(hwndParentDlg
, GWL_STYLE
),
716 FALSE
, GetWindowLongW(hwndParentDlg
, GWL_EXSTYLE
));
717 SetWindowPos(hwndParentDlg
, 0,
719 rectParent
.right
- rectParent
.left
,
720 rectParent
.bottom
- rectParent
.top
,
721 SWP_NOMOVE
| SWP_NOZORDER
);
724 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
733 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
743 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
744 * structure's hInstance parameter is not a HINSTANCE, but
745 * instead a pointer to a template resource to use.
747 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
750 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
752 hinst
= COMDLG32_hInstance
;
753 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
755 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
761 hinst
= fodInfos
->ofnInfos
->hInstance
;
762 if(fodInfos
->unicode
)
764 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
765 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
769 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
770 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
774 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
777 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
778 !(template = LockResource( hDlgTmpl
)))
780 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
784 if (fodInfos
->unicode
)
785 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
786 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
787 (LPARAM
)fodInfos
->ofnInfos
);
789 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
790 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
791 (LPARAM
)fodInfos
->ofnInfos
);
794 ShowWindow(hChildDlg
,SW_SHOW
);
798 else if( IsHooked(fodInfos
))
803 WORD menu
,class,title
;
805 GetClientRect(hwnd
,&rectHwnd
);
806 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
807 temp
.tmplate
.dwExtendedStyle
= 0;
808 temp
.tmplate
.cdit
= 0;
813 temp
.menu
= temp
.class = temp
.title
= 0;
815 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
816 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
823 /***********************************************************************
824 * SendCustomDlgNotificationMessage
826 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
829 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
831 LRESULT hook_result
= 0;
832 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
834 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
836 if(!fodInfos
) return 0;
838 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
840 TRACE("CALL NOTIFY for %x\n", uCode
);
841 if(fodInfos
->unicode
)
844 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
845 ofnNotify
.hdr
.idFrom
=0;
846 ofnNotify
.hdr
.code
= uCode
;
847 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
848 ofnNotify
.pszFile
= NULL
;
849 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
854 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
855 ofnNotify
.hdr
.idFrom
=0;
856 ofnNotify
.hdr
.code
= uCode
;
857 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
858 ofnNotify
.pszFile
= NULL
;
859 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
861 TRACE("RET NOTIFY\n");
863 TRACE("Retval: 0x%08lx\n", hook_result
);
867 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
871 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
873 TRACE("CDM_GETFILEPATH:\n");
875 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
878 /* get path and filenames */
879 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
880 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
881 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
884 p
= buffer
+ strlenW(buffer
);
886 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
888 if (fodInfos
->unicode
)
890 total
= strlenW( buffer
) + 1;
891 if (result
) lstrcpynW( result
, buffer
, size
);
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
896 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
897 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
898 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
900 HeapFree( GetProcessHeap(), 0, buffer
);
904 /***********************************************************************
905 * FILEDLG95_HandleCustomDialogMessages
907 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
909 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
911 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
912 WCHAR lpstrPath
[MAX_PATH
];
915 if(!fodInfos
) return FALSE
;
919 case CDM_GETFILEPATH
:
920 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
923 case CDM_GETFOLDERPATH
:
924 TRACE("CDM_GETFOLDERPATH:\n");
925 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
928 if (fodInfos
->unicode
)
929 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
931 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
932 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
934 retval
= lstrlenW(lpstrPath
);
937 case CDM_GETFOLDERIDLIST
:
938 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
939 if (retval
<= wParam
)
940 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
944 TRACE("CDM_GETSPEC:\n");
945 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
948 if (fodInfos
->unicode
)
949 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
951 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
955 case CDM_SETCONTROLTEXT
:
956 TRACE("CDM_SETCONTROLTEXT:\n");
959 if( fodInfos
->unicode
)
960 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
962 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
967 case CDM_HIDECONTROL
:
968 /* MSDN states that it should fail for not OFN_EXPLORER case */
969 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
971 HWND control
= GetDlgItem( hwnd
, wParam
);
972 if (control
) ShowWindow( control
, SW_HIDE
);
979 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
980 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
983 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
987 /***********************************************************************
988 * FILEDLG95_OnWMGetMMI
990 * WM_GETMINMAXINFO message handler for resizable dialogs
992 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
994 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
995 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
996 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
998 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
1003 /***********************************************************************
1004 * FILEDLG95_OnWMSize
1006 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1008 * FIXME: this could be made more elaborate. Now use a simple scheme
1009 * where the file view is enlarged and the controls are either moved
1010 * vertically or horizontally to get out of the way. Only the "grip"
1011 * is moved in both directions to stay in the corner.
1013 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1019 FileOpenDlgInfos
*fodInfos
;
1021 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1022 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1023 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1024 /* get the new dialog rectangle */
1025 GetWindowRect( hwnd
, &rc
);
1026 /* not initialized yet */
1027 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1028 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1029 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1031 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1032 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1033 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1034 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1035 /* change the size of the view window */
1036 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1037 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1038 hdwp
= BeginDeferWindowPos( 10);
1039 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1040 rcview
.right
- rcview
.left
+ chgx
,
1041 rcview
.bottom
- rcview
.top
+ chgy
,
1042 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1043 /* change position and sizes of the controls */
1044 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1046 GetWindowRect( ctrl
, &rc
);
1047 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1048 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1050 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1052 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1054 else if( rc
.top
> rcview
.bottom
)
1056 /* if it was below the shell view
1058 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1059 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1060 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1062 else if( rc
.left
> rcview
.right
)
1064 /* if it was to the right of the shell view
1066 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1067 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1068 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1071 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1072 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1074 GetClientRect(hwnd
, &rc
);
1075 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1076 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1077 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1078 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1080 GetWindowRect( ctrl
, &rc
);
1081 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1082 if( rc
.top
> rcview
.bottom
)
1084 /* if it was below the shell view
1086 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1087 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1088 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1090 else if( rc
.left
> rcview
.right
)
1092 /* if it was to the right of the shell view
1094 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1095 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1096 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1100 EndDeferWindowPos( hdwp
);
1101 /* should not be needed */
1102 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1106 /***********************************************************************
1109 * File open dialog procedure
1111 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1114 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
1121 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1123 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1124 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1126 /* Adds the FileOpenDlgInfos in the property list of the dialog
1127 so it will be easily accessible through a GetPropA(...) */
1128 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1130 FILEDLG95_InitControls(hwnd
);
1132 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1134 GetWindowRect( hwnd
, &rc
);
1135 fodInfos
->DlgInfos
.hwndGrip
=
1136 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1137 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1138 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1139 rc
.right
- gripx
, rc
.bottom
- gripy
,
1140 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1143 fodInfos
->DlgInfos
.hwndCustomDlg
=
1144 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1146 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1147 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1149 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1151 GetWindowRect( hwnd
, &rc
);
1152 /* FIXME: should remember sizes of last invocation */
1153 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1154 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1155 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1156 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1157 GetClientRect( hwnd
, &rc
);
1158 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1159 rc
.right
- gripx
, rc
.bottom
- gripy
,
1160 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1163 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1164 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1165 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1169 return FILEDLG95_OnWMSize(hwnd
, wParam
, lParam
);
1170 case WM_GETMINMAXINFO
:
1171 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1173 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1176 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1179 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1185 case WM_GETISHELLBROWSER
:
1186 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1189 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1194 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1197 /* set up the button tooltips strings */
1198 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1200 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1201 switch(lpnmh
->idFrom
)
1203 /* Up folder button */
1204 case FCIDM_TB_UPFOLDER
:
1205 stringId
= IDS_UPFOLDER
;
1207 /* New folder button */
1208 case FCIDM_TB_NEWFOLDER
:
1209 stringId
= IDS_NEWFOLDER
;
1211 /* List option button */
1212 case FCIDM_TB_SMALLICON
:
1213 stringId
= IDS_LISTVIEW
;
1215 /* Details option button */
1216 case FCIDM_TB_REPORTVIEW
:
1217 stringId
= IDS_REPORTVIEW
;
1219 /* Desktop button */
1220 case FCIDM_TB_DESKTOP
:
1221 stringId
= IDS_TODESKTOP
;
1226 lpdi
->hinst
= COMDLG32_hInstance
;
1227 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1232 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1233 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1238 /***********************************************************************
1239 * FILEDLG95_InitControls
1241 * WM_INITDIALOG message handler (before hook notification)
1243 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1245 int win2000plus
= 0;
1247 int handledPath
= FALSE
;
1248 OSVERSIONINFOW osVi
;
1249 static const WCHAR szwSlash
[] = { '\\', 0 };
1250 static const WCHAR szwStar
[] = { '*',0 };
1252 static const TBBUTTON tbb
[] =
1254 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1255 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1256 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1257 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1258 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1259 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1260 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1261 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1262 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1267 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1269 tba
[0].hInst
= HINST_COMMCTRL
;
1270 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1271 tba
[1].hInst
= COMDLG32_hInstance
;
1274 TRACE("%p\n", fodInfos
);
1276 /* Get windows version emulating */
1277 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1278 GetVersionExW(&osVi
);
1279 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1280 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1281 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1282 win2000plus
= (osVi
.dwMajorVersion
> 4);
1283 if (win2000plus
) win98plus
= TRUE
;
1285 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1287 /* Get the hwnd of the controls */
1288 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1289 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1290 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1292 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1293 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1295 /* construct the toolbar */
1296 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1297 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1299 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1300 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1301 rectTB
.left
= rectlook
.right
;
1302 rectTB
.top
= rectlook
.top
-1;
1304 if (fodInfos
->unicode
)
1305 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1306 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1307 rectTB
.left
, rectTB
.top
,
1308 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1309 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1311 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1312 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1313 rectTB
.left
, rectTB
.top
,
1314 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1315 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1317 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1319 /* FIXME: use TB_LOADIMAGES when implemented */
1320 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1321 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
[0]);
1322 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 1, (LPARAM
) &tba
[1]);
1324 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1325 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1327 /* Set the window text with the text specified in the OPENFILENAME structure */
1330 SetWindowTextW(hwnd
,fodInfos
->title
);
1332 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1335 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1336 SetWindowTextW(hwnd
, buf
);
1339 /* Initialise the file name edit control */
1340 handledPath
= FALSE
;
1341 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1343 if(fodInfos
->filename
)
1345 /* 1. If win2000 or higher and filename contains a path, use it
1346 in preference over the lpstrInitialDir */
1347 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1348 WCHAR tmpBuf
[MAX_PATH
];
1352 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1355 /* nameBit is always shorter than the original filename */
1356 lstrcpyW(fodInfos
->filename
,nameBit
);
1359 if (fodInfos
->initdir
== NULL
)
1360 MemFree(fodInfos
->initdir
);
1361 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1362 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1364 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1365 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1367 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1370 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1374 /* 2. (All platforms) If initdir is not null, then use it */
1375 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1376 (*fodInfos
->initdir
!=0x00))
1378 /* Work out the proper path as supplied one might be relative */
1379 /* (Here because supplying '.' as dir browses to My Computer) */
1380 if (handledPath
==FALSE
) {
1381 WCHAR tmpBuf
[MAX_PATH
];
1382 WCHAR tmpBuf2
[MAX_PATH
];
1386 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1387 if( PathFileExistsW(tmpBuf
) ) {
1388 /* initdir does not have to be a directory. If a file is
1389 * specified, the dir part is taken */
1390 if( PathIsDirectoryW(tmpBuf
)) {
1391 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1392 lstrcatW(tmpBuf
, szwSlash
);
1394 lstrcatW(tmpBuf
, szwStar
);
1396 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1399 MemFree(fodInfos
->initdir
);
1400 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1401 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1403 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1406 else if (fodInfos
->initdir
)
1408 MemFree(fodInfos
->initdir
);
1409 fodInfos
->initdir
= NULL
;
1410 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1415 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1416 (*fodInfos
->initdir
==0x00)))
1418 /* 3. All except w2k+: if filename contains a path use it */
1419 if (!win2000plus
&& fodInfos
->filename
&&
1420 *fodInfos
->filename
&&
1421 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1422 WCHAR tmpBuf
[MAX_PATH
];
1426 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1431 /* nameBit is always shorter than the original filename */
1432 lstrcpyW(fodInfos
->filename
, nameBit
);
1435 len
= lstrlenW(tmpBuf
);
1436 MemFree(fodInfos
->initdir
);
1437 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1438 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1441 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1442 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1444 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1447 /* 4. win98+ and win2000+ if any files of specified filter types in
1448 current directory, use it */
1449 if ( win98plus
&& handledPath
== FALSE
&&
1450 fodInfos
->filter
&& *fodInfos
->filter
) {
1452 BOOL searchMore
= TRUE
;
1453 LPCWSTR lpstrPos
= fodInfos
->filter
;
1454 WIN32_FIND_DATAW FindFileData
;
1459 /* filter is a list... title\0ext\0......\0\0 */
1461 /* Skip the title */
1462 if(! *lpstrPos
) break; /* end */
1463 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1465 /* See if any files exist in the current dir with this extension */
1466 if(! *lpstrPos
) break; /* end */
1468 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1470 if (hFind
== INVALID_HANDLE_VALUE
) {
1471 /* None found - continue search */
1472 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1477 MemFree(fodInfos
->initdir
);
1478 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1479 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1482 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1483 debugstr_w(lpstrPos
));
1489 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1491 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1492 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1493 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1495 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1497 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1500 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1501 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1503 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1506 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1509 } else if (handledPath
==FALSE
) {
1510 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1511 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1513 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1516 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1517 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1519 /* Must the open as read only check box be checked ?*/
1520 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1522 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1525 /* Must the open as read only check box be hidden? */
1526 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1528 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1529 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1532 /* Must the help button be hidden? */
1533 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1535 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1536 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1539 /* change Open to Save */
1540 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1543 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1544 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1545 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1546 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1549 /* Initialize the filter combo box */
1550 FILEDLG95_FILETYPE_Init(hwnd
);
1555 /***********************************************************************
1556 * FILEDLG95_ResizeControls
1558 * WM_INITDIALOG message handler (after hook notification)
1560 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1562 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1564 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1567 UINT flags
= SWP_NOACTIVATE
;
1569 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1570 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1572 /* resize the custom dialog to the parent size */
1573 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1574 GetClientRect(hwnd
, &rc
);
1577 /* our own fake template is zero sized and doesn't have children, so
1578 * there is no need to resize it. Picasa depends on it.
1580 flags
|= SWP_NOSIZE
;
1583 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1584 0, 0, rc
.right
, rc
.bottom
, flags
);
1588 /* Resize the height, if open as read only checkbox ad help button are
1589 * hidden and we are not using a custom template nor a customDialog
1591 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1592 (!(fodInfos
->ofnInfos
->Flags
&
1593 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1595 RECT rectDlg
, rectHelp
, rectCancel
;
1596 GetWindowRect(hwnd
, &rectDlg
);
1597 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1598 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1599 /* subtract the height of the help button plus the space between the help
1600 * button and the cancel button to the height of the dialog
1602 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1603 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1604 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1610 /***********************************************************************
1611 * FILEDLG95_FillControls
1613 * WM_INITDIALOG message handler (after hook notification)
1615 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1617 LPITEMIDLIST pidlItemId
= NULL
;
1619 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1621 TRACE("dir=%s file=%s\n",
1622 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1624 /* Get the initial directory pidl */
1626 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1628 WCHAR path
[MAX_PATH
];
1630 GetCurrentDirectoryW(MAX_PATH
,path
);
1631 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1634 /* Initialise shell objects */
1635 FILEDLG95_SHELL_Init(hwnd
);
1637 /* Initialize the Look In combo box */
1638 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1640 /* Browse to the initial directory */
1641 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1643 /* Free pidlItem memory */
1644 COMDLG32_SHFree(pidlItemId
);
1648 /***********************************************************************
1651 * Regroups all the cleaning functions of the filedlg
1653 void FILEDLG95_Clean(HWND hwnd
)
1655 FILEDLG95_FILETYPE_Clean(hwnd
);
1656 FILEDLG95_LOOKIN_Clean(hwnd
);
1657 FILEDLG95_SHELL_Clean(hwnd
);
1659 /***********************************************************************
1660 * FILEDLG95_OnWMCommand
1662 * WM_COMMAND message handler
1664 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1666 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1667 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1668 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1674 FILEDLG95_OnOpen(hwnd
);
1678 FILEDLG95_Clean(hwnd
);
1679 EndDialog(hwnd
, FALSE
);
1681 /* Filetype combo box */
1683 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1685 /* LookIn combo box */
1687 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1690 /* --- toolbar --- */
1691 /* Up folder button */
1692 case FCIDM_TB_UPFOLDER
:
1693 FILEDLG95_SHELL_UpFolder(hwnd
);
1695 /* New folder button */
1696 case FCIDM_TB_NEWFOLDER
:
1697 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1699 /* List option button */
1700 case FCIDM_TB_SMALLICON
:
1701 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1703 /* Details option button */
1704 case FCIDM_TB_REPORTVIEW
:
1705 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1707 /* Details option button */
1708 case FCIDM_TB_DESKTOP
:
1709 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1716 /* Do not use the listview selection anymore */
1717 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1721 /***********************************************************************
1722 * FILEDLG95_OnWMGetIShellBrowser
1724 * WM_GETISHELLBROWSER message handler
1726 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1728 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1732 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1738 /***********************************************************************
1739 * FILEDLG95_SendFileOK
1741 * Sends the CDN_FILEOK notification if required
1744 * TRUE if the dialog should close
1745 * FALSE if the dialog should not be closed
1747 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1749 /* ask the hook if we can close */
1750 if(IsHooked(fodInfos
))
1755 /* First send CDN_FILEOK as MSDN doc says */
1756 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1757 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1759 TRACE("canceled\n");
1760 return (retval
== 0);
1763 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1764 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1765 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1766 if (GetWindowLongPtrW(fodInfos
->DlgInfos
.hwndCustomDlg
, DWLP_MSGRESULT
))
1768 TRACE("canceled\n");
1769 return (retval
== 0);
1775 /***********************************************************************
1776 * FILEDLG95_OnOpenMultipleFiles
1778 * Handles the opening of multiple files.
1781 * check destination buffer size
1783 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1785 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1786 UINT nCount
, nSizePath
;
1787 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1791 if(fodInfos
->unicode
)
1793 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1794 ofn
->lpstrFile
[0] = '\0';
1798 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1799 ofn
->lpstrFile
[0] = '\0';
1802 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1804 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1805 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1806 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1808 LPWSTR lpstrTemp
= lpstrFileList
;
1810 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1814 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1817 WCHAR lpstrNotFound
[100];
1818 WCHAR lpstrMsg
[100];
1820 static const WCHAR nl
[] = {'\n',0};
1822 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1823 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1825 lstrcpyW(tmp
, lpstrTemp
);
1827 lstrcatW(tmp
, lpstrNotFound
);
1829 lstrcatW(tmp
, lpstrMsg
);
1831 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1835 /* move to the next file in the list of files */
1836 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1837 COMDLG32_SHFree(pidl
);
1841 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1842 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1844 /* For "oldstyle" dialog the components have to
1845 be separated by blanks (not '\0'!) and short
1846 filenames have to be used! */
1847 FIXME("Components have to be separated by blanks\n");
1849 if(fodInfos
->unicode
)
1851 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1852 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1853 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1857 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1859 if (ofn
->lpstrFile
!= NULL
)
1861 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1862 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1863 if (ofn
->nMaxFile
> nSizePath
)
1865 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1866 ofn
->lpstrFile
+ nSizePath
,
1867 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1872 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1873 fodInfos
->ofnInfos
->nFileExtension
= 0;
1875 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1878 /* clean and exit */
1879 FILEDLG95_Clean(hwnd
);
1880 return EndDialog(hwnd
,TRUE
);
1883 /***********************************************************************
1886 * Ok button WM_COMMAND message handler
1888 * If the function succeeds, the return value is nonzero.
1890 #define ONOPEN_BROWSE 1
1891 #define ONOPEN_OPEN 2
1892 #define ONOPEN_SEARCH 3
1893 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1895 WCHAR strMsgTitle
[MAX_PATH
];
1896 WCHAR strMsgText
[MAX_PATH
];
1898 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1900 strMsgTitle
[0] = '\0';
1901 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1902 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1905 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1907 LPWSTR lpstrFileList
;
1908 UINT nFileCount
= 0;
1911 WCHAR lpstrPathAndFile
[MAX_PATH
];
1912 WCHAR lpstrTemp
[MAX_PATH
];
1913 LPSHELLFOLDER lpsf
= NULL
;
1915 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1917 TRACE("hwnd=%p\n", hwnd
);
1919 /* get the files from the edit control */
1920 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1922 /* try if the user selected a folder in the shellview */
1925 BrowseSelectedFolder(hwnd
);
1931 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1935 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1938 Step 1: Build a complete path name from the current folder and
1939 the filename or path in the edit box.
1941 - the path in the edit box is a root path
1942 (with or without drive letter)
1943 - the edit box contains ".." (or a path with ".." in it)
1946 /* Get the current directory name */
1947 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1950 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1952 PathAddBackslashW(lpstrPathAndFile
);
1954 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1956 /* if the user specified a fully qualified path use it */
1957 if(PathIsRelativeW(lpstrFileList
))
1959 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
1963 /* does the path have a drive letter? */
1964 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1965 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1967 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
1970 /* resolve "." and ".." */
1971 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1972 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
1973 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1975 MemFree(lpstrFileList
);
1978 Step 2: here we have a cleaned up path
1980 We have to parse the path step by step to see if we have to browse
1981 to a folder if the path points to a directory or the last
1982 valid element is a directory.
1985 lpstrPathAndFile: cleaned up path
1989 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1990 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
1991 nOpenAction
= ONOPEN_OPEN
;
1993 nOpenAction
= ONOPEN_BROWSE
;
1995 /* don't apply any checks with OFN_NOVALIDATE */
1997 LPWSTR lpszTemp
, lpszTemp1
;
1998 LPITEMIDLIST pidl
= NULL
;
1999 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2001 /* check for invalid chars */
2002 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2004 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2009 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
2011 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2014 LPSHELLFOLDER lpsfChild
;
2015 WCHAR lpwstrTemp
[MAX_PATH
];
2016 DWORD dwEaten
, dwAttributes
;
2019 lstrcpyW(lpwstrTemp
, lpszTemp
);
2020 p
= PathFindNextComponentW(lpwstrTemp
);
2022 if (!p
) break; /* end of path */
2025 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2027 /* There are no wildcards when OFN_NOVALIDATE is set */
2028 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2030 static const WCHAR wszWild
[] = { '*', '?', 0 };
2031 /* if the last element is a wildcard do a search */
2032 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2034 nOpenAction
= ONOPEN_SEARCH
;
2038 lpszTemp1
= lpszTemp
;
2040 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
2042 /* append a backslash to drive letters */
2043 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2044 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2045 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2047 PathAddBackslashW(lpwstrTemp
);
2050 dwAttributes
= SFGAO_FOLDER
;
2051 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2053 /* the path component is valid, we have a pidl of the next path component */
2054 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2055 if(dwAttributes
& SFGAO_FOLDER
)
2057 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2059 ERR("bind to failed\n"); /* should not fail */
2062 IShellFolder_Release(lpsf
);
2070 /* end dialog, return value */
2071 nOpenAction
= ONOPEN_OPEN
;
2074 COMDLG32_SHFree(pidl
);
2077 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2079 if(*lpszTemp
|| /* points to trailing null for last path element */
2080 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2082 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
2084 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2090 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2091 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2093 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2097 /* change to the current folder */
2098 nOpenAction
= ONOPEN_OPEN
;
2103 nOpenAction
= ONOPEN_OPEN
;
2107 if(pidl
) COMDLG32_SHFree(pidl
);
2111 Step 3: here we have a cleaned up and validated path
2114 lpsf: ShellFolder bound to the rightmost valid path component
2115 lpstrPathAndFile: cleaned up path
2116 nOpenAction: action to do
2118 TRACE("end validate sf=%p\n", lpsf
);
2122 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2123 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2126 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2129 /* replace the current filter */
2130 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2131 len
= lstrlenW(lpszTemp
)+1;
2132 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2133 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2135 /* set the filter cb to the extension when possible */
2136 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2137 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2140 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2141 TRACE("ONOPEN_BROWSE\n");
2143 IPersistFolder2
* ppf2
;
2144 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2146 LPITEMIDLIST pidlCurrent
;
2147 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2148 IPersistFolder2_Release(ppf2
);
2149 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2151 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
)))
2153 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2156 else if( nOpenAction
== ONOPEN_SEARCH
)
2158 if (fodInfos
->Shell
.FOIShellView
)
2159 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2161 COMDLG32_SHFree(pidlCurrent
);
2162 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2167 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2168 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2172 /* update READONLY check box flag */
2173 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2174 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2176 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2178 /* Attach the file extension with file name*/
2179 ext
= PathFindExtensionW(lpstrPathAndFile
);
2182 /* if no extension is specified with file name, then */
2183 /* attach the extension from file filter or default one */
2185 WCHAR
*filterExt
= NULL
;
2186 LPWSTR lpstrFilter
= NULL
;
2187 static const WCHAR szwDot
[] = {'.',0};
2188 int PathLength
= lstrlenW(lpstrPathAndFile
);
2191 lstrcatW(lpstrPathAndFile
, szwDot
);
2193 /*Get the file extension from file type filter*/
2194 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2195 fodInfos
->ofnInfos
->nFilterIndex
-1);
2197 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2198 filterExt
= PathFindExtensionW(lpstrFilter
);
2200 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2201 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2202 else if ( fodInfos
->defext
) /* attach the default file extension*/
2203 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2205 /* In Open dialog: if file does not exist try without extension */
2206 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2207 lpstrPathAndFile
[PathLength
] = '\0';
2210 if (fodInfos
->defext
) /* add default extension */
2212 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2215 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2216 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2218 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2221 /* In Save dialog: check if the file already exists */
2222 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2223 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2224 && PathFileExistsW(lpstrPathAndFile
))
2226 WCHAR lpstrOverwrite
[100];
2229 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2230 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2231 MB_YESNO
| MB_ICONEXCLAMATION
);
2239 /* In Open dialog: check if it should be created if it doesn't exist */
2240 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2241 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2242 && !PathFileExistsW(lpstrPathAndFile
))
2244 WCHAR lpstrCreate
[100];
2247 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2248 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2249 MB_YESNO
| MB_ICONEXCLAMATION
);
2257 /* Check that the size of the file does not exceed buffer size.
2258 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2259 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2260 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2263 /* fill destination buffer */
2264 if (fodInfos
->ofnInfos
->lpstrFile
)
2266 if(fodInfos
->unicode
)
2268 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2270 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2271 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2272 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2276 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2278 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2279 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2280 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2281 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2285 if(fodInfos
->unicode
)
2289 /* set filename offset */
2290 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2291 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2293 /* set extension offset */
2294 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2295 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2300 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2302 /* set filename offset */
2303 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2304 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2306 /* set extension offset */
2307 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2308 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2311 /* set the lpstrFileTitle */
2312 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2314 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2315 if(fodInfos
->unicode
)
2317 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2318 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2322 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2323 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2324 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2328 /* copy currently selected filter to lpstrCustomFilter */
2329 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2331 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2332 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2333 NULL
, 0, NULL
, NULL
);
2334 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2336 LPSTR s
= ofn
->lpstrCustomFilter
;
2337 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2338 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2339 s
, len
, NULL
, NULL
);
2344 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2348 FILEDLG95_Clean(hwnd
);
2349 ret
= EndDialog(hwnd
, TRUE
);
2355 size
= lstrlenW(lpstrPathAndFile
) + 1;
2356 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2358 /* return needed size in first two bytes of lpstrFile */
2359 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2360 FILEDLG95_Clean(hwnd
);
2361 ret
= EndDialog(hwnd
, FALSE
);
2362 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2369 if(lpsf
) IShellFolder_Release(lpsf
);
2373 /***********************************************************************
2374 * FILEDLG95_SHELL_Init
2376 * Initialisation of the shell objects
2378 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2380 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2385 * Initialisation of the FileOpenDialogInfos structure
2391 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2393 /* Disable multi-select if flag not set */
2394 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2396 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2398 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2399 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2401 /* Construct the IShellBrowser interface */
2402 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2407 /***********************************************************************
2408 * FILEDLG95_SHELL_ExecuteCommand
2410 * Change the folder option and refresh the view
2411 * If the function succeeds, the return value is nonzero.
2413 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2415 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2418 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2420 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2425 CMINVOKECOMMANDINFO ci
;
2426 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2427 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2431 IContextMenu_InvokeCommand(pcm
, &ci
);
2432 IContextMenu_Release(pcm
);
2438 /***********************************************************************
2439 * FILEDLG95_SHELL_UpFolder
2441 * Browse to the specified object
2442 * If the function succeeds, the return value is nonzero.
2444 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2446 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2450 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2454 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2460 /***********************************************************************
2461 * FILEDLG95_SHELL_BrowseToDesktop
2463 * Browse to the Desktop
2464 * If the function succeeds, the return value is nonzero.
2466 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2468 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2474 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2475 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2476 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2477 COMDLG32_SHFree(pidl
);
2478 return SUCCEEDED(hres
);
2480 /***********************************************************************
2481 * FILEDLG95_SHELL_Clean
2483 * Cleans the memory used by shell objects
2485 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2487 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2491 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2493 /* clean Shell interfaces */
2494 if (fodInfos
->Shell
.FOIShellView
)
2496 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2497 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2499 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2500 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2501 if (fodInfos
->Shell
.FOIDataObject
)
2502 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2505 /***********************************************************************
2506 * FILEDLG95_FILETYPE_Init
2508 * Initialisation of the file type combo box
2510 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2512 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2513 int nFilters
= 0; /* number of filters */
2518 if(fodInfos
->customfilter
)
2520 /* customfilter has one entry... title\0ext\0
2521 * Set first entry of combo box item with customfilter
2524 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2527 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2529 /* Copy the extensions */
2530 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2531 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2532 lstrcpyW(lpstrExt
,lpstrPos
);
2534 /* Add the item at the end of the combo */
2535 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2536 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2539 if(fodInfos
->filter
)
2541 LPCWSTR lpstrPos
= fodInfos
->filter
;
2545 /* filter is a list... title\0ext\0......\0\0
2546 * Set the combo item text to the title and the item data
2549 LPCWSTR lpstrDisplay
;
2553 if(! *lpstrPos
) break; /* end */
2554 lpstrDisplay
= lpstrPos
;
2555 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2557 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2561 /* Copy the extensions */
2562 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2563 lstrcpyW(lpstrExt
,lpstrPos
);
2564 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2566 /* Add the item at the end of the combo */
2567 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2569 /* malformed filters are added anyway... */
2570 if (!*lpstrExt
) break;
2575 * Set the current filter to the one specified
2576 * in the initialisation structure
2578 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2582 /* Check to make sure our index isn't out of bounds. */
2583 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2584 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2585 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2587 /* set default filter index */
2588 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2589 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2591 /* calculate index of Combo Box item */
2592 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2593 if (fodInfos
->customfilter
== NULL
)
2596 /* Set the current index selection. */
2597 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2599 /* Get the corresponding text string from the combo box. */
2600 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2603 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2609 CharLowerW(lpstrFilter
); /* lowercase */
2610 len
= lstrlenW(lpstrFilter
)+1;
2611 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2612 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2615 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2619 /***********************************************************************
2620 * FILEDLG95_FILETYPE_OnCommand
2622 * WM_COMMAND of the file type combo box
2623 * If the function succeeds, the return value is nonzero.
2625 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2627 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2635 /* Get the current item of the filetype combo box */
2636 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2638 /* set the current filter index */
2639 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2640 (fodInfos
->customfilter
== NULL
? 1 : 0);
2642 /* Set the current filter with the current selection */
2643 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2645 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2647 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2650 CharLowerW(lpstrFilter
); /* lowercase */
2651 len
= lstrlenW(lpstrFilter
)+1;
2652 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2653 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2654 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2657 /* Refresh the actual view to display the included items*/
2658 if (fodInfos
->Shell
.FOIShellView
)
2659 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2664 /***********************************************************************
2665 * FILEDLG95_FILETYPE_SearchExt
2667 * searches for an extension in the filetype box
2669 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2671 int i
, iCount
= CBGetCount(hwnd
);
2673 TRACE("%s\n", debugstr_w(lpstrExt
));
2675 if(iCount
!= CB_ERR
)
2677 for(i
=0;i
<iCount
;i
++)
2679 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2686 /***********************************************************************
2687 * FILEDLG95_FILETYPE_Clean
2689 * Clean the memory used by the filetype combo box
2691 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2693 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2695 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2699 /* Delete each string of the combo and their associated data */
2700 if(iCount
!= CB_ERR
)
2702 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2704 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2705 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2708 /* Current filter */
2709 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2713 /***********************************************************************
2714 * FILEDLG95_LOOKIN_Init
2716 * Initialisation of the look in combo box
2719 /* Small helper function, to determine if the unixfs shell extension is rooted
2720 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2722 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2724 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2725 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2726 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2727 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2728 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2729 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2730 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2732 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2739 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2741 IShellFolder
*psfRoot
, *psfDrives
;
2742 IEnumIDList
*lpeRoot
, *lpeDrives
;
2743 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2745 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2749 liInfos
->iMaxIndentation
= 0;
2751 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
2753 /* set item height for both text field and listbox */
2754 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2755 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2757 /* Turn on the extended UI for the combo box like Windows does */
2758 CBSetExtendedUI(hwndCombo
, TRUE
);
2760 /* Initialise data of Desktop folder */
2761 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2762 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2763 COMDLG32_SHFree(pidlTmp
);
2765 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2767 SHGetDesktopFolder(&psfRoot
);
2771 /* enumerate the contents of the desktop */
2772 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2774 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2776 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2778 /* If the unixfs extension is rooted, we don't expand the drives by default */
2779 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2781 /* special handling for CSIDL_DRIVES */
2782 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2784 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2786 /* enumerate the drives */
2787 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2789 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2791 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2792 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2793 COMDLG32_SHFree(pidlAbsTmp
);
2794 COMDLG32_SHFree(pidlTmp1
);
2796 IEnumIDList_Release(lpeDrives
);
2798 IShellFolder_Release(psfDrives
);
2803 COMDLG32_SHFree(pidlTmp
);
2805 IEnumIDList_Release(lpeRoot
);
2807 IShellFolder_Release(psfRoot
);
2810 COMDLG32_SHFree(pidlDrives
);
2813 /***********************************************************************
2814 * FILEDLG95_LOOKIN_DrawItem
2816 * WM_DRAWITEM message handler
2818 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2820 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2821 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2822 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2826 HIMAGELIST ilItemImage
;
2829 LPSFOLDER tmpFolder
;
2830 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2834 if(pDIStruct
->itemID
== -1)
2837 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2838 pDIStruct
->itemID
)))
2842 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2844 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2848 SHGFI_PIDL
| SHGFI_SMALLICON
|
2849 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2850 SHGFI_DISPLAYNAME
);
2854 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2858 SHGFI_PIDL
| SHGFI_SMALLICON
|
2859 SHGFI_SYSICONINDEX
|
2863 /* Is this item selected ? */
2864 if(pDIStruct
->itemState
& ODS_SELECTED
)
2866 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2867 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2868 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2872 SetTextColor(pDIStruct
->hDC
,crText
);
2873 SetBkColor(pDIStruct
->hDC
,crWin
);
2874 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2877 /* Do not indent item if drawing in the edit of the combo */
2878 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2881 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2885 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2886 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2891 iIndentation
= tmpFolder
->m_iIndent
;
2893 /* Draw text and icon */
2895 /* Initialise the icon display area */
2896 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2897 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2898 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2899 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2901 /* Initialise the text display area */
2902 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2903 rectText
.left
= rectIcon
.right
;
2905 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2906 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2908 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2910 /* Draw the icon from the image list */
2911 ImageList_Draw(ilItemImage
,
2918 /* Draw the associated text */
2919 if(sfi
.szDisplayName
)
2920 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
2926 /***********************************************************************
2927 * FILEDLG95_LOOKIN_OnCommand
2929 * LookIn combo box WM_COMMAND message handler
2930 * If the function succeeds, the return value is nonzero.
2932 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2934 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2936 TRACE("%p\n", fodInfos
);
2942 LPSFOLDER tmpFolder
;
2945 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2947 if( iItem
== CB_ERR
) return FALSE
;
2949 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2954 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2955 tmpFolder
->pidlItem
,
2958 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2968 /***********************************************************************
2969 * FILEDLG95_LOOKIN_AddItem
2971 * Adds an absolute pidl item to the lookin combo box
2972 * returns the index of the inserted item
2974 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2976 LPITEMIDLIST pidlNext
;
2979 LookInInfos
*liInfos
;
2981 TRACE("%08x\n", iInsertId
);
2986 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
2989 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2990 tmpFolder
->m_iIndent
= 0;
2992 /* Calculate the indentation of the item in the lookin*/
2994 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2996 tmpFolder
->m_iIndent
++;
2999 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3001 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3002 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3004 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3005 SHGetFileInfoW((LPCWSTR
)pidl
,
3009 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3010 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3012 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3014 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3018 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3020 /* Add the item at the end of the list */
3023 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3025 /* Insert the item at the iInsertId position*/
3028 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3031 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3035 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3036 MemFree( tmpFolder
);
3041 /***********************************************************************
3042 * FILEDLG95_LOOKIN_InsertItemAfterParent
3044 * Insert an item below its parent
3046 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3049 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3054 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3058 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3061 /* Free pidlParent memory */
3062 COMDLG32_SHFree(pidlParent
);
3064 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3067 /***********************************************************************
3068 * FILEDLG95_LOOKIN_SelectItem
3070 * Adds an absolute pidl item to the lookin combo box
3071 * returns the index of the inserted item
3073 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3076 LookInInfos
*liInfos
;
3080 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3082 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3086 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3087 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3092 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3093 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3097 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3099 if(iRemovedItem
< iItemPos
)
3104 CBSetCurSel(hwnd
,iItemPos
);
3105 liInfos
->uSelectedItem
= iItemPos
;
3111 /***********************************************************************
3112 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3114 * Remove the item with an expansion level over iExpansionLevel
3116 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3119 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3123 if(liInfos
->iMaxIndentation
<= 2)
3126 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3128 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3129 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3131 CBDeleteString(hwnd
,iItemPos
);
3132 liInfos
->iMaxIndentation
--;
3140 /***********************************************************************
3141 * FILEDLG95_LOOKIN_SearchItem
3143 * Search for pidl in the lookin combo box
3144 * returns the index of the found item
3146 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3149 int iCount
= CBGetCount(hwnd
);
3151 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3153 if (iCount
!= CB_ERR
)
3157 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3159 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3161 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3169 /***********************************************************************
3170 * FILEDLG95_LOOKIN_Clean
3172 * Clean the memory used by the lookin combo box
3174 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3176 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3178 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3182 /* Delete each string of the combo and their associated data */
3183 if (iCount
!= CB_ERR
)
3185 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3187 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3188 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3190 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3194 /* LookInInfos structure */
3195 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3198 /***********************************************************************
3199 * FILEDLG95_FILENAME_FillFromSelection
3201 * fills the edit box from the cached DataObject
3203 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3205 FileOpenDlgInfos
*fodInfos
;
3207 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3208 WCHAR lpstrTemp
[MAX_PATH
];
3209 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3212 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3214 /* Count how many files we have */
3215 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3217 /* calculate the string length, count files */
3218 if (nFileSelected
>= 1)
3220 nLength
+= 3; /* first and last quotes, trailing \0 */
3221 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3223 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3227 /* get the total length of the selected file names */
3228 lpstrTemp
[0] = '\0';
3229 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3231 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3233 nLength
+= lstrlenW( lpstrTemp
) + 3;
3236 COMDLG32_SHFree( pidl
);
3241 /* allocate the buffer */
3242 if (nFiles
<= 1) nLength
= MAX_PATH
;
3243 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3245 /* Generate the string for the edit control */
3248 lpstrCurrFile
= lpstrAllFile
;
3249 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3251 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3255 /* get the file name */
3256 lpstrTemp
[0] = '\0';
3257 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3259 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3263 *lpstrCurrFile
++ = '\"';
3264 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3265 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3266 *lpstrCurrFile
++ = '\"';
3267 *lpstrCurrFile
++ = ' ';
3272 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3275 COMDLG32_SHFree( pidl
);
3278 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3280 /* Select the file name like Windows does */
3281 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3283 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3287 /* copied from shell32 to avoid linking to it
3288 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3289 * is dependent on whether emulated OS is unicode or not.
3291 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
3296 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3297 COMDLG32_SHFree(src
->u
.pOleStr
);
3301 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3306 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3311 FIXME("unknown type %x!\n", src
->uType
);
3312 if (len
) *dest
= '\0';
3318 /***********************************************************************
3319 * FILEDLG95_FILENAME_GetFileNames
3321 * Copies the filenames to a delimited string list.
3322 * The delimiter is specified by the parameter 'separator',
3323 * usually either a space or a nul
3325 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3327 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3328 UINT nStrCharCount
= 0; /* index in src buffer */
3329 UINT nFileIndex
= 0; /* index in dest buffer */
3330 UINT nFileCount
= 0; /* number of files */
3331 UINT nStrLen
= 0; /* length of string in edit control */
3332 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3336 /* get the filenames from the edit control */
3337 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3338 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3339 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3341 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3343 /* we might get single filename without any '"',
3344 * so we need nStrLen + terminating \0 + end-of-list \0 */
3345 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3348 /* build delimited file list from filenames */
3349 while ( nStrCharCount
<= nStrLen
)
3351 if ( lpstrEdit
[nStrCharCount
]=='"' )
3354 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3356 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3359 (*lpstrFileList
)[nFileIndex
++] = 0;
3365 /* single, unquoted string */
3366 if ((nStrLen
> 0) && (nFileIndex
== 0) )
3368 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3369 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3374 (*lpstrFileList
)[nFileIndex
++] = '\0';
3376 *sizeUsed
= nFileIndex
;
3381 #define SETDefFormatEtc(fe,cf,med) \
3383 (fe).cfFormat = cf;\
3384 (fe).dwAspect = DVASPECT_CONTENT; \
3391 * DATAOBJECT Helper functions
3394 /***********************************************************************
3395 * COMCTL32_ReleaseStgMedium
3397 * like ReleaseStgMedium from ole32
3399 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3401 if(medium
.pUnkForRelease
)
3403 IUnknown_Release(medium
.pUnkForRelease
);
3407 GlobalUnlock(medium
.u
.hGlobal
);
3408 GlobalFree(medium
.u
.hGlobal
);
3412 /***********************************************************************
3413 * GetPidlFromDataObject
3415 * Return pidl(s) by number from the cached DataObject
3417 * nPidlIndex=0 gets the fully qualified root path
3419 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3423 FORMATETC formatetc
;
3424 LPITEMIDLIST pidl
= NULL
;
3426 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3431 /* Set the FORMATETC structure*/
3432 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3434 /* Get the pidls from IDataObject */
3435 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3437 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3438 if(nPidlIndex
<= cida
->cidl
)
3440 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3442 COMCTL32_ReleaseStgMedium(medium
);
3447 /***********************************************************************
3450 * Return the number of selected items in the DataObject.
3453 static UINT
GetNumSelected( IDataObject
*doSelected
)
3457 FORMATETC formatetc
;
3459 TRACE("sv=%p\n", doSelected
);
3461 if (!doSelected
) return 0;
3463 /* Set the FORMATETC structure*/
3464 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3466 /* Get the pidls from IDataObject */
3467 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3469 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3470 retVal
= cida
->cidl
;
3471 COMCTL32_ReleaseStgMedium(medium
);
3481 /***********************************************************************
3484 * Get the pidl's display name (relative to folder) and
3485 * put it in lpstrFileName.
3487 * Return NOERROR on success,
3491 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3496 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3500 SHGetDesktopFolder(&lpsf
);
3501 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3502 IShellFolder_Release(lpsf
);
3506 /* Get the display name of the pidl relative to the folder */
3507 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3509 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3514 /***********************************************************************
3515 * GetShellFolderFromPidl
3517 * pidlRel is the item pidl relative
3518 * Return the IShellFolder of the absolute pidl
3520 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3522 IShellFolder
*psf
= NULL
,*psfParent
;
3524 TRACE("%p\n", pidlAbs
);
3526 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3529 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3531 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3533 IShellFolder_Release(psfParent
);
3537 /* return the desktop */
3543 /***********************************************************************
3546 * Return the LPITEMIDLIST to the parent of the pidl in the list
3548 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3550 LPITEMIDLIST pidlParent
;
3552 TRACE("%p\n", pidl
);
3554 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3555 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3560 /***********************************************************************
3563 * returns the pidl of the file name relative to folder
3564 * NULL if an error occurred
3566 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3568 LPITEMIDLIST pidl
= NULL
;
3571 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3573 if(!lpcstrFileName
) return NULL
;
3574 if(!*lpcstrFileName
) return NULL
;
3578 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3579 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3580 IShellFolder_Release(lpsf
);
3585 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3592 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3594 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3597 TRACE("%p, %p\n", psf
, pidl
);
3599 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3601 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3602 /* see documentation shell 4.1*/
3603 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3606 /***********************************************************************
3607 * BrowseSelectedFolder
3609 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3611 BOOL bBrowseSelFolder
= FALSE
;
3612 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3616 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3618 LPITEMIDLIST pidlSelection
;
3620 /* get the file selected */
3621 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3622 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3624 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3625 pidlSelection
, SBSP_RELATIVE
) ) )
3627 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3628 ' ','n','o','t',' ','e','x','i','s','t',0};
3629 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3631 bBrowseSelFolder
= TRUE
;
3632 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3634 COMDLG32_SHFree( pidlSelection
);
3637 return bBrowseSelFolder
;
3641 * Memory allocation methods */
3642 static void *MemAlloc(UINT size
)
3644 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3647 static void MemFree(void *mem
)
3649 HeapFree(GetProcessHeap(),0,mem
);
3653 * Old-style (win3.1) dialogs */
3655 /***********************************************************************
3656 * FD32_GetTemplate [internal]
3658 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3659 * by a 32 bits application
3662 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3664 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3665 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3668 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3670 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3672 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3676 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3680 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3681 priv
->ofnA
->lpTemplateName
,
3684 hResInfo
= FindResourceW(ofnW
->hInstance
,
3685 ofnW
->lpTemplateName
,
3689 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3692 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3694 !(lfs
->template = LockResource(hDlgTmpl
)))
3696 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3699 } else { /* get it from internal Wine resource */
3701 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3702 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3704 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3707 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3708 !(lfs
->template = LockResource( hDlgTmpl
)))
3710 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3718 /************************************************************************
3719 * FD32_Init [internal]
3720 * called from the common 16/32 code to initialize 32 bit data
3722 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3724 BOOL IsUnicode
= (BOOL
) data
;
3727 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3728 lfs
->private1632
= priv
;
3729 if (NULL
== lfs
->private1632
) return FALSE
;
3732 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3733 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3734 if (lfs
->ofnW
->lpfnHook
)
3739 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3740 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3741 if (priv
->ofnA
->lpfnHook
)
3743 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3744 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3747 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3752 /***********************************************************************
3753 * FD32_CallWindowProc [internal]
3755 * called from the common 16/32 code to call the appropriate hook
3757 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3761 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3765 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3766 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3767 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3768 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3769 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3773 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3774 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3775 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3776 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3777 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3781 /***********************************************************************
3782 * FD32_UpdateResult [internal]
3783 * update the real client structures if any
3785 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3787 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3788 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3793 if (ofnW
->nMaxFile
&&
3794 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3795 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3796 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3798 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3799 /* set filename offset */
3800 lpszTemp
= PathFindFileNameA(priv
->ofnA
->lpstrFile
);
3801 priv
->ofnA
->nFileOffset
= (lpszTemp
- priv
->ofnA
->lpstrFile
);
3803 /* set extension offset */
3804 lpszTemp
= PathFindExtensionA(priv
->ofnA
->lpstrFile
);
3805 priv
->ofnA
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- priv
->ofnA
->lpstrFile
) + 1 : 0;
3809 /***********************************************************************
3810 * FD32_UpdateFileTitle [internal]
3811 * update the real client structures if any
3813 static void CALLBACK
FD32_UpdateFileTitle(const FD31_DATA
*lfs
)
3815 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3816 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3820 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3821 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3822 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3827 /***********************************************************************
3828 * FD32_SendLbGetCurSel [internal]
3829 * retrieve selected listbox item
3831 static LRESULT CALLBACK
FD32_SendLbGetCurSel(const FD31_DATA
*lfs
)
3833 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3837 /************************************************************************
3838 * FD32_Destroy [internal]
3839 * called from the common 16/32 code to cleanup 32 bit data
3841 static void CALLBACK
FD32_Destroy(const FD31_DATA
*lfs
)
3843 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3845 /* if ofnW has been allocated, have to free everything in it */
3846 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3848 FD31_FreeOfnW(lfs
->ofnW
);
3849 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3853 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3855 callbacks
->Init
= FD32_Init
;
3856 callbacks
->CWP
= FD32_CallWindowProc
;
3857 callbacks
->UpdateResult
= FD32_UpdateResult
;
3858 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3859 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3860 callbacks
->Destroy
= FD32_Destroy
;
3863 /***********************************************************************
3864 * FD32_WMMeasureItem [internal]
3866 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3868 LPMEASUREITEMSTRUCT lpmeasure
;
3870 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3871 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3876 /***********************************************************************
3877 * FileOpenDlgProc [internal]
3878 * Used for open and save, in fact.
3880 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3881 WPARAM wParam
, LPARAM lParam
)
3883 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3885 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
3886 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3889 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3891 return lRet
; /* else continue message processing */
3896 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3898 case WM_MEASUREITEM
:
3899 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3902 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3905 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3908 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3909 switch (HIWORD(lParam
))
3912 SetTextColor((HDC16
)wParam
, 0x00000000);
3914 case CTLCOLOR_STATIC
:
3915 SetTextColor((HDC16
)wParam
, 0x00000000);
3925 /***********************************************************************
3926 * GetFileName31A [internal]
3928 * Creates a win31 style dialog box for the user to select a file to open/save.
3930 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
3931 UINT dlgType
/* type dialogue : open/save */
3937 FD31_CALLBACKS callbacks
;
3939 if (!lpofn
|| !FD31_Init()) return FALSE
;
3941 TRACE("ofn flags %08x\n", lpofn
->Flags
);
3942 FD32_SetupCallbacks(&callbacks
);
3943 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
3946 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3947 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
3948 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3949 FD31_DestroyPrivate(lfs
);
3952 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
3956 /***********************************************************************
3957 * GetFileName31W [internal]
3959 * Creates a win31 style dialog box for the user to select a file to open/save
3961 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
3962 UINT dlgType
/* type dialogue : open/save */
3968 FD31_CALLBACKS callbacks
;
3970 if (!lpofn
|| !FD31_Init()) return FALSE
;
3972 FD32_SetupCallbacks(&callbacks
);
3973 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
3976 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
3977 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
3978 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
3979 FD31_DestroyPrivate(lfs
);
3982 TRACE("file %s, file offset %d, ext offset %d\n",
3983 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
3987 /* ------------------ APIs ---------------------- */
3989 /***********************************************************************
3990 * GetOpenFileNameA (COMDLG32.@)
3992 * Creates a dialog box for the user to select a file to open.
3995 * TRUE on success: user enters a valid file
3996 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3999 BOOL WINAPI
GetOpenFileNameA(
4000 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4002 BOOL win16look
= FALSE
;
4004 TRACE("flags %08x\n", ofn
->Flags
);
4006 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4007 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4008 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4010 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4011 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4014 return GetFileName31A(ofn
, OPEN_DIALOG
);
4016 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4019 /***********************************************************************
4020 * GetOpenFileNameW (COMDLG32.@)
4022 * Creates a dialog box for the user to select a file to open.
4025 * TRUE on success: user enters a valid file
4026 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4029 BOOL WINAPI
GetOpenFileNameW(
4030 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4032 BOOL win16look
= FALSE
;
4034 TRACE("flags %08x\n", ofn
->Flags
);
4036 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4037 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4038 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4040 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4041 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4044 return GetFileName31W(ofn
, OPEN_DIALOG
);
4046 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4050 /***********************************************************************
4051 * GetSaveFileNameA (COMDLG32.@)
4053 * Creates a dialog box for the user to select a file to save.
4056 * TRUE on success: user enters a valid file
4057 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4060 BOOL WINAPI
GetSaveFileNameA(
4061 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4063 BOOL win16look
= FALSE
;
4065 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4066 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4069 return GetFileName31A(ofn
, SAVE_DIALOG
);
4071 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4074 /***********************************************************************
4075 * GetSaveFileNameW (COMDLG32.@)
4077 * Creates a dialog box for the user to select a file to save.
4080 * TRUE on success: user enters a valid file
4081 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4084 BOOL WINAPI
GetSaveFileNameW(
4085 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4087 BOOL win16look
= FALSE
;
4089 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4090 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4093 return GetFileName31W(ofn
, SAVE_DIALOG
);
4095 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4098 /***********************************************************************
4099 * GetFileTitleA (COMDLG32.@)
4101 * See GetFileTitleW.
4103 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4106 UNICODE_STRING strWFile
;
4109 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4110 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4111 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4112 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4113 RtlFreeUnicodeString( &strWFile
);
4114 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4119 /***********************************************************************
4120 * GetFileTitleW (COMDLG32.@)
4122 * Get the name of a file.
4125 * lpFile [I] name and location of file
4126 * lpTitle [O] returned file name
4127 * cbBuf [I] buffer size of lpTitle
4131 * Failure: negative number.
4133 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4136 static const WCHAR brkpoint
[] = {'*','[',']',0};
4137 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4139 if(lpFile
== NULL
|| lpTitle
== NULL
)
4142 len
= lstrlenW(lpFile
);
4147 if(strpbrkW(lpFile
, brkpoint
))
4152 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4155 for(i
= len
; i
>= 0; i
--)
4157 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4167 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4169 len
= lstrlenW(lpFile
+i
)+1;
4173 lstrcpyW(lpTitle
, &lpFile
[i
]);