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
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "wine/debug.h"
29 #include "undocshell.h"
32 #include "shell32_main.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
38 static HWND hwndTreeView
;
39 static LPBROWSEINFOW lpBrowseInfo
;
40 static LPITEMIDLIST pidlRet
;
42 static void FillTreeView(LPSHELLFOLDER lpsf
, LPITEMIDLIST lpifq
, HTREEITEM hParent
, IEnumIDList
* lpe
);
43 static HTREEITEM
InsertTreeViewItem(IShellFolder
* lpsf
, LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
, HTREEITEM hParent
);
45 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
46 BIF_BROWSEFORCOMPUTER | \
47 BIF_RETURNFSANCESTORS | \
48 BIF_RETURNONLYFSDIRS | \
49 BIF_BROWSEINCLUDEFILES)
51 static inline DWORD
BrowseFlagsToSHCONTF(UINT ulFlags
)
53 return SHCONTF_FOLDERS
| (ulFlags
& BIF_BROWSEINCLUDEFILES
? SHCONTF_NONFOLDERS
: 0);
56 static void InitializeTreeView(HWND hwndParent
, LPCITEMIDLIST root
)
58 HIMAGELIST hImageList
;
61 IEnumIDList
* pEnumIL
= NULL
;
62 LPITEMIDLIST parentofroot
;
63 parentofroot
= ILClone(root
);
64 ILRemoveLastID(parentofroot
);
66 hwndTreeView
= GetDlgItem (hwndParent
, IDD_TREEVIEW
);
67 Shell_GetImageList(NULL
, &hImageList
);
69 TRACE("dlg=%p tree=%p\n", hwndParent
, hwndTreeView
);
71 if (hImageList
&& hwndTreeView
)
72 TreeView_SetImageList(hwndTreeView
, hImageList
, 0);
74 if (_ILIsDesktop (root
)) {
75 hr
= SHGetDesktopFolder(&lpsf
);
77 IShellFolder
* lpsfdesktop
;
79 hr
= SHGetDesktopFolder(&lpsfdesktop
);
81 hr
= IShellFolder_BindToObject(lpsfdesktop
, parentofroot
, 0,(REFIID
)&IID_IShellFolder
,(LPVOID
*)&lpsf
);
82 IShellFolder_Release(lpsfdesktop
);
87 IShellFolder
* pSFRoot
;
88 if (_ILIsPidlSimple(root
))
91 IShellFolder_AddRef(pSFRoot
);
94 hr
= IShellFolder_BindToObject(lpsf
,ILFindLastID(root
),0,&IID_IShellFolder
,(LPVOID
*)&pSFRoot
);
97 hr
= IShellFolder_EnumObjects(
100 BrowseFlagsToSHCONTF(lpBrowseInfo
->ulFlags
),
102 IShellFolder_Release(pSFRoot
);
106 if (SUCCEEDED(hr
) && hwndTreeView
)
108 TreeView_DeleteAllItems(hwndTreeView
);
109 TreeView_Expand(hwndTreeView
,
110 InsertTreeViewItem(lpsf
, _ILIsPidlSimple(root
) ? root
: ILFindLastID(root
), parentofroot
, pEnumIL
, TVI_ROOT
),
115 IShellFolder_Release(lpsf
);
120 static int GetIcon(LPITEMIDLIST lpi
, UINT uFlags
)
123 SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), uFlags
);
127 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq
, LPTVITEMW lpTV_ITEM
)
129 LPITEMIDLIST pidlDesktop
= NULL
;
131 TRACE("%p %p\n",lpifq
, lpTV_ITEM
);
135 pidlDesktop
= _ILCreateDesktop();
139 lpTV_ITEM
->iImage
= GetIcon(lpifq
, SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
);
140 lpTV_ITEM
->iSelectedImage
= GetIcon(lpifq
, SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_OPENICON
);
150 LPSHELLFOLDER lpsfParent
;
153 IEnumIDList
* pEnumIL
;
154 } TV_ITEMDATA
, *LPTV_ITEMDATA
;
156 static BOOL
GetName(LPSHELLFOLDER lpsf
, LPCITEMIDLIST lpi
, DWORD dwFlags
, LPWSTR lpFriendlyName
)
161 TRACE("%p %p %lx %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
162 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf
, lpi
, dwFlags
, &str
)))
164 if (FAILED(StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
)))
172 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
176 static HTREEITEM
InsertTreeViewItem(IShellFolder
* lpsf
, LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
, HTREEITEM hParent
)
179 TVINSERTSTRUCTW tvins
;
180 WCHAR szBuff
[MAX_PATH
];
181 LPTV_ITEMDATA lptvid
=0;
183 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
185 tvi
.cChildren
= pEnumIL
? 1 : 0;
186 tvi
.mask
|= TVIF_CHILDREN
;
188 if (!(lptvid
= (LPTV_ITEMDATA
)SHAlloc(sizeof(TV_ITEMDATA
))))
191 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
194 tvi
.pszText
= szBuff
;
195 tvi
.cchTextMax
= MAX_PATH
;
196 tvi
.lParam
= (LPARAM
)lptvid
;
198 IShellFolder_AddRef(lpsf
);
199 lptvid
->lpsfParent
= lpsf
;
200 lptvid
->lpi
= ILClone(pidl
);
201 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
202 lptvid
->pEnumIL
= pEnumIL
;
203 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
205 tvins
.DUMMYUNIONNAME
.item
= tvi
;
206 tvins
.hInsertAfter
= NULL
;
207 tvins
.hParent
= hParent
;
209 return (HTREEITEM
)TreeView_InsertItemW(hwndTreeView
, &tvins
);
212 static void FillTreeView(IShellFolder
* lpsf
, LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
215 LPITEMIDLIST pidlTemp
= 0;
218 HWND hwnd
=GetParent(hwndTreeView
);
220 TRACE("%p %p %x\n",lpsf
, pidl
, (INT
)hParent
);
221 SetCapture(GetParent(hwndTreeView
));
222 SetCursor(LoadCursorA(0, IDC_WAITA
));
224 while (NOERROR
== IEnumIDList_Next(lpe
,1,&pidlTemp
,&ulFetched
))
226 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
227 IEnumIDList
* pEnumIL
= NULL
;
228 IShellFolder
* pSFChild
= NULL
;
229 IShellFolder_GetAttributesOf(lpsf
, 1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
230 if (ulAttrs
& SFGAO_FOLDER
)
232 hr
= IShellFolder_BindToObject(lpsf
,pidlTemp
,NULL
,&IID_IShellFolder
,(LPVOID
*)&pSFChild
);
235 hr
= IShellFolder_EnumObjects(pSFChild
, hwnd
, BrowseFlagsToSHCONTF(lpBrowseInfo
->ulFlags
), &pEnumIL
);
238 if ((IEnumIDList_Skip(pEnumIL
, 1) != S_OK
) || FAILED(IEnumIDList_Reset(pEnumIL
)))
240 IEnumIDList_Release(pEnumIL
);
244 IShellFolder_Release(pSFChild
);
248 if (!(hPrev
= InsertTreeViewItem(lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
250 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
256 SetCursor(LoadCursorW(0, IDC_ARROWW
));
262 static inline BOOL
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
264 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
267 return (data
->type
== type
);
270 static void BrsFolder_CheckValidSelection(HWND hWndTree
, LPTV_ITEMDATA lptvid
)
272 LPCITEMIDLIST pidl
= lptvid
->lpi
;
273 BOOL bEnabled
= TRUE
;
275 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
276 !PIDLIsType(pidl
, PT_COMP
))
278 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
280 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
281 if (FAILED(IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1, (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
)) ||
285 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
287 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
288 if (FAILED(IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1, (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
)) ||
289 (dwAttributes
!= (SFGAO_FOLDER
| SFGAO_FILESYSTEM
)))
292 SendMessageW(hWndTree
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
295 static LRESULT
MsgNotify(HWND hWnd
, UINT CtlID
, LPNMHDR lpnmh
)
297 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
298 LPTV_ITEMDATA lptvid
; /* Long pointer to TreeView item data */
299 IShellFolder
* lpsf2
=0;
302 TRACE("%p %x %p msg=%x\n", hWnd
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
304 switch (pnmtv
->hdr
.idFrom
)
306 switch (pnmtv
->hdr
.code
)
308 case TVN_DELETEITEMA
:
309 case TVN_DELETEITEMW
:
310 TRACE("TVN_DELETEITEMA/W\n");
311 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
312 IShellFolder_Release(lptvid
->lpsfParent
);
314 IEnumIDList_Release(lptvid
->pEnumIL
);
316 SHFree(lptvid
->lpifq
);
320 case TVN_ITEMEXPANDINGA
:
321 case TVN_ITEMEXPANDINGW
:
323 TRACE("TVN_ITEMEXPANDINGA/W\n");
324 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
327 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemNew
.lParam
;
328 if (SUCCEEDED(IShellFolder_BindToObject(lptvid
->lpsfParent
, lptvid
->lpi
,0,(REFIID
)&IID_IShellFolder
,(LPVOID
*)&lpsf2
)))
329 { FillTreeView( lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
331 TreeView_SortChildren(hwndTreeView
, pnmtv
->itemNew
.hItem
, FALSE
);
334 case TVN_SELCHANGEDA
:
335 case TVN_SELCHANGEDW
:
336 lptvid
=(LPTV_ITEMDATA
)pnmtv
->itemNew
.lParam
;
337 pidlRet
= lptvid
->lpifq
;
338 if (lpBrowseInfo
->lpfn
)
339 (lpBrowseInfo
->lpfn
)(hWnd
, BFFM_SELCHANGED
, (LPARAM
)pidlRet
, lpBrowseInfo
->lParam
);
340 BrsFolder_CheckValidSelection(hWnd
, lptvid
);
344 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
357 /*************************************************************************
358 * BrsFolderDlgProc32 (not an exported API function)
360 static INT_PTR CALLBACK
BrsFolderDlgProc(HWND hWnd
, UINT msg
, WPARAM wParam
,
363 TRACE("hwnd=%p msg=%04x 0x%08x 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
366 { case WM_INITDIALOG
:
368 lpBrowseInfo
= (LPBROWSEINFOW
) lParam
;
369 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
370 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
371 if (lpBrowseInfo
->lpszTitle
) {
372 SetWindowTextW(GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
374 ShowWindow(GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
376 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
))
377 ShowWindow(GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
379 InitializeTreeView(hWnd
, lpBrowseInfo
->pidlRoot
);
381 if (lpBrowseInfo
->lpfn
)
382 (lpBrowseInfo
->lpfn
)(hWnd
, BFFM_INITIALIZED
, 0, lpBrowseInfo
->lParam
);
387 MsgNotify( hWnd
, (UINT
)wParam
, (LPNMHDR
)lParam
);
394 SHGetPathFromIDListW(pidlRet
, lpBrowseInfo
->pszDisplayName
);
395 EndDialog(hWnd
, (DWORD
) ILClone(pidlRet
));
403 case BFFM_SETSTATUSTEXTA
:
404 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
405 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
407 case BFFM_SETSTATUSTEXTW
:
408 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
409 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
412 TRACE("Enable %ld\n", lParam
);
413 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
415 case BFFM_SETOKTEXT
: /* unicode only */
416 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
417 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
419 case BFFM_SETSELECTIONA
:
421 FIXME("Set selection %s\n", debugstr_a((LPSTR
)lParam
));
423 FIXME("Set selection %p\n", (void*)lParam
);
425 case BFFM_SETSELECTIONW
:
427 FIXME("Set selection %s\n", debugstr_w((LPWSTR
)lParam
));
429 FIXME("Set selection %p\n", (void*)lParam
);
431 case BFFM_SETEXPANDED
: /* unicode only */
433 FIXME("Set expanded %s\n", debugstr_w((LPWSTR
)lParam
));
435 FIXME("Set expanded %p\n", (void*)lParam
);
441 static WCHAR swBrowseTempName
[] = {'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
443 /*************************************************************************
444 * SHBrowseForFolderA [SHELL32.@]
445 * SHBrowseForFolder [SHELL32.@]
447 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
453 TRACE("(%p{lpszTitle=%s,owner=%p})\n", lpbi
,
454 lpbi
? debugstr_a(lpbi
->lpszTitle
) : NULL
, lpbi
? lpbi
->hwndOwner
: NULL
);
459 bi
.hwndOwner
= lpbi
->hwndOwner
;
460 bi
.pidlRoot
= lpbi
->pidlRoot
;
461 if (lpbi
->pszDisplayName
)
463 len
= MultiByteToWideChar(CP_ACP
, 0, lpbi
->pszDisplayName
, -1, NULL
, 0);
464 bi
.pszDisplayName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
465 MultiByteToWideChar(CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, len
);
468 bi
.pszDisplayName
= NULL
;
472 len
= MultiByteToWideChar(CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0);
473 bi
.lpszTitle
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
474 MultiByteToWideChar(CP_ACP
, 0, lpbi
->lpszTitle
, -1, (LPWSTR
)bi
.lpszTitle
, len
);
479 bi
.ulFlags
= lpbi
->ulFlags
;
480 bi
.lpfn
= lpbi
->lpfn
;
481 bi
.lParam
= lpbi
->lParam
;
482 bi
.iImage
= lpbi
->iImage
;
483 lpid
= (LPITEMIDLIST
) DialogBoxParamW(shell32_hInstance
,
484 swBrowseTempName
, lpbi
->hwndOwner
,
485 BrsFolderDlgProc
, (INT
)&bi
);
486 if (bi
.pszDisplayName
)
488 WideCharToMultiByte(CP_ACP
, 0, bi
.pszDisplayName
, -1, lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
489 HeapFree(GetProcessHeap(), 0, bi
.pszDisplayName
);
493 HeapFree(GetProcessHeap(), 0, (LPVOID
)bi
.lpszTitle
);
495 lpbi
->iImage
= bi
.iImage
;
500 /*************************************************************************
501 * SHBrowseForFolderW [SHELL32.@]
503 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
505 TRACE("((%p->{lpszTitle=%s,owner=%p})\n", lpbi
,
506 lpbi
? debugstr_w(lpbi
->lpszTitle
) : NULL
, lpbi
? lpbi
->hwndOwner
: 0);
511 return (LPITEMIDLIST
) DialogBoxParamW(shell32_hInstance
,
512 swBrowseTempName
, lpbi
->hwndOwner
,
513 BrsFolderDlgProc
, (INT
)lpbi
);