1111#include " precomp.h"
1212
1313#include < ui/layout.h> // Resizable window
14+ #include < compat_undoc.h> // RosGetProcessEffectiveVersion
1415
1516WINE_DEFAULT_DEBUG_CHANNEL (shell);
1617
1718#define SHV_CHANGE_NOTIFY (WM_USER + 0x1111 )
1819
20+ static LPITEMIDLIST
21+ ILCloneToDepth (LPCITEMIDLIST pidlSrc, UINT depth)
22+ {
23+ SIZE_T cb = 0 ;
24+ for (LPCITEMIDLIST pidl = pidlSrc; pidl && depth--; pidl = ILGetNext (pidl))
25+ cb += pidl->mkid .cb ;
26+
27+ LPITEMIDLIST pidlOut = (LPITEMIDLIST)SHAlloc (cb + sizeof (WORD));
28+ if (pidlOut)
29+ {
30+ CopyMemory (pidlOut, pidlSrc, cb);
31+ ZeroMemory (((BYTE*)pidlOut) + cb, sizeof (WORD));
32+ }
33+ return pidlOut;
34+ }
35+
36+ static INT
37+ GetIconIndex (PCIDLIST_ABSOLUTE pidl, UINT uFlags)
38+ {
39+ SHFILEINFOW sfi;
40+ SHGetFileInfoW ((LPCWSTR)pidl, 0 , &sfi, sizeof (sfi), uFlags);
41+ return sfi.iIcon ;
42+ }
43+
1944struct BrFolder
2045{
2146 LPBROWSEINFOW lpBrowseInfo;
@@ -145,12 +170,9 @@ BrFolder_InitTreeView(BrFolder *info)
145170{
146171 HIMAGELIST hImageList;
147172 HRESULT hr;
148- CComPtr<IShellFolder> lpsfParent;
149- CComPtr<IEnumIDList> pEnumChildren;
150173 HTREEITEM hItem;
151174
152175 Shell_GetImageLists (NULL , &hImageList);
153-
154176 if (hImageList)
155177 TreeView_SetImageList (info->hwndTreeView , hImageList, 0 );
156178
@@ -171,54 +193,25 @@ BrFolder_InitTreeView(BrFolder *info)
171193 ILRemoveLastID (pidlParent);
172194 PCIDLIST_RELATIVE pidlChild = ILFindLastID (pidlRoot);
173195
174- if (_ILIsDesktop (pidlParent))
175- {
176- hr = SHGetDesktopFolder (&lpsfParent);
177- if (FAILED_UNEXPECTEDLY (hr))
178- return ;
179- }
180- else
181- {
182- CComPtr<IShellFolder> lpsfDesktop;
183- hr = SHGetDesktopFolder (&lpsfDesktop);
184- if (FAILED_UNEXPECTEDLY (hr))
185- return ;
186-
187- hr = lpsfDesktop->BindToObject (pidlParent, NULL , IID_PPV_ARG (IShellFolder, &lpsfParent));
188- if (FAILED_UNEXPECTEDLY (hr))
189- return ;
190- }
196+ CComPtr<IShellFolder> lpsfParent;
197+ hr = SHBindToObject (NULL , pidlParent, /* NULL, */ IID_PPV_ARG (IShellFolder, &lpsfParent));
198+ if (FAILED_UNEXPECTEDLY (hr))
199+ return ;
191200
192201 TreeView_DeleteItem (info->hwndTreeView , TVI_ROOT);
193202 hItem = BrFolder_InsertItem (info, lpsfParent, pidlChild, pidlParent, TVI_ROOT);
194203 TreeView_Expand (info->hwndTreeView , hItem, TVE_EXPAND);
195204}
196205
197- static INT
198- BrFolder_GetIcon (PCIDLIST_ABSOLUTE pidl, UINT uFlags)
199- {
200- SHFILEINFOW sfi;
201- SHGetFileInfoW ((LPCWSTR)pidl, 0 , &sfi, sizeof (sfi), uFlags);
202- return sfi.iIcon ;
203- }
204-
205206static void
206207BrFolder_GetIconPair (PCIDLIST_ABSOLUTE pidl, LPTVITEMW pItem)
207208{
208- DWORD flags;
209-
210- CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlDesktop;
209+ static const ITEMIDLIST idlDesktop = { };
211210 if (!pidl)
212- {
213- pidlDesktop.Attach (_ILCreateDesktop ());
214- pidl = pidlDesktop;
215- }
216-
217- flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
218- pItem->iImage = BrFolder_GetIcon (pidl, flags);
219-
220- flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON;
221- pItem->iSelectedImage = BrFolder_GetIcon (pidl, flags);
211+ pidl = &idlDesktop;
212+ DWORD flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
213+ pItem->iImage = GetIconIndex (pidl, flags);
214+ pItem->iSelectedImage = GetIconIndex (pidl, flags | SHGFI_OPENICON);
222215}
223216
224217/* *****************************************************************************
@@ -766,6 +759,19 @@ BrFolder_OnInitDialog(HWND hWnd, BrFolder *info)
766759 SHCNE_ALLEVENTS,
767760 SHV_CHANGE_NOTIFY, 1 , &ntreg);
768761
762+ if (!lpBrowseInfo->pidlRoot )
763+ {
764+ UINT csidl = (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) ? CSIDL_PERSONAL : CSIDL_DRIVES;
765+ LPITEMIDLIST pidl = SHCloneSpecialIDList (NULL , csidl, TRUE );
766+ if (pidl)
767+ {
768+ SendMessageW (info->hWnd , BFFM_SETSELECTION, FALSE , (LPARAM)pidl);
769+ if (csidl == CSIDL_DRIVES)
770+ SendMessageW (info->hWnd , BFFM_SETEXPANDED, FALSE , (LPARAM)pidl);
771+ ILFree (pidl);
772+ }
773+ }
774+
769775 BrFolder_Callback (info->lpBrowseInfo , hWnd, BFFM_INITIALIZED, 0 );
770776
771777 SHAutoComplete (GetDlgItem (hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT),
@@ -985,60 +991,56 @@ BrFolder_OnContextMenu(BrFolder &info, LPARAM lParam)
985991}
986992
987993static BOOL
988- BrFolder_OnSetExpandedPidl (BrFolder *info, LPITEMIDLIST pidlSelection, HTREEITEM *phItem)
994+ BrFolder_ExpandToPidl (BrFolder *info, LPITEMIDLIST pidlSelection, HTREEITEM *phItem)
989995{
996+ LPITEMIDLIST pidlCurrent = pidlSelection;
990997 if (_ILIsDesktop (pidlSelection))
991998 {
992999 if (phItem)
9931000 *phItem = TVI_ROOT;
9941001 return TRUE ;
9951002 }
9961003
997- // Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
998- // the sub-tree currently displayed.
999- PCIDLIST_ABSOLUTE pidlRoot = info->lpBrowseInfo ->pidlRoot ;
1000- LPITEMIDLIST pidlCurrent = pidlSelection;
1001- while (!_ILIsEmpty (pidlRoot) && _ILIsEqualSimple (pidlRoot, pidlCurrent))
1002- {
1003- pidlRoot = ILGetNext (pidlRoot);
1004- pidlCurrent = ILGetNext (pidlCurrent);
1005- }
1006-
1007- // The given ID List is not part of the SHBrowseForFolder's current sub-tree.
1008- if (!_ILIsEmpty (pidlRoot))
1009- {
1010- if (phItem)
1011- *phItem = NULL ;
1012- return FALSE ;
1013- }
1014-
10151004 // Initialize item to point to the first child of the root folder.
10161005 TVITEMEXW item = { TVIF_PARAM };
10171006 item.hItem = TreeView_GetRoot (info->hwndTreeView );
10181007 if (item.hItem )
10191008 item.hItem = TreeView_GetChild (info->hwndTreeView , item.hItem );
10201009
10211010 // Walk the tree along the nodes corresponding to the remaining ITEMIDLIST
1022- while (item.hItem && !_ILIsEmpty (pidlCurrent))
1011+ UINT depth = _ILGetDepth (info->lpBrowseInfo ->pidlRoot );
1012+ while (item.hItem && pidlCurrent)
10231013 {
1014+ LPITEMIDLIST pidlNeedle = ILCloneToDepth (pidlSelection, ++depth);
1015+ if (_ILIsEmpty (pidlNeedle))
1016+ {
1017+ ILFree (pidlNeedle);
1018+ item.hItem = NULL ; // Failure
1019+ break ;
1020+ }
1021+ next:
10241022 TreeView_GetItem (info->hwndTreeView , &item);
1025- BrItemData *pItemData = (BrItemData *)item.lParam ;
1026-
1027- if (_ILIsEqualSimple (pItemData->pidlChild , pidlCurrent))
1023+ const BrItemData *pItemData = (BrItemData *)item.lParam ;
1024+ if (ILIsEqual (pItemData->pidlFull , pidlNeedle))
10281025 {
1029- pidlCurrent = ILGetNext (pidlCurrent);
1030- if (!_ILIsEmpty (pidlCurrent))
1026+ BOOL done = _ILGetDepth (pidlSelection) == _ILGetDepth (pidlNeedle);
1027+ if (done)
1028+ {
1029+ pidlCurrent = NULL ; // Success
1030+ }
1031+ else
10311032 {
1032- // Only expand current node and move on to its first child,
1033- // if we didn't already reach the last SHITEMID
10341033 TreeView_Expand (info->hwndTreeView , item.hItem , TVE_EXPAND);
10351034 item.hItem = TreeView_GetChild (info->hwndTreeView , item.hItem );
10361035 }
10371036 }
10381037 else
10391038 {
10401039 item.hItem = TreeView_GetNextSibling (info->hwndTreeView , item.hItem );
1040+ if (item.hItem )
1041+ goto next;
10411042 }
1043+ ILFree (pidlNeedle);
10421044 }
10431045
10441046 if (phItem)
@@ -1048,19 +1050,26 @@ BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST pidlSelection, HTREEITEM
10481050}
10491051
10501052static BOOL
1051- BrFolder_OnSetExpandedString (BrFolder *info, LPWSTR pszString, HTREEITEM *phItem)
1053+ BrFolder_ExpandToString (BrFolder *info, LPWSTR pszString, HTREEITEM *phItem)
10521054{
1053- CComPtr<IShellFolder> psfDesktop;
1054- HRESULT hr = SHGetDesktopFolder (&psfDesktop);
1055- if (FAILED_UNEXPECTEDLY (hr))
1056- return FALSE ;
1057-
10581055 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSelection;
1059- hr = psfDesktop->ParseDisplayName (NULL , NULL , pszString, NULL , &pidlSelection, NULL );
1060- if (FAILED_UNEXPECTEDLY (hr))
1061- return FALSE ;
1056+ HRESULT hr = SHParseDisplayName (pszString, NULL , &pidlSelection, 0 , NULL );
1057+ return SUCCEEDED (hr) && BrFolder_ExpandToPidl (info, pidlSelection, phItem);
1058+ }
1059+
1060+ static BOOL
1061+ BrFolder_OnSetExpanded (BrFolder *info, LPITEMIDLIST pidlSelection, LPWSTR pszString)
1062+ {
1063+ HTREEITEM hItem;
1064+ BOOL ret;
1065+ if (pszString)
1066+ ret = BrFolder_ExpandToString (info, pszString, &hItem);
1067+ else
1068+ ret = BrFolder_ExpandToPidl (info, pidlSelection, &hItem);
10621069
1063- return BrFolder_OnSetExpandedPidl (info, pidlSelection, phItem);
1070+ if (ret)
1071+ TreeView_Expand (info->hwndTreeView , hItem, TVE_EXPAND);
1072+ return ret;
10641073}
10651074
10661075static BOOL
@@ -1070,7 +1079,7 @@ BrFolder_OnSetSelectionPidl(BrFolder *info, LPITEMIDLIST pidlSelection)
10701079 return FALSE ;
10711080
10721081 HTREEITEM hItem;
1073- BOOL ret = BrFolder_OnSetExpandedPidl (info, pidlSelection, &hItem);
1082+ BOOL ret = BrFolder_ExpandToPidl (info, pidlSelection, &hItem);
10741083 if (ret)
10751084 TreeView_SelectItem (info->hwndTreeView , hItem);
10761085 return ret;
@@ -1083,7 +1092,7 @@ BrFolder_OnSetSelectionW(BrFolder *info, LPWSTR pszSelection)
10831092 return FALSE ;
10841093
10851094 HTREEITEM hItem;
1086- BOOL ret = BrFolder_OnSetExpandedString (info, pszSelection, &hItem);
1095+ BOOL ret = BrFolder_ExpandToString (info, pszSelection, &hItem);
10871096 if (ret)
10881097 TreeView_SelectItem (info->hwndTreeView , hItem);
10891098 return ret;
@@ -1304,9 +1313,9 @@ BrFolderDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
13041313
13051314 case BFFM_SETEXPANDED: // Unicode only
13061315 if (wParam) // String
1307- return BrFolder_OnSetExpandedString (info, (LPWSTR)lParam, NULL );
1316+ return BrFolder_OnSetExpanded (info, NULL , (LPWSTR)lParam);
13081317 else // PIDL
1309- return BrFolder_OnSetExpandedPidl (info, (LPITEMIDLIST)lParam, NULL );
1318+ return BrFolder_OnSetExpanded (info, (LPITEMIDLIST)lParam, NULL );
13101319
13111320 case SHV_CHANGE_NOTIFY:
13121321 BrFolder_OnChange (info, wParam, lParam);
@@ -1362,16 +1371,23 @@ SHBrowseForFolderW(LPBROWSEINFOW lpbi)
13621371{
13631372 TRACE (" %p\n " , lpbi);
13641373
1374+ // MSDN says the caller must initialize COM. We do it anyway in case the caller forgot.
1375+ COleInit OleInit;
13651376 BrFolder info = { lpbi };
13661377
1367- HRESULT hr = OleInitialize (NULL );
1368-
13691378 INT id = ((lpbi->ulFlags & BIF_USENEWUI) ? IDD_BROWSE_FOR_FOLDER_NEW : IDD_BROWSE_FOR_FOLDER);
13701379 INT_PTR ret = DialogBoxParamW (shell32_hInstance, MAKEINTRESOURCEW (id), lpbi->hwndOwner ,
13711380 BrFolderDlgProc, (LPARAM)&info);
1372- if (SUCCEEDED (hr))
1373- OleUninitialize ();
1374-
1381+ if (ret == IDOK && !(lpbi->ulFlags & BIF_NOTRANSLATETARGETS) &&
1382+ RosGetProcessEffectiveVersion () >= _WIN32_WINNT_WINXP)
1383+ {
1384+ PIDLIST_ABSOLUTE pidlTarget;
1385+ if (SHELL_GetIDListTarget (info.pidlRet , &pidlTarget) == S_OK)
1386+ {
1387+ ILFree (info.pidlRet );
1388+ info.pidlRet = pidlTarget;
1389+ }
1390+ }
13751391 if (ret != IDOK)
13761392 {
13771393 ILFree (info.pidlRet );
0 commit comments