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 */
175 static SIZE MemDialogSize
= { 0, 0}; /* keep size of the (resizable) dialog */
177 /***********************************************************************
181 /* Internal functions used by the dialog */
182 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
183 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
184 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
185 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
186 static BOOL
FILEDLG95_OnOpen(HWND hwnd
);
187 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
188 static void FILEDLG95_Clean(HWND hwnd
);
190 /* Functions used by the shell navigation */
191 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
192 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
193 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
195 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
);
200 /* Functions used by the filetype combo box */
201 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
202 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
208 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
209 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
217 /* Miscellaneous tool functions */
218 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
);
219 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
220 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
221 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
222 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
);
223 static UINT
GetNumSelected( IDataObject
*doSelected
);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size
);
227 static void MemFree(void *mem
);
229 static INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
230 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
231 static BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
232 static BOOL
BrowseSelectedFolder(HWND hwnd
);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL
GetFileName95(FileOpenDlgInfos
*fodInfos
)
253 /* test for missing functionality */
254 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
260 /* Create the dialog from a template */
262 if(!(hRes
= FindResourceW(COMDLG32_hInstance
,MAKEINTRESOURCEW(NEWFILEOPENORD
),(LPCWSTR
)RT_DIALOG
)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
267 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hRes
)) ||
268 !(template = LockResource( hDlgTmpl
)))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
274 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
276 ((LPDLGTEMPLATEW
)template)->style
|= WS_SIZEBOX
;
277 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
278 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
281 ((LPDLGTEMPLATEW
)template)->style
&= ~WS_SIZEBOX
;
284 /* old style hook messages */
285 if (IsHooked(fodInfos
))
287 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
288 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
289 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
290 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
293 /* Some shell namespace extensions depend on COM being initialized. */
294 hr
= OleInitialize(NULL
);
296 if (fodInfos
->unicode
)
297 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
299 fodInfos
->ofnInfos
->hwndOwner
,
303 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
305 fodInfos
->ofnInfos
->hwndOwner
,
311 /* Unable to create the dialog */
318 /***********************************************************************
321 * Call GetFileName95 with this structure and clean the memory.
323 * IN : The OPENFILENAMEA initialisation structure passed to
324 * GetOpenFileNameA win api function (see filedlg.c)
326 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
329 FileOpenDlgInfos fodInfos
;
330 LPSTR lpstrSavDir
= NULL
;
332 LPWSTR defext
= NULL
;
333 LPWSTR filter
= NULL
;
334 LPWSTR customfilter
= NULL
;
336 /* Initialize CommDlgExtendedError() */
337 COMDLG32_SetCommDlgExtendedError(0);
339 /* Initialize FileOpenDlgInfos structure */
340 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
342 /* Pass in the original ofn */
343 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
345 /* save current directory */
346 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
348 lpstrSavDir
= MemAlloc(MAX_PATH
);
349 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
352 fodInfos
.unicode
= FALSE
;
354 /* convert all the input strings to unicode */
355 if(ofn
->lpstrInitialDir
)
357 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
358 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
359 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
362 fodInfos
.initdir
= NULL
;
366 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
367 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
370 fodInfos
.filename
= NULL
;
374 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
375 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
376 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
378 fodInfos
.defext
= defext
;
382 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
383 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
384 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
386 fodInfos
.title
= title
;
388 if (ofn
->lpstrFilter
)
393 /* filter is a list... title\0ext\0......\0\0 */
394 s
= ofn
->lpstrFilter
;
395 while (*s
) s
= s
+strlen(s
)+1;
397 n
= s
- ofn
->lpstrFilter
;
398 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
399 filter
= MemAlloc(len
*sizeof(WCHAR
));
400 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
402 fodInfos
.filter
= filter
;
404 /* convert lpstrCustomFilter */
405 if (ofn
->lpstrCustomFilter
)
410 /* customfilter contains a pair of strings... title\0ext\0 */
411 s
= ofn
->lpstrCustomFilter
;
412 if (*s
) s
= s
+strlen(s
)+1;
413 if (*s
) s
= s
+strlen(s
)+1;
414 n
= s
- ofn
->lpstrCustomFilter
;
415 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
416 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
417 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
419 fodInfos
.customfilter
= customfilter
;
421 /* Initialize the dialog property */
422 fodInfos
.DlgInfos
.dwDlgProp
= 0;
423 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
428 ret
= GetFileName95(&fodInfos
);
431 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
432 ret
= GetFileName95(&fodInfos
);
440 SetCurrentDirectoryA(lpstrSavDir
);
441 MemFree(lpstrSavDir
);
447 MemFree(customfilter
);
448 MemFree(fodInfos
.initdir
);
449 MemFree(fodInfos
.filename
);
451 TRACE("selected file: %s\n",ofn
->lpstrFile
);
456 /***********************************************************************
459 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
460 * Call GetFileName95 with this structure and clean the memory.
463 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
466 FileOpenDlgInfos fodInfos
;
467 LPWSTR lpstrSavDir
= NULL
;
469 /* Initialize CommDlgExtendedError() */
470 COMDLG32_SetCommDlgExtendedError(0);
472 /* Initialize FileOpenDlgInfos structure */
473 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
475 /* Pass in the original ofn */
476 fodInfos
.ofnInfos
= ofn
;
478 fodInfos
.title
= ofn
->lpstrTitle
;
479 fodInfos
.defext
= ofn
->lpstrDefExt
;
480 fodInfos
.filter
= ofn
->lpstrFilter
;
481 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
483 /* convert string arguments, save others */
486 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
487 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
490 fodInfos
.filename
= NULL
;
492 if(ofn
->lpstrInitialDir
)
494 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
495 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
496 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
497 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
500 fodInfos
.initdir
= NULL
;
502 /* save current directory */
503 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
505 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
506 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
509 fodInfos
.unicode
= TRUE
;
514 ret
= GetFileName95(&fodInfos
);
517 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
518 ret
= GetFileName95(&fodInfos
);
526 SetCurrentDirectoryW(lpstrSavDir
);
527 MemFree(lpstrSavDir
);
530 /* restore saved IN arguments and convert OUT arguments back */
531 MemFree(fodInfos
.filename
);
532 MemFree(fodInfos
.initdir
);
536 /******************************************************************************
537 * COMDLG32_GetDisplayNameOf [internal]
539 * Helper function to get the display name for a pidl.
541 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
542 LPSHELLFOLDER psfDesktop
;
545 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
548 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
549 IShellFolder_Release(psfDesktop
);
553 IShellFolder_Release(psfDesktop
);
554 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
557 /***********************************************************************
558 * ArrangeCtrlPositions [internal]
560 * NOTE: Make sure to add testcases for any changes made here.
562 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
564 HWND hwndChild
, hwndStc32
;
565 RECT rectParent
, rectChild
, rectStc32
;
569 /* Take into account if open as read only checkbox and help button
574 RECT rectHelp
, rectCancel
;
575 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
576 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
577 /* subtract the height of the help button plus the space between
578 * the help button and the cancel button to the height of the dialog
580 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
584 There are two possibilities to add components to the default file dialog box.
586 By default, all the new components are added below the standard dialog box (the else case).
588 However, if there is a static text component with the stc32 id, a special case happens.
589 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
590 in the window and the cx and cy indicate how to size the window.
591 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
592 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
596 GetClientRect(hwndParentDlg
, &rectParent
);
598 /* when arranging controls we have to use fixed parent size */
599 rectParent
.bottom
-= help_fixup
;
601 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
604 GetWindowRect(hwndStc32
, &rectStc32
);
605 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
607 /* set the size of the stc32 control according to the size of
608 * client area of the parent dialog
610 SetWindowPos(hwndStc32
, 0,
612 rectParent
.right
, rectParent
.bottom
,
613 SWP_NOMOVE
| SWP_NOZORDER
);
616 SetRectEmpty(&rectStc32
);
618 /* this part moves controls of the child dialog */
619 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
622 if (hwndChild
!= hwndStc32
)
624 GetWindowRect(hwndChild
, &rectChild
);
625 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
627 /* move only if stc32 exist */
628 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
630 /* move to the right of visible controls of the parent dialog */
631 rectChild
.left
+= rectParent
.right
;
632 rectChild
.left
-= rectStc32
.right
;
634 /* move even if stc32 doesn't exist */
635 if (rectChild
.top
>= rectStc32
.bottom
)
637 /* move below visible controls of the parent dialog */
638 rectChild
.top
+= rectParent
.bottom
;
639 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
642 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
643 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
645 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
648 /* this part moves controls of the parent dialog */
649 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
652 if (hwndChild
!= hwndChildDlg
)
654 GetWindowRect(hwndChild
, &rectChild
);
655 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
657 /* left,top of stc32 marks the position of controls
658 * from the parent dialog
660 rectChild
.left
+= rectStc32
.left
;
661 rectChild
.top
+= rectStc32
.top
;
663 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
664 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
666 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
669 /* calculate the size of the resulting dialog */
671 /* here we have to use original parent size */
672 GetClientRect(hwndParentDlg
, &rectParent
);
673 GetClientRect(hwndChildDlg
, &rectChild
);
674 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
675 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
680 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
681 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
683 chgx
= rectChild
.right
- rectParent
.right
;
685 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
686 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
688 /* Unconditionally set new dialog
689 * height to that of the child
691 chgy
= rectChild
.bottom
- rectParent
.bottom
;
696 chgy
= rectChild
.bottom
- help_fixup
;
698 /* set the size of the parent dialog */
699 GetWindowRect(hwndParentDlg
, &rectParent
);
700 SetWindowPos(hwndParentDlg
, 0,
702 rectParent
.right
- rectParent
.left
+ chgx
,
703 rectParent
.bottom
- rectParent
.top
+ chgy
,
704 SWP_NOMOVE
| SWP_NOZORDER
);
707 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
716 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
726 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
727 * structure's hInstance parameter is not a HINSTANCE, but
728 * instead a pointer to a template resource to use.
730 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
733 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
735 hinst
= COMDLG32_hInstance
;
736 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
738 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
744 hinst
= fodInfos
->ofnInfos
->hInstance
;
745 if(fodInfos
->unicode
)
747 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
748 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
752 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
753 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
757 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
760 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
761 !(template = LockResource( hDlgTmpl
)))
763 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
767 if (fodInfos
->unicode
)
768 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
769 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
770 (LPARAM
)fodInfos
->ofnInfos
);
772 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
773 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
774 (LPARAM
)fodInfos
->ofnInfos
);
777 else if( IsHooked(fodInfos
))
782 WORD menu
,class,title
;
784 GetClientRect(hwnd
,&rectHwnd
);
785 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
786 temp
.tmplate
.dwExtendedStyle
= 0;
787 temp
.tmplate
.cdit
= 0;
792 temp
.menu
= temp
.class = temp
.title
= 0;
794 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
795 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
802 /***********************************************************************
803 * SendCustomDlgNotificationMessage
805 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
808 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
810 LRESULT hook_result
= 0;
811 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
813 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
815 if(!fodInfos
) return 0;
817 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
819 TRACE("CALL NOTIFY for %x\n", uCode
);
820 if(fodInfos
->unicode
)
823 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
824 ofnNotify
.hdr
.idFrom
=0;
825 ofnNotify
.hdr
.code
= uCode
;
826 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
827 ofnNotify
.pszFile
= NULL
;
828 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
833 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
834 ofnNotify
.hdr
.idFrom
=0;
835 ofnNotify
.hdr
.code
= uCode
;
836 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
837 ofnNotify
.pszFile
= NULL
;
838 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
840 TRACE("RET NOTIFY\n");
842 TRACE("Retval: 0x%08lx\n", hook_result
);
846 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
850 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
852 TRACE("CDM_GETFILEPATH:\n");
854 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
857 /* get path and filenames */
858 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
859 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
860 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
863 p
= buffer
+ strlenW(buffer
);
865 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
867 if (fodInfos
->unicode
)
869 total
= strlenW( buffer
) + 1;
870 if (result
) lstrcpynW( result
, buffer
, size
);
871 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
875 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
876 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
877 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
879 HeapFree( GetProcessHeap(), 0, buffer
);
883 /***********************************************************************
884 * FILEDLG95_HandleCustomDialogMessages
886 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
888 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
890 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
891 WCHAR lpstrPath
[MAX_PATH
];
894 if(!fodInfos
) return FALSE
;
898 case CDM_GETFILEPATH
:
899 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
902 case CDM_GETFOLDERPATH
:
903 TRACE("CDM_GETFOLDERPATH:\n");
904 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
907 if (fodInfos
->unicode
)
908 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
910 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
911 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
913 retval
= lstrlenW(lpstrPath
) + 1;
916 case CDM_GETFOLDERIDLIST
:
917 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
918 if (retval
<= wParam
)
919 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
923 TRACE("CDM_GETSPEC:\n");
924 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
927 if (fodInfos
->unicode
)
928 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
930 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
934 case CDM_SETCONTROLTEXT
:
935 TRACE("CDM_SETCONTROLTEXT:\n");
938 if( fodInfos
->unicode
)
939 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
941 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
946 case CDM_HIDECONTROL
:
947 /* MSDN states that it should fail for not OFN_EXPLORER case */
948 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
950 HWND control
= GetDlgItem( hwnd
, wParam
);
951 if (control
) ShowWindow( control
, SW_HIDE
);
958 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
959 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
962 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
966 /***********************************************************************
967 * FILEDLG95_OnWMGetMMI
969 * WM_GETMINMAXINFO message handler for resizable dialogs
971 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
973 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
974 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
975 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
977 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
982 /***********************************************************************
985 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
987 * FIXME: this could be made more elaborate. Now use a simple scheme
988 * where the file view is enlarged and the controls are either moved
989 * vertically or horizontally to get out of the way. Only the "grip"
990 * is moved in both directions to stay in the corner.
992 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
998 FileOpenDlgInfos
*fodInfos
;
1000 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1001 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1002 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1003 /* get the new dialog rectangle */
1004 GetWindowRect( hwnd
, &rc
);
1005 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1006 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1007 /* not initialized yet */
1008 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1009 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1010 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1012 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1013 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1014 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1015 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1016 /* change the size of the view window */
1017 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1018 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1019 hdwp
= BeginDeferWindowPos( 10);
1020 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1021 rcview
.right
- rcview
.left
+ chgx
,
1022 rcview
.bottom
- rcview
.top
+ chgy
,
1023 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1024 /* change position and sizes of the controls */
1025 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1027 int ctrlid
= GetDlgCtrlID( ctrl
);
1028 GetWindowRect( ctrl
, &rc
);
1029 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1030 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1032 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1034 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1036 else if( rc
.top
> rcview
.bottom
)
1038 /* if it was below the shell view
1042 /* file name box and file types combo change also width */
1045 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1046 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1047 SWP_NOACTIVATE
| SWP_NOZORDER
);
1049 /* then these buttons must move out of the way */
1053 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1055 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1058 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1060 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1063 else if( rc
.left
> rcview
.right
)
1065 /* if it was to the right of the shell view
1067 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1069 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1076 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1078 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1079 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1080 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1082 case IDC_TOOLBARSTATIC
:
1084 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1086 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1089 /* not resized in windows. Since wine uses this invisible control
1090 * to size the browser view it needs to be resized */
1091 case IDC_SHELLSTATIC
:
1092 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1093 rc
.right
- rc
.left
+ chgx
,
1094 rc
.bottom
- rc
.top
+ chgy
,
1095 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1100 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1101 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1103 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1104 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1106 GetWindowRect( ctrl
, &rc
);
1107 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1108 if( rc
.top
> rcview
.bottom
)
1110 /* if it was below the shell view
1112 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1113 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1114 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1116 else if( rc
.left
> rcview
.right
)
1118 /* if it was to the right of the shell view
1120 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1121 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1122 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1125 /* size the custom dialog at the end: some applications do some
1126 * control re-arranging at this point */
1127 GetClientRect(hwnd
, &rc
);
1128 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1129 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1131 EndDeferWindowPos( hdwp
);
1132 /* should not be needed */
1133 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1137 /***********************************************************************
1140 * File open dialog procedure
1142 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1145 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1152 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1154 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1155 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1157 /* Adds the FileOpenDlgInfos in the property list of the dialog
1158 so it will be easily accessible through a GetPropA(...) */
1159 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1161 FILEDLG95_InitControls(hwnd
);
1163 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1165 GetWindowRect( hwnd
, &rc
);
1166 fodInfos
->DlgInfos
.hwndGrip
=
1167 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1168 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1169 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1170 rc
.right
- gripx
, rc
.bottom
- gripy
,
1171 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1174 fodInfos
->DlgInfos
.hwndCustomDlg
=
1175 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1177 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1178 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1180 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1181 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1183 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1184 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1185 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1188 /* if the app has changed the position of the invisible listbox,
1189 * change that of the listview (browser) as well */
1190 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1191 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1192 if( !EqualRect( &rc
, &rcstc
))
1194 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1195 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1196 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1197 SWP_NOACTIVATE
| SWP_NOZORDER
);
1200 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1202 GetWindowRect( hwnd
, &rc
);
1203 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1204 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1205 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1206 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1207 GetClientRect( hwnd
, &rc
);
1208 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1209 rc
.right
- gripx
, rc
.bottom
- gripy
,
1210 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1211 /* resize the dialog to the previous invocation */
1212 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1213 SetWindowPos( hwnd
, NULL
,
1214 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1215 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1218 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1219 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1224 return FILEDLG95_OnWMSize(hwnd
, wParam
, lParam
);
1225 case WM_GETMINMAXINFO
:
1226 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1228 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1231 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1234 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1240 case WM_GETISHELLBROWSER
:
1241 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1245 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1246 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1247 MemDialogSize
= fodInfos
->sizedlg
;
1248 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1253 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1256 /* set up the button tooltips strings */
1257 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1259 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1260 switch(lpnmh
->idFrom
)
1262 /* Up folder button */
1263 case FCIDM_TB_UPFOLDER
:
1264 stringId
= IDS_UPFOLDER
;
1266 /* New folder button */
1267 case FCIDM_TB_NEWFOLDER
:
1268 stringId
= IDS_NEWFOLDER
;
1270 /* List option button */
1271 case FCIDM_TB_SMALLICON
:
1272 stringId
= IDS_LISTVIEW
;
1274 /* Details option button */
1275 case FCIDM_TB_REPORTVIEW
:
1276 stringId
= IDS_REPORTVIEW
;
1278 /* Desktop button */
1279 case FCIDM_TB_DESKTOP
:
1280 stringId
= IDS_TODESKTOP
;
1285 lpdi
->hinst
= COMDLG32_hInstance
;
1286 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1291 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1292 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1297 /***********************************************************************
1298 * FILEDLG95_InitControls
1300 * WM_INITDIALOG message handler (before hook notification)
1302 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1304 int win2000plus
= 0;
1306 int handledPath
= FALSE
;
1307 OSVERSIONINFOW osVi
;
1308 static const WCHAR szwSlash
[] = { '\\', 0 };
1309 static const WCHAR szwStar
[] = { '*',0 };
1311 static const TBBUTTON tbb
[] =
1313 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1314 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1315 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1316 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1317 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1318 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1319 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1320 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1321 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1326 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1328 tba
[0].hInst
= HINST_COMMCTRL
;
1329 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1330 tba
[1].hInst
= COMDLG32_hInstance
;
1333 TRACE("%p\n", fodInfos
);
1335 /* Get windows version emulating */
1336 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1337 GetVersionExW(&osVi
);
1338 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1339 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1340 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1341 win2000plus
= (osVi
.dwMajorVersion
> 4);
1342 if (win2000plus
) win98plus
= TRUE
;
1344 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1346 /* Get the hwnd of the controls */
1347 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1348 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1349 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1351 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1352 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1354 /* construct the toolbar */
1355 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1356 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1358 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1359 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1360 rectTB
.left
= rectlook
.right
;
1361 rectTB
.top
= rectlook
.top
-1;
1363 if (fodInfos
->unicode
)
1364 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1365 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1366 rectTB
.left
, rectTB
.top
,
1367 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1368 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1370 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1371 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1372 rectTB
.left
, rectTB
.top
,
1373 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1374 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1376 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1378 /* FIXME: use TB_LOADIMAGES when implemented */
1379 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1380 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1381 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
[0]);
1382 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 1, (LPARAM
) &tba
[1]);
1384 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1385 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1387 /* Set the window text with the text specified in the OPENFILENAME structure */
1390 SetWindowTextW(hwnd
,fodInfos
->title
);
1392 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1395 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1396 SetWindowTextW(hwnd
, buf
);
1399 /* Initialise the file name edit control */
1400 handledPath
= FALSE
;
1401 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1403 if(fodInfos
->filename
)
1405 /* 1. If win2000 or higher and filename contains a path, use it
1406 in preference over the lpstrInitialDir */
1407 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1408 WCHAR tmpBuf
[MAX_PATH
];
1412 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1415 /* nameBit is always shorter than the original filename */
1416 lstrcpyW(fodInfos
->filename
,nameBit
);
1419 if (fodInfos
->initdir
== NULL
)
1420 MemFree(fodInfos
->initdir
);
1421 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1422 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1424 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1425 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1427 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1430 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1434 /* 2. (All platforms) If initdir is not null, then use it */
1435 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1436 (*fodInfos
->initdir
!=0x00))
1438 /* Work out the proper path as supplied one might be relative */
1439 /* (Here because supplying '.' as dir browses to My Computer) */
1440 if (handledPath
==FALSE
) {
1441 WCHAR tmpBuf
[MAX_PATH
];
1442 WCHAR tmpBuf2
[MAX_PATH
];
1446 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1447 if( PathFileExistsW(tmpBuf
) ) {
1448 /* initdir does not have to be a directory. If a file is
1449 * specified, the dir part is taken */
1450 if( PathIsDirectoryW(tmpBuf
)) {
1451 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1452 lstrcatW(tmpBuf
, szwSlash
);
1454 lstrcatW(tmpBuf
, szwStar
);
1456 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1459 MemFree(fodInfos
->initdir
);
1460 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1461 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1463 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1466 else if (fodInfos
->initdir
)
1468 MemFree(fodInfos
->initdir
);
1469 fodInfos
->initdir
= NULL
;
1470 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1475 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1476 (*fodInfos
->initdir
==0x00)))
1478 /* 3. All except w2k+: if filename contains a path use it */
1479 if (!win2000plus
&& fodInfos
->filename
&&
1480 *fodInfos
->filename
&&
1481 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1482 WCHAR tmpBuf
[MAX_PATH
];
1486 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1491 /* nameBit is always shorter than the original filename */
1492 lstrcpyW(fodInfos
->filename
, nameBit
);
1495 len
= lstrlenW(tmpBuf
);
1496 MemFree(fodInfos
->initdir
);
1497 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1498 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1501 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1502 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1504 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1507 /* 4. win98+ and win2000+ if any files of specified filter types in
1508 current directory, use it */
1509 if ( win98plus
&& handledPath
== FALSE
&&
1510 fodInfos
->filter
&& *fodInfos
->filter
) {
1512 BOOL searchMore
= TRUE
;
1513 LPCWSTR lpstrPos
= fodInfos
->filter
;
1514 WIN32_FIND_DATAW FindFileData
;
1519 /* filter is a list... title\0ext\0......\0\0 */
1521 /* Skip the title */
1522 if(! *lpstrPos
) break; /* end */
1523 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1525 /* See if any files exist in the current dir with this extension */
1526 if(! *lpstrPos
) break; /* end */
1528 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1530 if (hFind
== INVALID_HANDLE_VALUE
) {
1531 /* None found - continue search */
1532 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1537 MemFree(fodInfos
->initdir
);
1538 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1539 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1542 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1543 debugstr_w(lpstrPos
));
1549 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1551 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1552 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1553 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1555 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1557 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1560 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1561 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1563 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1566 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1569 } else if (handledPath
==FALSE
) {
1570 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1571 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1573 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1576 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1577 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1579 /* Must the open as read only check box be checked ?*/
1580 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1582 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1585 /* Must the open as read only check box be hidden? */
1586 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1588 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1589 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1592 /* Must the help button be hidden? */
1593 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1595 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1596 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1599 /* change Open to Save */
1600 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1603 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1604 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1605 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1606 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1609 /* Initialize the filter combo box */
1610 FILEDLG95_FILETYPE_Init(hwnd
);
1615 /***********************************************************************
1616 * FILEDLG95_ResizeControls
1618 * WM_INITDIALOG message handler (after hook notification)
1620 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1622 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1624 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1627 UINT flags
= SWP_NOACTIVATE
;
1629 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1630 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1632 /* resize the custom dialog to the parent size */
1633 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1634 GetClientRect(hwnd
, &rc
);
1637 /* our own fake template is zero sized and doesn't have children, so
1638 * there is no need to resize it. Picasa depends on it.
1640 flags
|= SWP_NOSIZE
;
1643 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1644 0, 0, rc
.right
, rc
.bottom
, flags
);
1648 /* Resize the height, if open as read only checkbox ad help button are
1649 * hidden and we are not using a custom template nor a customDialog
1651 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1652 (!(fodInfos
->ofnInfos
->Flags
&
1653 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1655 RECT rectDlg
, rectHelp
, rectCancel
;
1656 GetWindowRect(hwnd
, &rectDlg
);
1657 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1658 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1659 /* subtract the height of the help button plus the space between the help
1660 * button and the cancel button to the height of the dialog
1662 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1663 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1664 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1670 /***********************************************************************
1671 * FILEDLG95_FillControls
1673 * WM_INITDIALOG message handler (after hook notification)
1675 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1677 LPITEMIDLIST pidlItemId
= NULL
;
1679 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1681 TRACE("dir=%s file=%s\n",
1682 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1684 /* Get the initial directory pidl */
1686 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1688 WCHAR path
[MAX_PATH
];
1690 GetCurrentDirectoryW(MAX_PATH
,path
);
1691 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1694 /* Initialise shell objects */
1695 FILEDLG95_SHELL_Init(hwnd
);
1697 /* Initialize the Look In combo box */
1698 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1700 /* Browse to the initial directory */
1701 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1703 /* Free pidlItem memory */
1704 COMDLG32_SHFree(pidlItemId
);
1708 /***********************************************************************
1711 * Regroups all the cleaning functions of the filedlg
1713 void FILEDLG95_Clean(HWND hwnd
)
1715 FILEDLG95_FILETYPE_Clean(hwnd
);
1716 FILEDLG95_LOOKIN_Clean(hwnd
);
1717 FILEDLG95_SHELL_Clean(hwnd
);
1719 /***********************************************************************
1720 * FILEDLG95_OnWMCommand
1722 * WM_COMMAND message handler
1724 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1726 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1727 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1728 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1734 FILEDLG95_OnOpen(hwnd
);
1738 FILEDLG95_Clean(hwnd
);
1739 EndDialog(hwnd
, FALSE
);
1741 /* Filetype combo box */
1743 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1745 /* LookIn combo box */
1747 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1750 /* --- toolbar --- */
1751 /* Up folder button */
1752 case FCIDM_TB_UPFOLDER
:
1753 FILEDLG95_SHELL_UpFolder(hwnd
);
1755 /* New folder button */
1756 case FCIDM_TB_NEWFOLDER
:
1757 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1759 /* List option button */
1760 case FCIDM_TB_SMALLICON
:
1761 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1763 /* Details option button */
1764 case FCIDM_TB_REPORTVIEW
:
1765 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1767 /* Details option button */
1768 case FCIDM_TB_DESKTOP
:
1769 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1776 /* Do not use the listview selection anymore */
1777 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1781 /***********************************************************************
1782 * FILEDLG95_OnWMGetIShellBrowser
1784 * WM_GETISHELLBROWSER message handler
1786 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1788 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1792 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1798 /***********************************************************************
1799 * FILEDLG95_SendFileOK
1801 * Sends the CDN_FILEOK notification if required
1804 * TRUE if the dialog should close
1805 * FALSE if the dialog should not be closed
1807 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1809 /* ask the hook if we can close */
1810 if(IsHooked(fodInfos
))
1815 /* First send CDN_FILEOK as MSDN doc says */
1816 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1817 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1820 TRACE("canceled\n");
1824 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1825 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1826 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1829 TRACE("canceled\n");
1836 /***********************************************************************
1837 * FILEDLG95_OnOpenMultipleFiles
1839 * Handles the opening of multiple files.
1842 * check destination buffer size
1844 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1846 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1847 UINT nCount
, nSizePath
;
1848 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1852 if(fodInfos
->unicode
)
1854 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1855 ofn
->lpstrFile
[0] = '\0';
1859 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1860 ofn
->lpstrFile
[0] = '\0';
1863 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1865 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1866 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1867 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1869 LPWSTR lpstrTemp
= lpstrFileList
;
1871 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1875 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1878 WCHAR lpstrNotFound
[100];
1879 WCHAR lpstrMsg
[100];
1881 static const WCHAR nl
[] = {'\n',0};
1883 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1884 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1886 lstrcpyW(tmp
, lpstrTemp
);
1888 lstrcatW(tmp
, lpstrNotFound
);
1890 lstrcatW(tmp
, lpstrMsg
);
1892 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1896 /* move to the next file in the list of files */
1897 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1898 COMDLG32_SHFree(pidl
);
1902 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1903 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1905 /* For "oldstyle" dialog the components have to
1906 be separated by blanks (not '\0'!) and short
1907 filenames have to be used! */
1908 FIXME("Components have to be separated by blanks\n");
1910 if(fodInfos
->unicode
)
1912 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1913 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1914 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1918 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1920 if (ofn
->lpstrFile
!= NULL
)
1922 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1923 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1924 if (ofn
->nMaxFile
> nSizePath
)
1926 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1927 ofn
->lpstrFile
+ nSizePath
,
1928 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1933 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1934 fodInfos
->ofnInfos
->nFileExtension
= 0;
1936 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1939 /* clean and exit */
1940 FILEDLG95_Clean(hwnd
);
1941 return EndDialog(hwnd
,TRUE
);
1944 /***********************************************************************
1947 * Ok button WM_COMMAND message handler
1949 * If the function succeeds, the return value is nonzero.
1951 #define ONOPEN_BROWSE 1
1952 #define ONOPEN_OPEN 2
1953 #define ONOPEN_SEARCH 3
1954 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1956 WCHAR strMsgTitle
[MAX_PATH
];
1957 WCHAR strMsgText
[MAX_PATH
];
1959 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1961 strMsgTitle
[0] = '\0';
1962 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1963 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1966 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1968 LPWSTR lpstrFileList
;
1969 UINT nFileCount
= 0;
1972 WCHAR lpstrPathAndFile
[MAX_PATH
];
1973 WCHAR lpstrTemp
[MAX_PATH
];
1974 LPSHELLFOLDER lpsf
= NULL
;
1976 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1978 TRACE("hwnd=%p\n", hwnd
);
1980 /* get the files from the edit control */
1981 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1983 /* try if the user selected a folder in the shellview */
1986 BrowseSelectedFolder(hwnd
);
1992 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1996 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1999 Step 1: Build a complete path name from the current folder and
2000 the filename or path in the edit box.
2002 - the path in the edit box is a root path
2003 (with or without drive letter)
2004 - the edit box contains ".." (or a path with ".." in it)
2007 /* Get the current directory name */
2008 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
2011 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
2013 PathAddBackslashW(lpstrPathAndFile
);
2015 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
2017 /* if the user specified a fully qualified path use it */
2018 if(PathIsRelativeW(lpstrFileList
))
2020 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
2024 /* does the path have a drive letter? */
2025 if (PathGetDriveNumberW(lpstrFileList
) == -1)
2026 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
2028 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
2031 /* resolve "." and ".." */
2032 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
2033 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
2034 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
2036 MemFree(lpstrFileList
);
2039 Step 2: here we have a cleaned up path
2041 We have to parse the path step by step to see if we have to browse
2042 to a folder if the path points to a directory or the last
2043 valid element is a directory.
2046 lpstrPathAndFile: cleaned up path
2050 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2051 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2052 nOpenAction
= ONOPEN_OPEN
;
2054 nOpenAction
= ONOPEN_BROWSE
;
2056 /* don't apply any checks with OFN_NOVALIDATE */
2058 LPWSTR lpszTemp
, lpszTemp1
;
2059 LPITEMIDLIST pidl
= NULL
;
2060 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2062 /* check for invalid chars */
2063 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2065 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2070 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
2072 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2075 LPSHELLFOLDER lpsfChild
;
2076 WCHAR lpwstrTemp
[MAX_PATH
];
2077 DWORD dwEaten
, dwAttributes
;
2080 lstrcpyW(lpwstrTemp
, lpszTemp
);
2081 p
= PathFindNextComponentW(lpwstrTemp
);
2083 if (!p
) break; /* end of path */
2086 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2088 /* There are no wildcards when OFN_NOVALIDATE is set */
2089 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2091 static const WCHAR wszWild
[] = { '*', '?', 0 };
2092 /* if the last element is a wildcard do a search */
2093 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2095 nOpenAction
= ONOPEN_SEARCH
;
2099 lpszTemp1
= lpszTemp
;
2101 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
2103 /* append a backslash to drive letters */
2104 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2105 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2106 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2108 PathAddBackslashW(lpwstrTemp
);
2111 dwAttributes
= SFGAO_FOLDER
;
2112 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2114 /* the path component is valid, we have a pidl of the next path component */
2115 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2116 if(dwAttributes
& SFGAO_FOLDER
)
2118 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2120 ERR("bind to failed\n"); /* should not fail */
2123 IShellFolder_Release(lpsf
);
2131 /* end dialog, return value */
2132 nOpenAction
= ONOPEN_OPEN
;
2135 COMDLG32_SHFree(pidl
);
2138 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2140 if(*lpszTemp
|| /* points to trailing null for last path element */
2141 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2143 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
2145 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2151 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2152 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2154 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2158 /* change to the current folder */
2159 nOpenAction
= ONOPEN_OPEN
;
2164 nOpenAction
= ONOPEN_OPEN
;
2168 if(pidl
) COMDLG32_SHFree(pidl
);
2172 Step 3: here we have a cleaned up and validated path
2175 lpsf: ShellFolder bound to the rightmost valid path component
2176 lpstrPathAndFile: cleaned up path
2177 nOpenAction: action to do
2179 TRACE("end validate sf=%p\n", lpsf
);
2183 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2184 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2187 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2190 /* replace the current filter */
2191 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2192 len
= lstrlenW(lpszTemp
)+1;
2193 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2194 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2196 /* set the filter cb to the extension when possible */
2197 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2198 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2201 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2202 TRACE("ONOPEN_BROWSE\n");
2204 IPersistFolder2
* ppf2
;
2205 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2207 LPITEMIDLIST pidlCurrent
;
2208 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2209 IPersistFolder2_Release(ppf2
);
2210 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2212 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2213 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2215 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2218 else if( nOpenAction
== ONOPEN_SEARCH
)
2220 if (fodInfos
->Shell
.FOIShellView
)
2221 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2223 COMDLG32_SHFree(pidlCurrent
);
2224 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2229 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2230 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2234 /* update READONLY check box flag */
2235 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2236 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2238 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2240 /* Attach the file extension with file name*/
2241 ext
= PathFindExtensionW(lpstrPathAndFile
);
2244 /* if no extension is specified with file name, then */
2245 /* attach the extension from file filter or default one */
2247 WCHAR
*filterExt
= NULL
;
2248 LPWSTR lpstrFilter
= NULL
;
2249 static const WCHAR szwDot
[] = {'.',0};
2250 int PathLength
= lstrlenW(lpstrPathAndFile
);
2253 lstrcatW(lpstrPathAndFile
, szwDot
);
2255 /*Get the file extension from file type filter*/
2256 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2257 fodInfos
->ofnInfos
->nFilterIndex
-1);
2259 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2260 filterExt
= PathFindExtensionW(lpstrFilter
);
2262 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2263 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2264 else if ( fodInfos
->defext
) /* attach the default file extension*/
2265 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2267 /* In Open dialog: if file does not exist try without extension */
2268 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2269 lpstrPathAndFile
[PathLength
] = '\0';
2272 if (fodInfos
->defext
) /* add default extension */
2274 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2277 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2278 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2280 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2283 /* In Save dialog: check if the file already exists */
2284 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2285 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2286 && PathFileExistsW(lpstrPathAndFile
))
2288 WCHAR lpstrOverwrite
[100];
2291 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2292 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2293 MB_YESNO
| MB_ICONEXCLAMATION
);
2301 /* In Open dialog: check if it should be created if it doesn't exist */
2302 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2303 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2304 && !PathFileExistsW(lpstrPathAndFile
))
2306 WCHAR lpstrCreate
[100];
2309 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2310 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2311 MB_YESNO
| MB_ICONEXCLAMATION
);
2319 /* Check that the size of the file does not exceed buffer size.
2320 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2321 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2322 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2325 /* fill destination buffer */
2326 if (fodInfos
->ofnInfos
->lpstrFile
)
2328 if(fodInfos
->unicode
)
2330 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2332 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2333 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2334 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2338 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2340 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2341 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2342 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2343 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2347 if(fodInfos
->unicode
)
2351 /* set filename offset */
2352 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2353 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2355 /* set extension offset */
2356 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2357 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2362 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2364 /* set filename offset */
2365 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2366 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2368 /* set extension offset */
2369 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2370 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2373 /* set the lpstrFileTitle */
2374 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2376 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2377 if(fodInfos
->unicode
)
2379 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2380 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2384 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2385 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2386 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2390 /* copy currently selected filter to lpstrCustomFilter */
2391 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2393 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2394 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2395 NULL
, 0, NULL
, NULL
);
2396 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2398 LPSTR s
= ofn
->lpstrCustomFilter
;
2399 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2400 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2401 s
, len
, NULL
, NULL
);
2406 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2410 FILEDLG95_Clean(hwnd
);
2411 ret
= EndDialog(hwnd
, TRUE
);
2417 size
= lstrlenW(lpstrPathAndFile
) + 1;
2418 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2420 /* return needed size in first two bytes of lpstrFile */
2421 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2422 FILEDLG95_Clean(hwnd
);
2423 ret
= EndDialog(hwnd
, FALSE
);
2424 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2431 if(lpsf
) IShellFolder_Release(lpsf
);
2435 /***********************************************************************
2436 * FILEDLG95_SHELL_Init
2438 * Initialisation of the shell objects
2440 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2442 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2447 * Initialisation of the FileOpenDialogInfos structure
2453 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2455 /* Disable multi-select if flag not set */
2456 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2458 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2460 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2461 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2463 /* Construct the IShellBrowser interface */
2464 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2469 /***********************************************************************
2470 * FILEDLG95_SHELL_ExecuteCommand
2472 * Change the folder option and refresh the view
2473 * If the function succeeds, the return value is nonzero.
2475 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2477 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2480 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2482 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2487 CMINVOKECOMMANDINFO ci
;
2488 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2489 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2493 IContextMenu_InvokeCommand(pcm
, &ci
);
2494 IContextMenu_Release(pcm
);
2500 /***********************************************************************
2501 * FILEDLG95_SHELL_UpFolder
2503 * Browse to the specified object
2504 * If the function succeeds, the return value is nonzero.
2506 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2508 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2512 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2516 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2517 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2523 /***********************************************************************
2524 * FILEDLG95_SHELL_BrowseToDesktop
2526 * Browse to the Desktop
2527 * If the function succeeds, the return value is nonzero.
2529 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2531 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2537 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2538 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2539 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2540 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2541 COMDLG32_SHFree(pidl
);
2542 return SUCCEEDED(hres
);
2544 /***********************************************************************
2545 * FILEDLG95_SHELL_Clean
2547 * Cleans the memory used by shell objects
2549 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2551 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2555 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2557 /* clean Shell interfaces */
2558 if (fodInfos
->Shell
.FOIShellView
)
2560 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2561 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2563 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2564 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2565 if (fodInfos
->Shell
.FOIDataObject
)
2566 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2569 /***********************************************************************
2570 * FILEDLG95_FILETYPE_Init
2572 * Initialisation of the file type combo box
2574 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2576 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2577 int nFilters
= 0; /* number of filters */
2582 if(fodInfos
->customfilter
)
2584 /* customfilter has one entry... title\0ext\0
2585 * Set first entry of combo box item with customfilter
2588 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2591 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2593 /* Copy the extensions */
2594 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2595 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2596 lstrcpyW(lpstrExt
,lpstrPos
);
2598 /* Add the item at the end of the combo */
2599 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2600 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2603 if(fodInfos
->filter
)
2605 LPCWSTR lpstrPos
= fodInfos
->filter
;
2609 /* filter is a list... title\0ext\0......\0\0
2610 * Set the combo item text to the title and the item data
2613 LPCWSTR lpstrDisplay
;
2617 if(! *lpstrPos
) break; /* end */
2618 lpstrDisplay
= lpstrPos
;
2619 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2621 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2625 /* Copy the extensions */
2626 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2627 lstrcpyW(lpstrExt
,lpstrPos
);
2628 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2630 /* Add the item at the end of the combo */
2631 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2633 /* malformed filters are added anyway... */
2634 if (!*lpstrExt
) break;
2639 * Set the current filter to the one specified
2640 * in the initialisation structure
2642 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2646 /* Check to make sure our index isn't out of bounds. */
2647 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2648 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2649 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2651 /* set default filter index */
2652 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2653 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2655 /* calculate index of Combo Box item */
2656 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2657 if (fodInfos
->customfilter
== NULL
)
2660 /* Set the current index selection. */
2661 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2663 /* Get the corresponding text string from the combo box. */
2664 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2667 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2673 CharLowerW(lpstrFilter
); /* lowercase */
2674 len
= lstrlenW(lpstrFilter
)+1;
2675 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2676 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2679 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2683 /***********************************************************************
2684 * FILEDLG95_FILETYPE_OnCommand
2686 * WM_COMMAND of the file type combo box
2687 * If the function succeeds, the return value is nonzero.
2689 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2691 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2699 /* Get the current item of the filetype combo box */
2700 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2702 /* set the current filter index */
2703 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2704 (fodInfos
->customfilter
== NULL
? 1 : 0);
2706 /* Set the current filter with the current selection */
2707 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2709 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2711 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2714 CharLowerW(lpstrFilter
); /* lowercase */
2715 len
= lstrlenW(lpstrFilter
)+1;
2716 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2717 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2718 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2719 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2722 /* Refresh the actual view to display the included items*/
2723 if (fodInfos
->Shell
.FOIShellView
)
2724 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2729 /***********************************************************************
2730 * FILEDLG95_FILETYPE_SearchExt
2732 * searches for an extension in the filetype box
2734 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2736 int i
, iCount
= CBGetCount(hwnd
);
2738 TRACE("%s\n", debugstr_w(lpstrExt
));
2740 if(iCount
!= CB_ERR
)
2742 for(i
=0;i
<iCount
;i
++)
2744 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2751 /***********************************************************************
2752 * FILEDLG95_FILETYPE_Clean
2754 * Clean the memory used by the filetype combo box
2756 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2758 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2760 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2764 /* Delete each string of the combo and their associated data */
2765 if(iCount
!= CB_ERR
)
2767 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2769 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2770 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2773 /* Current filter */
2774 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2778 /***********************************************************************
2779 * FILEDLG95_LOOKIN_Init
2781 * Initialisation of the look in combo box
2784 /* Small helper function, to determine if the unixfs shell extension is rooted
2785 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2787 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2789 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2790 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2791 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2792 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2793 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2794 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2795 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2797 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2804 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2806 IShellFolder
*psfRoot
, *psfDrives
;
2807 IEnumIDList
*lpeRoot
, *lpeDrives
;
2808 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2810 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2814 liInfos
->iMaxIndentation
= 0;
2816 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
2818 /* set item height for both text field and listbox */
2819 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2820 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2822 /* Turn on the extended UI for the combo box like Windows does */
2823 CBSetExtendedUI(hwndCombo
, TRUE
);
2825 /* Initialise data of Desktop folder */
2826 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2827 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2828 COMDLG32_SHFree(pidlTmp
);
2830 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2832 SHGetDesktopFolder(&psfRoot
);
2836 /* enumerate the contents of the desktop */
2837 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2839 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2841 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2843 /* If the unixfs extension is rooted, we don't expand the drives by default */
2844 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2846 /* special handling for CSIDL_DRIVES */
2847 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2849 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2851 /* enumerate the drives */
2852 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2854 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2856 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2857 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2858 COMDLG32_SHFree(pidlAbsTmp
);
2859 COMDLG32_SHFree(pidlTmp1
);
2861 IEnumIDList_Release(lpeDrives
);
2863 IShellFolder_Release(psfDrives
);
2868 COMDLG32_SHFree(pidlTmp
);
2870 IEnumIDList_Release(lpeRoot
);
2872 IShellFolder_Release(psfRoot
);
2875 COMDLG32_SHFree(pidlDrives
);
2878 /***********************************************************************
2879 * FILEDLG95_LOOKIN_DrawItem
2881 * WM_DRAWITEM message handler
2883 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2885 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2886 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2887 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2891 HIMAGELIST ilItemImage
;
2894 LPSFOLDER tmpFolder
;
2895 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2899 if(pDIStruct
->itemID
== -1)
2902 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2903 pDIStruct
->itemID
)))
2907 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2909 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2913 SHGFI_PIDL
| SHGFI_SMALLICON
|
2914 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2915 SHGFI_DISPLAYNAME
);
2919 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2923 SHGFI_PIDL
| SHGFI_SMALLICON
|
2924 SHGFI_SYSICONINDEX
|
2928 /* Is this item selected ? */
2929 if(pDIStruct
->itemState
& ODS_SELECTED
)
2931 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2932 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2933 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2937 SetTextColor(pDIStruct
->hDC
,crText
);
2938 SetBkColor(pDIStruct
->hDC
,crWin
);
2939 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2942 /* Do not indent item if drawing in the edit of the combo */
2943 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2946 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2950 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2951 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2956 iIndentation
= tmpFolder
->m_iIndent
;
2958 /* Draw text and icon */
2960 /* Initialise the icon display area */
2961 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2962 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2963 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2964 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2966 /* Initialise the text display area */
2967 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2968 rectText
.left
= rectIcon
.right
;
2970 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2971 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2973 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2975 /* Draw the icon from the image list */
2976 ImageList_Draw(ilItemImage
,
2983 /* Draw the associated text */
2984 if(sfi
.szDisplayName
)
2985 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
2991 /***********************************************************************
2992 * FILEDLG95_LOOKIN_OnCommand
2994 * LookIn combo box WM_COMMAND message handler
2995 * If the function succeeds, the return value is nonzero.
2997 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2999 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3001 TRACE("%p\n", fodInfos
);
3007 LPSFOLDER tmpFolder
;
3010 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3012 if( iItem
== CB_ERR
) return FALSE
;
3014 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3019 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3020 tmpFolder
->pidlItem
,
3023 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3024 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3034 /***********************************************************************
3035 * FILEDLG95_LOOKIN_AddItem
3037 * Adds an absolute pidl item to the lookin combo box
3038 * returns the index of the inserted item
3040 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3042 LPITEMIDLIST pidlNext
;
3045 LookInInfos
*liInfos
;
3047 TRACE("%08x\n", iInsertId
);
3052 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3055 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3056 tmpFolder
->m_iIndent
= 0;
3058 /* Calculate the indentation of the item in the lookin*/
3060 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3062 tmpFolder
->m_iIndent
++;
3065 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3067 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3068 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3070 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3071 SHGetFileInfoW((LPCWSTR
)pidl
,
3075 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3076 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3078 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3080 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3084 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3086 /* Add the item at the end of the list */
3089 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3091 /* Insert the item at the iInsertId position*/
3094 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3097 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3101 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3102 MemFree( tmpFolder
);
3107 /***********************************************************************
3108 * FILEDLG95_LOOKIN_InsertItemAfterParent
3110 * Insert an item below its parent
3112 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3115 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3120 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3124 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3127 /* Free pidlParent memory */
3128 COMDLG32_SHFree(pidlParent
);
3130 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3133 /***********************************************************************
3134 * FILEDLG95_LOOKIN_SelectItem
3136 * Adds an absolute pidl item to the lookin combo box
3137 * returns the index of the inserted item
3139 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3142 LookInInfos
*liInfos
;
3146 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3148 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3152 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3153 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3158 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3159 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3163 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3165 if(iRemovedItem
< iItemPos
)
3170 CBSetCurSel(hwnd
,iItemPos
);
3171 liInfos
->uSelectedItem
= iItemPos
;
3177 /***********************************************************************
3178 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3180 * Remove the item with an expansion level over iExpansionLevel
3182 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3185 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3189 if(liInfos
->iMaxIndentation
<= 2)
3192 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3194 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3195 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3197 CBDeleteString(hwnd
,iItemPos
);
3198 liInfos
->iMaxIndentation
--;
3206 /***********************************************************************
3207 * FILEDLG95_LOOKIN_SearchItem
3209 * Search for pidl in the lookin combo box
3210 * returns the index of the found item
3212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3215 int iCount
= CBGetCount(hwnd
);
3217 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3219 if (iCount
!= CB_ERR
)
3223 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3225 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3227 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3235 /***********************************************************************
3236 * FILEDLG95_LOOKIN_Clean
3238 * Clean the memory used by the lookin combo box
3240 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3242 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3244 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3248 /* Delete each string of the combo and their associated data */
3249 if (iCount
!= CB_ERR
)
3251 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3253 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3254 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3256 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3260 /* LookInInfos structure */
3261 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3264 /***********************************************************************
3265 * FILEDLG95_FILENAME_FillFromSelection
3267 * fills the edit box from the cached DataObject
3269 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3271 FileOpenDlgInfos
*fodInfos
;
3273 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3274 WCHAR lpstrTemp
[MAX_PATH
];
3275 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3278 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3280 /* Count how many files we have */
3281 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3283 /* calculate the string length, count files */
3284 if (nFileSelected
>= 1)
3286 nLength
+= 3; /* first and last quotes, trailing \0 */
3287 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3289 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3293 /* get the total length of the selected file names */
3294 lpstrTemp
[0] = '\0';
3295 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3297 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3299 nLength
+= lstrlenW( lpstrTemp
) + 3;
3302 COMDLG32_SHFree( pidl
);
3307 /* allocate the buffer */
3308 if (nFiles
<= 1) nLength
= MAX_PATH
;
3309 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3311 /* Generate the string for the edit control */
3314 lpstrCurrFile
= lpstrAllFile
;
3315 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3317 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3321 /* get the file name */
3322 lpstrTemp
[0] = '\0';
3323 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3325 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3329 *lpstrCurrFile
++ = '\"';
3330 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3331 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3332 *lpstrCurrFile
++ = '\"';
3333 *lpstrCurrFile
++ = ' ';
3338 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3341 COMDLG32_SHFree( pidl
);
3344 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3346 /* Select the file name like Windows does */
3347 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3349 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3353 /* copied from shell32 to avoid linking to it
3354 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3355 * is dependent on whether emulated OS is unicode or not.
3357 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3362 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3363 COMDLG32_SHFree(src
->u
.pOleStr
);
3367 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3372 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3377 FIXME("unknown type %x!\n", src
->uType
);
3378 if (len
) *dest
= '\0';
3384 /***********************************************************************
3385 * FILEDLG95_FILENAME_GetFileNames
3387 * Copies the filenames to a delimited string list.
3388 * The delimiter is specified by the parameter 'separator',
3389 * usually either a space or a nul
3391 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3393 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3394 UINT nStrCharCount
= 0; /* index in src buffer */
3395 UINT nFileIndex
= 0; /* index in dest buffer */
3396 UINT nFileCount
= 0; /* number of files */
3397 UINT nStrLen
= 0; /* length of string in edit control */
3398 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3402 /* get the filenames from the edit control */
3403 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3404 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3405 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3407 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3409 /* we might get single filename without any '"',
3410 * so we need nStrLen + terminating \0 + end-of-list \0 */
3411 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3414 /* build delimited file list from filenames */
3415 while ( nStrCharCount
<= nStrLen
)
3417 if ( lpstrEdit
[nStrCharCount
]=='"' )
3420 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3422 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3425 (*lpstrFileList
)[nFileIndex
++] = 0;
3431 /* single, unquoted string */
3432 if ((nStrLen
> 0) && (nFileIndex
== 0) )
3434 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3435 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3440 (*lpstrFileList
)[nFileIndex
++] = '\0';
3442 *sizeUsed
= nFileIndex
;
3447 #define SETDefFormatEtc(fe,cf,med) \
3449 (fe).cfFormat = cf;\
3450 (fe).dwAspect = DVASPECT_CONTENT; \
3457 * DATAOBJECT Helper functions
3460 /***********************************************************************
3461 * COMCTL32_ReleaseStgMedium
3463 * like ReleaseStgMedium from ole32
3465 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3467 if(medium
.pUnkForRelease
)
3469 IUnknown_Release(medium
.pUnkForRelease
);
3473 GlobalUnlock(medium
.u
.hGlobal
);
3474 GlobalFree(medium
.u
.hGlobal
);
3478 /***********************************************************************
3479 * GetPidlFromDataObject
3481 * Return pidl(s) by number from the cached DataObject
3483 * nPidlIndex=0 gets the fully qualified root path
3485 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3489 FORMATETC formatetc
;
3490 LPITEMIDLIST pidl
= NULL
;
3492 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3497 /* Set the FORMATETC structure*/
3498 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3500 /* Get the pidls from IDataObject */
3501 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3503 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3504 if(nPidlIndex
<= cida
->cidl
)
3506 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3508 COMCTL32_ReleaseStgMedium(medium
);
3513 /***********************************************************************
3516 * Return the number of selected items in the DataObject.
3519 static UINT
GetNumSelected( IDataObject
*doSelected
)
3523 FORMATETC formatetc
;
3525 TRACE("sv=%p\n", doSelected
);
3527 if (!doSelected
) return 0;
3529 /* Set the FORMATETC structure*/
3530 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3532 /* Get the pidls from IDataObject */
3533 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3535 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3536 retVal
= cida
->cidl
;
3537 COMCTL32_ReleaseStgMedium(medium
);
3547 /***********************************************************************
3550 * Get the pidl's display name (relative to folder) and
3551 * put it in lpstrFileName.
3553 * Return NOERROR on success,
3557 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3562 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3566 SHGetDesktopFolder(&lpsf
);
3567 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3568 IShellFolder_Release(lpsf
);
3572 /* Get the display name of the pidl relative to the folder */
3573 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3575 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3580 /***********************************************************************
3581 * GetShellFolderFromPidl
3583 * pidlRel is the item pidl relative
3584 * Return the IShellFolder of the absolute pidl
3586 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3588 IShellFolder
*psf
= NULL
,*psfParent
;
3590 TRACE("%p\n", pidlAbs
);
3592 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3595 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3597 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3599 IShellFolder_Release(psfParent
);
3603 /* return the desktop */
3609 /***********************************************************************
3612 * Return the LPITEMIDLIST to the parent of the pidl in the list
3614 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3616 LPITEMIDLIST pidlParent
;
3618 TRACE("%p\n", pidl
);
3620 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3621 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3626 /***********************************************************************
3629 * returns the pidl of the file name relative to folder
3630 * NULL if an error occurred
3632 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3634 LPITEMIDLIST pidl
= NULL
;
3637 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3639 if(!lpcstrFileName
) return NULL
;
3640 if(!*lpcstrFileName
) return NULL
;
3644 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3645 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3646 IShellFolder_Release(lpsf
);
3651 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3658 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3660 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3663 TRACE("%p, %p\n", psf
, pidl
);
3665 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3667 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3668 /* see documentation shell 4.1*/
3669 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3672 /***********************************************************************
3673 * BrowseSelectedFolder
3675 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3677 BOOL bBrowseSelFolder
= FALSE
;
3678 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3682 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3684 LPITEMIDLIST pidlSelection
;
3686 /* get the file selected */
3687 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3688 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3690 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3691 pidlSelection
, SBSP_RELATIVE
) ) )
3693 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3694 ' ','n','o','t',' ','e','x','i','s','t',0};
3695 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3697 bBrowseSelFolder
= TRUE
;
3698 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3699 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3701 COMDLG32_SHFree( pidlSelection
);
3704 return bBrowseSelFolder
;
3708 * Memory allocation methods */
3709 static void *MemAlloc(UINT size
)
3711 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3714 static void MemFree(void *mem
)
3716 HeapFree(GetProcessHeap(),0,mem
);
3720 * Old-style (win3.1) dialogs */
3722 /***********************************************************************
3723 * FD32_GetTemplate [internal]
3725 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3726 * by a 32 bits application
3729 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3731 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3732 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3735 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3737 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3739 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3743 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3747 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3748 priv
->ofnA
->lpTemplateName
,
3751 hResInfo
= FindResourceW(ofnW
->hInstance
,
3752 ofnW
->lpTemplateName
,
3756 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3759 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3761 !(lfs
->template = LockResource(hDlgTmpl
)))
3763 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3766 } else { /* get it from internal Wine resource */
3768 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3769 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3771 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3774 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3775 !(lfs
->template = LockResource( hDlgTmpl
)))
3777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3785 /************************************************************************
3786 * FD32_Init [internal]
3787 * called from the common 16/32 code to initialize 32 bit data
3789 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3791 BOOL IsUnicode
= (BOOL
) data
;
3794 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3795 lfs
->private1632
= priv
;
3796 if (NULL
== lfs
->private1632
) return FALSE
;
3799 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3800 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3801 if (lfs
->ofnW
->lpfnHook
)
3806 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3807 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3808 if (priv
->ofnA
->lpfnHook
)
3810 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3811 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3814 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3819 /***********************************************************************
3820 * FD32_CallWindowProc [internal]
3822 * called from the common 16/32 code to call the appropriate hook
3824 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3828 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3832 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3833 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3834 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3835 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3836 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3840 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3841 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3842 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3843 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3844 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3848 /***********************************************************************
3849 * FD32_UpdateResult [internal]
3850 * update the real client structures if any
3852 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3854 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3855 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3860 if (ofnW
->nMaxFile
&&
3861 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3862 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3863 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3865 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3866 /* set filename offset */
3867 lpszTemp
= PathFindFileNameA(priv
->ofnA
->lpstrFile
);
3868 priv
->ofnA
->nFileOffset
= (lpszTemp
- priv
->ofnA
->lpstrFile
);
3870 /* set extension offset */
3871 lpszTemp
= PathFindExtensionA(priv
->ofnA
->lpstrFile
);
3872 priv
->ofnA
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- priv
->ofnA
->lpstrFile
) + 1 : 0;
3876 /***********************************************************************
3877 * FD32_UpdateFileTitle [internal]
3878 * update the real client structures if any
3880 static void CALLBACK
FD32_UpdateFileTitle(const FD31_DATA
*lfs
)
3882 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3883 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3887 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3888 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3889 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3894 /***********************************************************************
3895 * FD32_SendLbGetCurSel [internal]
3896 * retrieve selected listbox item
3898 static LRESULT CALLBACK
FD32_SendLbGetCurSel(const FD31_DATA
*lfs
)
3900 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3904 /************************************************************************
3905 * FD32_Destroy [internal]
3906 * called from the common 16/32 code to cleanup 32 bit data
3908 static void CALLBACK
FD32_Destroy(const FD31_DATA
*lfs
)
3910 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3912 /* if ofnW has been allocated, have to free everything in it */
3913 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3915 FD31_FreeOfnW(lfs
->ofnW
);
3916 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3920 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3922 callbacks
->Init
= FD32_Init
;
3923 callbacks
->CWP
= FD32_CallWindowProc
;
3924 callbacks
->UpdateResult
= FD32_UpdateResult
;
3925 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3926 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3927 callbacks
->Destroy
= FD32_Destroy
;
3930 /***********************************************************************
3931 * FD32_WMMeasureItem [internal]
3933 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3935 LPMEASUREITEMSTRUCT lpmeasure
;
3937 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3938 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3943 /***********************************************************************
3944 * FileOpenDlgProc [internal]
3945 * Used for open and save, in fact.
3947 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3948 WPARAM wParam
, LPARAM lParam
)
3950 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3952 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
3953 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3956 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3958 return lRet
; /* else continue message processing */
3963 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3965 case WM_MEASUREITEM
:
3966 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3969 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3972 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3975 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3976 switch (HIWORD(lParam
))
3979 SetTextColor((HDC16
)wParam
, 0x00000000);
3981 case CTLCOLOR_STATIC
:
3982 SetTextColor((HDC16
)wParam
, 0x00000000);
3992 /***********************************************************************
3993 * GetFileName31A [internal]
3995 * Creates a win31 style dialog box for the user to select a file to open/save.
3997 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
3998 UINT dlgType
/* type dialogue : open/save */
4004 FD31_CALLBACKS callbacks
;
4006 if (!lpofn
|| !FD31_Init()) return FALSE
;
4008 TRACE("ofn flags %08x\n", lpofn
->Flags
);
4009 FD32_SetupCallbacks(&callbacks
);
4010 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
4013 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
4014 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
4015 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4016 FD31_DestroyPrivate(lfs
);
4019 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
4023 /***********************************************************************
4024 * GetFileName31W [internal]
4026 * Creates a win31 style dialog box for the user to select a file to open/save
4028 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
4029 UINT dlgType
/* type dialogue : open/save */
4035 FD31_CALLBACKS callbacks
;
4037 if (!lpofn
|| !FD31_Init()) return FALSE
;
4039 FD32_SetupCallbacks(&callbacks
);
4040 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
4043 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
4044 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
4045 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4046 FD31_DestroyPrivate(lfs
);
4049 TRACE("file %s, file offset %d, ext offset %d\n",
4050 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
4054 /* ------------------ APIs ---------------------- */
4056 /***********************************************************************
4057 * GetOpenFileNameA (COMDLG32.@)
4059 * Creates a dialog box for the user to select a file to open.
4062 * TRUE on success: user enters a valid file
4063 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4066 BOOL WINAPI
GetOpenFileNameA(
4067 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4069 BOOL win16look
= FALSE
;
4071 TRACE("flags %08x\n", ofn
->Flags
);
4073 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4074 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4075 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4077 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4078 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4081 return GetFileName31A(ofn
, OPEN_DIALOG
);
4083 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4086 /***********************************************************************
4087 * GetOpenFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to open.
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI
GetOpenFileNameW(
4097 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4099 BOOL win16look
= FALSE
;
4101 TRACE("flags %08x\n", ofn
->Flags
);
4103 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4104 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4105 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4107 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4108 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4111 return GetFileName31W(ofn
, OPEN_DIALOG
);
4113 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4117 /***********************************************************************
4118 * GetSaveFileNameA (COMDLG32.@)
4120 * Creates a dialog box for the user to select a file to save.
4123 * TRUE on success: user enters a valid file
4124 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4127 BOOL WINAPI
GetSaveFileNameA(
4128 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4130 BOOL win16look
= FALSE
;
4132 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4133 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4136 return GetFileName31A(ofn
, SAVE_DIALOG
);
4138 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4141 /***********************************************************************
4142 * GetSaveFileNameW (COMDLG32.@)
4144 * Creates a dialog box for the user to select a file to save.
4147 * TRUE on success: user enters a valid file
4148 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4151 BOOL WINAPI
GetSaveFileNameW(
4152 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4154 BOOL win16look
= FALSE
;
4156 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4157 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4160 return GetFileName31W(ofn
, SAVE_DIALOG
);
4162 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4165 /***********************************************************************
4166 * GetFileTitleA (COMDLG32.@)
4168 * See GetFileTitleW.
4170 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4173 UNICODE_STRING strWFile
;
4176 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4177 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4178 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4179 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4180 RtlFreeUnicodeString( &strWFile
);
4181 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4186 /***********************************************************************
4187 * GetFileTitleW (COMDLG32.@)
4189 * Get the name of a file.
4192 * lpFile [I] name and location of file
4193 * lpTitle [O] returned file name
4194 * cbBuf [I] buffer size of lpTitle
4198 * Failure: negative number.
4200 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4203 static const WCHAR brkpoint
[] = {'*','[',']',0};
4204 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4206 if(lpFile
== NULL
|| lpTitle
== NULL
)
4209 len
= lstrlenW(lpFile
);
4214 if(strpbrkW(lpFile
, brkpoint
))
4219 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4222 for(i
= len
; i
>= 0; i
--)
4224 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4234 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4236 len
= lstrlenW(lpFile
+i
)+1;
4240 lstrcpyW(lpTitle
, &lpFile
[i
]);