2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expecting 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 if would likely cause
26 * a complete rewrite with after we shouldhandle 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: lpstrCustomFilter not handled
37 * FIXME: if the size of lpstrFile (nMaxFile) is too small the first
38 * two bytes of lpstrFile should contain the needed size
40 * FIXME: algorithm for selecting the initial directory is too simple
42 * FIXME: add to recent docs
44 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
45 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, OFN_EXTENSIONDIFFERENT,
46 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
47 * OFN_NOTESTFILECREATE, OFN_OVERWRITEPROMPT, OFN_USEMONIKERS
49 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
55 #include "wine/port.h"
65 #include "wine/unicode.h"
69 #include "wine/debug.h"
73 #include "filedlgbrowser.h"
75 #include "wine/obj_contextmenu.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
79 #define UNIMPLEMENTED_FLAGS \
80 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
81 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
82 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
83 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
85 #define IsHooked(fodInfos) \
86 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
87 /***********************************************************************
88 * Data structure and global variables
90 typedef struct SFolder
92 int m_iImageIndex
; /* Index of picture in image list */
94 int m_iIndent
; /* Indentation index */
95 LPITEMIDLIST pidlItem
; /* absolute pidl of the item */
99 typedef struct tagLookInInfo
106 /***********************************************************************
107 * Defines and global variables
110 /* Draw item constant */
112 #define XTEXTOFFSET 3
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
133 #define CBAddStringW(hwnd,str) \
134 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
136 #define CBInsertString(hwnd,str,pos) \
137 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
139 #define CBDeleteString(hwnd,pos) \
140 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
142 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
143 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
145 #define CBGetItemDataPtr(hwnd,iItemId) \
146 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
148 #define CBGetLBText(hwnd,iItemId,str) \
149 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
151 #define CBGetCurSel(hwnd) \
152 SendMessageA(hwnd,CB_GETCURSEL,0,0);
154 #define CBSetCurSel(hwnd,pos) \
155 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
157 #define CBGetCount(hwnd) \
158 SendMessageA(hwnd,CB_GETCOUNT,0,0);
159 #define CBShowDropDown(hwnd,show) \
160 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
161 #define CBSetItemHeight(hwnd,index,height) \
162 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
165 const char *FileOpenDlgInfosStr
= "FileOpenDlgInfos"; /* windows property description string */
166 const char *LookInInfosStr
= "LookInInfos"; /* LOOKIN combo box property */
168 /***********************************************************************
172 /* Internal functions used by the dialog */
173 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
174 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
175 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
);
176 BOOL
FILEDLG95_OnOpen(HWND hwnd
);
177 static LRESULT
FILEDLG95_InitControls(HWND hwnd
);
178 static void FILEDLG95_Clean(HWND hwnd
);
180 /* Functions used by the shell navigation */
181 static LRESULT
FILEDLG95_SHELL_Init(HWND hwnd
);
182 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
);
183 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
);
184 static void FILEDLG95_SHELL_Clean(HWND hwnd
);
185 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
);
187 /* Functions used by the filetype combo box */
188 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
);
189 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
);
190 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
);
191 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
);
193 /* Functions used by the Look In combo box */
194 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
);
195 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
);
196 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
);
197 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
);
198 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
);
199 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
);
200 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
);
201 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
);
202 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
);
204 /* Miscellaneous tool functions */
205 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
);
206 HRESULT
GetFileName(HWND hwnd
, LPITEMIDLIST pidl
, LPSTR lpstrFileName
);
207 IShellFolder
* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
);
208 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
);
209 LPITEMIDLIST
GetPidlFromName(IShellFolder
*psf
,LPWSTR lpcstrFileName
);
211 /* Shell memory allocation */
212 static void *MemAlloc(UINT size
);
213 static void MemFree(void *mem
);
215 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
);
216 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
217 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
);
218 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
219 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
);
220 static BOOL
BrowseSelectedFolder(HWND hwnd
);
222 /***********************************************************************
225 * Creates an Open common dialog box that lets the user select
226 * the drive, directory, and the name of a file or set of files to open.
228 * IN : The FileOpenDlgInfos structure associated with the dialog
229 * OUT : TRUE on success
230 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
232 BOOL WINAPI
GetFileName95(FileOpenDlgInfos
*fodInfos
)
240 /* test for missing functionality */
241 if (fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
)
243 FIXME("Flags 0x%08lx not yet implemented\n",
244 fodInfos
->ofnInfos
->Flags
& UNIMPLEMENTED_FLAGS
);
247 /* Create the dialog from a template */
249 if(!(hRes
= FindResourceA(COMMDLG_hInstance32
,MAKEINTRESOURCEA(NEWFILEOPENORD
),RT_DIALOGA
)))
251 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
254 if (!(hDlgTmpl
= LoadResource(COMMDLG_hInstance32
, hRes
)) ||
255 !(template = LockResource( hDlgTmpl
)))
257 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
261 /* old style hook messages */
262 if (IsHooked(fodInfos
))
264 fodInfos
->HookMsg
.fileokstring
= RegisterWindowMessageA(FILEOKSTRINGA
);
265 fodInfos
->HookMsg
.lbselchstring
= RegisterWindowMessageA(LBSELCHSTRINGA
);
266 fodInfos
->HookMsg
.helpmsgstring
= RegisterWindowMessageA(HELPMSGSTRINGA
);
267 fodInfos
->HookMsg
.sharevistring
= RegisterWindowMessageA(SHAREVISTRINGA
);
270 lRes
= DialogBoxIndirectParamA(COMMDLG_hInstance32
,
271 (LPDLGTEMPLATEA
) template,
272 fodInfos
->ofnInfos
->hwndOwner
,
276 /* Unable to create the dialog */
283 /***********************************************************************
286 * Call GetFileName95 with this structure and clean the memory.
288 * IN : The OPENFILENAMEA initialisation structure passed to
289 * GetOpenFileNameA win api function (see filedlg.c)
291 BOOL WINAPI
GetFileDialog95A(LPOPENFILENAMEA ofn
,UINT iDlgType
)
294 FileOpenDlgInfos fodInfos
;
295 LPSTR lpstrSavDir
= NULL
;
297 LPWSTR defext
= NULL
;
298 LPWSTR filter
= NULL
;
299 LPWSTR customfilter
= NULL
;
301 /* Initialize FileOpenDlgInfos structure */
302 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
304 /* Pass in the original ofn */
305 fodInfos
.ofnInfos
= ofn
;
307 /* save current directory */
308 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
310 lpstrSavDir
= MemAlloc(MAX_PATH
);
311 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
314 fodInfos
.unicode
= FALSE
;
316 /* convert all the input strings to unicode */
317 if(ofn
->lpstrInitialDir
)
319 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, NULL
, 0 );
320 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
321 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrInitialDir
, -1, fodInfos
.initdir
, len
);
324 fodInfos
.initdir
= NULL
;
328 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
329 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFile
, -1, fodInfos
.filename
, ofn
->nMaxFile
);
332 fodInfos
.filename
= NULL
;
336 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, NULL
, 0 );
337 defext
= MemAlloc((len
+1)*sizeof(WCHAR
));
338 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrDefExt
, -1, defext
, len
);
340 fodInfos
.defext
= defext
;
344 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, NULL
, 0 );
345 title
= MemAlloc((len
+1)*sizeof(WCHAR
));
346 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrTitle
, -1, title
, len
);
348 fodInfos
.title
= title
;
350 if (ofn
->lpstrFilter
)
355 /* filter is a list... title\0ext\0......\0\0 */
356 s
= ofn
->lpstrFilter
;
357 while (*s
) s
= s
+strlen(s
)+1;
359 n
= s
- ofn
->lpstrFilter
;
360 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, NULL
, 0 );
361 filter
= MemAlloc(len
*sizeof(WCHAR
));
362 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrFilter
, n
, filter
, len
);
364 fodInfos
.filter
= filter
;
366 /* convert lpstrCustomFilter */
367 if (ofn
->lpstrCustomFilter
)
372 /* filter is a list... title\0ext\0......\0\0 */
373 s
= ofn
->lpstrCustomFilter
;
374 while (*s
) s
= s
+strlen(s
)+1;
376 n
= s
- ofn
->lpstrCustomFilter
;
377 len
= MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, NULL
, 0 );
378 customfilter
= MemAlloc(len
*sizeof(WCHAR
));
379 MultiByteToWideChar( CP_ACP
, 0, ofn
->lpstrCustomFilter
, n
, customfilter
, len
);
381 fodInfos
.customfilter
= customfilter
;
383 /* Initialize the dialog property */
384 fodInfos
.DlgInfos
.dwDlgProp
= 0;
385 fodInfos
.DlgInfos
.hwndCustomDlg
= NULL
;
390 ret
= GetFileName95(&fodInfos
);
393 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
394 ret
= GetFileName95(&fodInfos
);
402 SetCurrentDirectoryA(lpstrSavDir
);
403 MemFree(lpstrSavDir
);
413 MemFree(customfilter
);
415 MemFree(fodInfos
.initdir
);
417 if(fodInfos
.filename
)
418 MemFree(fodInfos
.filename
);
420 TRACE("selected file: %s\n",ofn
->lpstrFile
);
425 /***********************************************************************
428 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
429 * Call GetFileName95 with this structure and clean the memory.
431 * FIXME: lpstrCustomFilter has to be converted back
434 BOOL WINAPI
GetFileDialog95W(LPOPENFILENAMEW ofn
,UINT iDlgType
)
437 FileOpenDlgInfos fodInfos
;
438 LPSTR lpstrSavDir
= NULL
;
440 /* Initialize FileOpenDlgInfos structure */
441 ZeroMemory(&fodInfos
, sizeof(FileOpenDlgInfos
));
443 /* Pass in the original ofn */
444 fodInfos
.ofnInfos
= (LPOPENFILENAMEA
) ofn
;
446 fodInfos
.title
= ofn
->lpstrTitle
;
447 fodInfos
.defext
= ofn
->lpstrDefExt
;
448 fodInfos
.filter
= ofn
->lpstrFilter
;
449 fodInfos
.customfilter
= ofn
->lpstrCustomFilter
;
451 /* convert string arguments, save others */
454 fodInfos
.filename
= MemAlloc(ofn
->nMaxFile
*sizeof(WCHAR
));
455 strncpyW(fodInfos
.filename
,ofn
->lpstrFile
,ofn
->nMaxFile
);
458 fodInfos
.filename
= NULL
;
460 if(ofn
->lpstrInitialDir
)
462 DWORD len
= strlenW(ofn
->lpstrInitialDir
);
463 fodInfos
.initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
464 strcpyW(fodInfos
.initdir
,ofn
->lpstrInitialDir
);
467 fodInfos
.initdir
= NULL
;
469 /* save current directory */
470 if (ofn
->Flags
& OFN_NOCHANGEDIR
)
472 lpstrSavDir
= MemAlloc(MAX_PATH
);
473 GetCurrentDirectoryA(MAX_PATH
, lpstrSavDir
);
476 fodInfos
.unicode
= TRUE
;
481 ret
= GetFileName95(&fodInfos
);
484 fodInfos
.DlgInfos
.dwDlgProp
|= FODPROP_SAVEDLG
;
485 ret
= GetFileName95(&fodInfos
);
493 SetCurrentDirectoryA(lpstrSavDir
);
494 MemFree(lpstrSavDir
);
497 /* restore saved IN arguments and convert OUT arguments back */
498 MemFree(fodInfos
.filename
);
499 MemFree(fodInfos
.initdir
);
503 void ArrangeCtrlPositions( HWND hwndChildDlg
, HWND hwndParentDlg
)
505 HWND hwndChild
,hwndStc32
;
506 RECT rectParent
, rectChild
, rectCtrl
, rectStc32
, rectTemp
;
508 POINT ptParentClient
;
512 ptMoveCtl
.x
= ptMoveCtl
.y
= 0;
513 hwndStc32
=GetDlgItem(hwndChildDlg
,stc32
);
514 GetClientRect(hwndParentDlg
,&rectParent
);
515 GetClientRect(hwndChildDlg
,&rectChild
);
519 GetWindowRect(hwndStc32
,&rectStc32
);
520 MapWindowPoints(0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
521 CopyRect(&rectTemp
,&rectStc32
);
523 SetRect(&rectStc32
,rectStc32
.left
,rectStc32
.top
,rectStc32
.left
+ (rectParent
.right
-rectParent
.left
),rectStc32
.top
+(rectParent
.bottom
-rectParent
.top
));
524 SetWindowPos(hwndStc32
,0,rectStc32
.left
,rectStc32
.top
,rectStc32
.right
-rectStc32
.left
,rectStc32
.bottom
-rectStc32
.top
,SWP_NOMOVE
|SWP_NOZORDER
| SWP_NOACTIVATE
);
526 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
527 if(rectStc32
.right
< rectTemp
.right
)
530 ptMoveCtl
.x
= (rectStc32
.right
- rectTemp
.right
);
532 ptParentClient
.y
= max((rectParent
.bottom
-rectParent
.top
),(rectChild
.bottom
-rectChild
.top
));
533 if(rectStc32
.bottom
< rectTemp
.bottom
)
536 ptMoveCtl
.y
= (rectStc32
.bottom
- rectTemp
.bottom
);
540 if( (GetWindow(hwndChildDlg
,GW_CHILD
)) == NULL
) return;
542 SetRectEmpty(&rectTemp
);
543 ptParentClient
.x
= max((rectParent
.right
-rectParent
.left
),(rectChild
.right
-rectChild
.left
));
544 ptParentClient
.y
= (rectParent
.bottom
-rectParent
.top
) + (rectChild
.bottom
-rectChild
.top
);
545 ptMoveCtl
.y
= rectParent
.bottom
-rectParent
.top
;
548 SetRect(&rectParent
,rectParent
.left
,rectParent
.top
,rectParent
.left
+ptParentClient
.x
,rectParent
.top
+ptParentClient
.y
);
549 AdjustWindowRectEx( &rectParent
,GetWindowLongA(hwndParentDlg
,GWL_STYLE
),FALSE
,GetWindowLongA(hwndParentDlg
,GWL_EXSTYLE
));
551 SetWindowPos(hwndChildDlg
, 0, 0,0, ptParentClient
.x
,ptParentClient
.y
, SWP_NOZORDER
);
552 SetWindowPos(hwndParentDlg
, 0, rectParent
.left
,rectParent
.top
, (rectParent
.right
- rectParent
.left
),
553 (rectParent
.bottom
-rectParent
.top
),SWP_NOMOVE
| SWP_NOZORDER
);
555 hwndChild
= GetWindow(hwndChildDlg
,GW_CHILD
);
558 GetWindowRect(hwndStc32
,&rectStc32
);
559 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
562 SetRect(&rectStc32
,0,0,0,0);
568 if(hwndChild
!= hwndStc32
)
570 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
572 GetWindowRect(hwndChild
,&rectCtrl
);
573 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
576 Check the initial position of the controls relative to the initial
577 position and size of stc32 (before it is expanded).
579 if (rectCtrl
.left
>= rectTemp
.right
&& rectCtrl
.top
>= rectTemp
.bottom
)
581 rectCtrl
.left
+= ptMoveCtl
.x
;
582 rectCtrl
.top
+= ptMoveCtl
.y
;
584 else if (rectCtrl
.left
>= rectTemp
.right
)
586 rectCtrl
.left
+= ptMoveCtl
.x
;
588 else if (rectCtrl
.top
>= rectTemp
.bottom
)
590 rectCtrl
.top
+= ptMoveCtl
.y
;
593 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
594 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
595 SWP_NOSIZE
| SWP_NOZORDER
);
597 } while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != NULL
);
599 hwndChild
= GetWindow(hwndParentDlg
,GW_CHILD
);
603 GetWindowRect(hwndStc32
,&rectStc32
);
604 MapWindowPoints( 0, hwndChildDlg
,(LPPOINT
)&rectStc32
,2);
605 ptMoveCtl
.x
= rectStc32
.left
- 0;
606 ptMoveCtl
.y
= rectStc32
.top
- 0;
611 if(hwndChild
!= hwndChildDlg
)
613 if (GetWindowLongA( hwndChild
, GWL_STYLE
) & WS_MAXIMIZE
)
615 GetWindowRect(hwndChild
,&rectCtrl
);
616 MapWindowPoints( 0, hwndParentDlg
,(LPPOINT
)&rectCtrl
,2);
618 rectCtrl
.left
+= ptMoveCtl
.x
;
619 rectCtrl
.top
+= ptMoveCtl
.y
;
621 SetWindowPos( hwndChild
, 0, rectCtrl
.left
, rectCtrl
.top
,
622 rectCtrl
.right
-rectCtrl
.left
,rectCtrl
.bottom
-rectCtrl
.top
,
623 SWP_NOSIZE
|SWP_NOZORDER
);
625 } while ((hwndChild
=GetWindow( hwndChild
, GW_HWNDNEXT
)) != NULL
);
631 INT_PTR CALLBACK
FileOpenDlgProcUserTemplate(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
633 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(GetParent(hwnd
),FileOpenDlgInfosStr
);
636 TRACE("0x%04x\n", uMsg
);
643 /* Hide caption since some program may leave it */
644 DWORD Style
= GetWindowLongA(hwnd
, GWL_STYLE
);
645 if (Style
& WS_CAPTION
) SetWindowLongA(hwnd
, GWL_STYLE
, Style
& (~WS_CAPTION
));
647 fodInfos
= (FileOpenDlgInfos
*)lParam
;
648 lParam
= (LPARAM
) fodInfos
->ofnInfos
;
649 ArrangeCtrlPositions(hwnd
,GetParent(hwnd
));
651 if(fodInfos
&& IsHooked(fodInfos
))
652 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
657 if(fodInfos
&& IsHooked(fodInfos
))
658 return CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,hwnd
,uMsg
,wParam
,lParam
);
660 return DefWindowProcA(hwnd
,uMsg
,wParam
,lParam
);
663 HWND
CreateTemplateDialog(FileOpenDlgInfos
*fodInfos
, HWND hwnd
)
673 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
674 * structure's hInstance parameter is not a HINSTANCE, but
675 * instead a pointer to a template resource to use.
677 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATE
||
678 fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
682 if (fodInfos
->ofnInfos
->Flags
& OFN_ENABLETEMPLATEHANDLE
)
685 if( !(template = LockResource( fodInfos
->ofnInfos
->hInstance
)))
687 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
693 hinst
= fodInfos
->ofnInfos
->hInstance
;
694 if(fodInfos
->unicode
)
696 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
697 hRes
= FindResourceW( hinst
, ofn
->lpTemplateName
, RT_DIALOGW
);
701 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
702 hRes
= FindResourceA( hinst
, ofn
->lpTemplateName
, RT_DIALOGA
);
706 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
709 if (!(hDlgTmpl
= LoadResource( hinst
, hRes
)) ||
710 !(template = LockResource( hDlgTmpl
)))
712 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
717 hChildDlg
= CreateDialogIndirectParamA(hinst
, template,
718 hwnd
, FileOpenDlgProcUserTemplate
, (LPARAM
)fodInfos
);
721 ShowWindow(hChildDlg
,SW_SHOW
);
725 else if( IsHooked(fodInfos
))
730 WORD menu
,class,title
;
732 GetClientRect(hwnd
,&rectHwnd
);
733 temp
.tmplate
.style
= WS_CHILD
| WS_CLIPSIBLINGS
;
734 temp
.tmplate
.dwExtendedStyle
= 0;
735 temp
.tmplate
.cdit
= 0;
738 temp
.tmplate
.cx
= rectHwnd
.right
-rectHwnd
.left
;
739 temp
.tmplate
.cy
= rectHwnd
.bottom
-rectHwnd
.top
;
740 temp
.menu
= temp
.class = temp
.title
= 0;
741 hChildDlg
= CreateDialogIndirectParamA(fodInfos
->ofnInfos
->hInstance
,&temp
.tmplate
,
742 hwnd
, FileOpenDlgProcUserTemplate
, (LPARAM
)fodInfos
);
748 /***********************************************************************
749 * SendCustomDlgNotificationMessage
751 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
754 HRESULT
SendCustomDlgNotificationMessage(HWND hwndParentDlg
, UINT uCode
)
756 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwndParentDlg
,FileOpenDlgInfosStr
);
758 TRACE("%p 0x%04x\n",hwndParentDlg
, uCode
);
760 if(!fodInfos
) return 0;
762 if(fodInfos
->unicode
)
763 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
765 if(fodInfos
->DlgInfos
.hwndCustomDlg
)
769 ofnNotify
.hdr
.hwndFrom
=hwndParentDlg
;
770 ofnNotify
.hdr
.idFrom
=0;
771 ofnNotify
.hdr
.code
= uCode
;
772 ofnNotify
.lpOFN
= fodInfos
->ofnInfos
;
773 TRACE("CALL NOTIFY for %x\n", uCode
);
774 ret
= SendMessageA(fodInfos
->DlgInfos
.hwndCustomDlg
,WM_NOTIFY
,0,(LPARAM
)&ofnNotify
);
775 TRACE("RET NOTIFY\n");
781 HRESULT
FILEDLG95_Handle_GetFilePath(HWND hwnd
, DWORD size
, LPSTR buffer
)
783 UINT sizeUsed
= 0, n
, total
;
784 LPWSTR lpstrFileList
= NULL
;
785 WCHAR lpstrCurrentDir
[MAX_PATH
];
786 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
788 TRACE("CDM_GETFILEPATH:\n");
790 if ( ! (fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
793 /* get path and filenames */
794 SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrCurrentDir
);
795 n
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
797 TRACE("path >%s< filespec >%s< %d files\n",
798 debugstr_w(lpstrCurrentDir
),debugstr_w(lpstrFileList
),n
);
800 total
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
801 NULL
, 0, NULL
, NULL
);
802 total
+= WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
803 NULL
, 0, NULL
, NULL
);
805 /* Prepend the current path */
806 n
= WideCharToMultiByte(CP_ACP
, 0, lpstrCurrentDir
, -1,
807 buffer
, size
, NULL
, NULL
);
810 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
811 &buffer
[n
], size
-n
, NULL
, NULL
);
812 MemFree(lpstrFileList
);
814 TRACE("returned -> %s\n",debugstr_a(buffer
));
819 HRESULT
FILEDLG95_Handle_GetFileSpec(HWND hwnd
, DWORD size
, LPSTR buffer
)
822 LPWSTR lpstrFileList
= NULL
;
824 TRACE("CDM_GETSPEC:\n");
826 FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
827 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
, buffer
, size
, NULL
, NULL
);
828 MemFree(lpstrFileList
);
833 /***********************************************************************
834 * FILEDLG95_HandleCustomDialogMessages
836 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
838 HRESULT
FILEDLG95_HandleCustomDialogMessages(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
840 char lpstrPath
[MAX_PATH
];
841 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
842 if(!fodInfos
) return -1;
846 case CDM_GETFILEPATH
:
847 return FILEDLG95_Handle_GetFilePath(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
849 case CDM_GETFOLDERPATH
:
850 TRACE("CDM_GETFOLDERPATH:\n");
851 SHGetPathFromIDListA(fodInfos
->ShellInfos
.pidlAbsCurrent
,lpstrPath
);
852 if ((LPSTR
)lParam
!=NULL
)
853 lstrcpynA((LPSTR
)lParam
,lpstrPath
,(int)wParam
);
854 return strlen(lpstrPath
);
857 return FILEDLG95_Handle_GetFileSpec(hwnd
, (UINT
)wParam
, (LPSTR
)lParam
);
859 case CDM_SETCONTROLTEXT
:
860 TRACE("CDM_SETCONTROLTEXT:\n");
862 SetDlgItemTextA( hwnd
, (UINT
) wParam
, (LPSTR
) lParam
);
865 case CDM_HIDECONTROL
:
867 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
873 /***********************************************************************
876 * File open dialog procedure
878 INT_PTR CALLBACK
FileOpenDlgProc95(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
881 TRACE("0x%04x 0x%04x\n", hwnd
, uMsg
);
888 FileOpenDlgInfos
* fodInfos
= (FileOpenDlgInfos
*)lParam
;
890 /* Adds the FileOpenDlgInfos in the property list of the dialog
891 so it will be easily accessible through a GetPropA(...) */
892 SetPropA(hwnd
, FileOpenDlgInfosStr
, (HANDLE
) fodInfos
);
894 fodInfos
->DlgInfos
.hwndCustomDlg
=
895 CreateTemplateDialog((FileOpenDlgInfos
*)lParam
, hwnd
);
897 FILEDLG95_InitControls(hwnd
);
898 SendCustomDlgNotificationMessage(hwnd
,CDN_INITDONE
);
899 FILEDLG95_FillControls(hwnd
, wParam
, lParam
);
900 SendCustomDlgNotificationMessage(hwnd
,CDN_FOLDERCHANGE
);
901 SendCustomDlgNotificationMessage(hwnd
,CDN_SELCHANGE
);
902 SetWindowPos(fodInfos
->DlgInfos
.hwndCustomDlg
, HWND_BOTTOM
,
903 0,0,0,0, SWP_NOMOVE
|SWP_NOSIZE
);
907 return FILEDLG95_OnWMCommand(hwnd
, wParam
, lParam
);
910 switch(((LPDRAWITEMSTRUCT
)lParam
)->CtlID
)
913 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT
) lParam
);
919 case WM_GETISHELLBROWSER
:
920 return FILEDLG95_OnWMGetIShellBrowser(hwnd
);
923 RemovePropA(hwnd
, FileOpenDlgInfosStr
);
928 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
931 /* set up the button tooltips strings */
932 if(TTN_GETDISPINFOA
== lpnmh
->code
)
934 LPNMTTDISPINFOA lpdi
= (LPNMTTDISPINFOA
)lParam
;
935 switch(lpnmh
->idFrom
)
937 /* Up folder button */
938 case FCIDM_TB_UPFOLDER
:
939 stringId
= IDS_UPFOLDER
;
941 /* New folder button */
942 case FCIDM_TB_NEWFOLDER
:
943 stringId
= IDS_NEWFOLDER
;
945 /* List option button */
946 case FCIDM_TB_SMALLICON
:
947 stringId
= IDS_LISTVIEW
;
949 /* Details option button */
950 case FCIDM_TB_REPORTVIEW
:
951 stringId
= IDS_REPORTVIEW
;
954 case FCIDM_TB_DESKTOP
:
955 stringId
= IDS_TODESKTOP
;
960 lpdi
->hinst
= COMMDLG_hInstance32
;
961 lpdi
->lpszText
= (LPSTR
) stringId
;
966 if(uMsg
>= CDM_FIRST
&& uMsg
<= CDM_LAST
)
967 return FILEDLG95_HandleCustomDialogMessages(hwnd
, uMsg
, wParam
, lParam
);
972 /***********************************************************************
973 * FILEDLG95_InitControls
975 * WM_INITDIALOG message handler (before hook notification)
977 static LRESULT
FILEDLG95_InitControls(HWND hwnd
)
981 int handledPath
= FALSE
;
983 const WCHAR szwSlash
[] = { '\\', 0 };
984 const WCHAR szwStar
[] = { '*',0 };
988 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
989 {VIEW_PARENTFOLDER
, FCIDM_TB_UPFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
990 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
991 {VIEW_NEWFOLDER
+1, FCIDM_TB_DESKTOP
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
992 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
993 {VIEW_NEWFOLDER
, FCIDM_TB_NEWFOLDER
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
994 {0, 0, TBSTATE_ENABLED
, TBSTYLE_SEP
, {0, 0}, 0, 0 },
995 {VIEW_LIST
, FCIDM_TB_SMALLICON
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
996 {VIEW_DETAILS
, FCIDM_TB_REPORTVIEW
, TBSTATE_ENABLED
, TBSTYLE_BUTTON
, {0, 0}, 0, 0 },
1000 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1002 tba
[0].hInst
= HINST_COMMCTRL
;
1003 tba
[0].nID
= IDB_VIEW_SMALL_COLOR
;
1004 tba
[1].hInst
= COMDLG32_hInstance
;
1007 TRACE("%p\n", fodInfos
);
1009 /* Get windows version emulating */
1010 osVi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1011 GetVersionExA(&osVi
);
1012 if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) {
1013 win98plus
= ((osVi
.dwMajorVersion
> 4) || ((osVi
.dwMajorVersion
== 4) && (osVi
.dwMinorVersion
> 0)));
1014 } else if (osVi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1015 win2000plus
= (osVi
.dwMajorVersion
> 4);
1016 if (win2000plus
) win98plus
= TRUE
;
1018 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus
, win98plus
);
1020 /* Get the hwnd of the controls */
1021 fodInfos
->DlgInfos
.hwndFileName
= GetDlgItem(hwnd
,IDC_FILENAME
);
1022 fodInfos
->DlgInfos
.hwndFileTypeCB
= GetDlgItem(hwnd
,IDC_FILETYPE
);
1023 fodInfos
->DlgInfos
.hwndLookInCB
= GetDlgItem(hwnd
,IDC_LOOKIN
);
1025 /* construct the toolbar */
1026 GetWindowRect(GetDlgItem(hwnd
,IDC_TOOLBARSTATIC
),&rectTB
);
1027 MapWindowPoints( 0, hwnd
,(LPPOINT
)&rectTB
,2);
1029 fodInfos
->DlgInfos
.hwndTB
= CreateWindowExA(0, TOOLBARCLASSNAMEA
, (LPSTR
) NULL
,
1030 WS_CHILD
| WS_GROUP
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
,
1031 0, 0, 150, 26, hwnd
, (HMENU
) IDC_TOOLBAR
, COMMDLG_hInstance32
, NULL
);
1033 SetWindowPos(fodInfos
->DlgInfos
.hwndTB
, 0,
1034 rectTB
.left
,rectTB
.top
, rectTB
.right
-rectTB
.left
, rectTB
.bottom
-rectTB
.top
,
1035 SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
1037 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
1039 /* FIXME: use TB_LOADIMAGES when implemented */
1040 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1041 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 12, (LPARAM
) &tba
[0]);
1042 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBITMAP
, (WPARAM
) 1, (LPARAM
) &tba
[1]);
1044 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_ADDBUTTONSA
, (WPARAM
) 9,(LPARAM
) &tbb
);
1045 SendMessageA(fodInfos
->DlgInfos
.hwndTB
, TB_AUTOSIZE
, 0, 0);
1047 /* Set the window text with the text specified in the OPENFILENAME structure */
1050 SetWindowTextW(hwnd
,fodInfos
->title
);
1052 else if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1054 SetWindowTextA(hwnd
,"Save");
1057 /* Initialise the file name edit control */
1058 handledPath
= FALSE
;
1059 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1061 if(fodInfos
->filename
)
1063 /* 1. If win2000 or higher and filename contains a path, use it
1064 in preference over the lpstrInitialDir */
1065 if (win2000plus
&& *fodInfos
->filename
&& strpbrkW(fodInfos
->filename
, szwSlash
)) {
1066 WCHAR tmpBuf
[MAX_PATH
];
1070 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
, tmpBuf
, &nameBit
);
1073 /* nameBit is always shorter than the original filename */
1074 strcpyW(fodInfos
->filename
,nameBit
);
1077 if (fodInfos
->initdir
== NULL
)
1078 MemFree(fodInfos
->initdir
);
1079 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf
) + 1)*sizeof(WCHAR
));
1080 strcpyW(fodInfos
->initdir
, tmpBuf
);
1082 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1083 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1085 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1088 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1092 /* 2. (All platforms) If initdir is not null, then use it */
1093 if ((handledPath
== FALSE
) && (fodInfos
->initdir
!=NULL
) &&
1094 (*fodInfos
->initdir
!=0x00))
1096 /* Work out the proper path as supplied one might be relative */
1097 /* (Here because supplying '.' as dir browses to My Computer) */
1098 if (handledPath
==FALSE
) {
1099 WCHAR tmpBuf
[MAX_PATH
];
1100 WCHAR tmpBuf2
[MAX_PATH
];
1104 strcpyW(tmpBuf
, fodInfos
->initdir
);
1105 if (tmpBuf
[strlenW(tmpBuf
)-1] != '\\') {
1106 strcatW(tmpBuf
, szwSlash
);
1108 strcatW(tmpBuf
, szwStar
);
1109 result
= GetFullPathNameW(tmpBuf
, MAX_PATH
, tmpBuf2
, &nameBit
);
1112 if (fodInfos
->initdir
)
1113 MemFree(fodInfos
->initdir
);
1114 fodInfos
->initdir
= MemAlloc((strlenW(tmpBuf2
) + 1)*sizeof(WCHAR
));
1115 strcpyW(fodInfos
->initdir
, tmpBuf2
);
1117 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos
->initdir
));
1122 if ((handledPath
== FALSE
) && ((fodInfos
->initdir
==NULL
) ||
1123 (*fodInfos
->initdir
==0x00)))
1125 /* 3. All except w2k+: if filename contains a path use it */
1126 if (!win2000plus
&& fodInfos
->filename
&&
1127 *fodInfos
->filename
&&
1128 strpbrkW(fodInfos
->filename
, szwSlash
)) {
1129 WCHAR tmpBuf
[MAX_PATH
];
1133 result
= GetFullPathNameW(fodInfos
->filename
, MAX_PATH
,
1138 /* nameBit is always shorter than the original filename */
1139 strcpyW(fodInfos
->filename
, nameBit
);
1142 len
= strlenW(tmpBuf
);
1143 if(fodInfos
->initdir
)
1144 MemFree(fodInfos
->initdir
);
1145 fodInfos
->initdir
= MemAlloc((len
+1)*sizeof(WCHAR
));
1146 strcpyW(fodInfos
->initdir
, tmpBuf
);
1149 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1150 debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1152 SetDlgItemTextW(hwnd
, IDC_FILENAME
, fodInfos
->filename
);
1155 /* 4. win98+ and win2000+ if any files of specified filter types in
1156 current directory, use it */
1157 if ( win98plus
&& handledPath
== FALSE
&&
1158 fodInfos
->filter
&& *fodInfos
->filter
) {
1160 BOOL searchMore
= TRUE
;
1161 LPCWSTR lpstrPos
= fodInfos
->filter
;
1162 WIN32_FIND_DATAW FindFileData
;
1167 /* filter is a list... title\0ext\0......\0\0 */
1169 /* Skip the title */
1170 if(! *lpstrPos
) break; /* end */
1171 lpstrPos
+= strlenW(lpstrPos
) + 1;
1173 /* See if any files exist in the current dir with this extension */
1174 if(! *lpstrPos
) break; /* end */
1176 hFind
= FindFirstFileW(lpstrPos
, &FindFileData
);
1178 if (hFind
== INVALID_HANDLE_VALUE
) {
1179 /* None found - continue search */
1180 lpstrPos
+= strlenW(lpstrPos
) + 1;
1185 if(fodInfos
->initdir
)
1186 MemFree(fodInfos
->initdir
);
1187 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1188 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1191 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1192 debugstr_w(lpstrPos
));
1198 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1200 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1201 if (handledPath
== FALSE
&& (win2000plus
|| win98plus
)) {
1202 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1204 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_PERSONAL
, 0, 0, fodInfos
->initdir
)))
1206 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, fodInfos
->initdir
)))
1209 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1210 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos
->initdir
));
1212 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos
->initdir
));
1215 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos
->initdir
));
1218 } else if (handledPath
==FALSE
) {
1219 fodInfos
->initdir
= MemAlloc(MAX_PATH
*sizeof(WCHAR
));
1220 GetCurrentDirectoryW(MAX_PATH
, fodInfos
->initdir
);
1222 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos
->initdir
));
1225 TRACE("After manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos
->filename
), debugstr_w(fodInfos
->initdir
));
1227 /* Must the open as read only check box be checked ?*/
1228 if(fodInfos
->ofnInfos
->Flags
& OFN_READONLY
)
1230 SendDlgItemMessageA(hwnd
,IDC_OPENREADONLY
,BM_SETCHECK
,(WPARAM
)TRUE
,0);
1233 /* Must the open as read only check box be hid ?*/
1234 if(fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
)
1236 ShowWindow(GetDlgItem(hwnd
,IDC_OPENREADONLY
),SW_HIDE
);
1239 /* Must the help button be hid ?*/
1240 if (!(fodInfos
->ofnInfos
->Flags
& OFN_SHOWHELP
))
1242 ShowWindow(GetDlgItem(hwnd
, pshHelp
), SW_HIDE
);
1245 /* Resize the height, if open as read only checkbox ad help button
1246 are hidden and we are not using a custom template */
1247 if ( (fodInfos
->ofnInfos
->Flags
& OFN_HIDEREADONLY
) &&
1248 (!(fodInfos
->ofnInfos
->Flags
&
1249 (OFN_SHOWHELP
|OFN_ENABLETEMPLATE
|OFN_ENABLETEMPLATEHANDLE
))))
1251 RECT rectDlg
, rectHelp
, rectCancel
;
1252 GetWindowRect(hwnd
, &rectDlg
);
1253 GetWindowRect(GetDlgItem(hwnd
, pshHelp
), &rectHelp
);
1254 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rectCancel
);
1255 /* subtract the height of the help button plus the space between
1256 the help button and the cancel button to the height of the dialog */
1257 SetWindowPos(hwnd
, 0, 0, 0, rectDlg
.right
-rectDlg
.left
,
1258 (rectDlg
.bottom
-rectDlg
.top
) - (rectHelp
.bottom
- rectCancel
.bottom
),
1259 SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
1262 /* change Open to Save FIXME: use resources */
1263 if (fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
)
1265 SetDlgItemTextA(hwnd
,IDOK
,"&Save");
1266 SetDlgItemTextA(hwnd
,IDC_LOOKINSTATIC
,"Save &in");
1271 /***********************************************************************
1272 * FILEDLG95_FillControls
1274 * WM_INITDIALOG message handler (after hook notification)
1276 static LRESULT
FILEDLG95_FillControls(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1278 LPITEMIDLIST pidlItemId
= NULL
;
1280 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) lParam
;
1282 TRACE("dir=%s file=%s\n",
1283 debugstr_w(fodInfos
->initdir
), debugstr_w(fodInfos
->filename
));
1285 /* Get the initial directory pidl */
1287 if(!(pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
,fodInfos
->initdir
)))
1289 WCHAR path
[MAX_PATH
];
1291 GetCurrentDirectoryW(MAX_PATH
,path
);
1292 pidlItemId
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, path
);
1295 /* Initialise shell objects */
1296 FILEDLG95_SHELL_Init(hwnd
);
1298 /* Initialize the Look In combo box */
1299 FILEDLG95_LOOKIN_Init(fodInfos
->DlgInfos
.hwndLookInCB
);
1301 /* Initialize the filter combo box */
1302 FILEDLG95_FILETYPE_Init(hwnd
);
1304 /* Browse to the initial directory */
1305 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,pidlItemId
, SBSP_ABSOLUTE
);
1307 /* Free pidlItem memory */
1308 COMDLG32_SHFree(pidlItemId
);
1312 /***********************************************************************
1315 * Regroups all the cleaning functions of the filedlg
1317 void FILEDLG95_Clean(HWND hwnd
)
1319 FILEDLG95_FILETYPE_Clean(hwnd
);
1320 FILEDLG95_LOOKIN_Clean(hwnd
);
1321 FILEDLG95_SHELL_Clean(hwnd
);
1323 /***********************************************************************
1324 * FILEDLG95_OnWMCommand
1326 * WM_COMMAND message handler
1328 static LRESULT
FILEDLG95_OnWMCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1330 WORD wNotifyCode
= HIWORD(wParam
); /* notification code */
1331 WORD wID
= LOWORD(wParam
); /* item, control, or accelerator identifier */
1332 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1338 FILEDLG95_OnOpen(hwnd
);
1342 FILEDLG95_Clean(hwnd
);
1343 EndDialog(hwnd
, FALSE
);
1345 /* Filetype combo box */
1347 FILEDLG95_FILETYPE_OnCommand(hwnd
,wNotifyCode
);
1349 /* LookIn combo box */
1351 FILEDLG95_LOOKIN_OnCommand(hwnd
,wNotifyCode
);
1354 /* --- toolbar --- */
1355 /* Up folder button */
1356 case FCIDM_TB_UPFOLDER
:
1357 FILEDLG95_SHELL_UpFolder(hwnd
);
1359 /* New folder button */
1360 case FCIDM_TB_NEWFOLDER
:
1361 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_NEWFOLDER
);
1363 /* List option button */
1364 case FCIDM_TB_SMALLICON
:
1365 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWLIST
);
1367 /* Details option button */
1368 case FCIDM_TB_REPORTVIEW
:
1369 FILEDLG95_SHELL_ExecuteCommand(hwnd
,CMDSTR_VIEWDETAILS
);
1371 /* Details option button */
1372 case FCIDM_TB_DESKTOP
:
1373 FILEDLG95_SHELL_BrowseToDesktop(hwnd
);
1380 /* Do not use the listview selection anymore */
1381 fodInfos
->DlgInfos
.dwDlgProp
&= ~FODPROP_USEVIEW
;
1385 /***********************************************************************
1386 * FILEDLG95_OnWMGetIShellBrowser
1388 * WM_GETISHELLBROWSER message handler
1390 static LRESULT
FILEDLG95_OnWMGetIShellBrowser(HWND hwnd
)
1393 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1397 SetWindowLongA(hwnd
,DWL_MSGRESULT
,(LONG
)fodInfos
->Shell
.FOIShellBrowser
);
1403 /***********************************************************************
1404 * FILEDLG95_SendFileOK
1406 * Sends the CDN_FILEOK notification if required
1409 * TRUE if the dialog should close
1410 * FALSE if the dialog should not be closed
1412 static BOOL
FILEDLG95_SendFileOK( HWND hwnd
, FileOpenDlgInfos
*fodInfos
)
1414 /* ask the hook if we can close */
1415 if(IsHooked(fodInfos
))
1418 /* First send CDN_FILEOK as MSDN doc says */
1419 SendCustomDlgNotificationMessage(hwnd
,CDN_FILEOK
);
1421 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1422 CallWindowProcA((WNDPROC
)fodInfos
->ofnInfos
->lpfnHook
,
1423 fodInfos
->DlgInfos
.hwndCustomDlg
,
1424 fodInfos
->HookMsg
.fileokstring
, 0, (LPARAM
)fodInfos
->ofnInfos
);
1425 if (GetWindowLongA(fodInfos
->DlgInfos
.hwndCustomDlg
, DWL_MSGRESULT
))
1427 TRACE("canceled\n");
1434 /***********************************************************************
1435 * FILEDLG95_OnOpenMultipleFiles
1437 * Handles the opening of multiple files.
1440 * check destination buffer size
1442 BOOL
FILEDLG95_OnOpenMultipleFiles(HWND hwnd
, LPWSTR lpstrFileList
, UINT nFileCount
, UINT sizeUsed
)
1444 WCHAR lpstrPathSpec
[MAX_PATH
] = {0};
1445 UINT nCount
, nSizePath
;
1446 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1450 if(fodInfos
->unicode
)
1452 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1453 ofn
->lpstrFile
[0] = '\0';
1457 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1458 ofn
->lpstrFile
[0] = '\0';
1461 SHGetPathFromIDListW( fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathSpec
);
1463 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
) &&
1464 ( fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1465 ! ( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1467 LPWSTR lpstrTemp
= lpstrFileList
;
1469 for ( nCount
= 0; nCount
< nFileCount
; nCount
++ )
1473 pidl
= GetPidlFromName(fodInfos
->Shell
.FOIShellFolder
, lpstrTemp
);
1476 WCHAR lpstrNotFound
[100];
1477 WCHAR lpstrMsg
[100];
1479 WCHAR nl
[] = {'\n',0};
1481 LoadStringW(COMMDLG_hInstance32
, IDS_FILENOTFOUND
, lpstrNotFound
, 100);
1482 LoadStringW(COMMDLG_hInstance32
, IDS_VERIFYFILE
, lpstrMsg
, 100);
1484 strcpyW(tmp
, lpstrTemp
);
1486 strcatW(tmp
, lpstrNotFound
);
1488 strcatW(tmp
, lpstrMsg
);
1490 MessageBoxW(hwnd
, tmp
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
1494 /* move to the next file in the list of files */
1495 lpstrTemp
+= strlenW(lpstrTemp
) + 1;
1496 COMDLG32_SHFree(pidl
);
1500 nSizePath
= strlenW(lpstrPathSpec
) + 1;
1501 if ( !(fodInfos
->ofnInfos
->Flags
& OFN_EXPLORER
) )
1503 /* For "oldstyle" dialog the components have to
1504 be spearated by blanks (not '\0'!) and short
1505 filenames have to be used! */
1506 FIXME("Components have to be separated by blanks");
1508 if(fodInfos
->unicode
)
1510 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1511 strcpyW( ofn
->lpstrFile
, lpstrPathSpec
);
1512 memcpy( ofn
->lpstrFile
+ nSizePath
, lpstrFileList
, sizeUsed
*sizeof(WCHAR
) );
1516 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1518 if (ofn
->lpstrFile
!= NULL
)
1520 WideCharToMultiByte(CP_ACP
, 0, lpstrPathSpec
, -1,
1521 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1522 if (ofn
->nMaxFile
> nSizePath
)
1524 WideCharToMultiByte(CP_ACP
, 0, lpstrFileList
, sizeUsed
,
1525 ofn
->lpstrFile
+ nSizePath
,
1526 ofn
->nMaxFile
- nSizePath
, NULL
, NULL
);
1531 fodInfos
->ofnInfos
->nFileOffset
= nSizePath
+ 1;
1532 fodInfos
->ofnInfos
->nFileExtension
= 0;
1534 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1537 /* clean and exit */
1538 FILEDLG95_Clean(hwnd
);
1539 return EndDialog(hwnd
,TRUE
);
1542 /***********************************************************************
1545 * Ok button WM_COMMAND message handler
1547 * If the function succeeds, the return value is nonzero.
1549 #define ONOPEN_BROWSE 1
1550 #define ONOPEN_OPEN 2
1551 #define ONOPEN_SEARCH 3
1552 static void FILEDLG95_OnOpenMessage(HWND hwnd
, int idCaption
, int idText
)
1554 char strMsgTitle
[MAX_PATH
];
1555 char strMsgText
[MAX_PATH
];
1557 LoadStringA(COMDLG32_hInstance
, idCaption
, strMsgTitle
, sizeof(strMsgTitle
));
1559 strMsgTitle
[0] = '\0';
1560 LoadStringA(COMDLG32_hInstance
, idText
, strMsgText
, sizeof(strMsgText
));
1561 MessageBoxA(hwnd
,strMsgText
, strMsgTitle
, MB_OK
| MB_ICONHAND
);
1564 BOOL
FILEDLG95_OnOpen(HWND hwnd
)
1566 LPWSTR lpstrFileList
;
1567 UINT nFileCount
= 0;
1570 WCHAR lpstrPathAndFile
[MAX_PATH
];
1571 WCHAR lpstrTemp
[MAX_PATH
];
1572 LPSHELLFOLDER lpsf
= NULL
;
1574 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1576 TRACE("hwnd=%p\n", hwnd
);
1578 /* get the files from the edit control */
1579 nFileCount
= FILEDLG95_FILENAME_GetFileNames(hwnd
, &lpstrFileList
, &sizeUsed
);
1581 /* try if the user selected a folder in the shellview */
1584 BrowseSelectedFolder(hwnd
);
1590 ret
= FILEDLG95_OnOpenMultipleFiles(hwnd
, lpstrFileList
, nFileCount
, sizeUsed
);
1594 TRACE("count=%u len=%u file=%s\n", nFileCount
, sizeUsed
, debugstr_w(lpstrFileList
));
1597 Step 1: Build a complete path name from the current folder and
1598 the filename or path in the edit box.
1600 - the path in the edit box is a root path
1601 (with or without drive letter)
1602 - the edit box contains ".." (or a path with ".." in it)
1605 /* Get the current directory name */
1606 if (!SHGetPathFromIDListW(fodInfos
->ShellInfos
.pidlAbsCurrent
, lpstrPathAndFile
))
1608 /* we are in a special folder, default to desktop */
1609 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd
, CSIDL_DESKTOPDIRECTORY
|CSIDL_FLAG_CREATE
, 0, 0, lpstrPathAndFile
)))
1612 GetCurrentDirectoryW(MAX_PATH
, lpstrPathAndFile
);
1615 PathAddBackslashW(lpstrPathAndFile
);
1617 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile
));
1619 /* if the user specifyed a fully qualified path use it */
1620 if(PathIsRelativeW(lpstrFileList
))
1622 strcatW(lpstrPathAndFile
, lpstrFileList
);
1626 /* does the path have a drive letter? */
1627 if (PathGetDriveNumberW(lpstrFileList
) == -1)
1628 strcpyW(lpstrPathAndFile
+2, lpstrFileList
);
1630 strcpyW(lpstrPathAndFile
, lpstrFileList
);
1633 /* resolve "." and ".." */
1634 PathCanonicalizeW(lpstrTemp
, lpstrPathAndFile
);
1635 strcpyW(lpstrPathAndFile
, lpstrTemp
);
1636 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile
));
1638 MemFree(lpstrFileList
);
1641 Step 2: here we have a cleaned up path
1643 We have to parse the path step by step to see if we have to browse
1644 to a folder if the path points to a directory or the last
1645 valid element is a directory.
1648 lpstrPathAndFile: cleaned up path
1651 nOpenAction
= ONOPEN_BROWSE
;
1653 /* dont apply any checks with OFN_NOVALIDATE */
1655 LPWSTR lpszTemp
, lpszTemp1
;
1656 LPITEMIDLIST pidl
= NULL
;
1657 WCHAR szwInvalid
[] = { '/',':','<','>','|', 0};
1659 /* check for invalid chars */
1660 if((strpbrkW(lpstrPathAndFile
+3, szwInvalid
) != NULL
) && !(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1662 FILEDLG95_OnOpenMessage(hwnd
, IDS_INVALID_FILENAME_TITLE
, IDS_INVALID_FILENAME
);
1667 if (FAILED (SHGetDesktopFolder(&lpsf
))) return FALSE
;
1669 lpszTemp1
= lpszTemp
= lpstrPathAndFile
;
1672 LPSHELLFOLDER lpsfChild
;
1673 WCHAR lpwstrTemp
[MAX_PATH
];
1674 DWORD dwEaten
, dwAttributes
;
1677 strcpyW(lpwstrTemp
, lpszTemp
);
1678 p
= PathFindNextComponentW(lpwstrTemp
);
1680 if (!p
) break; /* end of path */
1683 lpszTemp
= lpszTemp
+ strlenW(lpwstrTemp
);
1687 WCHAR wszWild
[] = { '*', '?', 0 };
1688 /* if the last element is a wildcard do a search */
1689 if(strpbrkW(lpszTemp1
, wszWild
) != NULL
)
1691 nOpenAction
= ONOPEN_SEARCH
;
1695 lpszTemp1
= lpszTemp
;
1697 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp
), debugstr_w(lpszTemp
), lpsf
);
1699 if(lstrlenW(lpwstrTemp
)==2) PathAddBackslashW(lpwstrTemp
);
1701 dwAttributes
= SFGAO_FOLDER
;
1702 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf
, hwnd
, NULL
, lpwstrTemp
, &dwEaten
, &pidl
, &dwAttributes
)))
1704 /* the path component is valid, we have a pidl of the next path component */
1705 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes
, pidl
);
1706 if(dwAttributes
& SFGAO_FOLDER
)
1708 if(FAILED(IShellFolder_BindToObject(lpsf
, pidl
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfChild
)))
1710 ERR("bind to failed\n"); /* should not fail */
1713 IShellFolder_Release(lpsf
);
1721 /* end dialog, return value */
1722 nOpenAction
= ONOPEN_OPEN
;
1725 COMDLG32_SHFree(pidl
);
1728 else if (!(fodInfos
->ofnInfos
->Flags
& OFN_NOVALIDATE
))
1730 if(*lpszTemp
) /* points to trailing null for last path element */
1732 if(fodInfos
->ofnInfos
->Flags
& OFN_PATHMUSTEXIST
)
1734 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_PATHNOTEXISTING
);
1740 if( (fodInfos
->ofnInfos
->Flags
& OFN_FILEMUSTEXIST
) &&
1741 !( fodInfos
->DlgInfos
.dwDlgProp
& FODPROP_SAVEDLG
) )
1743 FILEDLG95_OnOpenMessage(hwnd
, 0, IDS_FILENOTEXISTING
);
1747 /* change to the current folder */
1748 nOpenAction
= ONOPEN_OPEN
;
1753 nOpenAction
= ONOPEN_OPEN
;
1757 if(pidl
) COMDLG32_SHFree(pidl
);
1761 Step 3: here we have a cleaned up and validated path
1764 lpsf: ShellFolder bound to the rightmost valid path component
1765 lpstrPathAndFile: cleaned up path
1766 nOpenAction: action to do
1768 TRACE("end validate sf=%p\n", lpsf
);
1772 case ONOPEN_SEARCH
: /* set the current filter to the file mask and refresh */
1773 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile
));
1776 LPWSTR lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1779 /* replace the current filter */
1780 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
1781 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
1782 len
= strlenW(lpszTemp
)+1;
1783 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc(len
* sizeof(WCHAR
));
1784 strcpyW( fodInfos
->ShellInfos
.lpstrCurrentFilter
, lpszTemp
);
1786 /* set the filter cb to the extension when possible */
1787 if(-1 < (iPos
= FILEDLG95_FILETYPE_SearchExt(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpszTemp
)))
1788 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, iPos
);
1791 case ONOPEN_BROWSE
: /* browse to the highest folder we could bind to */
1792 TRACE("ONOPEN_BROWSE\n");
1794 IPersistFolder2
* ppf2
;
1795 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf
, &IID_IPersistFolder2
, (LPVOID
*)&ppf2
)))
1797 LPITEMIDLIST pidlCurrent
;
1798 IPersistFolder2_GetCurFolder(ppf2
, &pidlCurrent
);
1799 IPersistFolder2_Release(ppf2
);
1800 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent
, fodInfos
->ShellInfos
.pidlAbsCurrent
))
1802 IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidlCurrent
, SBSP_ABSOLUTE
);
1804 else if( nOpenAction
== ONOPEN_SEARCH
)
1806 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
1808 COMDLG32_SHFree(pidlCurrent
);
1813 case ONOPEN_OPEN
: /* fill in the return struct and close the dialog */
1814 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile
));
1816 /* add default extension */
1817 if (fodInfos
->defext
)
1819 if (! *PathFindExtensionW(lpstrPathAndFile
))
1821 /* only add "." in case a default extension does exist */
1822 if (*fodInfos
->defext
!= '\0')
1824 const WCHAR szwDot
[] = {'.',0};
1825 int PathLength
= strlenW(lpstrPathAndFile
);
1827 strcatW(lpstrPathAndFile
, szwDot
);
1828 strcatW(lpstrPathAndFile
, fodInfos
->defext
);
1830 /* if file does not exist try without extension */
1831 if (!PathFileExistsW(lpstrPathAndFile
))
1832 lpstrPathAndFile
[PathLength
] = '\0';
1837 /* Check that the size of the file does not exceed buffer size.
1838 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1839 if(strlenW(lpstrPathAndFile
) < fodInfos
->ofnInfos
->nMaxFile
-
1840 ((fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
) ? 1 : 0))
1844 /* fill destination buffer */
1845 if (fodInfos
->ofnInfos
->lpstrFile
)
1847 if(fodInfos
->unicode
)
1849 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1851 strncpyW(ofn
->lpstrFile
, lpstrPathAndFile
, ofn
->nMaxFile
);
1852 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1853 ofn
->lpstrFile
[lstrlenW(ofn
->lpstrFile
) + 1] = '\0';
1857 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1859 WideCharToMultiByte(CP_ACP
, 0, lpstrPathAndFile
, -1,
1860 ofn
->lpstrFile
, ofn
->nMaxFile
, NULL
, NULL
);
1861 if (ofn
->Flags
& OFN_ALLOWMULTISELECT
)
1862 ofn
->lpstrFile
[lstrlenA(ofn
->lpstrFile
) + 1] = '\0';
1866 /* set filename offset */
1867 lpszTemp
= PathFindFileNameW(lpstrPathAndFile
);
1868 fodInfos
->ofnInfos
->nFileOffset
= (lpszTemp
- lpstrPathAndFile
);
1870 /* set extension offset */
1871 lpszTemp
= PathFindExtensionW(lpstrPathAndFile
);
1872 fodInfos
->ofnInfos
->nFileExtension
= (*lpszTemp
) ? (lpszTemp
- lpstrPathAndFile
) + 1 : 0;
1874 /* set the lpstrFileTitle */
1875 if(fodInfos
->ofnInfos
->lpstrFileTitle
)
1877 LPWSTR lpstrFileTitle
= PathFindFileNameW(lpstrPathAndFile
);
1878 if(fodInfos
->unicode
)
1880 LPOPENFILENAMEW ofn
= (LPOPENFILENAMEW
) fodInfos
->ofnInfos
;
1881 strncpyW(ofn
->lpstrFileTitle
, lpstrFileTitle
, ofn
->nMaxFileTitle
);
1885 LPOPENFILENAMEA ofn
= fodInfos
->ofnInfos
;
1886 WideCharToMultiByte(CP_ACP
, 0, lpstrFileTitle
, -1,
1887 ofn
->lpstrFileTitle
, ofn
->nMaxFileTitle
, NULL
, NULL
);
1891 if ( !FILEDLG95_SendFileOK(hwnd
, fodInfos
) )
1895 FILEDLG95_Clean(hwnd
);
1896 ret
= EndDialog(hwnd
, TRUE
);
1900 /* FIXME set error FNERR_BUFFERTOSMALL */
1901 FILEDLG95_Clean(hwnd
);
1902 ret
= EndDialog(hwnd
, FALSE
);
1910 if(lpsf
) IShellFolder_Release(lpsf
);
1914 /***********************************************************************
1915 * FILEDLG95_SHELL_Init
1917 * Initialisation of the shell objects
1919 static HRESULT
FILEDLG95_SHELL_Init(HWND hwnd
)
1921 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1926 * Initialisation of the FileOpenDialogInfos structure
1932 fodInfos
->ShellInfos
.hwndOwner
= hwnd
;
1934 /* Disable multi-select if flag not set */
1935 if (!(fodInfos
->ofnInfos
->Flags
& OFN_ALLOWMULTISELECT
))
1937 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_SINGLESEL
;
1939 fodInfos
->ShellInfos
.folderSettings
.fFlags
|= FWF_AUTOARRANGE
| FWF_ALIGNLEFT
;
1940 fodInfos
->ShellInfos
.folderSettings
.ViewMode
= FVM_LIST
;
1942 GetWindowRect(GetDlgItem(hwnd
,IDC_SHELLSTATIC
),&fodInfos
->ShellInfos
.rectView
);
1943 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.left
);
1944 ScreenToClient(hwnd
,(LPPOINT
)&fodInfos
->ShellInfos
.rectView
.right
);
1946 /* Construct the IShellBrowser interface */
1947 fodInfos
->Shell
.FOIShellBrowser
= IShellBrowserImpl_Construct(hwnd
);
1952 /***********************************************************************
1953 * FILEDLG95_SHELL_ExecuteCommand
1955 * Change the folder option and refresh the view
1956 * If the function succeeds, the return value is nonzero.
1958 static BOOL
FILEDLG95_SHELL_ExecuteCommand(HWND hwnd
, LPCSTR lpVerb
)
1960 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1963 TRACE("(%p,%p)\n", hwnd
, lpVerb
);
1965 if(SUCCEEDED(IShellView_GetItemObject(fodInfos
->Shell
.FOIShellView
,
1970 CMINVOKECOMMANDINFO ci
;
1971 ZeroMemory(&ci
, sizeof(CMINVOKECOMMANDINFO
));
1972 ci
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
1976 IContextMenu_InvokeCommand(pcm
, &ci
);
1977 IContextMenu_Release(pcm
);
1983 /***********************************************************************
1984 * FILEDLG95_SHELL_UpFolder
1986 * Browse to the specified object
1987 * If the function succeeds, the return value is nonzero.
1989 static BOOL
FILEDLG95_SHELL_UpFolder(HWND hwnd
)
1991 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
1995 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2004 /***********************************************************************
2005 * FILEDLG95_SHELL_BrowseToDesktop
2007 * Browse to the Desktop
2008 * If the function succeeds, the return value is nonzero.
2010 static BOOL
FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd
)
2012 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2018 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidl
);
2019 hres
= IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
, pidl
, SBSP_ABSOLUTE
);
2020 COMDLG32_SHFree(pidl
);
2021 return SUCCEEDED(hres
);
2023 /***********************************************************************
2024 * FILEDLG95_SHELL_Clean
2026 * Cleans the memory used by shell objects
2028 static void FILEDLG95_SHELL_Clean(HWND hwnd
)
2030 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2034 COMDLG32_SHFree(fodInfos
->ShellInfos
.pidlAbsCurrent
);
2036 /* clean Shell interfaces */
2037 IShellView_DestroyViewWindow(fodInfos
->Shell
.FOIShellView
);
2038 IShellView_Release(fodInfos
->Shell
.FOIShellView
);
2039 IShellFolder_Release(fodInfos
->Shell
.FOIShellFolder
);
2040 IShellBrowser_Release(fodInfos
->Shell
.FOIShellBrowser
);
2041 if (fodInfos
->Shell
.FOIDataObject
)
2042 IDataObject_Release(fodInfos
->Shell
.FOIDataObject
);
2045 /***********************************************************************
2046 * FILEDLG95_FILETYPE_Init
2048 * Initialisation of the file type combo box
2050 static HRESULT
FILEDLG95_FILETYPE_Init(HWND hwnd
)
2052 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2056 if(fodInfos
->filter
)
2058 int nFilters
= 0; /* number of filters */
2060 LPCWSTR lpstrPos
= fodInfos
->filter
;
2064 /* filter is a list... title\0ext\0......\0\0
2065 * Set the combo item text to the title and the item data
2068 LPCWSTR lpstrDisplay
;
2072 if(! *lpstrPos
) break; /* end */
2073 lpstrDisplay
= lpstrPos
;
2074 lpstrPos
+= strlenW(lpstrPos
) + 1;
2076 /* Copy the extensions */
2077 if (! *lpstrPos
) return E_FAIL
; /* malformed filter */
2078 if (!(lpstrExt
= MemAlloc((strlenW(lpstrPos
)+1)*sizeof(WCHAR
)))) return E_FAIL
;
2079 strcpyW(lpstrExt
,lpstrPos
);
2080 lpstrPos
+= strlenW(lpstrPos
) + 1;
2082 /* Add the item at the end of the combo */
2083 CBAddStringW(fodInfos
->DlgInfos
.hwndFileTypeCB
, lpstrDisplay
);
2084 CBSetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
, nFilters
, lpstrExt
);
2088 * Set the current filter to the one specified
2089 * in the initialisation structure
2090 * FIXME: lpstrCustomFilter not handled at all
2093 /* set default filter index */
2094 if(fodInfos
->ofnInfos
->nFilterIndex
== 0 && fodInfos
->customfilter
== NULL
)
2095 fodInfos
->ofnInfos
->nFilterIndex
= 1;
2097 /* First, check to make sure our index isn't out of bounds. */
2098 if ( fodInfos
->ofnInfos
->nFilterIndex
> nFilters
)
2099 fodInfos
->ofnInfos
->nFilterIndex
= nFilters
;
2101 /* Set the current index selection. */
2102 CBSetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
, fodInfos
->ofnInfos
->nFilterIndex
-1);
2104 /* Get the corresponding text string from the combo box. */
2105 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2106 fodInfos
->ofnInfos
->nFilterIndex
-1);
2108 if ((INT
)lpstrFilter
== CB_ERR
) /* control is empty */
2114 CharLowerW(lpstrFilter
); /* lowercase */
2115 len
= strlenW(lpstrFilter
)+1;
2116 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2117 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2123 /***********************************************************************
2124 * FILEDLG95_FILETYPE_OnCommand
2126 * WM_COMMAND of the file type combo box
2127 * If the function succeeds, the return value is nonzero.
2129 static BOOL
FILEDLG95_FILETYPE_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2131 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2139 /* Get the current item of the filetype combo box */
2140 int iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2142 /* set the current filter index - indexed from 1 */
2143 fodInfos
->ofnInfos
->nFilterIndex
= iItem
+ 1;
2145 /* Set the current filter with the current selection */
2146 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2147 MemFree((LPVOID
)fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2149 lpstrFilter
= (LPWSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,
2151 if((int)lpstrFilter
!= CB_ERR
)
2154 CharLowerW(lpstrFilter
); /* lowercase */
2155 len
= strlenW(lpstrFilter
)+1;
2156 fodInfos
->ShellInfos
.lpstrCurrentFilter
= MemAlloc( len
* sizeof(WCHAR
) );
2157 strcpyW(fodInfos
->ShellInfos
.lpstrCurrentFilter
,lpstrFilter
);
2158 SendCustomDlgNotificationMessage(hwnd
,CDN_TYPECHANGE
);
2161 /* Refresh the actual view to display the included items*/
2162 IShellView_Refresh(fodInfos
->Shell
.FOIShellView
);
2167 /***********************************************************************
2168 * FILEDLG95_FILETYPE_SearchExt
2170 * searches for a extension in the filetype box
2172 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd
,LPCWSTR lpstrExt
)
2174 int i
, iCount
= CBGetCount(hwnd
);
2176 TRACE("%s\n", debugstr_w(lpstrExt
));
2178 if(iCount
!= CB_ERR
)
2180 for(i
=0;i
<iCount
;i
++)
2182 if(!lstrcmpiW(lpstrExt
,(LPWSTR
)CBGetItemDataPtr(hwnd
,i
)))
2189 /***********************************************************************
2190 * FILEDLG95_FILETYPE_Clean
2192 * Clean the memory used by the filetype combo box
2194 static void FILEDLG95_FILETYPE_Clean(HWND hwnd
)
2196 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2198 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndFileTypeCB
);
2202 /* Delete each string of the combo and their associated data */
2203 if(iCount
!= CB_ERR
)
2205 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2207 MemFree((LPSTR
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
));
2208 CBDeleteString(fodInfos
->DlgInfos
.hwndFileTypeCB
,iPos
);
2211 /* Current filter */
2212 if(fodInfos
->ShellInfos
.lpstrCurrentFilter
)
2213 MemFree(fodInfos
->ShellInfos
.lpstrCurrentFilter
);
2217 /***********************************************************************
2218 * FILEDLG95_LOOKIN_Init
2220 * Initialisation of the look in combo box
2222 static HRESULT
FILEDLG95_LOOKIN_Init(HWND hwndCombo
)
2224 IShellFolder
*psfRoot
, *psfDrives
;
2225 IEnumIDList
*lpeRoot
, *lpeDrives
;
2226 LPITEMIDLIST pidlDrives
, pidlTmp
, pidlTmp1
, pidlAbsTmp
;
2228 LookInInfos
*liInfos
= MemAlloc(sizeof(LookInInfos
));
2232 liInfos
->iMaxIndentation
= 0;
2234 SetPropA(hwndCombo
, LookInInfosStr
, (HANDLE
) liInfos
);
2236 /* set item height for both text field and listbox */
2237 CBSetItemHeight(hwndCombo
,-1,GetSystemMetrics(SM_CYSMICON
));
2238 CBSetItemHeight(hwndCombo
,0,GetSystemMetrics(SM_CYSMICON
));
2240 /* Initialise data of Desktop folder */
2241 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP
,&pidlTmp
);
2242 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2243 COMDLG32_SHFree(pidlTmp
);
2245 SHGetSpecialFolderLocation(0,CSIDL_DRIVES
,&pidlDrives
);
2247 SHGetDesktopFolder(&psfRoot
);
2251 /* enumerate the contents of the desktop */
2252 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot
, hwndCombo
, SHCONTF_FOLDERS
, &lpeRoot
)))
2254 while (S_OK
== IEnumIDList_Next(lpeRoot
, 1, &pidlTmp
, NULL
))
2256 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlTmp
,LISTEND
);
2258 /* special handling for CSIDL_DRIVES */
2259 if (COMDLG32_PIDL_ILIsEqual(pidlTmp
, pidlDrives
))
2261 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot
, pidlTmp
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfDrives
)))
2263 /* enumerate the drives */
2264 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives
, hwndCombo
,SHCONTF_FOLDERS
, &lpeDrives
)))
2266 while (S_OK
== IEnumIDList_Next(lpeDrives
, 1, &pidlTmp1
, NULL
))
2268 pidlAbsTmp
= COMDLG32_PIDL_ILCombine(pidlTmp
, pidlTmp1
);
2269 FILEDLG95_LOOKIN_AddItem(hwndCombo
, pidlAbsTmp
,LISTEND
);
2270 COMDLG32_SHFree(pidlAbsTmp
);
2271 COMDLG32_SHFree(pidlTmp1
);
2273 IEnumIDList_Release(lpeDrives
);
2275 IShellFolder_Release(psfDrives
);
2278 COMDLG32_SHFree(pidlTmp
);
2280 IEnumIDList_Release(lpeRoot
);
2284 IShellFolder_Release(psfRoot
);
2285 COMDLG32_SHFree(pidlDrives
);
2289 /***********************************************************************
2290 * FILEDLG95_LOOKIN_DrawItem
2292 * WM_DRAWITEM message handler
2294 static LRESULT
FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct
)
2296 COLORREF crWin
= GetSysColor(COLOR_WINDOW
);
2297 COLORREF crHighLight
= GetSysColor(COLOR_HIGHLIGHT
);
2298 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
2302 HIMAGELIST ilItemImage
;
2305 LPSFOLDER tmpFolder
;
2308 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(pDIStruct
->hwndItem
,LookInInfosStr
);
2312 if(pDIStruct
->itemID
== -1)
2315 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(pDIStruct
->hwndItem
,
2316 pDIStruct
->itemID
)))
2320 if(pDIStruct
->itemID
== liInfos
->uSelectedItem
)
2322 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2325 sizeof (SHFILEINFOA
),
2326 SHGFI_PIDL
| SHGFI_SMALLICON
|
2327 SHGFI_OPENICON
| SHGFI_SYSICONINDEX
|
2328 SHGFI_DISPLAYNAME
);
2332 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2335 sizeof (SHFILEINFOA
),
2336 SHGFI_PIDL
| SHGFI_SMALLICON
|
2337 SHGFI_SYSICONINDEX
|
2341 /* Is this item selected ? */
2342 if(pDIStruct
->itemState
& ODS_SELECTED
)
2344 SetTextColor(pDIStruct
->hDC
,(0x00FFFFFF & ~(crText
)));
2345 SetBkColor(pDIStruct
->hDC
,crHighLight
);
2346 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_HIGHLIGHT
));
2350 SetTextColor(pDIStruct
->hDC
,crText
);
2351 SetBkColor(pDIStruct
->hDC
,crWin
);
2352 FillRect(pDIStruct
->hDC
,&pDIStruct
->rcItem
,GetSysColorBrush(COLOR_WINDOW
));
2355 /* Do not indent item if drawing in the edit of the combo */
2356 if(pDIStruct
->itemState
& ODS_COMBOBOXEDIT
)
2359 ilItemImage
= (HIMAGELIST
) SHGetFileInfoA ((LPCSTR
) tmpFolder
->pidlItem
,
2362 sizeof (SHFILEINFOA
),
2363 SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_OPENICON
2364 | SHGFI_SYSICONINDEX
| SHGFI_DISPLAYNAME
);
2369 iIndentation
= tmpFolder
->m_iIndent
;
2371 /* Draw text and icon */
2373 /* Initialise the icon display area */
2374 rectIcon
.left
= pDIStruct
->rcItem
.left
+ ICONWIDTH
/2 * iIndentation
;
2375 rectIcon
.top
= pDIStruct
->rcItem
.top
;
2376 rectIcon
.right
= rectIcon
.left
+ ICONWIDTH
;
2377 rectIcon
.bottom
= pDIStruct
->rcItem
.bottom
;
2379 /* Initialise the text display area */
2380 GetTextMetricsA(pDIStruct
->hDC
, &tm
);
2381 rectText
.left
= rectIcon
.right
;
2383 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
- tm
.tmHeight
) / 2;
2384 rectText
.right
= pDIStruct
->rcItem
.right
+ XTEXTOFFSET
;
2386 (pDIStruct
->rcItem
.top
+ pDIStruct
->rcItem
.bottom
+ tm
.tmHeight
) / 2;
2388 /* Draw the icon from the image list */
2389 ImageList_Draw(ilItemImage
,
2396 /* Draw the associated text */
2397 if(sfi
.szDisplayName
)
2398 TextOutA(pDIStruct
->hDC
,rectText
.left
,rectText
.top
,sfi
.szDisplayName
,strlen(sfi
.szDisplayName
));
2404 /***********************************************************************
2405 * FILEDLG95_LOOKIN_OnCommand
2407 * LookIn combo box WM_COMMAND message handler
2408 * If the function succeeds, the return value is nonzero.
2410 static BOOL
FILEDLG95_LOOKIN_OnCommand(HWND hwnd
, WORD wNotifyCode
)
2412 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2414 TRACE("%p\n", fodInfos
);
2420 LPSFOLDER tmpFolder
;
2423 iItem
= CBGetCurSel(fodInfos
->DlgInfos
.hwndLookInCB
);
2425 if(!(tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,
2430 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos
->Shell
.FOIShellBrowser
,
2431 tmpFolder
->pidlItem
,
2443 /***********************************************************************
2444 * FILEDLG95_LOOKIN_AddItem
2446 * Adds an absolute pidl item to the lookin combo box
2447 * returns the index of the inserted item
2449 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd
,LPITEMIDLIST pidl
, int iInsertId
)
2451 LPITEMIDLIST pidlNext
;
2454 LookInInfos
*liInfos
;
2456 TRACE("%08x\n", iInsertId
);
2461 if(!(liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
)))
2464 tmpFolder
= MemAlloc(sizeof(SFOLDER
));
2465 tmpFolder
->m_iIndent
= 0;
2467 /* Calculate the indentation of the item in the lookin*/
2469 while( (pidlNext
=COMDLG32_PIDL_ILGetNext(pidlNext
)) )
2471 tmpFolder
->m_iIndent
++;
2474 tmpFolder
->pidlItem
= COMDLG32_PIDL_ILClone(pidl
);
2476 if(tmpFolder
->m_iIndent
> liInfos
->iMaxIndentation
)
2477 liInfos
->iMaxIndentation
= tmpFolder
->m_iIndent
;
2479 sfi
.dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
2480 SHGetFileInfoA((LPSTR
)pidl
,
2484 SHGFI_DISPLAYNAME
| SHGFI_SYSICONINDEX
2485 | SHGFI_PIDL
| SHGFI_SMALLICON
| SHGFI_ATTRIBUTES
| SHGFI_ATTR_SPECIFIED
);
2487 TRACE("-- Add %s attr=%08lx\n", sfi
.szDisplayName
, sfi
.dwAttributes
);
2489 if((sfi
.dwAttributes
& SFGAO_FILESYSANCESTOR
) || (sfi
.dwAttributes
& SFGAO_FILESYSTEM
))
2493 TRACE("-- Add %s at %u\n", sfi
.szDisplayName
, tmpFolder
->m_iIndent
);
2495 /* Add the item at the end of the list */
2498 iItemID
= CBAddString(hwnd
,sfi
.szDisplayName
);
2500 /* Insert the item at the iInsertId position*/
2503 iItemID
= CBInsertString(hwnd
,sfi
.szDisplayName
,iInsertId
);
2506 CBSetItemDataPtr(hwnd
,iItemID
,tmpFolder
);
2510 COMDLG32_SHFree( tmpFolder
->pidlItem
);
2511 MemFree( tmpFolder
);
2516 /***********************************************************************
2517 * FILEDLG95_LOOKIN_InsertItemAfterParent
2519 * Insert an item below its parent
2521 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd
,LPITEMIDLIST pidl
)
2524 LPITEMIDLIST pidlParent
= GetParentPidl(pidl
);
2529 iParentPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidlParent
,SEARCH_PIDL
);
2533 iParentPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidlParent
);
2536 /* Free pidlParent memory */
2537 COMDLG32_SHFree((LPVOID
)pidlParent
);
2539 return FILEDLG95_LOOKIN_AddItem(hwnd
,pidl
,iParentPos
+ 1);
2542 /***********************************************************************
2543 * FILEDLG95_LOOKIN_SelectItem
2545 * Adds an absolute pidl item to the lookin combo box
2546 * returns the index of the inserted item
2548 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd
,LPITEMIDLIST pidl
)
2551 LookInInfos
*liInfos
;
2555 iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)pidl
,SEARCH_PIDL
);
2557 liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2561 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
) > -1);
2562 iItemPos
= FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd
,pidl
);
2567 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2568 while(liInfos
->iMaxIndentation
> tmpFolder
->m_iIndent
)
2572 if(-1 == (iRemovedItem
= FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd
)))
2574 if(iRemovedItem
< iItemPos
)
2579 CBSetCurSel(hwnd
,iItemPos
);
2580 liInfos
->uSelectedItem
= iItemPos
;
2586 /***********************************************************************
2587 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2589 * Remove the item with an expansion level over iExpansionLevel
2591 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd
)
2595 LookInInfos
*liInfos
= (LookInInfos
*)GetPropA(hwnd
,LookInInfosStr
);
2599 if(liInfos
->iMaxIndentation
<= 2)
2602 if((iItemPos
= FILEDLG95_LOOKIN_SearchItem(hwnd
,(WPARAM
)liInfos
->iMaxIndentation
,SEARCH_EXP
)) >=0)
2604 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,iItemPos
);
2605 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2607 CBDeleteString(hwnd
,iItemPos
);
2608 liInfos
->iMaxIndentation
--;
2616 /***********************************************************************
2617 * FILEDLG95_LOOKIN_SearchItem
2619 * Search for pidl in the lookin combo box
2620 * returns the index of the found item
2622 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd
,WPARAM searchArg
,int iSearchMethod
)
2625 int iCount
= CBGetCount(hwnd
);
2627 TRACE("0x%08x 0x%x\n",searchArg
, iSearchMethod
);
2629 if (iCount
!= CB_ERR
)
2633 LPSFOLDER tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(hwnd
,i
);
2635 if(iSearchMethod
== SEARCH_PIDL
&& COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST
)searchArg
,tmpFolder
->pidlItem
))
2637 if(iSearchMethod
== SEARCH_EXP
&& tmpFolder
->m_iIndent
== (int)searchArg
)
2645 /***********************************************************************
2646 * FILEDLG95_LOOKIN_Clean
2648 * Clean the memory used by the lookin combo box
2650 static void FILEDLG95_LOOKIN_Clean(HWND hwnd
)
2652 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2654 int iCount
= CBGetCount(fodInfos
->DlgInfos
.hwndLookInCB
);
2658 /* Delete each string of the combo and their associated data */
2659 if (iCount
!= CB_ERR
)
2661 for(iPos
= iCount
-1;iPos
>=0;iPos
--)
2663 SFOLDER
*tmpFolder
= (LPSFOLDER
) CBGetItemDataPtr(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2664 COMDLG32_SHFree(tmpFolder
->pidlItem
);
2666 CBDeleteString(fodInfos
->DlgInfos
.hwndLookInCB
,iPos
);
2670 /* LookInInfos structure */
2671 RemovePropA(fodInfos
->DlgInfos
.hwndLookInCB
,LookInInfosStr
);
2674 /***********************************************************************
2675 * FILEDLG95_FILENAME_FillFromSelection
2677 * fills the edit box from the cached DataObject
2679 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd
)
2681 FileOpenDlgInfos
*fodInfos
;
2683 UINT nFiles
= 0, nFileToOpen
, nFileSelected
, nLength
= 0;
2684 char lpstrTemp
[MAX_PATH
];
2685 LPSTR lpstrAllFile
= NULL
, lpstrCurrFile
= NULL
;
2688 fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2690 /* Count how many files we have */
2691 nFileSelected
= GetNumSelected( fodInfos
->Shell
.FOIDataObject
);
2693 /* calculate the string length, count files */
2694 if (nFileSelected
>= 1)
2696 nLength
+= 3; /* first and last quotes, trailing \0 */
2697 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2699 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2703 /* get the total length of the selected file names*/
2704 lpstrTemp
[0] = '\0';
2705 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2707 if ( ! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
) ) /* Ignore folders */
2709 nLength
+= strlen( lpstrTemp
) + 3;
2712 COMDLG32_SHFree( pidl
);
2717 /* allocate the buffer */
2718 if (nFiles
<= 1) nLength
= MAX_PATH
;
2719 lpstrAllFile
= (LPSTR
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, nLength
);
2720 lpstrAllFile
[0] = '\0';
2722 /* Generate the string for the edit control */
2725 lpstrCurrFile
= lpstrAllFile
;
2726 for ( nFileToOpen
= 0; nFileToOpen
< nFileSelected
; nFileToOpen
++ )
2728 pidl
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, nFileToOpen
+1 );
2732 /* get the file name */
2733 lpstrTemp
[0] = '\0';
2734 GetName( fodInfos
->Shell
.FOIShellFolder
, pidl
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, lpstrTemp
);
2736 if (! IsPidlFolder(fodInfos
->Shell
.FOIShellFolder
, pidl
)) /* Ignore folders */
2740 *lpstrCurrFile
++ = '\"';
2741 strcpy( lpstrCurrFile
, lpstrTemp
);
2742 lpstrCurrFile
+= strlen( lpstrTemp
);
2743 strcpy( lpstrCurrFile
, "\" " );
2748 strcpy( lpstrAllFile
, lpstrTemp
);
2751 COMDLG32_SHFree( (LPVOID
) pidl
);
2754 SetWindowTextA( fodInfos
->DlgInfos
.hwndFileName
, lpstrAllFile
);
2756 HeapFree(GetProcessHeap(),0, lpstrAllFile
);
2760 /* copied from shell32 to avoid linking to it */
2761 static HRESULT
COMDLG32_StrRetToStrNA (LPVOID dest
, DWORD len
, LPSTRRET src
, LPITEMIDLIST pidl
)
2766 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, (LPSTR
)dest
, len
, NULL
, NULL
);
2767 COMDLG32_SHFree(src
->u
.pOleStr
);
2771 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
2775 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
2779 FIXME("unknown type!\n");
2782 *(LPSTR
)dest
= '\0';
2789 /***********************************************************************
2790 * FILEDLG95_FILENAME_GetFileNames
2792 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2794 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd
, LPWSTR
* lpstrFileList
, UINT
* sizeUsed
)
2796 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
2797 UINT nStrCharCount
= 0; /* index in src buffer */
2798 UINT nFileIndex
= 0; /* index in dest buffer */
2799 UINT nFileCount
= 0; /* number of files */
2800 UINT nStrLen
= 0; /* length of string in edit control */
2801 LPWSTR lpstrEdit
; /* buffer for string from edit control */
2805 /* get the filenames from the edit control */
2806 nStrLen
= SendMessageW(fodInfos
->DlgInfos
.hwndFileName
, WM_GETTEXTLENGTH
, 0, 0);
2807 lpstrEdit
= MemAlloc( (nStrLen
+1)*sizeof(WCHAR
) );
2808 GetDlgItemTextW(hwnd
, IDC_FILENAME
, lpstrEdit
, nStrLen
+1);
2810 TRACE("nStrLen=%u str=%s\n", nStrLen
, debugstr_w(lpstrEdit
));
2812 /* we might get single filename without any '"',
2813 * so we need nStrLen + terminating \0 + end-of-list \0 */
2814 *lpstrFileList
= MemAlloc( (nStrLen
+2)*sizeof(WCHAR
) );
2817 /* build 0-delimited file list from filenames */
2818 while ( nStrCharCount
<= nStrLen
)
2820 if ( lpstrEdit
[nStrCharCount
]=='"' )
2823 while ((lpstrEdit
[nStrCharCount
]!='"') && (nStrCharCount
<= nStrLen
))
2825 (*lpstrFileList
)[nFileIndex
++] = lpstrEdit
[nStrCharCount
];
2829 (*lpstrFileList
)[nFileIndex
++] = '\0';
2836 /* single, unquoted string */
2837 if ((nStrLen
> 0) && (*sizeUsed
== 0) )
2839 strcpyW(*lpstrFileList
, lpstrEdit
);
2840 nFileIndex
= strlenW(lpstrEdit
) + 1;
2841 (*sizeUsed
) = nFileIndex
;
2846 (*lpstrFileList
)[nFileIndex
] = '\0';
2853 #define SETDefFormatEtc(fe,cf,med) \
2855 (fe).cfFormat = cf;\
2856 (fe).dwAspect = DVASPECT_CONTENT; \
2863 * DATAOBJECT Helper functions
2866 /***********************************************************************
2867 * COMCTL32_ReleaseStgMedium
2869 * like ReleaseStgMedium from ole32
2871 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium
)
2873 if(medium
.pUnkForRelease
)
2875 IUnknown_Release(medium
.pUnkForRelease
);
2879 GlobalUnlock(medium
.u
.hGlobal
);
2880 GlobalFree(medium
.u
.hGlobal
);
2884 /***********************************************************************
2885 * GetPidlFromDataObject
2887 * Return pidl(s) by number from the cached DataObject
2889 * nPidlIndex=0 gets the fully qualified root path
2891 LPITEMIDLIST
GetPidlFromDataObject ( IDataObject
*doSelected
, UINT nPidlIndex
)
2895 FORMATETC formatetc
;
2896 LPITEMIDLIST pidl
= NULL
;
2898 TRACE("sv=%p index=%u\n", doSelected
, nPidlIndex
);
2900 /* Set the FORMATETC structure*/
2901 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2903 /* Get the pidls from IDataObject */
2904 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2906 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2907 if(nPidlIndex
<= cida
->cidl
)
2909 pidl
= COMDLG32_PIDL_ILClone((LPITEMIDLIST
)(&((LPBYTE
)cida
)[cida
->aoffset
[nPidlIndex
]]));
2911 COMCTL32_ReleaseStgMedium(medium
);
2916 /***********************************************************************
2919 * Return the number of selected items in the DataObject.
2922 UINT
GetNumSelected( IDataObject
*doSelected
)
2926 FORMATETC formatetc
;
2928 TRACE("sv=%p\n", doSelected
);
2930 if (!doSelected
) return 0;
2932 /* Set the FORMATETC structure*/
2933 SETDefFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
2935 /* Get the pidls from IDataObject */
2936 if(SUCCEEDED(IDataObject_GetData(doSelected
,&formatetc
,&medium
)))
2938 LPIDA cida
= GlobalLock(medium
.u
.hGlobal
);
2939 retVal
= cida
->cidl
;
2940 COMCTL32_ReleaseStgMedium(medium
);
2950 /***********************************************************************
2953 * Get the pidl's display name (relative to folder) and
2954 * put it in lpstrFileName.
2956 * Return NOERROR on success,
2960 HRESULT
GetName(LPSHELLFOLDER lpsf
, LPITEMIDLIST pidl
,DWORD dwFlags
,LPSTR lpstrFileName
)
2965 TRACE("sf=%p pidl=%p\n", lpsf
, pidl
);
2970 SHGetDesktopFolder(&lpsf
);
2971 hRes
= GetName(lpsf
,pidl
,dwFlags
,lpstrFileName
);
2972 IShellFolder_Release(lpsf
);
2976 /* Get the display name of the pidl relative to the folder */
2977 if (SUCCEEDED(hRes
= IShellFolder_GetDisplayNameOf(lpsf
, pidl
, dwFlags
, &str
)))
2979 return COMDLG32_StrRetToStrNA(lpstrFileName
, MAX_PATH
, &str
, pidl
);
2984 /***********************************************************************
2985 * GetShellFolderFromPidl
2987 * pidlRel is the item pidl relative
2988 * Return the IShellFolder of the absolute pidl
2990 IShellFolder
*GetShellFolderFromPidl(LPITEMIDLIST pidlAbs
)
2992 IShellFolder
*psf
= NULL
,*psfParent
;
2994 TRACE("%p\n", pidlAbs
);
2996 if(SUCCEEDED(SHGetDesktopFolder(&psfParent
)))
2999 if(pidlAbs
&& pidlAbs
->mkid
.cb
)
3001 if(SUCCEEDED(IShellFolder_BindToObject(psfParent
, pidlAbs
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psf
)))
3003 IShellFolder_Release(psfParent
);
3007 /* return the desktop */
3013 /***********************************************************************
3016 * Return the LPITEMIDLIST to the parent of the pidl in the list
3018 LPITEMIDLIST
GetParentPidl(LPITEMIDLIST pidl
)
3020 LPITEMIDLIST pidlParent
;
3022 TRACE("%p\n", pidl
);
3024 pidlParent
= COMDLG32_PIDL_ILClone(pidl
);
3025 COMDLG32_PIDL_ILRemoveLastID(pidlParent
);
3030 /***********************************************************************
3033 * returns the pidl of the file name relative to folder
3034 * NULL if an error occurred
3036 LPITEMIDLIST
GetPidlFromName(IShellFolder
*lpsf
,LPWSTR lpcstrFileName
)
3038 LPITEMIDLIST pidl
= NULL
;
3041 TRACE("sf=%p file=%s\n", lpsf
, debugstr_w(lpcstrFileName
));
3043 if(!lpcstrFileName
) return NULL
;
3044 if(!*lpcstrFileName
) return NULL
;
3048 if (SUCCEEDED(SHGetDesktopFolder(&lpsf
))) {
3049 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3050 IShellFolder_Release(lpsf
);
3055 IShellFolder_ParseDisplayName(lpsf
, 0, NULL
, lpcstrFileName
, &ulEaten
, &pidl
, NULL
);
3062 BOOL
IsPidlFolder (LPSHELLFOLDER psf
, LPITEMIDLIST pidl
)
3064 ULONG uAttr
= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
3067 TRACE("%p, %p\n", psf
, pidl
);
3069 ret
= IShellFolder_GetAttributesOf( psf
, 1, &pidl
, &uAttr
);
3071 TRACE("-- 0x%08lx 0x%08lx\n", uAttr
, ret
);
3072 /* see documentation shell 4.1*/
3073 return uAttr
& (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
);
3076 /***********************************************************************
3077 * BrowseSelectedFolder
3079 static BOOL
BrowseSelectedFolder(HWND hwnd
)
3081 BOOL bBrowseSelFolder
= FALSE
;
3082 FileOpenDlgInfos
*fodInfos
= (FileOpenDlgInfos
*) GetPropA(hwnd
,FileOpenDlgInfosStr
);
3086 if (GetNumSelected(fodInfos
->Shell
.FOIDataObject
) == 1)
3088 LPITEMIDLIST pidlSelection
;
3090 /* get the file selected */
3091 pidlSelection
= GetPidlFromDataObject( fodInfos
->Shell
.FOIDataObject
, 1);
3092 if (IsPidlFolder (fodInfos
->Shell
.FOIShellFolder
, pidlSelection
))
3094 if ( FAILED( IShellBrowser_BrowseObject( fodInfos
->Shell
.FOIShellBrowser
,
3095 pidlSelection
, SBSP_RELATIVE
) ) )
3097 WCHAR notexist
[] = {'P','a','t','h',' ','d','o','e','s',
3098 ' ','n','o','t',' ','e','x','i','s','t',0};
3099 MessageBoxW( hwnd
, notexist
, fodInfos
->title
, MB_OK
| MB_ICONEXCLAMATION
);
3102 bBrowseSelFolder
= TRUE
;
3104 COMDLG32_SHFree( pidlSelection
);
3107 return bBrowseSelFolder
;
3111 * Memory allocation methods */
3112 static void *MemAlloc(UINT size
)
3114 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,size
);
3117 static void MemFree(void *mem
)
3121 HeapFree(GetProcessHeap(),0,mem
);