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 /* msdn: explorer style dialogs permit sizing by default.
275 * The OFN_ENABLESIZING flag is only needed when a hook or
276 * custom tmeplate is provided */
277 if( (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) &&
278 !(fodInfos
->ofnInfos
->Flags
& ( OFN_ENABLEHOOK
| OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
279 fodInfos
->ofnInfos
->Flags
|= OFN_ENABLESIZING
;
281 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
283 ((LPDLGTEMPLATEW
)template)->style
|= WS_SIZEBOX
;
284 fodInfos
->sizedlg
.cx
= fodInfos
->sizedlg
.cy
= 0;
285 fodInfos
->initial_size
.x
= fodInfos
->initial_size
.y
= 0;
288 ((LPDLGTEMPLATEW
)template)->style
&= ~WS_SIZEBOX
;
291 /* old style hook messages */
292 if (IsHooked(fodInfos
))
294 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageW(FILEOKSTRINGW
);
295 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageW(LBSELCHSTRINGW
);
296 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageW(HELPMSGSTRINGW
);
297 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageW(SHAREVISTRINGW
);
300 /* Some shell namespace extensions depend on COM being initialized. */
301 hr
= OleInitialize(NULL
);
303 if (fodInfos
->unicode
)
304 lRes
= DialogBoxIndirectParamW(COMDLG32_hInstance
,
306 fodInfos
->ofnInfos
->hwndOwner
,
310 lRes
= DialogBoxIndirectParamA(COMDLG32_hInstance
,
312 fodInfos
->ofnInfos
->hwndOwner
,
318 /* Unable to create the dialog */
325 /***********************************************************************
328 * Call GetFileName95 with this structure and clean the memory.
330 * IN : The OPENFILENAMEA initialisation structure passed to
331 * GetOpenFileNameA win api function (see filedlg.c)
333 static BOOL
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
336 FileOpenDlgInfos fodInfos
;
337 LPSTR lpstrSavDir
= NULL
;
339 LPWSTR defext
= NULL
;
340 LPWSTR filter
= NULL
;
341 LPWSTR customfilter
= NULL
;
343 /* Initialize CommDlgExtendedError() */
344 COMDLG32_SetCommDlgExtendedError(0);
346 /* Initialize FileOpenDlgInfos structure */
347 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
349 /* Pass in the original ofn */
350 fodInfos
.ofnInfos
= (LPOPENFILENAMEW
)ofn
;
352 /* save current directory */
353 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
355 lpstrSavDir
= MemAlloc(MAX_PATH
);
356 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
359 fodInfos
.unicode
= FALSE
;
361 /* convert all the input strings to unicode */
362 if(ofn
->lpstrInitialDir
)
364 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
365 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
366 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
369 fodInfos
.initdir
= NULL
;
373 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
374 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
377 fodInfos
.filename
= NULL
;
381 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
382 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
383 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
385 fodInfos
.defext
= defext
;
389 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
390 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
391 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
393 fodInfos
.title
= title
;
395 if (ofn
->lpstrFilter
)
400 /* filter is a list... title\0ext\0......\0\0 */
401 s
= ofn
->lpstrFilter
;
402 while (*s
) s
= s
+strlen(s
)+1;
404 n
= s
- ofn
->lpstrFilter
;
405 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
406 filter
= MemAlloc(len
*sizeof(WCHAR
));
407 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
409 fodInfos
.filter
= filter
;
411 /* convert lpstrCustomFilter */
412 if (ofn
->lpstrCustomFilter
)
417 /* customfilter contains a pair of strings... title\0ext\0 */
418 s
= ofn
->lpstrCustomFilter
;
419 if (*s
) s
= s
+strlen(s
)+1;
420 if (*s
) s
= s
+strlen(s
)+1;
421 n
= s
- ofn
->lpstrCustomFilter
;
422 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
423 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
424 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
426 fodInfos
.customfilter
= customfilter
;
428 /* Initialize the dialog property */
429 fodInfos
.DlgInfos
.dwDlgProp
= 0;
430 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
435 ret
= GetFileName95(&fodInfos
);
438 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
439 ret
= GetFileName95(&fodInfos
);
447 SetCurrentDirectoryA(lpstrSavDir
);
448 MemFree(lpstrSavDir
);
454 MemFree(customfilter
);
455 MemFree(fodInfos
.initdir
);
456 MemFree(fodInfos
.filename
);
458 TRACE("selected file: %s\n",ofn
->lpstrFile
);
463 /***********************************************************************
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
470 static BOOL
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
473 FileOpenDlgInfos fodInfos
;
474 LPWSTR lpstrSavDir
= NULL
;
476 /* Initialize CommDlgExtendedError() */
477 COMDLG32_SetCommDlgExtendedError(0);
479 /* Initialize FileOpenDlgInfos structure */
480 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
482 /* Pass in the original ofn */
483 fodInfos
.ofnInfos
= ofn
;
485 fodInfos
.title
= ofn
->lpstrTitle
;
486 fodInfos
.defext
= ofn
->lpstrDefExt
;
487 fodInfos
.filter
= ofn
->lpstrFilter
;
488 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
490 /* convert string arguments, save others */
493 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
494 lstrcpynW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
497 fodInfos
.filename
= NULL
;
499 if(ofn
->lpstrInitialDir
)
501 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
502 DWORD len
= lstrlenW(ofn
->lpstrInitialDir
)+1;
503 fodInfos
.initdir
= MemAlloc(len
*sizeof(WCHAR
));
504 memcpy(fodInfos
.initdir
,ofn
->lpstrInitialDir
,len
*sizeof(WCHAR
));
507 fodInfos
.initdir
= NULL
;
509 /* save current directory */
510 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
512 lpstrSavDir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
513 GetCurrentDirectoryW(MAX_PATH
, lpstrSavDir
);
516 fodInfos
.unicode
= TRUE
;
521 ret
= GetFileName95(&fodInfos
);
524 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
525 ret
= GetFileName95(&fodInfos
);
533 SetCurrentDirectoryW(lpstrSavDir
);
534 MemFree(lpstrSavDir
);
537 /* restore saved IN arguments and convert OUT arguments back */
538 MemFree(fodInfos
.filename
);
539 MemFree(fodInfos
.initdir
);
543 /******************************************************************************
544 * COMDLG32_GetDisplayNameOf [internal]
546 * Helper function to get the display name for a pidl.
548 static BOOL
COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl
, LPWSTR pwszPath
) {
549 LPSHELLFOLDER psfDesktop
;
552 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
555 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop
, pidl
, SHGDN_FORPARSING
, &strret
))) {
556 IShellFolder_Release(psfDesktop
);
560 IShellFolder_Release(psfDesktop
);
561 return SUCCEEDED(StrRetToBufW(&strret
, pidl
, pwszPath
, MAX_PATH
));
564 /***********************************************************************
565 * ArrangeCtrlPositions [internal]
567 * NOTE: Make sure to add testcases for any changes made here.
569 static void ArrangeCtrlPositions(HWND hwndChildDlg
, HWND hwndParentDlg
, BOOL hide_help
)
571 HWND hwndChild
, hwndStc32
;
572 RECT rectParent
, rectChild
, rectStc32
;
576 /* Take into account if open as read only checkbox and help button
581 RECT rectHelp
, rectCancel
;
582 GetWindowRect(GetDlgItem(hwndParentDlg
, pshHelp
), &rectHelp
);
583 GetWindowRect(GetDlgItem(hwndParentDlg
, IDCANCEL
), &rectCancel
);
584 /* subtract the height of the help button plus the space between
585 * the help button and the cancel button to the height of the dialog
587 help_fixup
= rectHelp
.bottom
- rectCancel
.bottom
;
591 There are two possibilities to add components to the default file dialog box.
593 By default, all the new components are added below the standard dialog box (the else case).
595 However, if there is a static text component with the stc32 id, a special case happens.
596 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
597 in the window and the cx and cy indicate how to size the window.
598 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
599 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
603 GetClientRect(hwndParentDlg
, &rectParent
);
605 /* when arranging controls we have to use fixed parent size */
606 rectParent
.bottom
-= help_fixup
;
608 hwndStc32
= GetDlgItem(hwndChildDlg
, stc32
);
611 GetWindowRect(hwndStc32
, &rectStc32
);
612 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectStc32
, 2);
614 /* set the size of the stc32 control according to the size of
615 * client area of the parent dialog
617 SetWindowPos(hwndStc32
, 0,
619 rectParent
.right
, rectParent
.bottom
,
620 SWP_NOMOVE
| SWP_NOZORDER
);
623 SetRectEmpty(&rectStc32
);
625 /* this part moves controls of the child dialog */
626 hwndChild
= GetWindow(hwndChildDlg
, GW_CHILD
);
629 if (hwndChild
!= hwndStc32
)
631 GetWindowRect(hwndChild
, &rectChild
);
632 MapWindowPoints(0, hwndChildDlg
, (LPPOINT
)&rectChild
, 2);
634 /* move only if stc32 exist */
635 if (hwndStc32
&& rectChild
.left
> rectStc32
.right
)
637 /* move to the right of visible controls of the parent dialog */
638 rectChild
.left
+= rectParent
.right
;
639 rectChild
.left
-= rectStc32
.right
;
641 /* move even if stc32 doesn't exist */
642 if (rectChild
.top
>= rectStc32
.bottom
)
644 /* move below visible controls of the parent dialog */
645 rectChild
.top
+= rectParent
.bottom
;
646 rectChild
.top
-= rectStc32
.bottom
- rectStc32
.top
;
649 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
650 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
652 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
655 /* this part moves controls of the parent dialog */
656 hwndChild
= GetWindow(hwndParentDlg
, GW_CHILD
);
659 if (hwndChild
!= hwndChildDlg
)
661 GetWindowRect(hwndChild
, &rectChild
);
662 MapWindowPoints(0, hwndParentDlg
, (LPPOINT
)&rectChild
, 2);
664 /* left,top of stc32 marks the position of controls
665 * from the parent dialog
667 rectChild
.left
+= rectStc32
.left
;
668 rectChild
.top
+= rectStc32
.top
;
670 SetWindowPos(hwndChild
, 0, rectChild
.left
, rectChild
.top
,
671 0, 0, SWP_NOSIZE
| SWP_NOZORDER
);
673 hwndChild
= GetWindow(hwndChild
, GW_HWNDNEXT
);
676 /* calculate the size of the resulting dialog */
678 /* here we have to use original parent size */
679 GetClientRect(hwndParentDlg
, &rectParent
);
680 GetClientRect(hwndChildDlg
, &rectChild
);
681 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent
),
682 wine_dbgstr_rect( &rectChild
), wine_dbgstr_rect( &rectStc32
));
687 if (rectParent
.right
> rectStc32
.right
- rectStc32
.left
)
688 chgx
= rectChild
.right
- ( rectStc32
.right
- rectStc32
.left
);
690 chgx
= rectChild
.right
- rectParent
.right
;
692 if (rectParent
.bottom
> rectStc32
.bottom
- rectStc32
.top
)
693 chgy
= rectChild
.bottom
- ( rectStc32
.bottom
- rectStc32
.top
) - help_fixup
;
695 /* Unconditionally set new dialog
696 * height to that of the child
698 chgy
= rectChild
.bottom
- rectParent
.bottom
;
703 chgy
= rectChild
.bottom
- help_fixup
;
705 /* set the size of the parent dialog */
706 GetWindowRect(hwndParentDlg
, &rectParent
);
707 SetWindowPos(hwndParentDlg
, 0,
709 rectParent
.right
- rectParent
.left
+ chgx
,
710 rectParent
.bottom
- rectParent
.top
+ chgy
,
711 SWP_NOMOVE
| SWP_NOZORDER
);
714 static INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
723 static HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
740 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
742 hinst
= COMDLG32_hInstance
;
743 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
751 hinst
= fodInfos
->ofnInfos
->hInstance
;
752 if(fodInfos
->unicode
)
754 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
755 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, (LPWSTR
)RT_DIALOG
);
759 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
760 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, (LPSTR
)RT_DIALOG
);
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
767 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
768 !(template = LockResource( hDlgTmpl
)))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
774 if (fodInfos
->unicode
)
775 hChildDlg
= CreateDialogIndirectParamW(hinst
, template, hwnd
,
776 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
777 (LPARAM
)fodInfos
->ofnInfos
);
779 hChildDlg
= CreateDialogIndirectParamA(hinst
, template, hwnd
,
780 IsHooked(fodInfos
) ? (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
: FileOpenDlgProcUserTemplate
,
781 (LPARAM
)fodInfos
->ofnInfos
);
784 else if( IsHooked(fodInfos
))
789 WORD menu
,class,title
;
791 GetClientRect(hwnd
,&rectHwnd
);
792 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
| DS_CONTROL
| DS_3DLOOK
;
793 temp
.tmplate
.dwExtendedStyle
= 0;
794 temp
.tmplate
.cdit
= 0;
799 temp
.menu
= temp
.class = temp
.title
= 0;
801 hChildDlg
= CreateDialogIndirectParamA(COMDLG32_hInstance
, &temp
.tmplate
,
802 hwnd
, (DLGPROC
)fodInfos
->ofnInfos
->lpfnHook
, (LPARAM
)fodInfos
->ofnInfos
);
809 /***********************************************************************
810 * SendCustomDlgNotificationMessage
812 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
815 LRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
817 LRESULT hook_result
= 0;
818 FileOpenDlgInfos
*fodInfos
= GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
820 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
822 if(!fodInfos
) return 0;
824 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
826 TRACE("CALL NOTIFY for %x\n", uCode
);
827 if(fodInfos
->unicode
)
830 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
831 ofnNotify
.hdr
.idFrom
=0;
832 ofnNotify
.hdr
.code
= uCode
;
833 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
834 ofnNotify
.pszFile
= NULL
;
835 hook_result
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
840 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
841 ofnNotify
.hdr
.idFrom
=0;
842 ofnNotify
.hdr
.code
= uCode
;
843 ofnNotify
.lpOFN
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
844 ofnNotify
.pszFile
= NULL
;
845 hook_result
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result
);
853 static INT_PTR
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPVOID result
)
857 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
864 /* get path and filenames */
865 len
= SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0 );
866 buffer
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2 + MAX_PATH
) * sizeof(WCHAR
) );
867 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, buffer
);
870 p
= buffer
+ strlenW(buffer
);
872 SendMessageW( fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, len
+ 1, (LPARAM
)p
);
874 if (fodInfos
->unicode
)
876 total
= strlenW( buffer
) + 1;
877 if (result
) lstrcpynW( result
, buffer
, size
);
878 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_w(result
));
882 total
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
883 if (total
<= size
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, result
, size
, NULL
, NULL
);
884 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total
, debugstr_a(result
));
886 HeapFree( GetProcessHeap(), 0, buffer
);
890 /***********************************************************************
891 * FILEDLG95_HandleCustomDialogMessages
893 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
895 static INT_PTR
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
897 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
898 WCHAR lpstrPath
[MAX_PATH
];
901 if(!fodInfos
) return FALSE
;
905 case CDM_GETFILEPATH
:
906 retval
= FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPVOID
)lParam
);
909 case CDM_GETFOLDERPATH
:
910 TRACE("CDM_GETFOLDERPATH:\n");
911 COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPath
);
914 if (fodInfos
->unicode
)
915 lstrcpynW((LPWSTR
)lParam
, lpstrPath
, (int)wParam
);
917 WideCharToMultiByte(CP_ACP
, 0, lpstrPath
, -1,
918 (LPSTR
)lParam
, (int)wParam
, NULL
, NULL
);
920 retval
= lstrlenW(lpstrPath
) + 1;
923 case CDM_GETFOLDERIDLIST
:
924 retval
= COMDLG32_PIDL_ILGetSize(fodInfos
->ShellInfos
.pidlAbsCurrent
);
925 if (retval
<= wParam
)
926 memcpy((void*)lParam
, fodInfos
->ShellInfos
.pidlAbsCurrent
, retval
);
930 TRACE("CDM_GETSPEC:\n");
931 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0) + 1;
934 if (fodInfos
->unicode
)
935 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
937 SendMessageA(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXT
, wParam
, lParam
);
941 case CDM_SETCONTROLTEXT
:
942 TRACE("CDM_SETCONTROLTEXT:\n");
945 if( fodInfos
->unicode
)
946 SetDlgItemTextW( hwnd
, (UINT
) wParam
, (LPWSTR
) lParam
);
948 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
953 case CDM_HIDECONTROL
:
954 /* MSDN states that it should fail for not OFN_EXPLORER case */
955 if (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
957 HWND control
= GetDlgItem( hwnd
, wParam
);
958 if (control
) ShowWindow( control
, SW_HIDE
);
965 if (uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
966 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg
- CDM_FIRST
);
969 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, retval
);
973 /***********************************************************************
974 * FILEDLG95_OnWMGetMMI
976 * WM_GETMINMAXINFO message handler for resizable dialogs
978 static LRESULT
FILEDLG95_OnWMGetMMI( HWND hwnd
, LPMINMAXINFO mmiptr
)
980 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
981 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
982 if( fodInfos
->initial_size
.x
|| fodInfos
->initial_size
.y
)
984 mmiptr
->ptMinTrackSize
= fodInfos
->initial_size
;
989 /***********************************************************************
992 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
994 * FIXME: this could be made more elaborate. Now use a simple scheme
995 * where the file view is enlarged and the controls are either moved
996 * vertically or horizontally to get out of the way. Only the "grip"
997 * is moved in both directions to stay in the corner.
999 static LRESULT
FILEDLG95_OnWMSize(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1005 FileOpenDlgInfos
*fodInfos
;
1007 if( wParam
!= SIZE_RESTORED
) return FALSE
;
1008 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1009 if( !(fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)) return FALSE
;
1010 /* get the new dialog rectangle */
1011 GetWindowRect( hwnd
, &rc
);
1012 TRACE("Size from %d,%d to %d,%d\n", fodInfos
->sizedlg
.cx
, fodInfos
->sizedlg
.cy
,
1013 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
1014 /* not initialized yet */
1015 if( (fodInfos
->sizedlg
.cx
== 0 && fodInfos
->sizedlg
.cy
== 0) ||
1016 ((fodInfos
->sizedlg
.cx
== rc
.right
-rc
.left
) && /* no change */
1017 (fodInfos
->sizedlg
.cy
== rc
.bottom
-rc
.top
)))
1019 chgx
= rc
.right
- rc
.left
- fodInfos
->sizedlg
.cx
;
1020 chgy
= rc
.bottom
- rc
.top
- fodInfos
->sizedlg
.cy
;
1021 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1022 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1023 /* change the size of the view window */
1024 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rcview
);
1025 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcview
, 2);
1026 hdwp
= BeginDeferWindowPos( 10);
1027 DeferWindowPos( hdwp
, fodInfos
->ShellInfos
.hwndView
, NULL
, 0, 0,
1028 rcview
.right
- rcview
.left
+ chgx
,
1029 rcview
.bottom
- rcview
.top
+ chgy
,
1030 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1031 /* change position and sizes of the controls */
1032 for( ctrl
= GetWindow( hwnd
, GW_CHILD
); ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1034 int ctrlid
= GetDlgCtrlID( ctrl
);
1035 GetWindowRect( ctrl
, &rc
);
1036 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1037 if( ctrl
== fodInfos
->DlgInfos
.hwndGrip
)
1039 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1041 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1043 else if( rc
.top
> rcview
.bottom
)
1045 /* if it was below the shell view
1049 /* file name box and file types combo change also width */
1052 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1053 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1054 SWP_NOACTIVATE
| SWP_NOZORDER
);
1056 /* then these buttons must move out of the way */
1060 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
+ chgy
,
1062 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1065 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1067 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1070 else if( rc
.left
> rcview
.right
)
1072 /* if it was to the right of the shell view
1074 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1076 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1083 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1085 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1086 rc
.right
- rc
.left
+ chgx
, rc
.bottom
- rc
.top
,
1087 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1089 case IDC_TOOLBARSTATIC
:
1091 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1093 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1096 /* not resized in windows. Since wine uses this invisible control
1097 * to size the browser view it needs to be resized */
1098 case IDC_SHELLSTATIC
:
1099 DeferWindowPos( hdwp
, ctrl
, NULL
, 0, 0,
1100 rc
.right
- rc
.left
+ chgx
,
1101 rc
.bottom
- rc
.top
+ chgy
,
1102 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1107 if(fodInfos
->DlgInfos
.hwndCustomDlg
&&
1108 (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
)))
1110 for( ctrl
= GetWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, GW_CHILD
);
1111 ctrl
; ctrl
= GetWindow( ctrl
, GW_HWNDNEXT
))
1113 GetWindowRect( ctrl
, &rc
);
1114 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rc
, 2);
1115 if( rc
.top
> rcview
.bottom
)
1117 /* if it was below the shell view
1119 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
, rc
.top
+ chgy
,
1120 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1121 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1123 else if( rc
.left
> rcview
.right
)
1125 /* if it was to the right of the shell view
1127 DeferWindowPos( hdwp
, ctrl
, NULL
, rc
.left
+ chgx
, rc
.top
,
1128 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1129 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1132 /* size the custom dialog at the end: some applications do some
1133 * control re-arranging at this point */
1134 GetClientRect(hwnd
, &rc
);
1135 DeferWindowPos( hdwp
,fodInfos
->DlgInfos
.hwndCustomDlg
, NULL
,
1136 0, 0, rc
.right
, rc
.bottom
, SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1138 EndDeferWindowPos( hdwp
);
1139 /* should not be needed */
1140 RedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_INVALIDATE
);
1144 /***********************************************************************
1147 * File open dialog procedure
1149 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1152 TRACE("%p 0x%04x\n", hwnd
, uMsg
);
1159 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
1161 int gripx
= GetSystemMetrics( SM_CYHSCROLL
);
1162 int gripy
= GetSystemMetrics( SM_CYVSCROLL
);
1164 /* Adds the FileOpenDlgInfos in the property list of the dialog
1165 so it will be easily accessible through a GetPropA(...) */
1166 SetPropA(hwnd
, FileOpenDlgInfosStr
, fodInfos
);
1168 FILEDLG95_InitControls(hwnd
);
1170 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1172 GetWindowRect( hwnd
, &rc
);
1173 fodInfos
->DlgInfos
.hwndGrip
=
1174 CreateWindowExA( 0, "SCROLLBAR", NULL
,
1175 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1176 SBS_SIZEGRIP
| SBS_SIZEBOXBOTTOMRIGHTALIGN
,
1177 rc
.right
- gripx
, rc
.bottom
- gripy
,
1178 gripx
, gripy
, hwnd
, (HMENU
) -1, COMDLG32_hInstance
, NULL
);
1181 fodInfos
->DlgInfos
.hwndCustomDlg
=
1182 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
1184 FILEDLG95_ResizeControls(hwnd
, wParam
, lParam
);
1185 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
1187 if( fodInfos
->DlgInfos
.hwndCustomDlg
)
1188 ShowWindow( fodInfos
->DlgInfos
.hwndCustomDlg
, SW_SHOW
);
1190 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) {
1191 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
1192 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
1195 /* if the app has changed the position of the invisible listbox,
1196 * change that of the listview (browser) as well */
1197 GetWindowRect( fodInfos
->ShellInfos
.hwndView
, &rc
);
1198 GetWindowRect( GetDlgItem( hwnd
, IDC_SHELLSTATIC
), &rcstc
);
1199 if( !EqualRect( &rc
, &rcstc
))
1201 MapWindowPoints( NULL
, hwnd
, (LPPOINT
) &rcstc
, 2);
1202 SetWindowPos( fodInfos
->ShellInfos
.hwndView
, NULL
,
1203 rcstc
.left
, rcstc
.top
, rcstc
.right
- rcstc
.left
, rcstc
.bottom
- rcstc
.top
,
1204 SWP_NOACTIVATE
| SWP_NOZORDER
);
1207 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1209 GetWindowRect( hwnd
, &rc
);
1210 fodInfos
->sizedlg
.cx
= rc
.right
- rc
.left
;
1211 fodInfos
->sizedlg
.cy
= rc
.bottom
- rc
.top
;
1212 fodInfos
->initial_size
.x
= fodInfos
->sizedlg
.cx
;
1213 fodInfos
->initial_size
.y
= fodInfos
->sizedlg
.cy
;
1214 GetClientRect( hwnd
, &rc
);
1215 SetWindowPos( fodInfos
->DlgInfos
.hwndGrip
, NULL
,
1216 rc
.right
- gripx
, rc
.bottom
- gripy
,
1217 0, 0, SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1218 /* resize the dialog to the previous invocation */
1219 if( MemDialogSize
.cx
&& MemDialogSize
.cy
)
1220 SetWindowPos( hwnd
, NULL
,
1221 0, 0, MemDialogSize
.cx
, MemDialogSize
.cy
,
1222 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1225 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1226 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
1231 return FILEDLG95_OnWMSize(hwnd
, wParam
, lParam
);
1232 case WM_GETMINMAXINFO
:
1233 return FILEDLG95_OnWMGetMMI( hwnd
, (LPMINMAXINFO
)lParam
);
1235 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
1238 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
1241 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
1247 case WM_GETISHELLBROWSER
:
1248 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
1252 FileOpenDlgInfos
* fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1253 if (fodInfos
&& fodInfos
->ofnInfos
->Flags
& OFN_ENABLESIZING
)
1254 MemDialogSize
= fodInfos
->sizedlg
;
1255 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
1260 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
1263 /* set up the button tooltips strings */
1264 if(TTN_GETDISPINFOA
== lpnmh
->code
)
1266 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
1267 switch(lpnmh
->idFrom
)
1269 /* Up folder button */
1270 case FCIDM_TB_UPFOLDER
:
1271 stringId
= IDS_UPFOLDER
;
1273 /* New folder button */
1274 case FCIDM_TB_NEWFOLDER
:
1275 stringId
= IDS_NEWFOLDER
;
1277 /* List option button */
1278 case FCIDM_TB_SMALLICON
:
1279 stringId
= IDS_LISTVIEW
;
1281 /* Details option button */
1282 case FCIDM_TB_REPORTVIEW
:
1283 stringId
= IDS_REPORTVIEW
;
1285 /* Desktop button */
1286 case FCIDM_TB_DESKTOP
:
1287 stringId
= IDS_TODESKTOP
;
1292 lpdi
->hinst
= COMDLG32_hInstance
;
1293 lpdi
->lpszText
= MAKEINTRESOURCEA(stringId
);
1298 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
1299 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
1304 /***********************************************************************
1305 * FILEDLG95_InitControls
1307 * WM_INITDIALOG message handler (before hook notification)
1309 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
1311 int win2000plus
= 0;
1313 int handledPath
= FALSE
;
1314 OSVERSIONINFOW osVi
;
1315 static const WCHAR szwSlash
[] = { '\\', 0 };
1316 static const WCHAR szwStar
[] = { '*',0 };
1318 static const TBBUTTON tbb
[] =
1320 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1321 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1322 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1323 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1324 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1325 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1326 {0, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0, 0}, 0, 0 },
1327 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1328 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0, 0}, 0, 0 },
1330 static const TBADDBITMAP tba
= {HINST_COMMCTRL
, IDB_VIEW_SMALL_COLOR
};
1335 HIMAGELIST toolbarImageList
;
1336 SHFILEINFOA shFileInfo
;
1337 ITEMIDLIST
*desktopPidl
;
1339 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1341 TRACE("%p\n", fodInfos
);
1343 /* Get windows version emulating */
1344 osVi
.dwOSVersionInfoSize
= sizeof(osVi
);
1345 GetVersionExW(&osVi
);
1346 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1347 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1348 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1349 win2000plus
= (osVi
.dwMajorVersion
> 4);
1350 if (win2000plus
) win98plus
= TRUE
;
1352 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1354 /* Get the hwnd of the controls */
1355 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1356 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1357 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1359 GetWindowRect( fodInfos
->DlgInfos
.hwndLookInCB
,&rectlook
);
1360 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectlook
,2);
1362 /* construct the toolbar */
1363 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1364 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1366 rectTB
.right
= rectlook
.right
+ rectTB
.right
- rectTB
.left
;
1367 rectTB
.bottom
= rectlook
.top
- 1 + rectTB
.bottom
- rectTB
.top
;
1368 rectTB
.left
= rectlook
.right
;
1369 rectTB
.top
= rectlook
.top
-1;
1371 if (fodInfos
->unicode
)
1372 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExW(0, TOOLBARCLASSNAMEW
, NULL
,
1373 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1374 rectTB
.left
, rectTB
.top
,
1375 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1376 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1378 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, NULL
,
1379 WS_CHILD
| WS_GROUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1380 rectTB
.left
, rectTB
.top
,
1381 rectTB
.right
- rectTB
.left
, rectTB
.bottom
- rectTB
.top
,
1382 hwnd
, (HMENU
)IDC_TOOLBAR
, COMDLG32_hInstance
, NULL
);
1384 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
1386 /* FIXME: use TB_LOADIMAGES when implemented */
1387 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1388 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_SETMAXTEXTROWS
, 0, 0);
1389 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, 12, (LPARAM
) &tba
);
1391 /* Retrieve and add desktop icon to the toolbar */
1392 toolbarImageList
= (HIMAGELIST
)SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_GETIMAGELIST
, 0, 0L);
1393 SHGetSpecialFolderLocation(hwnd
, CSIDL_DESKTOP
, &desktopPidl
);
1394 SHGetFileInfoA((LPCSTR
)desktopPidl
, 0, &shFileInfo
, sizeof(shFileInfo
),
1395 SHGFI_PIDL
| SHGFI_ICON
| SHGFI_SMALLICON
);
1396 ImageList_AddIcon(toolbarImageList
, shFileInfo
.hIcon
);
1398 DestroyIcon(shFileInfo
.hIcon
);
1399 CoTaskMemFree(desktopPidl
);
1401 /* Finish Toolbar Construction */
1402 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSW
, 9, (LPARAM
) tbb
);
1403 SendMessageW(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1405 /* Set the window text with the text specified in the OPENFILENAME structure */
1408 SetWindowTextW(hwnd
,fodInfos
->title
);
1410 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1413 LoadStringW(COMDLG32_hInstance
, IDS_SAVE
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1414 SetWindowTextW(hwnd
, buf
);
1417 /* Initialise the file name edit control */
1418 handledPath
= FALSE
;
1419 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1421 if(fodInfos
->filename
)
1423 /* 1. If win2000 or higher and filename contains a path, use it
1424 in preference over the lpstrInitialDir */
1425 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1426 WCHAR tmpBuf
[MAX_PATH
];
1430 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1433 /* nameBit is always shorter than the original filename */
1434 lstrcpyW(fodInfos
->filename
,nameBit
);
1437 if (fodInfos
->initdir
== NULL
)
1438 MemFree(fodInfos
->initdir
);
1439 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1440 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1442 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1443 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1445 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1448 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1452 /* 2. (All platforms) If initdir is not null, then use it */
1453 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1454 (*fodInfos
->initdir
!=0x00))
1456 /* Work out the proper path as supplied one might be relative */
1457 /* (Here because supplying '.' as dir browses to My Computer) */
1458 if (handledPath
==FALSE
) {
1459 WCHAR tmpBuf
[MAX_PATH
];
1460 WCHAR tmpBuf2
[MAX_PATH
];
1464 lstrcpyW(tmpBuf
, fodInfos
->initdir
);
1465 if( PathFileExistsW(tmpBuf
) ) {
1466 /* initdir does not have to be a directory. If a file is
1467 * specified, the dir part is taken */
1468 if( PathIsDirectoryW(tmpBuf
)) {
1469 if (tmpBuf
[lstrlenW(tmpBuf
)-1] != '\\') {
1470 lstrcatW(tmpBuf
, szwSlash
);
1472 lstrcatW(tmpBuf
, szwStar
);
1474 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1477 MemFree(fodInfos
->initdir
);
1478 fodInfos
->initdir
= MemAlloc((lstrlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1479 lstrcpyW(fodInfos
->initdir
, tmpBuf2
);
1481 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1484 else if (fodInfos
->initdir
)
1486 MemFree(fodInfos
->initdir
);
1487 fodInfos
->initdir
= NULL
;
1488 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1493 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1494 (*fodInfos
->initdir
==0x00)))
1496 /* 3. All except w2k+: if filename contains a path use it */
1497 if (!win2000plus
&& fodInfos
->filename
&&
1498 *fodInfos
->filename
&&
1499 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1500 WCHAR tmpBuf
[MAX_PATH
];
1504 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1509 /* nameBit is always shorter than the original filename */
1510 lstrcpyW(fodInfos
->filename
, nameBit
);
1513 len
= lstrlenW(tmpBuf
);
1514 MemFree(fodInfos
->initdir
);
1515 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1516 lstrcpyW(fodInfos
->initdir
, tmpBuf
);
1519 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1520 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1522 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1525 /* 4. win98+ and win2000+ if any files of specified filter types in
1526 current directory, use it */
1527 if ( win98plus
&& handledPath
== FALSE
&&
1528 fodInfos
->filter
&& *fodInfos
->filter
) {
1530 LPCWSTR lpstrPos
= fodInfos
->filter
;
1531 WIN32_FIND_DATAW FindFileData
;
1536 /* filter is a list... title\0ext\0......\0\0 */
1538 /* Skip the title */
1539 if(! *lpstrPos
) break; /* end */
1540 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1542 /* See if any files exist in the current dir with this extension */
1543 if(! *lpstrPos
) break; /* end */
1545 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1547 if (hFind
== INVALID_HANDLE_VALUE
) {
1548 /* None found - continue search */
1549 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
1553 MemFree(fodInfos
->initdir
);
1554 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1555 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1558 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1559 debugstr_w(lpstrPos
));
1566 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1568 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1569 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1570 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1572 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
))
1574 if(!COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
))
1577 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1578 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1580 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1583 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1586 } else if (handledPath
==FALSE
) {
1587 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1588 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1590 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1593 SetFocus(GetDlgItem(hwnd
, IDC_FILENAME
));
1594 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1596 /* Must the open as read only check box be checked ?*/
1597 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1599 SendDlgItemMessageW(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,TRUE
,0);
1602 /* Must the open as read only check box be hidden? */
1603 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1605 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1606 EnableWindow(GetDlgItem(hwnd
, IDC_OPENREADONLY
), FALSE
);
1609 /* Must the help button be hidden? */
1610 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1612 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1613 EnableWindow(GetDlgItem(hwnd
, pshHelp
), FALSE
);
1616 /* change Open to Save */
1617 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1620 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_BUTTON
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1621 SetDlgItemTextW(hwnd
, IDOK
, buf
);
1622 LoadStringW(COMDLG32_hInstance
, IDS_SAVE_IN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
1623 SetDlgItemTextW(hwnd
, IDC_LOOKINSTATIC
, buf
);
1626 /* Initialize the filter combo box */
1627 FILEDLG95_FILETYPE_Init(hwnd
);
1632 /***********************************************************************
1633 * FILEDLG95_ResizeControls
1635 * WM_INITDIALOG message handler (after hook notification)
1637 static LRESULT
FILEDLG95_ResizeControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1639 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1641 if (fodInfos
->DlgInfos
.hwndCustomDlg
)
1644 UINT flags
= SWP_NOACTIVATE
;
1646 ArrangeCtrlPositions(fodInfos
->DlgInfos
.hwndCustomDlg
, hwnd
,
1647 (fodInfos
->ofnInfos
->Flags
& (OFN_HIDEREADONLY
| OFN_SHOWHELP
)) == OFN_HIDEREADONLY
);
1649 /* resize the custom dialog to the parent size */
1650 if (fodInfos
->ofnInfos
->Flags
& (OFN_ENABLETEMPLATE
| OFN_ENABLETEMPLATEHANDLE
))
1651 GetClientRect(hwnd
, &rc
);
1654 /* our own fake template is zero sized and doesn't have children, so
1655 * there is no need to resize it. Picasa depends on it.
1657 flags
|= SWP_NOSIZE
;
1660 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
1661 0, 0, rc
.right
, rc
.bottom
, flags
);
1665 /* Resize the height, if open as read only checkbox ad help button are
1666 * hidden and we are not using a custom template nor a customDialog
1668 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1669 (!(fodInfos
->ofnInfos
->Flags
&
1670 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1672 RECT rectDlg
, rectHelp
, rectCancel
;
1673 GetWindowRect(hwnd
, &rectDlg
);
1674 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1675 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1676 /* subtract the height of the help button plus the space between the help
1677 * button and the cancel button to the height of the dialog
1679 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1680 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1681 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1687 /***********************************************************************
1688 * FILEDLG95_FillControls
1690 * WM_INITDIALOG message handler (after hook notification)
1692 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1694 LPITEMIDLIST pidlItemId
= NULL
;
1696 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1698 TRACE("dir=%s file=%s\n",
1699 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1701 /* Get the initial directory pidl */
1703 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1705 WCHAR path
[MAX_PATH
];
1707 GetCurrentDirectoryW(MAX_PATH
,path
);
1708 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1711 /* Initialise shell objects */
1712 FILEDLG95_SHELL_Init(hwnd
);
1714 /* Initialize the Look In combo box */
1715 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1717 /* Browse to the initial directory */
1718 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1720 /* Free pidlItem memory */
1721 COMDLG32_SHFree(pidlItemId
);
1725 /***********************************************************************
1728 * Regroups all the cleaning functions of the filedlg
1730 void FILEDLG95_Clean(HWND hwnd
)
1732 FILEDLG95_FILETYPE_Clean(hwnd
);
1733 FILEDLG95_LOOKIN_Clean(hwnd
);
1734 FILEDLG95_SHELL_Clean(hwnd
);
1736 /***********************************************************************
1737 * FILEDLG95_OnWMCommand
1739 * WM_COMMAND message handler
1741 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1743 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1744 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1745 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1751 FILEDLG95_OnOpen(hwnd
);
1755 FILEDLG95_Clean(hwnd
);
1756 EndDialog(hwnd
, FALSE
);
1758 /* Filetype combo box */
1760 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1762 /* LookIn combo box */
1764 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1767 /* --- toolbar --- */
1768 /* Up folder button */
1769 case FCIDM_TB_UPFOLDER
:
1770 FILEDLG95_SHELL_UpFolder(hwnd
);
1772 /* New folder button */
1773 case FCIDM_TB_NEWFOLDER
:
1774 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDERA
);
1776 /* List option button */
1777 case FCIDM_TB_SMALLICON
:
1778 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLISTA
);
1780 /* Details option button */
1781 case FCIDM_TB_REPORTVIEW
:
1782 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILSA
);
1784 /* Details option button */
1785 case FCIDM_TB_DESKTOP
:
1786 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1793 /* Do not use the listview selection anymore */
1794 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1798 /***********************************************************************
1799 * FILEDLG95_OnWMGetIShellBrowser
1801 * WM_GETISHELLBROWSER message handler
1803 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1805 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1809 SetWindowLongPtrW(hwnd
,DWLP_MSGRESULT
,(LONG_PTR
)fodInfos
->Shell
.FOIShellBrowser
);
1815 /***********************************************************************
1816 * FILEDLG95_SendFileOK
1818 * Sends the CDN_FILEOK notification if required
1821 * TRUE if the dialog should close
1822 * FALSE if the dialog should not be closed
1824 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1826 /* ask the hook if we can close */
1827 if(IsHooked(fodInfos
))
1832 /* First send CDN_FILEOK as MSDN doc says */
1833 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
1834 retval
= SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1837 TRACE("canceled\n");
1841 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1842 retval
= SendMessageW(fodInfos
->DlgInfos
.hwndCustomDlg
,
1843 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1846 TRACE("canceled\n");
1853 /***********************************************************************
1854 * FILEDLG95_OnOpenMultipleFiles
1856 * Handles the opening of multiple files.
1859 * check destination buffer size
1861 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1863 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1864 UINT nCount
, nSizePath
;
1865 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1869 if(fodInfos
->unicode
)
1871 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1872 ofn
->lpstrFile
[0] = '\0';
1876 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
) fodInfos
->ofnInfos
;
1877 ofn
->lpstrFile
[0] = '\0';
1880 COMDLG32_GetDisplayNameOf( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1882 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1883 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1884 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1886 LPWSTR lpstrTemp
= lpstrFileList
;
1888 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1892 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1895 WCHAR lpstrNotFound
[100];
1896 WCHAR lpstrMsg
[100];
1898 static const WCHAR nl
[] = {'\n',0};
1900 LoadStringW(COMDLG32_hInstance
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1901 LoadStringW(COMDLG32_hInstance
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1903 lstrcpyW(tmp
, lpstrTemp
);
1905 lstrcatW(tmp
, lpstrNotFound
);
1907 lstrcatW(tmp
, lpstrMsg
);
1909 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1913 /* move to the next file in the list of files */
1914 lpstrTemp
+= lstrlenW(lpstrTemp
) + 1;
1915 COMDLG32_SHFree(pidl
);
1919 nSizePath
= lstrlenW(lpstrPathSpec
) + 1;
1920 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1922 /* For "oldstyle" dialog the components have to
1923 be separated by blanks (not '\0'!) and short
1924 filenames have to be used! */
1925 FIXME("Components have to be separated by blanks\n");
1927 if(fodInfos
->unicode
)
1929 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
1930 lstrcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1931 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1935 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
1937 if (ofn
->lpstrFile
!= NULL
)
1939 nSizePath
= WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1940 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1941 if (ofn
->nMaxFile
> nSizePath
)
1943 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1944 ofn
->lpstrFile
+ nSizePath
,
1945 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1950 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
;
1951 fodInfos
->ofnInfos
->nFileExtension
= 0;
1953 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1956 /* clean and exit */
1957 FILEDLG95_Clean(hwnd
);
1958 return EndDialog(hwnd
,TRUE
);
1961 /***********************************************************************
1964 * Ok button WM_COMMAND message handler
1966 * If the function succeeds, the return value is nonzero.
1968 #define ONOPEN_BROWSE 1
1969 #define ONOPEN_OPEN 2
1970 #define ONOPEN_SEARCH 3
1971 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1973 WCHAR strMsgTitle
[MAX_PATH
];
1974 WCHAR strMsgText
[MAX_PATH
];
1976 LoadStringW(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
)/sizeof(WCHAR
));
1978 strMsgTitle
[0] = '\0';
1979 LoadStringW(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
)/sizeof(WCHAR
));
1980 MessageBoxW(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1983 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1985 LPWSTR lpstrFileList
;
1986 UINT nFileCount
= 0;
1989 WCHAR lpstrPathAndFile
[MAX_PATH
];
1990 WCHAR lpstrTemp
[MAX_PATH
];
1991 LPSHELLFOLDER lpsf
= NULL
;
1993 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
1995 TRACE("hwnd=%p\n", hwnd
);
1997 /* get the files from the edit control */
1998 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
2000 /* try if the user selected a folder in the shellview */
2003 BrowseSelectedFolder(hwnd
);
2009 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
2013 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
2016 Step 1: Build a complete path name from the current folder and
2017 the filename or path in the edit box.
2019 - the path in the edit box is a root path
2020 (with or without drive letter)
2021 - the edit box contains ".." (or a path with ".." in it)
2024 /* Get the current directory name */
2025 if (!COMDLG32_GetDisplayNameOf(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
2028 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
2030 PathAddBackslashW(lpstrPathAndFile
);
2032 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
2034 /* if the user specified a fully qualified path use it */
2035 if(PathIsRelativeW(lpstrFileList
))
2037 lstrcatW(lpstrPathAndFile
, lpstrFileList
);
2041 /* does the path have a drive letter? */
2042 if (PathGetDriveNumberW(lpstrFileList
) == -1)
2043 lstrcpyW(lpstrPathAndFile
+2, lpstrFileList
);
2045 lstrcpyW(lpstrPathAndFile
, lpstrFileList
);
2048 /* resolve "." and ".." */
2049 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
2050 lstrcpyW(lpstrPathAndFile
, lpstrTemp
);
2051 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
2053 MemFree(lpstrFileList
);
2056 Step 2: here we have a cleaned up path
2058 We have to parse the path step by step to see if we have to browse
2059 to a folder if the path points to a directory or the last
2060 valid element is a directory.
2063 lpstrPathAndFile: cleaned up path
2067 (fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
2068 !(fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
))
2069 nOpenAction
= ONOPEN_OPEN
;
2071 nOpenAction
= ONOPEN_BROWSE
;
2073 /* don't apply any checks with OFN_NOVALIDATE */
2075 LPWSTR lpszTemp
, lpszTemp1
;
2076 LPITEMIDLIST pidl
= NULL
;
2077 static const WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
2079 /* check for invalid chars */
2080 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2082 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
2087 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
2089 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
2092 LPSHELLFOLDER lpsfChild
;
2093 WCHAR lpwstrTemp
[MAX_PATH
];
2094 DWORD dwEaten
, dwAttributes
;
2097 lstrcpyW(lpwstrTemp
, lpszTemp
);
2098 p
= PathFindNextComponentW(lpwstrTemp
);
2100 if (!p
) break; /* end of path */
2103 lpszTemp
= lpszTemp
+ lstrlenW(lpwstrTemp
);
2105 /* There are no wildcards when OFN_NOVALIDATE is set */
2106 if(*lpszTemp
==0 && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2108 static const WCHAR wszWild
[] = { '*', '?', 0 };
2109 /* if the last element is a wildcard do a search */
2110 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
2112 nOpenAction
= ONOPEN_SEARCH
;
2116 lpszTemp1
= lpszTemp
;
2118 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
2120 /* append a backslash to drive letters */
2121 if(lstrlenW(lpwstrTemp
)==2 && lpwstrTemp
[1] == ':' &&
2122 ((lpwstrTemp
[0] >= 'a' && lpwstrTemp
[0] <= 'z') ||
2123 (lpwstrTemp
[0] >= 'A' && lpwstrTemp
[0] <= 'Z')))
2125 PathAddBackslashW(lpwstrTemp
);
2128 dwAttributes
= SFGAO_FOLDER
;
2129 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
2131 /* the path component is valid, we have a pidl of the next path component */
2132 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes
, pidl
);
2133 if(dwAttributes
& SFGAO_FOLDER
)
2135 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
2137 ERR("bind to failed\n"); /* should not fail */
2140 IShellFolder_Release(lpsf
);
2148 /* end dialog, return value */
2149 nOpenAction
= ONOPEN_OPEN
;
2152 COMDLG32_SHFree(pidl
);
2155 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
2157 if(*lpszTemp
|| /* points to trailing null for last path element */
2158 (lpwstrTemp
[strlenW(lpwstrTemp
)-1] == '\\')) /* or if last element ends in '\' */
2160 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
2162 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
2168 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
2169 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
2171 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
2175 /* change to the current folder */
2176 nOpenAction
= ONOPEN_OPEN
;
2181 nOpenAction
= ONOPEN_OPEN
;
2185 if(pidl
) COMDLG32_SHFree(pidl
);
2189 Step 3: here we have a cleaned up and validated path
2192 lpsf: ShellFolder bound to the rightmost valid path component
2193 lpstrPathAndFile: cleaned up path
2194 nOpenAction: action to do
2196 TRACE("end validate sf=%p\n", lpsf
);
2200 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
2201 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
2204 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2207 /* replace the current filter */
2208 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2209 len
= lstrlenW(lpszTemp
)+1;
2210 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
2211 lstrcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
2213 /* set the filter cb to the extension when possible */
2214 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
2215 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
2218 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
2219 TRACE("ONOPEN_BROWSE\n");
2221 IPersistFolder2
* ppf2
;
2222 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
2224 LPITEMIDLIST pidlCurrent
;
2225 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
2226 IPersistFolder2_Release(ppf2
);
2227 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
2229 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
))
2230 && fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2232 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2235 else if( nOpenAction
== ONOPEN_SEARCH
)
2237 if (fodInfos
->Shell
.FOIShellView
)
2238 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2240 COMDLG32_SHFree(pidlCurrent
);
2241 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, -1);
2246 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
2247 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
2251 /* update READONLY check box flag */
2252 if ((SendMessageW(GetDlgItem(hwnd
,IDC_OPENREADONLY
),BM_GETCHECK
,0,0) & 0x03) == BST_CHECKED
)
2253 fodInfos
->ofnInfos
->Flags
|= OFN_READONLY
;
2255 fodInfos
->ofnInfos
->Flags
&= ~OFN_READONLY
;
2257 /* Attach the file extension with file name*/
2258 ext
= PathFindExtensionW(lpstrPathAndFile
);
2261 /* if no extension is specified with file name, then */
2262 /* attach the extension from file filter or default one */
2264 WCHAR
*filterExt
= NULL
;
2265 LPWSTR lpstrFilter
= NULL
;
2266 static const WCHAR szwDot
[] = {'.',0};
2267 int PathLength
= lstrlenW(lpstrPathAndFile
);
2270 lstrcatW(lpstrPathAndFile
, szwDot
);
2272 /*Get the file extension from file type filter*/
2273 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2274 fodInfos
->ofnInfos
->nFilterIndex
-1);
2276 if (lpstrFilter
!= (LPWSTR
)CB_ERR
) /* control is not empty */
2277 filterExt
= PathFindExtensionW(lpstrFilter
);
2279 if ( filterExt
&& *filterExt
) /* attach the file extension from file type filter*/
2280 lstrcatW(lpstrPathAndFile
, filterExt
+ 1);
2281 else if ( fodInfos
->defext
) /* attach the default file extension*/
2282 lstrcatW(lpstrPathAndFile
, fodInfos
->defext
);
2284 /* In Open dialog: if file does not exist try without extension */
2285 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) && !PathFileExistsW(lpstrPathAndFile
))
2286 lpstrPathAndFile
[PathLength
] = '\0';
2289 if (fodInfos
->defext
) /* add default extension */
2291 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2294 if (!lstrcmpiW(fodInfos
->defext
, ext
))
2295 fodInfos
->ofnInfos
->Flags
&= ~OFN_EXTENSIONDIFFERENT
;
2297 fodInfos
->ofnInfos
->Flags
|= OFN_EXTENSIONDIFFERENT
;
2300 /* In Save dialog: check if the file already exists */
2301 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
2302 && fodInfos
->ofnInfos
->Flags
& OFN_OVERWRITEPROMPT
2303 && PathFileExistsW(lpstrPathAndFile
))
2305 WCHAR lpstrOverwrite
[100];
2308 LoadStringW(COMDLG32_hInstance
, IDS_OVERWRITEFILE
, lpstrOverwrite
, 100);
2309 answer
= MessageBoxW(hwnd
, lpstrOverwrite
, fodInfos
->title
,
2310 MB_YESNO
| MB_ICONEXCLAMATION
);
2318 /* In Open dialog: check if it should be created if it doesn't exist */
2319 if (!(fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
2320 && fodInfos
->ofnInfos
->Flags
& OFN_CREATEPROMPT
2321 && !PathFileExistsW(lpstrPathAndFile
))
2323 WCHAR lpstrCreate
[100];
2326 LoadStringW(COMDLG32_hInstance
, IDS_CREATEFILE
, lpstrCreate
, 100);
2327 answer
= MessageBoxW(hwnd
, lpstrCreate
, fodInfos
->title
,
2328 MB_YESNO
| MB_ICONEXCLAMATION
);
2336 /* Check that the size of the file does not exceed buffer size.
2337 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2338 if(lstrlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
2339 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
2342 /* fill destination buffer */
2343 if (fodInfos
->ofnInfos
->lpstrFile
)
2345 if(fodInfos
->unicode
)
2347 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2349 lstrcpynW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
2350 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2351 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
2355 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2357 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
2358 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
2359 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
2360 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
2364 if(fodInfos
->unicode
)
2368 /* set filename offset */
2369 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
2370 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
2372 /* set extension offset */
2373 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
2374 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
2379 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2381 /* set filename offset */
2382 lpszTemp
= PathFindFileNameA(ofn
->lpstrFile
);
2383 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- ofn
->lpstrFile
);
2385 /* set extension offset */
2386 lpszTemp
= PathFindExtensionA(ofn
->lpstrFile
);
2387 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- ofn
->lpstrFile
) + 1 : 0;
2390 /* set the lpstrFileTitle */
2391 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
2393 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
2394 if(fodInfos
->unicode
)
2396 LPOPENFILENAMEW ofn
= fodInfos
->ofnInfos
;
2397 lstrcpynW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
2401 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2402 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
2403 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
2407 /* copy currently selected filter to lpstrCustomFilter */
2408 if (fodInfos
->ofnInfos
->lpstrCustomFilter
)
2410 LPOPENFILENAMEA ofn
= (LPOPENFILENAMEA
)fodInfos
->ofnInfos
;
2411 int len
= WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2412 NULL
, 0, NULL
, NULL
);
2413 if (len
+ strlen(ofn
->lpstrCustomFilter
) + 1 <= ofn
->nMaxCustFilter
)
2415 LPSTR s
= ofn
->lpstrCustomFilter
;
2416 s
+= strlen(ofn
->lpstrCustomFilter
)+1;
2417 WideCharToMultiByte(CP_ACP
, 0, fodInfos
->ShellInfos
.lpstrCurrentFilter
, -1,
2418 s
, len
, NULL
, NULL
);
2423 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
2427 FILEDLG95_Clean(hwnd
);
2428 ret
= EndDialog(hwnd
, TRUE
);
2434 size
= lstrlenW(lpstrPathAndFile
) + 1;
2435 if (fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
)
2437 /* return needed size in first two bytes of lpstrFile */
2438 *(WORD
*)fodInfos
->ofnInfos
->lpstrFile
= size
;
2439 FILEDLG95_Clean(hwnd
);
2440 ret
= EndDialog(hwnd
, FALSE
);
2441 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL
);
2448 if(lpsf
) IShellFolder_Release(lpsf
);
2452 /***********************************************************************
2453 * FILEDLG95_SHELL_Init
2455 * Initialisation of the shell objects
2457 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
2459 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2464 * Initialisation of the FileOpenDialogInfos structure
2470 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
2472 /* Disable multi-select if flag not set */
2473 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
2475 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
2477 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
2478 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
2480 /* Construct the IShellBrowser interface */
2481 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
2486 /***********************************************************************
2487 * FILEDLG95_SHELL_ExecuteCommand
2489 * Change the folder option and refresh the view
2490 * If the function succeeds, the return value is nonzero.
2492 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
2494 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2497 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
2499 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
2504 CMINVOKECOMMANDINFO ci
;
2505 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
2506 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
2510 IContextMenu_InvokeCommand(pcm
, &ci
);
2511 IContextMenu_Release(pcm
);
2517 /***********************************************************************
2518 * FILEDLG95_SHELL_UpFolder
2520 * Browse to the specified object
2521 * If the function succeeds, the return value is nonzero.
2523 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
2525 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2529 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2533 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2534 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2540 /***********************************************************************
2541 * FILEDLG95_SHELL_BrowseToDesktop
2543 * Browse to the Desktop
2544 * If the function succeeds, the return value is nonzero.
2546 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2548 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2554 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2555 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2556 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2557 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
2558 COMDLG32_SHFree(pidl
);
2559 return SUCCEEDED(hres
);
2561 /***********************************************************************
2562 * FILEDLG95_SHELL_Clean
2564 * Cleans the memory used by shell objects
2566 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2568 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2572 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2574 /* clean Shell interfaces */
2575 if (fodInfos
->Shell
.FOIShellView
)
2577 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2578 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2580 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2581 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2582 if (fodInfos
->Shell
.FOIDataObject
)
2583 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2586 /***********************************************************************
2587 * FILEDLG95_FILETYPE_Init
2589 * Initialisation of the file type combo box
2591 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2593 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2594 int nFilters
= 0; /* number of filters */
2599 if(fodInfos
->customfilter
)
2601 /* customfilter has one entry... title\0ext\0
2602 * Set first entry of combo box item with customfilter
2605 LPCWSTR lpstrPos
= fodInfos
->customfilter
;
2608 lpstrPos
+= lstrlenW(fodInfos
->customfilter
) + 1;
2610 /* Copy the extensions */
2611 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2612 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2613 lstrcpyW(lpstrExt
,lpstrPos
);
2615 /* Add the item at the end of the combo */
2616 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->customfilter
);
2617 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2620 if(fodInfos
->filter
)
2622 LPCWSTR lpstrPos
= fodInfos
->filter
;
2626 /* filter is a list... title\0ext\0......\0\0
2627 * Set the combo item text to the title and the item data
2630 LPCWSTR lpstrDisplay
;
2634 if(! *lpstrPos
) break; /* end */
2635 lpstrDisplay
= lpstrPos
;
2636 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2638 CBAddString(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2642 /* Copy the extensions */
2643 if (!(lpstrExt
= MemAlloc((lstrlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2644 lstrcpyW(lpstrExt
,lpstrPos
);
2645 lpstrPos
+= lstrlenW(lpstrPos
) + 1;
2647 /* Add the item at the end of the combo */
2648 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
-1, lpstrExt
);
2650 /* malformed filters are added anyway... */
2651 if (!*lpstrExt
) break;
2656 * Set the current filter to the one specified
2657 * in the initialisation structure
2659 if (fodInfos
->filter
|| fodInfos
->customfilter
)
2663 /* Check to make sure our index isn't out of bounds. */
2664 if ( fodInfos
->ofnInfos
->nFilterIndex
>
2665 nFilters
- (fodInfos
->customfilter
== NULL
? 0 : 1) )
2666 fodInfos
->ofnInfos
->nFilterIndex
= (fodInfos
->customfilter
== NULL
? 1 : 0);
2668 /* set default filter index */
2669 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2670 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2672 /* calculate index of Combo Box item */
2673 nFilterIndexCB
= fodInfos
->ofnInfos
->nFilterIndex
;
2674 if (fodInfos
->customfilter
== NULL
)
2677 /* Set the current index selection. */
2678 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilterIndexCB
);
2680 /* Get the corresponding text string from the combo box. */
2681 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2684 if ((INT_PTR
)lpstrFilter
== CB_ERR
) /* control is empty */
2690 CharLowerW(lpstrFilter
); /* lowercase */
2691 len
= lstrlenW(lpstrFilter
)+1;
2692 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2693 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2696 fodInfos
->ofnInfos
->nFilterIndex
= 0;
2700 /***********************************************************************
2701 * FILEDLG95_FILETYPE_OnCommand
2703 * WM_COMMAND of the file type combo box
2704 * If the function succeeds, the return value is nonzero.
2706 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2708 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2716 /* Get the current item of the filetype combo box */
2717 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2719 /* set the current filter index */
2720 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+
2721 (fodInfos
->customfilter
== NULL
? 1 : 0);
2723 /* Set the current filter with the current selection */
2724 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2726 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2728 if((INT_PTR
)lpstrFilter
!= CB_ERR
)
2731 CharLowerW(lpstrFilter
); /* lowercase */
2732 len
= lstrlenW(lpstrFilter
)+1;
2733 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2734 lstrcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2735 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
2736 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2739 /* Refresh the actual view to display the included items*/
2740 if (fodInfos
->Shell
.FOIShellView
)
2741 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2746 /***********************************************************************
2747 * FILEDLG95_FILETYPE_SearchExt
2749 * searches for an extension in the filetype box
2751 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2753 int i
, iCount
= CBGetCount(hwnd
);
2755 TRACE("%s\n", debugstr_w(lpstrExt
));
2757 if(iCount
!= CB_ERR
)
2759 for(i
=0;i
<iCount
;i
++)
2761 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2768 /***********************************************************************
2769 * FILEDLG95_FILETYPE_Clean
2771 * Clean the memory used by the filetype combo box
2773 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2775 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
2777 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2781 /* Delete each string of the combo and their associated data */
2782 if(iCount
!= CB_ERR
)
2784 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2786 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2787 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2790 /* Current filter */
2791 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2795 /***********************************************************************
2796 * FILEDLG95_LOOKIN_Init
2798 * Initialisation of the look in combo box
2801 /* Small helper function, to determine if the unixfs shell extension is rooted
2802 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2804 static inline BOOL
FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2806 static const WCHAR wszRootedAtDesktop
[] = { 'S','o','f','t','w','a','r','e','\\',
2807 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2808 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2809 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2810 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2811 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2812 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2814 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszRootedAtDesktop
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2821 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2823 IShellFolder
*psfRoot
, *psfDrives
;
2824 IEnumIDList
*lpeRoot
, *lpeDrives
;
2825 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2827 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2831 liInfos
->iMaxIndentation
= 0;
2833 SetPropA(hwndCombo
, LookInInfosStr
, liInfos
);
2835 /* set item height for both text field and listbox */
2836 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2837 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2839 /* Turn on the extended UI for the combo box like Windows does */
2840 CBSetExtendedUI(hwndCombo
, TRUE
);
2842 /* Initialise data of Desktop folder */
2843 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2844 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2845 COMDLG32_SHFree(pidlTmp
);
2847 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2849 SHGetDesktopFolder(&psfRoot
);
2853 /* enumerate the contents of the desktop */
2854 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2856 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2858 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2860 /* If the unixfs extension is rooted, we don't expand the drives by default */
2861 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2863 /* special handling for CSIDL_DRIVES */
2864 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2866 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2868 /* enumerate the drives */
2869 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2871 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2873 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2874 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2875 COMDLG32_SHFree(pidlAbsTmp
);
2876 COMDLG32_SHFree(pidlTmp1
);
2878 IEnumIDList_Release(lpeDrives
);
2880 IShellFolder_Release(psfDrives
);
2885 COMDLG32_SHFree(pidlTmp
);
2887 IEnumIDList_Release(lpeRoot
);
2889 IShellFolder_Release(psfRoot
);
2892 COMDLG32_SHFree(pidlDrives
);
2895 /***********************************************************************
2896 * FILEDLG95_LOOKIN_DrawItem
2898 * WM_DRAWITEM message handler
2900 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2902 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2903 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2904 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2908 HIMAGELIST ilItemImage
;
2911 LPSFOLDER tmpFolder
;
2912 LookInInfos
*liInfos
= GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2916 if(pDIStruct
->itemID
== -1)
2919 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2920 pDIStruct
->itemID
)))
2924 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2926 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2930 SHGFI_PIDL
| SHGFI_SMALLICON
|
2931 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2932 SHGFI_DISPLAYNAME
);
2936 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2940 SHGFI_PIDL
| SHGFI_SMALLICON
|
2941 SHGFI_SYSICONINDEX
|
2945 /* Is this item selected ? */
2946 if(pDIStruct
->itemState
& ODS_SELECTED
)
2948 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2949 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2950 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2954 SetTextColor(pDIStruct
->hDC
,crText
);
2955 SetBkColor(pDIStruct
->hDC
,crWin
);
2956 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2959 /* Do not indent item if drawing in the edit of the combo */
2960 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2963 ilItemImage
= (HIMAGELIST
) SHGetFileInfoW ((LPCWSTR
) tmpFolder
->pidlItem
,
2967 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2968 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2973 iIndentation
= tmpFolder
->m_iIndent
;
2975 /* Draw text and icon */
2977 /* Initialise the icon display area */
2978 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2979 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2980 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2981 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2983 /* Initialise the text display area */
2984 GetTextMetricsW(pDIStruct
->hDC
, &tm
);
2985 rectText
.left
= rectIcon
.right
;
2987 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2988 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2990 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2992 /* Draw the icon from the image list */
2993 ImageList_Draw(ilItemImage
,
3000 /* Draw the associated text */
3001 if(sfi
.szDisplayName
)
3002 TextOutW(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,lstrlenW(sfi
.szDisplayName
));
3008 /***********************************************************************
3009 * FILEDLG95_LOOKIN_OnCommand
3011 * LookIn combo box WM_COMMAND message handler
3012 * If the function succeeds, the return value is nonzero.
3014 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
3016 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3018 TRACE("%p\n", fodInfos
);
3024 LPSFOLDER tmpFolder
;
3027 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
3029 if( iItem
== CB_ERR
) return FALSE
;
3031 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
3036 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
3037 tmpFolder
->pidlItem
,
3040 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3041 SendCustomDlgNotificationMessage(hwnd
, CDN_FOLDERCHANGE
);
3051 /***********************************************************************
3052 * FILEDLG95_LOOKIN_AddItem
3054 * Adds an absolute pidl item to the lookin combo box
3055 * returns the index of the inserted item
3057 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
3059 LPITEMIDLIST pidlNext
;
3062 LookInInfos
*liInfos
;
3064 TRACE("%08x\n", iInsertId
);
3069 if(!(liInfos
= GetPropA(hwnd
,LookInInfosStr
)))
3072 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
3073 tmpFolder
->m_iIndent
= 0;
3075 /* Calculate the indentation of the item in the lookin*/
3077 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
3079 tmpFolder
->m_iIndent
++;
3082 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
3084 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
3085 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
3087 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
3088 SHGetFileInfoW((LPCWSTR
)pidl
,
3092 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
3093 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
3095 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi
.szDisplayName
), sfi
.dwAttributes
);
3097 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
3101 TRACE("-- Add %s at %u\n", debugstr_w(sfi
.szDisplayName
), tmpFolder
->m_iIndent
);
3103 /* Add the item at the end of the list */
3106 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
3108 /* Insert the item at the iInsertId position*/
3111 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
3114 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
3118 COMDLG32_SHFree( tmpFolder
->pidlItem
);
3119 MemFree( tmpFolder
);
3124 /***********************************************************************
3125 * FILEDLG95_LOOKIN_InsertItemAfterParent
3127 * Insert an item below its parent
3129 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
3132 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
3137 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
3141 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
3144 /* Free pidlParent memory */
3145 COMDLG32_SHFree(pidlParent
);
3147 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
3150 /***********************************************************************
3151 * FILEDLG95_LOOKIN_SelectItem
3153 * Adds an absolute pidl item to the lookin combo box
3154 * returns the index of the inserted item
3156 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
3159 LookInInfos
*liInfos
;
3163 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
3165 liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3169 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
3170 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
3175 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3176 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
3180 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
3182 if(iRemovedItem
< iItemPos
)
3187 CBSetCurSel(hwnd
,iItemPos
);
3188 liInfos
->uSelectedItem
= iItemPos
;
3194 /***********************************************************************
3195 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3197 * Remove the item with an expansion level over iExpansionLevel
3199 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
3202 LookInInfos
*liInfos
= GetPropA(hwnd
,LookInInfosStr
);
3206 if(liInfos
->iMaxIndentation
<= 2)
3209 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
3211 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
3212 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3214 CBDeleteString(hwnd
,iItemPos
);
3215 liInfos
->iMaxIndentation
--;
3223 /***********************************************************************
3224 * FILEDLG95_LOOKIN_SearchItem
3226 * Search for pidl in the lookin combo box
3227 * returns the index of the found item
3229 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
3232 int iCount
= CBGetCount(hwnd
);
3234 TRACE("0x%08lx 0x%x\n",searchArg
, iSearchMethod
);
3236 if (iCount
!= CB_ERR
)
3240 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
3242 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
3244 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
3252 /***********************************************************************
3253 * FILEDLG95_LOOKIN_Clean
3255 * Clean the memory used by the lookin combo box
3257 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
3259 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3260 LookInInfos
*liInfos
= GetPropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3262 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
3266 /* Delete each string of the combo and their associated data */
3267 if (iCount
!= CB_ERR
)
3269 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
3271 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3272 COMDLG32_SHFree(tmpFolder
->pidlItem
);
3274 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
3278 /* LookInInfos structure */
3280 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
3283 /***********************************************************************
3284 * FILEDLG95_FILENAME_FillFromSelection
3286 * fills the edit box from the cached DataObject
3288 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
3290 FileOpenDlgInfos
*fodInfos
;
3292 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
3293 WCHAR lpstrTemp
[MAX_PATH
];
3294 LPWSTR lpstrAllFile
, lpstrCurrFile
;
3297 fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3299 /* Count how many files we have */
3300 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
3302 /* calculate the string length, count files */
3303 if (nFileSelected
>= 1)
3305 nLength
+= 3; /* first and last quotes, trailing \0 */
3306 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3308 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3312 /* get the total length of the selected file names */
3313 lpstrTemp
[0] = '\0';
3314 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3316 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
3318 nLength
+= lstrlenW( lpstrTemp
) + 3;
3321 COMDLG32_SHFree( pidl
);
3326 /* allocate the buffer */
3327 if (nFiles
<= 1) nLength
= MAX_PATH
;
3328 lpstrAllFile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
* sizeof(WCHAR
));
3330 /* Generate the string for the edit control */
3333 lpstrCurrFile
= lpstrAllFile
;
3334 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
3336 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
3340 /* get the file name */
3341 lpstrTemp
[0] = '\0';
3342 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
3344 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
3348 *lpstrCurrFile
++ = '\"';
3349 lstrcpyW( lpstrCurrFile
, lpstrTemp
);
3350 lpstrCurrFile
+= lstrlenW( lpstrTemp
);
3351 *lpstrCurrFile
++ = '\"';
3352 *lpstrCurrFile
++ = ' ';
3357 lstrcpyW( lpstrAllFile
, lpstrTemp
);
3360 COMDLG32_SHFree( pidl
);
3363 SetWindowTextW( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
3365 /* Select the file name like Windows does */
3366 SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, EM_SETSEL
, 0, (LPARAM
)-1);
3368 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
3372 /* copied from shell32 to avoid linking to it
3373 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3374 * is dependent on whether emulated OS is unicode or not.
3376 static HRESULT
COMDLG32_StrRetToStrNW (LPWSTR dest
, DWORD len
, LPSTRRET src
, const ITEMIDLIST
*pidl
)
3381 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
3382 COMDLG32_SHFree(src
->u
.pOleStr
);
3386 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
3391 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1, dest
, len
) && len
)
3396 FIXME("unknown type %x!\n", src
->uType
);
3397 if (len
) *dest
= '\0';
3403 /***********************************************************************
3404 * FILEDLG95_FILENAME_GetFileNames
3406 * Copies the filenames to a delimited string list.
3407 * The delimiter is specified by the parameter 'separator',
3408 * usually either a space or a nul
3410 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
3412 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3413 UINT nStrCharCount
= 0; /* index in src buffer */
3414 UINT nFileIndex
= 0; /* index in dest buffer */
3415 UINT nFileCount
= 0; /* number of files */
3416 UINT nStrLen
= 0; /* length of string in edit control */
3417 LPWSTR lpstrEdit
; /* buffer for string from edit control */
3421 /* get the filenames from the edit control */
3422 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
3423 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
3424 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
3426 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
3428 /* we might get single filename without any '"',
3429 * so we need nStrLen + terminating \0 + end-of-list \0 */
3430 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
3433 /* build delimited file list from filenames */
3434 while ( nStrCharCount
<= nStrLen
)
3436 if ( lpstrEdit
[nStrCharCount
]=='"' )
3439 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
3441 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
3444 (*lpstrFileList
)[nFileIndex
++] = 0;
3450 /* single, unquoted string */
3451 if ((nStrLen
> 0) && (nFileIndex
== 0) )
3453 lstrcpyW(*lpstrFileList
, lpstrEdit
);
3454 nFileIndex
= lstrlenW(lpstrEdit
) + 1;
3459 (*lpstrFileList
)[nFileIndex
++] = '\0';
3461 *sizeUsed
= nFileIndex
;
3466 #define SETDefFormatEtc(fe,cf,med) \
3468 (fe).cfFormat = cf;\
3469 (fe).dwAspect = DVASPECT_CONTENT; \
3476 * DATAOBJECT Helper functions
3479 /***********************************************************************
3480 * COMCTL32_ReleaseStgMedium
3482 * like ReleaseStgMedium from ole32
3484 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
3486 if(medium
.pUnkForRelease
)
3488 IUnknown_Release(medium
.pUnkForRelease
);
3492 GlobalUnlock(medium
.u
.hGlobal
);
3493 GlobalFree(medium
.u
.hGlobal
);
3497 /***********************************************************************
3498 * GetPidlFromDataObject
3500 * Return pidl(s) by number from the cached DataObject
3502 * nPidlIndex=0 gets the fully qualified root path
3504 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
3508 FORMATETC formatetc
;
3509 LPITEMIDLIST pidl
= NULL
;
3511 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
3516 /* Set the FORMATETC structure*/
3517 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3519 /* Get the pidls from IDataObject */
3520 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3522 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3523 if(nPidlIndex
<= cida
->cidl
)
3525 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
3527 COMCTL32_ReleaseStgMedium(medium
);
3532 /***********************************************************************
3535 * Return the number of selected items in the DataObject.
3538 static UINT
GetNumSelected( IDataObject
*doSelected
)
3542 FORMATETC formatetc
;
3544 TRACE("sv=%p\n", doSelected
);
3546 if (!doSelected
) return 0;
3548 /* Set the FORMATETC structure*/
3549 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA
), TYMED_HGLOBAL
);
3551 /* Get the pidls from IDataObject */
3552 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
3554 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
3555 retVal
= cida
->cidl
;
3556 COMCTL32_ReleaseStgMedium(medium
);
3566 /***********************************************************************
3569 * Get the pidl's display name (relative to folder) and
3570 * put it in lpstrFileName.
3572 * Return NOERROR on success,
3576 static HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPWSTR lpstrFileName
)
3581 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
3585 SHGetDesktopFolder(&lpsf
);
3586 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
3587 IShellFolder_Release(lpsf
);
3591 /* Get the display name of the pidl relative to the folder */
3592 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
3594 return COMDLG32_StrRetToStrNW(lpstrFileName
, MAX_PATH
, &str
, pidl
);
3599 /***********************************************************************
3600 * GetShellFolderFromPidl
3602 * pidlRel is the item pidl relative
3603 * Return the IShellFolder of the absolute pidl
3605 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
3607 IShellFolder
*psf
= NULL
,*psfParent
;
3609 TRACE("%p\n", pidlAbs
);
3611 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
3614 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3616 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3618 IShellFolder_Release(psfParent
);
3622 /* return the desktop */
3628 /***********************************************************************
3631 * Return the LPITEMIDLIST to the parent of the pidl in the list
3633 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3635 LPITEMIDLIST pidlParent
;
3637 TRACE("%p\n", pidl
);
3639 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3640 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3645 /***********************************************************************
3648 * returns the pidl of the file name relative to folder
3649 * NULL if an error occurred
3651 static LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3653 LPITEMIDLIST pidl
= NULL
;
3656 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3658 if(!lpcstrFileName
) return NULL
;
3659 if(!*lpcstrFileName
) return NULL
;
3663 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3664 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3665 IShellFolder_Release(lpsf
);
3670 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3677 static BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPCITEMIDLIST pidl
)
3679 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3682 TRACE("%p, %p\n", psf
, pidl
);
3684 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3686 TRACE("-- 0x%08x 0x%08x\n", uAttr
, ret
);
3687 /* see documentation shell 4.1*/
3688 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3691 /***********************************************************************
3692 * BrowseSelectedFolder
3694 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3696 BOOL bBrowseSelFolder
= FALSE
;
3697 FileOpenDlgInfos
*fodInfos
= GetPropA(hwnd
,FileOpenDlgInfosStr
);
3701 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3703 LPITEMIDLIST pidlSelection
;
3705 /* get the file selected */
3706 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3707 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3709 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3710 pidlSelection
, SBSP_RELATIVE
) ) )
3712 static const WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3713 ' ','n','o','t',' ','e','x','i','s','t',0};
3714 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3716 bBrowseSelFolder
= TRUE
;
3717 if(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
)
3718 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
3720 COMDLG32_SHFree( pidlSelection
);
3723 return bBrowseSelFolder
;
3727 * Memory allocation methods */
3728 static void *MemAlloc(UINT size
)
3730 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3733 static void MemFree(void *mem
)
3735 HeapFree(GetProcessHeap(),0,mem
);
3739 * Old-style (win3.1) dialogs */
3741 /***********************************************************************
3742 * FD32_GetTemplate [internal]
3744 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3745 * by a 32 bits application
3748 static BOOL
FD32_GetTemplate(PFD31_DATA lfs
)
3750 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3751 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3754 if (ofnW
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
3756 if (!(lfs
->template = LockResource( ofnW
->hInstance
)))
3758 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3762 else if (ofnW
->Flags
& OFN_ENABLETEMPLATE
)
3766 hResInfo
= FindResourceA(priv
->ofnA
->hInstance
,
3767 priv
->ofnA
->lpTemplateName
,
3770 hResInfo
= FindResourceW(ofnW
->hInstance
,
3771 ofnW
->lpTemplateName
,
3775 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3778 if (!(hDlgTmpl
= LoadResource(ofnW
->hInstance
,
3780 !(lfs
->template = LockResource(hDlgTmpl
)))
3782 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3785 } else { /* get it from internal Wine resource */
3787 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
3788 lfs
->open
? "OPEN_FILE":"SAVE_FILE", (LPSTR
)RT_DIALOG
)))
3790 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
3793 if (!(hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
3794 !(lfs
->template = LockResource( hDlgTmpl
)))
3796 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
3804 /************************************************************************
3805 * FD32_Init [internal]
3806 * called from the common 16/32 code to initialize 32 bit data
3808 static BOOL CALLBACK
FD32_Init(LPARAM lParam
, PFD31_DATA lfs
, DWORD data
)
3810 BOOL IsUnicode
= (BOOL
) data
;
3813 priv
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FD32_PRIVATE
));
3814 lfs
->private1632
= priv
;
3815 if (NULL
== lfs
->private1632
) return FALSE
;
3818 lfs
->ofnW
= (LPOPENFILENAMEW
) lParam
;
3819 if (lfs
->ofnW
->Flags
& OFN_ENABLEHOOK
)
3820 if (lfs
->ofnW
->lpfnHook
)
3825 priv
->ofnA
= (LPOPENFILENAMEA
) lParam
;
3826 if (priv
->ofnA
->Flags
& OFN_ENABLEHOOK
)
3827 if (priv
->ofnA
->lpfnHook
)
3829 lfs
->ofnW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*lfs
->ofnW
));
3830 FD31_MapOfnStructA(priv
->ofnA
, lfs
->ofnW
, lfs
->open
);
3833 if (! FD32_GetTemplate(lfs
)) return FALSE
;
3838 /***********************************************************************
3839 * FD32_CallWindowProc [internal]
3841 * called from the common 16/32 code to call the appropriate hook
3843 static BOOL CALLBACK
FD32_CallWindowProc(const FD31_DATA
*lfs
, UINT wMsg
, WPARAM wParam
,
3847 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3851 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3852 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3853 ret
= priv
->ofnA
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3854 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3855 priv
->ofnA
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3859 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3860 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3861 ret
= lfs
->ofnW
->lpfnHook(lfs
->hwnd
, wMsg
, wParam
, lParam
);
3862 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3863 lfs
->ofnW
->lpfnHook
, lfs
->hwnd
, wMsg
, wParam
, lParam
);
3867 /***********************************************************************
3868 * FD32_UpdateResult [internal]
3869 * update the real client structures if any
3871 static void CALLBACK
FD32_UpdateResult(const FD31_DATA
*lfs
)
3873 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3874 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3879 if (ofnW
->nMaxFile
&&
3880 !WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFile
, -1,
3881 priv
->ofnA
->lpstrFile
, ofnW
->nMaxFile
, NULL
, NULL
))
3882 priv
->ofnA
->lpstrFile
[ofnW
->nMaxFile
-1] = 0;
3884 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3885 /* set filename offset */
3886 lpszTemp
= PathFindFileNameA(priv
->ofnA
->lpstrFile
);
3887 priv
->ofnA
->nFileOffset
= (lpszTemp
- priv
->ofnA
->lpstrFile
);
3889 /* set extension offset */
3890 lpszTemp
= PathFindExtensionA(priv
->ofnA
->lpstrFile
);
3891 priv
->ofnA
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- priv
->ofnA
->lpstrFile
) + 1 : 0;
3895 /***********************************************************************
3896 * FD32_UpdateFileTitle [internal]
3897 * update the real client structures if any
3899 static void CALLBACK
FD32_UpdateFileTitle(const FD31_DATA
*lfs
)
3901 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3902 LPOPENFILENAMEW ofnW
= lfs
->ofnW
;
3906 if (!WideCharToMultiByte( CP_ACP
, 0, ofnW
->lpstrFileTitle
, -1,
3907 priv
->ofnA
->lpstrFileTitle
, ofnW
->nMaxFileTitle
, NULL
, NULL
))
3908 priv
->ofnA
->lpstrFileTitle
[ofnW
->nMaxFileTitle
-1] = 0;
3913 /***********************************************************************
3914 * FD32_SendLbGetCurSel [internal]
3915 * retrieve selected listbox item
3917 static LRESULT CALLBACK
FD32_SendLbGetCurSel(const FD31_DATA
*lfs
)
3919 return SendDlgItemMessageW(lfs
->hwnd
, lst1
, LB_GETCURSEL
, 0, 0);
3923 /************************************************************************
3924 * FD32_Destroy [internal]
3925 * called from the common 16/32 code to cleanup 32 bit data
3927 static void CALLBACK
FD32_Destroy(const FD31_DATA
*lfs
)
3929 PFD32_PRIVATE priv
= (PFD32_PRIVATE
) lfs
->private1632
;
3931 /* if ofnW has been allocated, have to free everything in it */
3932 if (NULL
!= priv
&& NULL
!= priv
->ofnA
)
3934 FD31_FreeOfnW(lfs
->ofnW
);
3935 HeapFree(GetProcessHeap(), 0, lfs
->ofnW
);
3939 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks
)
3941 callbacks
->Init
= FD32_Init
;
3942 callbacks
->CWP
= FD32_CallWindowProc
;
3943 callbacks
->UpdateResult
= FD32_UpdateResult
;
3944 callbacks
->UpdateFileTitle
= FD32_UpdateFileTitle
;
3945 callbacks
->SendLbGetCurSel
= FD32_SendLbGetCurSel
;
3946 callbacks
->Destroy
= FD32_Destroy
;
3949 /***********************************************************************
3950 * FD32_WMMeasureItem [internal]
3952 static LONG
FD32_WMMeasureItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
3954 LPMEASUREITEMSTRUCT lpmeasure
;
3956 lpmeasure
= (LPMEASUREITEMSTRUCT
)lParam
;
3957 lpmeasure
->itemHeight
= FD31_GetFldrHeight();
3962 /***********************************************************************
3963 * FileOpenDlgProc [internal]
3964 * Used for open and save, in fact.
3966 static INT_PTR CALLBACK
FD32_FileOpenDlgProc(HWND hWnd
, UINT wMsg
,
3967 WPARAM wParam
, LPARAM lParam
)
3969 PFD31_DATA lfs
= (PFD31_DATA
)GetPropA(hWnd
,FD31_OFN_PROP
);
3971 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg
, wParam
, lParam
);
3972 if ((wMsg
!= WM_INITDIALOG
) && lfs
&& lfs
->hook
)
3975 lRet
= (INT_PTR
)FD31_CallWindowProc(lfs
, wMsg
, wParam
, lParam
);
3977 return lRet
; /* else continue message processing */
3982 return FD31_WMInitDialog(hWnd
, wParam
, lParam
);
3984 case WM_MEASUREITEM
:
3985 return FD32_WMMeasureItem(hWnd
, wParam
, lParam
);
3988 return FD31_WMDrawItem(hWnd
, wParam
, lParam
, !lfs
->open
, (DRAWITEMSTRUCT
*)lParam
);
3991 return FD31_WMCommand(hWnd
, lParam
, HIWORD(wParam
), LOWORD(wParam
), lfs
);
3994 SetBkColor((HDC16
)wParam
, 0x00C0C0C0);
3995 switch (HIWORD(lParam
))
3998 SetTextColor((HDC16
)wParam
, 0x00000000);
4000 case CTLCOLOR_STATIC
:
4001 SetTextColor((HDC16
)wParam
, 0x00000000);
4011 /***********************************************************************
4012 * GetFileName31A [internal]
4014 * Creates a win31 style dialog box for the user to select a file to open/save.
4016 static BOOL
GetFileName31A(LPOPENFILENAMEA lpofn
, /* address of structure with data*/
4017 UINT dlgType
/* type dialogue : open/save */
4023 FD31_CALLBACKS callbacks
;
4025 if (!lpofn
|| !FD31_Init()) return FALSE
;
4027 TRACE("ofn flags %08x\n", lpofn
->Flags
);
4028 FD32_SetupCallbacks(&callbacks
);
4029 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) FALSE
);
4032 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
4033 bRet
= DialogBoxIndirectParamA( hInst
, lfs
->template, lpofn
->hwndOwner
,
4034 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4035 FD31_DestroyPrivate(lfs
);
4038 TRACE("return lpstrFile='%s' !\n", lpofn
->lpstrFile
);
4042 /***********************************************************************
4043 * GetFileName31W [internal]
4045 * Creates a win31 style dialog box for the user to select a file to open/save
4047 static BOOL
GetFileName31W(LPOPENFILENAMEW lpofn
, /* address of structure with data*/
4048 UINT dlgType
/* type dialogue : open/save */
4054 FD31_CALLBACKS callbacks
;
4056 if (!lpofn
|| !FD31_Init()) return FALSE
;
4058 FD32_SetupCallbacks(&callbacks
);
4059 lfs
= FD31_AllocPrivate((LPARAM
) lpofn
, dlgType
, &callbacks
, (DWORD
) TRUE
);
4062 hInst
= (HINSTANCE
)GetWindowLongPtrW( lpofn
->hwndOwner
, GWLP_HINSTANCE
);
4063 bRet
= DialogBoxIndirectParamW( hInst
, lfs
->template, lpofn
->hwndOwner
,
4064 FD32_FileOpenDlgProc
, (LPARAM
)lfs
);
4065 FD31_DestroyPrivate(lfs
);
4068 TRACE("file %s, file offset %d, ext offset %d\n",
4069 debugstr_w(lpofn
->lpstrFile
), lpofn
->nFileOffset
, lpofn
->nFileExtension
);
4073 /* ------------------ APIs ---------------------- */
4075 /***********************************************************************
4076 * GetOpenFileNameA (COMDLG32.@)
4078 * Creates a dialog box for the user to select a file to open.
4081 * TRUE on success: user enters a valid file
4082 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4085 BOOL WINAPI
GetOpenFileNameA(
4086 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4088 BOOL win16look
= FALSE
;
4090 TRACE("flags %08x\n", ofn
->Flags
);
4092 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4093 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4094 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4096 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4097 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4100 return GetFileName31A(ofn
, OPEN_DIALOG
);
4102 return GetFileDialog95A(ofn
, OPEN_DIALOG
);
4105 /***********************************************************************
4106 * GetOpenFileNameW (COMDLG32.@)
4108 * Creates a dialog box for the user to select a file to open.
4111 * TRUE on success: user enters a valid file
4112 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4115 BOOL WINAPI
GetOpenFileNameW(
4116 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4118 BOOL win16look
= FALSE
;
4120 TRACE("flags %08x\n", ofn
->Flags
);
4122 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4123 if (ofn
->Flags
& OFN_FILEMUSTEXIST
)
4124 ofn
->Flags
|= OFN_PATHMUSTEXIST
;
4126 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4127 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4130 return GetFileName31W(ofn
, OPEN_DIALOG
);
4132 return GetFileDialog95W(ofn
, OPEN_DIALOG
);
4136 /***********************************************************************
4137 * GetSaveFileNameA (COMDLG32.@)
4139 * Creates a dialog box for the user to select a file to save.
4142 * TRUE on success: user enters a valid file
4143 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4146 BOOL WINAPI
GetSaveFileNameA(
4147 LPOPENFILENAMEA ofn
) /* [in/out] address of init structure */
4149 BOOL win16look
= FALSE
;
4151 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4152 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4155 return GetFileName31A(ofn
, SAVE_DIALOG
);
4157 return GetFileDialog95A(ofn
, SAVE_DIALOG
);
4160 /***********************************************************************
4161 * GetSaveFileNameW (COMDLG32.@)
4163 * Creates a dialog box for the user to select a file to save.
4166 * TRUE on success: user enters a valid file
4167 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4170 BOOL WINAPI
GetSaveFileNameW(
4171 LPOPENFILENAMEW ofn
) /* [in/out] address of init structure */
4173 BOOL win16look
= FALSE
;
4175 if (ofn
->Flags
& (OFN_ALLOWMULTISELECT
|OFN_ENABLEHOOK
|OFN_ENABLETEMPLATE
))
4176 win16look
= (ofn
->Flags
& OFN_EXPLORER
) ? FALSE
: TRUE
;
4179 return GetFileName31W(ofn
, SAVE_DIALOG
);
4181 return GetFileDialog95W(ofn
, SAVE_DIALOG
);
4184 /***********************************************************************
4185 * GetFileTitleA (COMDLG32.@)
4187 * See GetFileTitleW.
4189 short WINAPI
GetFileTitleA(LPCSTR lpFile
, LPSTR lpTitle
, WORD cbBuf
)
4192 UNICODE_STRING strWFile
;
4195 RtlCreateUnicodeStringFromAsciiz(&strWFile
, lpFile
);
4196 lpWTitle
= RtlAllocateHeap( GetProcessHeap(), 0, cbBuf
*sizeof(WCHAR
));
4197 ret
= GetFileTitleW(strWFile
.Buffer
, lpWTitle
, cbBuf
);
4198 if (!ret
) WideCharToMultiByte( CP_ACP
, 0, lpWTitle
, -1, lpTitle
, cbBuf
, NULL
, NULL
);
4199 RtlFreeUnicodeString( &strWFile
);
4200 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle
);
4205 /***********************************************************************
4206 * GetFileTitleW (COMDLG32.@)
4208 * Get the name of a file.
4211 * lpFile [I] name and location of file
4212 * lpTitle [O] returned file name
4213 * cbBuf [I] buffer size of lpTitle
4217 * Failure: negative number.
4219 short WINAPI
GetFileTitleW(LPCWSTR lpFile
, LPWSTR lpTitle
, WORD cbBuf
)
4222 static const WCHAR brkpoint
[] = {'*','[',']',0};
4223 TRACE("(%p %p %d);\n", lpFile
, lpTitle
, cbBuf
);
4225 if(lpFile
== NULL
|| lpTitle
== NULL
)
4228 len
= lstrlenW(lpFile
);
4233 if(strpbrkW(lpFile
, brkpoint
))
4238 if(lpFile
[len
] == '/' || lpFile
[len
] == '\\' || lpFile
[len
] == ':')
4241 for(i
= len
; i
>= 0; i
--)
4243 if (lpFile
[i
] == '/' || lpFile
[i
] == '\\' || lpFile
[i
] == ':')
4253 TRACE("---> %s\n", debugstr_w(&lpFile
[i
]));
4255 len
= lstrlenW(lpFile
+i
)+1;
4259 lstrcpyW(lpTitle
, &lpFile
[i
]);