diff --git a/dlls/shell32/brsfolder.c b/dlls/shell32/brsfolder.c index 198c18d40f8..63be4a38079 100644 --- a/dlls/shell32/brsfolder.c +++ b/dlls/shell32/brsfolder.c @@ -55,68 +55,95 @@ static inline DWORD BrowseFlagsToSHCONTF(UINT ulFlags) return SHCONTF_FOLDERS | (ulFlags & BIF_BROWSEINCLUDEFILES ? SHCONTF_NONFOLDERS : 0); } +/****************************************************************************** + * InitializeTreeView [Internal] + * + * Called from WM_INITDIALOG handler. + * + * PARAMS + * hwndParent [I] The BrowseForFolder dialog + * root [I] ITEMIDLIST of the root shell folder + */ static void InitializeTreeView(HWND hwndParent, LPCITEMIDLIST root) { - HIMAGELIST hImageList; - IShellFolder * lpsf; - HRESULT hr; - IEnumIDList * pEnumIL = NULL; - LPITEMIDLIST parentofroot; - parentofroot = ILClone(root); - ILRemoveLastID(parentofroot); + LPITEMIDLIST pidlParent, pidlChild; + HIMAGELIST hImageList; + HRESULT hr; + IShellFolder *lpsfParent, *lpsfRoot; + IEnumIDList * pEnumChildren = NULL; - hwndTreeView = GetDlgItem (hwndParent, IDD_TREEVIEW); - Shell_GetImageList(NULL, &hImageList); + TRACE("dlg=%p tree=%p\n", hwndParent, hwndTreeView ); + + hwndTreeView = GetDlgItem (hwndParent, IDD_TREEVIEW); + if (!hwndTreeView) { + FIXME("Could not get handle to treeview control! Error: %08lx\n", GetLastError()); + return; + } + Shell_GetImageList(NULL, &hImageList); - TRACE("dlg=%p tree=%p\n", hwndParent, hwndTreeView ); + if (hImageList) + TreeView_SetImageList(hwndTreeView, hImageList, 0); - if (hImageList && hwndTreeView) - TreeView_SetImageList(hwndTreeView, hImageList, 0); + /* We want to call InsertTreeViewItem down the code, in order to insert + * the root item of the treeview. Due to InsertTreeViewItem's signature, + * we need the following to do this: + * + * + An ITEMIDLIST corresponding to _the parent_ of root. + * + An ITEMIDLIST, which is a relative path from root's parent to root + * (containing a single SHITEMID). + * + An IShellFolder interface pointer of root's parent folder. + * + * If root is 'Desktop', then root's parent is also 'Desktop'. + */ - if (_ILIsDesktop (root)) { - hr = SHGetDesktopFolder(&lpsf); - } else { - IShellFolder * lpsfdesktop; + pidlParent = ILClone(root); + ILRemoveLastID(pidlParent); + pidlChild = ILClone(ILFindLastID(root)); + + if (_ILIsDesktop(pidlParent)) { + hr = SHGetDesktopFolder(&lpsfParent); + } else { + IShellFolder *lpsfDesktop; + hr = SHGetDesktopFolder(&lpsfDesktop); + if (!SUCCEEDED(hr)) { + WARN("SHGetDesktopFolder failed! hr = %08lx\n", hr); + return; + } + hr = IShellFolder_BindToObject(lpsfDesktop, pidlParent, 0, &IID_IShellFolder, (LPVOID*)&lpsfParent); + IShellFolder_Release(lpsfDesktop); + } + + if (!SUCCEEDED(hr)) { + WARN("Could not bind to parent shell folder! hr = %08lx\n", hr); + return; + } - hr = SHGetDesktopFolder(&lpsfdesktop); - if (SUCCEEDED(hr)) { - hr = IShellFolder_BindToObject(lpsfdesktop, parentofroot, 0,(REFIID)&IID_IShellFolder,(LPVOID *)&lpsf); - IShellFolder_Release(lpsfdesktop); - } - } - if (SUCCEEDED(hr)) - { - IShellFolder * pSFRoot; - if (_ILIsPidlSimple(root)) - { - pSFRoot = lpsf; - IShellFolder_AddRef(pSFRoot); - } - else - hr = IShellFolder_BindToObject(lpsf,ILFindLastID(root),0,&IID_IShellFolder,(LPVOID *)&pSFRoot); - if (SUCCEEDED(hr)) - { - hr = IShellFolder_EnumObjects( - pSFRoot, - hwndParent, - BrowseFlagsToSHCONTF(lpBrowseInfo->ulFlags), - &pEnumIL); - IShellFolder_Release(pSFRoot); - } - } + if (pidlChild && pidlChild->mkid.cb) { + hr = IShellFolder_BindToObject(lpsfParent, pidlChild, 0, &IID_IShellFolder, (LPVOID*)&lpsfRoot); + } else { + lpsfRoot = lpsfParent; + hr = IShellFolder_AddRef(lpsfParent); + } + + if (!SUCCEEDED(hr)) { + WARN("Could not bind to root shell folder! hr = %08lx\n", hr); + IShellFolder_Release(lpsfParent); + return; + } - if (SUCCEEDED(hr) && hwndTreeView) - { - TreeView_DeleteAllItems(hwndTreeView); - TreeView_Expand(hwndTreeView, - InsertTreeViewItem(lpsf, _ILIsPidlSimple(root) ? root : ILFindLastID(root), parentofroot, pEnumIL, TVI_ROOT), - TVE_EXPAND); - } + hr = IShellFolder_EnumObjects(lpsfRoot, hwndParent, BrowseFlagsToSHCONTF(lpBrowseInfo->ulFlags), &pEnumChildren); + if (!SUCCEEDED(hr)) { + WARN("Could not get child iterator! hr = %08lx\n", hr); + IShellFolder_Release(lpsfParent); + IShellFolder_Release(lpsfRoot); + return; + } - if (SUCCEEDED(hr)) - IShellFolder_Release(lpsf); + TreeView_DeleteAllItems(hwndTreeView); + TreeView_Expand(hwndTreeView, InsertTreeViewItem(lpsfParent, pidlChild, pidlParent, pEnumChildren, TVI_ROOT), TVE_EXPAND); - TRACE("done\n"); + IShellFolder_Release(lpsfRoot); + IShellFolder_Release(lpsfParent); } static int GetIcon(LPITEMIDLIST lpi, UINT uFlags) @@ -149,12 +176,27 @@ static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTVITEMW lpTV_ITEM) typedef struct tagID { - LPSHELLFOLDER lpsfParent; - LPITEMIDLIST lpi; - LPITEMIDLIST lpifq; - IEnumIDList* pEnumIL; + LPSHELLFOLDER lpsfParent; /* IShellFolder of the parent */ + LPITEMIDLIST lpi; /* PIDL relativ to parent */ + LPITEMIDLIST lpifq; /* Fully qualified PIDL */ + IEnumIDList* pEnumIL; /* Children iterator */ } TV_ITEMDATA, *LPTV_ITEMDATA; +/****************************************************************************** + * GetName [Internal] + * + * Query a shell folder for the display name of one of it's children + * + * PARAMS + * lpsf [I] IShellFolder interface of the folder to be queried. + * lpi [I] ITEMIDLIST of the child, relative to parent + * dwFlags [I] as in IShellFolder::GetDisplayNameOf + * lpFriendlyName [O] The desired display name in unicode + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ static BOOL GetName(LPSHELLFOLDER lpsf, LPCITEMIDLIST lpi, DWORD dwFlags, LPWSTR lpFriendlyName) { BOOL bSuccess=TRUE; @@ -175,7 +217,22 @@ static BOOL GetName(LPSHELLFOLDER lpsf, LPCITEMIDLIST lpi, DWORD dwFlags, LPWSTR return bSuccess; } -static HTREEITEM InsertTreeViewItem(IShellFolder * lpsf, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlParent, IEnumIDList* pEnumIL, HTREEITEM hParent) +/****************************************************************************** + * InsertTreeViewItem [Internal] + * + * PARAMS + * lpsf [I] IShellFolder interface of the item's parent shell folder + * pidl [I] ITEMIDLIST of the child to insert, relativ to parent + * pidlParent [I] ITEMIDLIST of the parent shell folder + * pEnumIL [I] Iterator for the children of the item to be inserted + * hParent [I] The treeview-item that represents the parent shell folder + * + * RETURNS + * Success: Handle to the created and inserted treeview-item + * Failure: NULL + */ +static HTREEITEM InsertTreeViewItem(IShellFolder * lpsf, LPCITEMIDLIST pidl, + LPCITEMIDLIST pidlParent, IEnumIDList* pEnumIL, HTREEITEM hParent) { TVITEMW tvi; TVINSERTSTRUCTW tvins; @@ -211,6 +268,18 @@ static HTREEITEM InsertTreeViewItem(IShellFolder * lpsf, LPCITEMIDLIST pidl, LPC return (HTREEITEM)TreeView_InsertItemW(hwndTreeView, &tvins); } +/****************************************************************************** + * FillTreeView [Internal] + * + * For each child (given by lpe) of the parent shell folder, which is given by + * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent + * + * PARAMS + * lpsf [I] IShellFolder interface of the parent shell folder + * pidl [I] ITEMIDLIST of the parent shell folder + * hParent [I] The treeview item that represents the parent shell folder + * lpe [I] An iterator for the children of the parent shell folder + */ static void FillTreeView(IShellFolder * lpsf, LPITEMIDLIST pidl, HTREEITEM hParent, IEnumIDList* lpe) { HTREEITEM hPrev = 0; @@ -219,7 +288,11 @@ static void FillTreeView(IShellFolder * lpsf, LPITEMIDLIST pidl, HTREEITEM hPar HRESULT hr; HWND hwnd=GetParent(hwndTreeView); - TRACE("%p %p %x\n",lpsf, pidl, (INT)hParent); + TRACE("%p %p %x %p\n",lpsf, pidl, (INT)hParent, lpe); + + /* No IEnumIDList -> No children */ + if (!lpe) return; + SetCapture(GetParent(hwndTreeView)); SetCursor(LoadCursorA(0, (LPSTR)IDC_WAIT));