2 * Copyright 1999 Juergen Schmied
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * - many flags unimplemented
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
30 #include "wine/debug.h"
31 #include "undocshell.h"
34 #include "shell32_main.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
40 static HWND hwndTreeView
;
41 static LPBROWSEINFOW lpBrowseInfo
;
42 static LPITEMIDLIST pidlRet
;
44 static void FillTreeView(LPSHELLFOLDER lpsf
, LPITEMIDLIST lpifq
, HTREEITEM hParent
, IEnumIDList
* lpe
);
45 static HTREEITEM
InsertTreeViewItem(IShellFolder
* lpsf
, LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
, HTREEITEM hParent
);
47 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
48 BIF_BROWSEFORCOMPUTER | \
49 BIF_RETURNFSANCESTORS | \
50 BIF_RETURNONLYFSDIRS | \
51 BIF_BROWSEINCLUDEFILES)
53 static inline DWORD
BrowseFlagsToSHCONTF(UINT ulFlags
)
55 return SHCONTF_FOLDERS
| (ulFlags
& BIF_BROWSEINCLUDEFILES
? SHCONTF_NONFOLDERS
: 0);
58 static void InitializeTreeView(HWND hwndParent
, LPCITEMIDLIST root
)
60 HIMAGELIST hImageList
;
63 IEnumIDList
* pEnumIL
= NULL
;
64 LPITEMIDLIST parentofroot
;
65 parentofroot
= ILClone(root
);
66 ILRemoveLastID(parentofroot
);
68 hwndTreeView
= GetDlgItem (hwndParent
, IDD_TREEVIEW
);
69 Shell_GetImageList(NULL
, &hImageList
);
71 TRACE("dlg=%p tree=%p\n", hwndParent
, hwndTreeView
);
73 if (hImageList
&& hwndTreeView
)
74 TreeView_SetImageList(hwndTreeView
, hImageList
, 0);
76 if (_ILIsDesktop (root
)) {
77 hr
= SHGetDesktopFolder(&lpsf
);
79 IShellFolder
* lpsfdesktop
;
81 hr
= SHGetDesktopFolder(&lpsfdesktop
);
83 hr
= IShellFolder_BindToObject(lpsfdesktop
, parentofroot
, 0,(REFIID
)&IID_IShellFolder
,(LPVOID
*)&lpsf
);
84 IShellFolder_Release(lpsfdesktop
);
89 IShellFolder
* pSFRoot
;
90 if (_ILIsPidlSimple(root
))
93 IShellFolder_AddRef(pSFRoot
);
96 hr
= IShellFolder_BindToObject(lpsf
,ILFindLastID(root
),0,&IID_IShellFolder
,(LPVOID
*)&pSFRoot
);
99 hr
= IShellFolder_EnumObjects(
102 BrowseFlagsToSHCONTF(lpBrowseInfo
->ulFlags
),
104 IShellFolder_Release(pSFRoot
);
108 if (SUCCEEDED(hr
) && hwndTreeView
)
110 TreeView_DeleteAllItems(hwndTreeView
);
111 TreeView_Expand(hwndTreeView
,
112 InsertTreeViewItem(lpsf
, _ILIsPidlSimple(root
) ? root
: ILFindLastID(root
), parentofroot
, pEnumIL
, TVI_ROOT
),
117 IShellFolder_Release(lpsf
);
122 static int GetIcon(LPITEMIDLIST lpi
, UINT uFlags
)
125 SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), uFlags
);
129 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq
, LPTVITEMW lpTV_ITEM
)
131 LPITEMIDLIST pidlDesktop
= NULL
;
133 TRACE("%p %p\n",lpifq
, lpTV_ITEM
);
137 pidlDesktop
= _ILCreateDesktop();
141 lpTV_ITEM
->iImage
= GetIcon(lpifq
, SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
);
142 lpTV_ITEM
->iSelectedImage
= GetIcon(lpifq
, SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_OPENICON
);
152 LPSHELLFOLDER lpsfParent
;
155 IEnumIDList
* pEnumIL
;
156 } TV_ITEMDATA
, *LPTV_ITEMDATA
;
158 static BOOL
GetName(LPSHELLFOLDER lpsf
, LPCITEMIDLIST lpi
, DWORD dwFlags
, LPWSTR lpFriendlyName
)
163 TRACE("%p %p %lx %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
164 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf
, lpi
, dwFlags
, &str
)))
166 if (FAILED(StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
)))
174 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
178 static HTREEITEM
InsertTreeViewItem(IShellFolder
* lpsf
, LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
, HTREEITEM hParent
)
181 TVINSERTSTRUCTW tvins
;
182 WCHAR szBuff
[MAX_PATH
];
183 LPTV_ITEMDATA lptvid
=0;
185 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
187 tvi
.cChildren
= pEnumIL
? 1 : 0;
188 tvi
.mask
|= TVIF_CHILDREN
;
190 if (!(lptvid
= (LPTV_ITEMDATA
)SHAlloc(sizeof(TV_ITEMDATA
))))
193 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
196 tvi
.pszText
= szBuff
;
197 tvi
.cchTextMax
= MAX_PATH
;
198 tvi
.lParam
= (LPARAM
)lptvid
;
200 IShellFolder_AddRef(lpsf
);
201 lptvid
->lpsfParent
= lpsf
;
202 lptvid
->lpi
= ILClone(pidl
);
203 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
204 lptvid
->pEnumIL
= pEnumIL
;
205 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
208 tvins
.hInsertAfter
= NULL
;
209 tvins
.hParent
= hParent
;
211 return (HTREEITEM
)TreeView_InsertItemW(hwndTreeView
, &tvins
);
214 static void FillTreeView(IShellFolder
* lpsf
, LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
217 LPITEMIDLIST pidlTemp
= 0;
220 HWND hwnd
=GetParent(hwndTreeView
);
222 TRACE("%p %p %x\n",lpsf
, pidl
, (INT
)hParent
);
223 SetCapture(GetParent(hwndTreeView
));
224 SetCursor(LoadCursorA(0, (LPSTR
)IDC_WAIT
));
226 while (NOERROR
== IEnumIDList_Next(lpe
,1,&pidlTemp
,&ulFetched
))
228 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
229 IEnumIDList
* pEnumIL
= NULL
;
230 IShellFolder
* pSFChild
= NULL
;
231 IShellFolder_GetAttributesOf(lpsf
, 1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
232 if (ulAttrs
& SFGAO_FOLDER
)
234 hr
= IShellFolder_BindToObject(lpsf
,pidlTemp
,NULL
,&IID_IShellFolder
,(LPVOID
*)&pSFChild
);
237 hr
= IShellFolder_EnumObjects(pSFChild
, hwnd
, BrowseFlagsToSHCONTF(lpBrowseInfo
->ulFlags
), &pEnumIL
);
240 if ((IEnumIDList_Skip(pEnumIL
, 1) != S_OK
) || FAILED(IEnumIDList_Reset(pEnumIL
)))
242 IEnumIDList_Release(pEnumIL
);
246 IShellFolder_Release(pSFChild
);
250 if (!(hPrev
= InsertTreeViewItem(lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
252 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
258 SetCursor(LoadCursorW(0, (LPWSTR
)IDC_ARROW
));
264 static inline BOOL
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
266 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
269 return (data
->type
== type
);
272 static void BrsFolder_CheckValidSelection(HWND hWndTree
, LPTV_ITEMDATA lptvid
)
274 LPCITEMIDLIST pidl
= lptvid
->lpi
;
275 BOOL bEnabled
= TRUE
;
277 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
278 !PIDLIsType(pidl
, PT_COMP
))
280 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
282 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
283 if (FAILED(IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1, (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
)) ||
287 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
289 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
290 if (FAILED(IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1, (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
)) ||
291 (dwAttributes
!= (SFGAO_FOLDER
| SFGAO_FILESYSTEM
)))
294 SendMessageW(hWndTree
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
297 static LRESULT
MsgNotify(HWND hWnd
, UINT CtlID
, LPNMHDR lpnmh
)
299 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
300 LPTV_ITEMDATA lptvid
; /* Long pointer to TreeView item data */
301 IShellFolder
* lpsf2
=0;
304 TRACE("%p %x %p msg=%x\n", hWnd
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
306 switch (pnmtv
->hdr
.idFrom
)
308 switch (pnmtv
->hdr
.code
)
310 case TVN_DELETEITEMA
:
311 case TVN_DELETEITEMW
:
312 TRACE("TVN_DELETEITEMA/W\n");
313 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
314 IShellFolder_Release(lptvid
->lpsfParent
);
316 IEnumIDList_Release(lptvid
->pEnumIL
);
318 SHFree(lptvid
->lpifq
);
322 case TVN_ITEMEXPANDINGA
:
323 case TVN_ITEMEXPANDINGW
:
325 TRACE("TVN_ITEMEXPANDINGA/W\n");
326 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
329 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemNew
.lParam
;
330 if (SUCCEEDED(IShellFolder_BindToObject(lptvid
->lpsfParent
, lptvid
->lpi
,0,(REFIID
)&IID_IShellFolder
,(LPVOID
*)&lpsf2
)))
331 { FillTreeView( lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
333 TreeView_SortChildren(hwndTreeView
, pnmtv
->itemNew
.hItem
, FALSE
);
336 case TVN_SELCHANGEDA
:
337 case TVN_SELCHANGEDW
:
338 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemNew
.lParam
;
339 pidlRet
= lptvid
->lpifq
;
340 if (lpBrowseInfo
->lpfn
)
341 (lpBrowseInfo
->lpfn
)(hWnd
, BFFM_SELCHANGED
, (LPARAM
)pidlRet
, lpBrowseInfo
->lParam
);
342 BrsFolder_CheckValidSelection(hWnd
, lptvid
);
346 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
359 /*************************************************************************
360 * BrsFolderDlgProc32 (not an exported API function)
362 static INT_PTR CALLBACK
BrsFolderDlgProc(HWND hWnd
, UINT msg
, WPARAM wParam
,
365 TRACE("hwnd=%p msg=%04x 0x%08x 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
368 { case WM_INITDIALOG
:
370 lpBrowseInfo
= (LPBROWSEINFOW
) lParam
;
371 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
372 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
373 if (lpBrowseInfo
->lpszTitle
) {
374 SetWindowTextW(GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
376 ShowWindow(GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
378 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
))
379 ShowWindow(GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
381 InitializeTreeView(hWnd
, lpBrowseInfo
->pidlRoot
);
383 if (lpBrowseInfo
->lpfn
)
384 (lpBrowseInfo
->lpfn
)(hWnd
, BFFM_INITIALIZED
, 0, lpBrowseInfo
->lParam
);
389 MsgNotify( hWnd
, (UINT
)wParam
, (LPNMHDR
)lParam
);
396 if (lpBrowseInfo
->pszDisplayName
)
397 SHGetPathFromIDListW(pidlRet
, lpBrowseInfo
->pszDisplayName
);
398 EndDialog(hWnd
, (DWORD
) ILClone(pidlRet
));
406 case BFFM_SETSTATUSTEXTA
:
407 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
408 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
410 case BFFM_SETSTATUSTEXTW
:
411 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
412 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
415 TRACE("Enable %ld\n", lParam
);
416 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
418 case BFFM_SETOKTEXT
: /* unicode only */
419 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
420 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
422 case BFFM_SETSELECTIONA
:
424 FIXME("Set selection %s\n", debugstr_a((LPSTR
)lParam
));
426 FIXME("Set selection %p\n", (void*)lParam
);
428 case BFFM_SETSELECTIONW
:
430 FIXME("Set selection %s\n", debugstr_w((LPWSTR
)lParam
));
432 FIXME("Set selection %p\n", (void*)lParam
);
434 case BFFM_SETEXPANDED
: /* unicode only */
436 FIXME("Set expanded %s\n", debugstr_w((LPWSTR
)lParam
));
438 FIXME("Set expanded %p\n", (void*)lParam
);
444 static const WCHAR swBrowseTempName
[] = {'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
446 /*************************************************************************
447 * SHBrowseForFolderA [SHELL32.@]
448 * SHBrowseForFolder [SHELL32.@]
450 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
456 TRACE("(%p{lpszTitle=%s,owner=%p})\n", lpbi
,
457 lpbi
? debugstr_a(lpbi
->lpszTitle
) : NULL
, lpbi
? lpbi
->hwndOwner
: NULL
);
462 bi
.hwndOwner
= lpbi
->hwndOwner
;
463 bi
.pidlRoot
= lpbi
->pidlRoot
;
464 if (lpbi
->pszDisplayName
)
466 /*lpbi->pszDisplayName is assumed to be MAX_PATH (MSDN) */
467 bi
.pszDisplayName
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
));
468 MultiByteToWideChar(CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, MAX_PATH
);
471 bi
.pszDisplayName
= NULL
;
475 len
= MultiByteToWideChar(CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0);
476 bi
.lpszTitle
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
477 MultiByteToWideChar(CP_ACP
, 0, lpbi
->lpszTitle
, -1, (LPWSTR
)bi
.lpszTitle
, len
);
482 bi
.ulFlags
= lpbi
->ulFlags
;
483 bi
.lpfn
= lpbi
->lpfn
;
484 bi
.lParam
= lpbi
->lParam
;
485 bi
.iImage
= lpbi
->iImage
;
486 lpid
= (LPITEMIDLIST
) DialogBoxParamW(shell32_hInstance
,
487 swBrowseTempName
, lpbi
->hwndOwner
,
488 BrsFolderDlgProc
, (INT
)&bi
);
489 if (bi
.pszDisplayName
)
491 WideCharToMultiByte(CP_ACP
, 0, bi
.pszDisplayName
, -1, lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
492 HeapFree(GetProcessHeap(), 0, bi
.pszDisplayName
);
496 HeapFree(GetProcessHeap(), 0, (LPVOID
)bi
.lpszTitle
);
498 lpbi
->iImage
= bi
.iImage
;
503 /*************************************************************************
504 * SHBrowseForFolderW [SHELL32.@]
506 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
508 TRACE("((%p->{lpszTitle=%s,owner=%p})\n", lpbi
,
509 lpbi
? debugstr_w(lpbi
->lpszTitle
) : NULL
, lpbi
? lpbi
->hwndOwner
: 0);
514 return (LPITEMIDLIST
) DialogBoxParamW(shell32_hInstance
,
515 swBrowseTempName
, lpbi
->hwndOwner
,
516 BrsFolderDlgProc
, (INT
)lpbi
);