dllhost: Add ISurrogate stub implementation.
[wine.git] / dlls / shell32 / brsfolder.c
blob63b51fc81df7ccc1d943ab212af646f7923cf83c
1 /*
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * FIXME:
19 * - many memory leaks
20 * - many flags unimplemented
21 * - implement editbox
24 #include <stdlib.h>
25 #include <string.h>
27 #define COBJMACROS
28 #define NONAMELESSUNION
30 #include "wine/debug.h"
31 #include "pidl.h"
32 #include "shell32_main.h"
33 #include "commoncontrols.h"
34 #include "shellapi.h"
35 #include "shresdef.h"
36 #include "shellfolder.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shell);
40 #define SHV_CHANGE_NOTIFY (WM_USER + 0x1111)
42 /* original margins and control size */
43 typedef struct tagLAYOUT_DATA
45 LONG left, width, right;
46 LONG top, height, bottom;
47 } LAYOUT_DATA;
49 typedef struct tagbrowse_info
51 HWND hWnd;
52 HWND hwndTreeView;
53 LPBROWSEINFOW lpBrowseInfo;
54 LPITEMIDLIST pidlRet;
55 LAYOUT_DATA *layout; /* filled by LayoutInit, used by LayoutUpdate */
56 SIZE szMin;
57 ULONG hNotify; /* change notification handle */
58 } browse_info;
60 typedef struct tagTV_ITEMDATA
62 LPSHELLFOLDER lpsfParent; /* IShellFolder of the parent */
63 LPITEMIDLIST lpi; /* PIDL relative to parent */
64 LPITEMIDLIST lpifq; /* Fully qualified PIDL */
65 IEnumIDList* pEnumIL; /* Children iterator */
66 } TV_ITEMDATA, *LPTV_ITEMDATA;
68 typedef struct tagLAYOUT_INFO
70 int iItemId; /* control id */
71 DWORD dwAnchor; /* BF_* flags specifying which margins should remain constant */
72 } LAYOUT_INFO;
74 static const LAYOUT_INFO g_layout_info[] =
76 {IDD_TITLE, BF_TOP|BF_LEFT|BF_RIGHT},
77 {IDD_STATUS, BF_TOP|BF_LEFT|BF_RIGHT},
78 {IDD_FOLDER, BF_TOP|BF_LEFT|BF_RIGHT},
79 {IDD_TREEVIEW, BF_TOP|BF_BOTTOM|BF_LEFT|BF_RIGHT},
80 {IDD_FOLDER, BF_BOTTOM|BF_LEFT},
81 {IDD_FOLDERTEXT, BF_BOTTOM|BF_LEFT|BF_RIGHT},
82 {IDD_MAKENEWFOLDER, BF_BOTTOM|BF_LEFT},
83 {IDOK, BF_BOTTOM|BF_RIGHT},
84 {IDCANCEL, BF_BOTTOM|BF_RIGHT}
87 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
88 BIF_BROWSEFORCOMPUTER | \
89 BIF_RETURNFSANCESTORS | \
90 BIF_RETURNONLYFSDIRS | \
91 BIF_NONEWFOLDERBUTTON | \
92 BIF_NEWDIALOGSTYLE | \
93 BIF_BROWSEINCLUDEFILES)
95 static void FillTreeView(browse_info*, LPSHELLFOLDER,
96 LPITEMIDLIST, HTREEITEM, IEnumIDList*);
97 static HTREEITEM InsertTreeViewItem( browse_info*, IShellFolder *,
98 LPCITEMIDLIST, LPCITEMIDLIST, IEnumIDList*, HTREEITEM);
100 static inline DWORD BrowseFlagsToSHCONTF(UINT ulFlags)
102 return SHCONTF_FOLDERS | (ulFlags & BIF_BROWSEINCLUDEFILES ? SHCONTF_NONFOLDERS : 0);
105 static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo, HWND hWnd,
106 UINT msg, LPARAM param )
108 if (!lpBrowseInfo->lpfn)
109 return;
110 lpBrowseInfo->lpfn( hWnd, msg, param, lpBrowseInfo->lParam );
113 static LAYOUT_DATA *LayoutInit(HWND hwnd, const LAYOUT_INFO *layout_info, int layout_count)
115 LAYOUT_DATA *data;
116 RECT rcWnd;
117 int i;
119 GetClientRect(hwnd, &rcWnd);
120 data = SHAlloc(sizeof(LAYOUT_DATA)*layout_count);
121 for (i = 0; i < layout_count; i++)
123 RECT r;
124 HWND hItem = GetDlgItem(hwnd, layout_info[i].iItemId);
126 if (hItem == NULL)
127 ERR("Item %d not found\n", i);
128 GetWindowRect(hItem, &r);
129 MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&r, 2);
131 data[i].left = r.left;
132 data[i].right = rcWnd.right - r.right;
133 data[i].width = r.right - r.left;
135 data[i].top = r.top;
136 data[i].bottom = rcWnd.bottom - r.bottom;
137 data[i].height = r.bottom - r.top;
139 return data;
142 static void LayoutUpdate(HWND hwnd, LAYOUT_DATA *data, const LAYOUT_INFO *layout_info, int layout_count)
144 RECT rcWnd;
145 int i;
147 GetClientRect(hwnd, &rcWnd);
148 for (i = 0; i < layout_count; i++)
150 RECT r;
151 HWND hItem = GetDlgItem(hwnd, layout_info[i].iItemId);
153 GetWindowRect(hItem, &r);
154 MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&r, 2);
156 if (layout_info[i].dwAnchor & BF_RIGHT)
158 r.right = rcWnd.right - data[i].right;
159 if (!(layout_info[i].dwAnchor & BF_LEFT))
160 r.left = r.right - data[i].width;
163 if (layout_info[i].dwAnchor & BF_BOTTOM)
165 r.bottom = rcWnd.bottom - data[i].bottom;
166 if (!(layout_info[i].dwAnchor & BF_TOP))
167 r.top = r.bottom - data[i].height;
170 SetWindowPos(hItem, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER);
175 /******************************************************************************
176 * InitializeTreeView [Internal]
178 * Called from WM_INITDIALOG handler.
180 * PARAMS
181 * hwndParent [I] The BrowseForFolder dialog
182 * root [I] ITEMIDLIST of the root shell folder
184 static void InitializeTreeView( browse_info *info )
186 LPITEMIDLIST pidlParent, pidlChild;
187 HIMAGELIST hImageList;
188 HRESULT hr;
189 IShellFolder *lpsfParent, *lpsfRoot;
190 IEnumIDList * pEnumChildren = NULL;
191 HTREEITEM item;
192 DWORD flags;
193 LPCITEMIDLIST root = info->lpBrowseInfo->pidlRoot;
195 TRACE("%p\n", info );
197 Shell_GetImageLists(NULL, &hImageList);
199 if (hImageList)
200 SendMessageW( info->hwndTreeView, TVM_SETIMAGELIST, 0, (LPARAM)hImageList );
202 /* We want to call InsertTreeViewItem down the code, in order to insert
203 * the root item of the treeview. Due to InsertTreeViewItem's signature,
204 * we need the following to do this:
206 * + An ITEMIDLIST corresponding to _the parent_ of root.
207 * + An ITEMIDLIST, which is a relative path from root's parent to root
208 * (containing a single SHITEMID).
209 * + An IShellFolder interface pointer of root's parent folder.
211 * If root is 'Desktop', then root's parent is also 'Desktop'.
214 pidlParent = ILClone(root);
215 ILRemoveLastID(pidlParent);
216 pidlChild = ILClone(ILFindLastID(root));
218 if (_ILIsDesktop(pidlParent)) {
219 hr = SHGetDesktopFolder(&lpsfParent);
220 } else {
221 IShellFolder *lpsfDesktop;
222 hr = SHGetDesktopFolder(&lpsfDesktop);
223 if (FAILED(hr)) {
224 WARN("SHGetDesktopFolder failed! hr = %08lx\n", hr);
225 ILFree(pidlChild);
226 ILFree(pidlParent);
227 return;
229 hr = IShellFolder_BindToObject(lpsfDesktop, pidlParent, 0, &IID_IShellFolder, (LPVOID*)&lpsfParent);
230 IShellFolder_Release(lpsfDesktop);
233 if (FAILED(hr)) {
234 WARN("Could not bind to parent shell folder! hr = %08lx\n", hr);
235 ILFree(pidlChild);
236 ILFree(pidlParent);
237 return;
240 if (!_ILIsEmpty(pidlChild)) {
241 hr = IShellFolder_BindToObject(lpsfParent, pidlChild, 0, &IID_IShellFolder, (LPVOID*)&lpsfRoot);
242 } else {
243 lpsfRoot = lpsfParent;
244 hr = IShellFolder_AddRef(lpsfParent);
247 if (FAILED(hr)) {
248 WARN("Could not bind to root shell folder! hr = %08lx\n", hr);
249 IShellFolder_Release(lpsfParent);
250 ILFree(pidlChild);
251 ILFree(pidlParent);
252 return;
255 flags = BrowseFlagsToSHCONTF( info->lpBrowseInfo->ulFlags );
256 hr = IShellFolder_EnumObjects( lpsfRoot, info->hWnd, flags, &pEnumChildren );
257 if (FAILED(hr)) {
258 WARN("Could not get child iterator! hr = %08lx\n", hr);
259 IShellFolder_Release(lpsfParent);
260 IShellFolder_Release(lpsfRoot);
261 ILFree(pidlChild);
262 ILFree(pidlParent);
263 return;
266 SendMessageW( info->hwndTreeView, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT );
267 item = InsertTreeViewItem( info, lpsfParent, pidlChild,
268 pidlParent, pEnumChildren, TVI_ROOT );
269 SendMessageW( info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item );
271 ILFree(pidlChild);
272 ILFree(pidlParent);
273 IShellFolder_Release(lpsfRoot);
274 IShellFolder_Release(lpsfParent);
277 static int GetIcon(LPCITEMIDLIST lpi, UINT uFlags)
279 SHFILEINFOW sfi;
280 IImageList *list;
282 list = (IImageList *)SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), uFlags);
283 if (list) IImageList_Release(list);
284 return sfi.iIcon;
287 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTVITEMW lpTV_ITEM)
289 LPITEMIDLIST pidlDesktop = NULL;
290 DWORD flags;
292 TRACE("%p %p\n",lpifq, lpTV_ITEM);
294 if (!lpifq)
296 pidlDesktop = _ILCreateDesktop();
297 lpifq = pidlDesktop;
300 flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
301 lpTV_ITEM->iImage = GetIcon( lpifq, flags );
303 flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON;
304 lpTV_ITEM->iSelectedImage = GetIcon( lpifq, flags );
306 if (pidlDesktop)
307 ILFree( pidlDesktop );
310 /******************************************************************************
311 * GetName [Internal]
313 * Query a shell folder for the display name of one of its children
315 * PARAMS
316 * lpsf [I] IShellFolder interface of the folder to be queried.
317 * lpi [I] ITEMIDLIST of the child, relative to parent
318 * dwFlags [I] as in IShellFolder::GetDisplayNameOf
319 * lpFriendlyName [O] The desired display name in unicode
321 * RETURNS
322 * Success: TRUE
323 * Failure: FALSE
325 static BOOL GetName(LPSHELLFOLDER lpsf, LPCITEMIDLIST lpi, DWORD dwFlags, LPWSTR lpFriendlyName)
327 BOOL bSuccess=TRUE;
328 STRRET str;
330 TRACE("%p %p %lx %p\n", lpsf, lpi, dwFlags, lpFriendlyName);
331 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf, lpi, dwFlags, &str)))
332 bSuccess = StrRetToStrNW(lpFriendlyName, MAX_PATH, &str, lpi);
333 else
334 bSuccess = FALSE;
336 TRACE("-- %s\n", debugstr_w(lpFriendlyName));
337 return bSuccess;
340 /******************************************************************************
341 * InsertTreeViewItem [Internal]
343 * PARAMS
344 * info [I] data for the dialog
345 * lpsf [I] IShellFolder interface of the item's parent shell folder
346 * pidl [I] ITEMIDLIST of the child to insert, relative to parent
347 * pidlParent [I] ITEMIDLIST of the parent shell folder
348 * pEnumIL [I] Iterator for the children of the item to be inserted
349 * hParent [I] The treeview-item that represents the parent shell folder
351 * RETURNS
352 * Success: Handle to the created and inserted treeview-item
353 * Failure: NULL
355 static HTREEITEM InsertTreeViewItem( browse_info *info, IShellFolder * lpsf,
356 LPCITEMIDLIST pidl, LPCITEMIDLIST pidlParent, IEnumIDList* pEnumIL,
357 HTREEITEM hParent)
359 TVITEMW tvi;
360 TVINSERTSTRUCTW tvins;
361 WCHAR szBuff[MAX_PATH];
362 LPTV_ITEMDATA lptvid=0;
364 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
366 tvi.cChildren= pEnumIL ? 1 : 0;
367 tvi.mask |= TVIF_CHILDREN;
369 if (!GetName(lpsf, pidl, SHGDN_NORMAL, szBuff))
370 return NULL;
372 lptvid = SHAlloc( sizeof(TV_ITEMDATA) );
373 if (!lptvid)
374 return NULL;
376 tvi.pszText = szBuff;
377 tvi.cchTextMax = MAX_PATH;
378 tvi.lParam = (LPARAM)lptvid;
380 IShellFolder_AddRef(lpsf);
381 lptvid->lpsfParent = lpsf;
382 lptvid->lpi = ILClone(pidl);
383 lptvid->lpifq = pidlParent ? ILCombine(pidlParent, pidl) : ILClone(pidl);
384 lptvid->pEnumIL = pEnumIL;
385 GetNormalAndSelectedIcons(lptvid->lpifq, &tvi);
387 tvins.u.item = tvi;
388 tvins.hInsertAfter = NULL;
389 tvins.hParent = hParent;
391 return TreeView_InsertItemW( info->hwndTreeView, &tvins );
394 /******************************************************************************
395 * FillTreeView [Internal]
397 * For each child (given by lpe) of the parent shell folder, which is given by
398 * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
400 * PARAMS
401 * info [I] data for the dialog
402 * lpsf [I] IShellFolder interface of the parent shell folder
403 * pidl [I] ITEMIDLIST of the parent shell folder
404 * hParent [I] The treeview item that represents the parent shell folder
405 * lpe [I] An iterator for the children of the parent shell folder
407 static void FillTreeView( browse_info *info, IShellFolder * lpsf,
408 LPITEMIDLIST pidl, HTREEITEM hParent, IEnumIDList* lpe)
410 LPITEMIDLIST pidlTemp = 0;
411 ULONG ulFetched;
412 HRESULT hr;
413 HWND hwnd = GetParent( info->hwndTreeView );
415 TRACE("%p %p %p %p\n",lpsf, pidl, hParent, lpe);
417 /* No IEnumIDList -> No children */
418 if (!lpe) return;
420 SetCapture( hwnd );
421 SetCursor( LoadCursorA( 0, (LPSTR)IDC_WAIT ) );
423 while (S_OK == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched))
425 ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
426 IEnumIDList* pEnumIL = NULL;
427 IShellFolder* pSFChild = NULL;
428 IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulAttrs);
429 if (ulAttrs & SFGAO_FOLDER)
431 hr = IShellFolder_BindToObject(lpsf,pidlTemp,NULL,&IID_IShellFolder,(LPVOID*)&pSFChild);
432 if (SUCCEEDED(hr))
434 DWORD flags = BrowseFlagsToSHCONTF(info->lpBrowseInfo->ulFlags);
435 hr = IShellFolder_EnumObjects(pSFChild, hwnd, flags, &pEnumIL);
436 if (hr == S_OK)
438 if ((IEnumIDList_Skip(pEnumIL, 1) != S_OK) ||
439 FAILED(IEnumIDList_Reset(pEnumIL)))
441 IEnumIDList_Release(pEnumIL);
442 pEnumIL = NULL;
445 IShellFolder_Release(pSFChild);
449 if (!InsertTreeViewItem(info, lpsf, pidlTemp, pidl, pEnumIL, hParent))
450 goto done;
451 SHFree(pidlTemp); /* Finally, free the pidl that the shell gave us... */
452 pidlTemp=NULL;
455 done:
456 ReleaseCapture();
457 SetCursor(LoadCursorW(0, (LPWSTR)IDC_ARROW));
458 SHFree(pidlTemp);
461 static inline BOOL PIDLIsType(LPCITEMIDLIST pidl, PIDLTYPE type)
463 LPPIDLDATA data = _ILGetDataPointer(pidl);
464 if (!data)
465 return FALSE;
466 return (data->type == type);
469 static void BrsFolder_CheckValidSelection( browse_info *info, LPTV_ITEMDATA lptvid )
471 LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
472 LPCITEMIDLIST pidl = lptvid->lpi;
473 BOOL bEnabled = TRUE;
474 DWORD dwAttributes;
475 HRESULT r;
477 if ((lpBrowseInfo->ulFlags & BIF_BROWSEFORCOMPUTER) &&
478 !PIDLIsType(pidl, PT_COMP))
479 bEnabled = FALSE;
480 if (lpBrowseInfo->ulFlags & BIF_RETURNFSANCESTORS)
482 dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
483 r = IShellFolder_GetAttributesOf(lptvid->lpsfParent, 1,
484 (LPCITEMIDLIST*)&lptvid->lpi, &dwAttributes);
485 if (FAILED(r) || !(dwAttributes & (SFGAO_FILESYSANCESTOR|SFGAO_FILESYSTEM)))
486 bEnabled = FALSE;
489 dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM;
490 r = IShellFolder_GetAttributesOf(lptvid->lpsfParent, 1,
491 (LPCITEMIDLIST*)&lptvid->lpi, &dwAttributes);
492 if (FAILED(r) ||
493 ((dwAttributes & (SFGAO_FOLDER|SFGAO_FILESYSTEM)) != (SFGAO_FOLDER|SFGAO_FILESYSTEM)))
495 if (lpBrowseInfo->ulFlags & BIF_RETURNONLYFSDIRS)
496 bEnabled = FALSE;
497 EnableWindow(GetDlgItem(info->hWnd, IDD_MAKENEWFOLDER), FALSE);
499 else
500 EnableWindow(GetDlgItem(info->hWnd, IDD_MAKENEWFOLDER), TRUE);
502 SendMessageW(info->hWnd, BFFM_ENABLEOK, 0, bEnabled);
505 static LRESULT BrsFolder_Treeview_Delete( browse_info *info, NMTREEVIEWW *pnmtv )
507 LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA)pnmtv->itemOld.lParam;
509 TRACE("TVN_DELETEITEMA/W %p\n", lptvid);
511 IShellFolder_Release(lptvid->lpsfParent);
512 if (lptvid->pEnumIL)
513 IEnumIDList_Release(lptvid->pEnumIL);
514 SHFree(lptvid->lpi);
515 SHFree(lptvid->lpifq);
516 SHFree(lptvid);
517 return 0;
520 static LRESULT BrsFolder_Treeview_Expand( browse_info *info, NMTREEVIEWW *pnmtv )
522 IShellFolder *lpsf2 = NULL;
523 LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam;
524 HRESULT r;
526 TRACE("TVN_ITEMEXPANDINGA/W\n");
528 if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
529 return 0;
531 if (!_ILIsEmpty(lptvid->lpi)) {
532 r = IShellFolder_BindToObject( lptvid->lpsfParent, lptvid->lpi, 0,
533 &IID_IShellFolder, (void**)&lpsf2 );
534 } else {
535 lpsf2 = lptvid->lpsfParent;
536 IShellFolder_AddRef(lpsf2);
537 r = S_OK;
540 if (SUCCEEDED(r))
542 FillTreeView( info, lpsf2, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL);
543 IShellFolder_Release( lpsf2 );
546 /* My Computer is already sorted and trying to do a simple text
547 * sort will only mess things up */
548 if (!_ILIsMyComputer(lptvid->lpi))
549 SendMessageW( info->hwndTreeView, TVM_SORTCHILDREN,
550 FALSE, (LPARAM)pnmtv->itemNew.hItem );
552 return 0;
555 static HRESULT BrsFolder_Treeview_Changed( browse_info *info, NMTREEVIEWW *pnmtv )
557 LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam;
558 WCHAR name[MAX_PATH];
560 ILFree(info->pidlRet);
561 info->pidlRet = ILClone(lptvid->lpifq);
563 if (GetName(lptvid->lpsfParent, lptvid->lpi, SHGDN_NORMAL, name))
564 SetWindowTextW( GetDlgItem(info->hWnd, IDD_FOLDERTEXT), name );
566 browsefolder_callback( info->lpBrowseInfo, info->hWnd, BFFM_SELCHANGED,
567 (LPARAM)info->pidlRet );
568 BrsFolder_CheckValidSelection( info, lptvid );
569 return S_OK;
572 static LRESULT BrsFolder_Treeview_Rename(browse_info *info, NMTVDISPINFOW *pnmtv)
574 LPTV_ITEMDATA item_data;
575 WCHAR old_path[MAX_PATH], new_path[MAX_PATH], *p;
576 NMTREEVIEWW nmtv;
577 TVITEMW item;
579 if(!pnmtv->item.pszText)
580 return 0;
582 item.mask = TVIF_HANDLE|TVIF_PARAM;
583 item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CARET, 0);
584 SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
585 item_data = (LPTV_ITEMDATA)item.lParam;
587 SHGetPathFromIDListW(item_data->lpifq, old_path);
588 if(!(p = wcsrchr(old_path, '\\')))
589 return 0;
590 p = new_path+(p-old_path+1);
591 memcpy(new_path, old_path, (p-new_path)*sizeof(WCHAR));
592 lstrcpyW(p, pnmtv->item.pszText);
594 if(!MoveFileW(old_path, new_path))
595 return 0;
597 SHFree(item_data->lpifq);
598 SHFree(item_data->lpi);
599 item_data->lpifq = SHSimpleIDListFromPathW(new_path);
600 IShellFolder_ParseDisplayName(item_data->lpsfParent, NULL, NULL,
601 pnmtv->item.pszText, NULL, &item_data->lpi, NULL);
603 item.mask = TVIF_HANDLE|TVIF_TEXT;
604 item.pszText = pnmtv->item.pszText;
605 SendMessageW(info->hwndTreeView, TVM_SETITEMW, 0, (LPARAM)&item);
607 nmtv.itemNew.lParam = item.lParam;
608 BrsFolder_Treeview_Changed(info, &nmtv);
609 return 0;
612 static HRESULT BrsFolder_Rename(browse_info *info, HTREEITEM rename)
614 SendMessageW(info->hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM)rename);
615 SendMessageW(info->hwndTreeView, TVM_EDITLABELW, 0, (LPARAM)rename);
616 return S_OK;
619 static LRESULT BrsFolder_Treeview_Keydown(browse_info *info, LPNMTVKEYDOWN keydown)
621 HTREEITEM selected_item;
623 /* Old dialog doesn't support those advanced features */
624 if (!(info->lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE))
625 return 0;
627 selected_item = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CARET, 0);
629 switch (keydown->wVKey)
631 case VK_F2:
632 BrsFolder_Rename(info, selected_item);
633 break;
634 case VK_DELETE:
636 const ITEMIDLIST *item_id;
637 ISFHelper *psfhlp;
638 HRESULT hr;
639 TVITEMW item;
640 TV_ITEMDATA *item_data;
642 item.mask = TVIF_PARAM;
643 item.hItem = selected_item;
644 SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
645 item_data = (TV_ITEMDATA *)item.lParam;
646 item_id = item_data->lpi;
648 hr = IShellFolder_QueryInterface(item_data->lpsfParent, &IID_ISFHelper, (void**)&psfhlp);
649 if(FAILED(hr))
650 return 0;
652 /* perform the item deletion - tree view gets updated over shell notification */
653 ISFHelper_DeleteItems(psfhlp, 1, &item_id);
654 ISFHelper_Release(psfhlp);
656 break;
658 return 0;
661 static LRESULT BrsFolder_OnNotify( browse_info *info, UINT CtlID, LPNMHDR lpnmh )
663 NMTREEVIEWW *pnmtv = (NMTREEVIEWW *)lpnmh;
665 TRACE("%p %x %p msg=%x\n", info, CtlID, lpnmh, pnmtv->hdr.code);
667 if (pnmtv->hdr.idFrom != IDD_TREEVIEW)
668 return 0;
670 switch (pnmtv->hdr.code)
672 case TVN_DELETEITEMA:
673 case TVN_DELETEITEMW:
674 return BrsFolder_Treeview_Delete( info, pnmtv );
676 case TVN_ITEMEXPANDINGA:
677 case TVN_ITEMEXPANDINGW:
678 return BrsFolder_Treeview_Expand( info, pnmtv );
680 case TVN_SELCHANGEDA:
681 case TVN_SELCHANGEDW:
682 return BrsFolder_Treeview_Changed( info, pnmtv );
684 case TVN_ENDLABELEDITA:
685 case TVN_ENDLABELEDITW:
686 return BrsFolder_Treeview_Rename( info, (LPNMTVDISPINFOW)pnmtv );
688 case TVN_KEYDOWN:
689 return BrsFolder_Treeview_Keydown( info, (LPNMTVKEYDOWN)pnmtv );
691 default:
692 WARN("unhandled (%d)\n", pnmtv->hdr.code);
693 break;
696 return 0;
700 static BOOL BrsFolder_OnCreate( HWND hWnd, browse_info *info )
702 LPITEMIDLIST computer_pidl;
703 SHChangeNotifyEntry ntreg;
704 LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
706 info->hWnd = hWnd;
707 SetPropW( hWnd, L"__WINE_BRSFOLDERDLG_INFO", info );
709 if (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
710 FIXME("flags BIF_NEWDIALOGSTYLE partially implemented\n");
711 if (lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS)
712 FIXME("flags %x not implemented\n", lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS);
714 if (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
716 RECT rcWnd;
718 info->layout = LayoutInit(hWnd, g_layout_info, ARRAY_SIZE(g_layout_info));
720 /* TODO: Windows allows shrinking the windows a bit */
721 GetWindowRect(hWnd, &rcWnd);
722 info->szMin.cx = rcWnd.right - rcWnd.left;
723 info->szMin.cy = rcWnd.bottom - rcWnd.top;
725 else
727 info->layout = NULL;
730 if (lpBrowseInfo->lpszTitle)
731 SetWindowTextW( GetDlgItem(hWnd, IDD_TITLE), lpBrowseInfo->lpszTitle );
732 else
733 ShowWindow( GetDlgItem(hWnd, IDD_TITLE), SW_HIDE );
735 if (!(lpBrowseInfo->ulFlags & BIF_STATUSTEXT)
736 || (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE))
737 ShowWindow( GetDlgItem(hWnd, IDD_STATUS), SW_HIDE );
739 /* Hide "Make New Folder" Button? */
740 if ((lpBrowseInfo->ulFlags & BIF_NONEWFOLDERBUTTON)
741 || !(lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE))
742 ShowWindow( GetDlgItem(hWnd, IDD_MAKENEWFOLDER), SW_HIDE );
744 /* Hide the editbox? */
745 if (!(lpBrowseInfo->ulFlags & BIF_EDITBOX))
747 ShowWindow( GetDlgItem(hWnd, IDD_FOLDER), SW_HIDE );
748 ShowWindow( GetDlgItem(hWnd, IDD_FOLDERTEXT), SW_HIDE );
751 info->hwndTreeView = GetDlgItem( hWnd, IDD_TREEVIEW );
752 if (info->hwndTreeView)
754 InitializeTreeView( info );
756 /* Resize the treeview if there's not editbox */
757 if ((lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
758 && !(lpBrowseInfo->ulFlags & BIF_EDITBOX))
760 RECT rc;
761 GetClientRect(info->hwndTreeView, &rc);
762 SetWindowPos(info->hwndTreeView, HWND_TOP, 0, 0,
763 rc.right, rc.bottom + 40, SWP_NOMOVE);
766 else
767 ERR("treeview control missing!\n");
769 /* Register for change notifications */
770 SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 0, &computer_pidl);
772 ntreg.pidl = computer_pidl;
773 ntreg.fRecursive = TRUE;
775 info->hNotify = SHChangeNotifyRegister(hWnd, SHCNRF_InterruptLevel, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
777 browsefolder_callback( info->lpBrowseInfo, hWnd, BFFM_INITIALIZED, 0 );
779 ILFree(computer_pidl);
781 return TRUE;
784 static HRESULT BrsFolder_NewFolder(browse_info *info)
786 DWORD flags = BrowseFlagsToSHCONTF(info->lpBrowseInfo->ulFlags);
787 IShellFolder *desktop, *cur;
788 ISFHelper *sfhelper;
789 WCHAR name[MAX_PATH];
790 HTREEITEM parent, added;
791 LPTV_ITEMDATA item_data;
792 LPITEMIDLIST new_item;
793 TVITEMW item;
794 HRESULT hr;
795 int len;
797 if(!info->pidlRet) {
798 ERR("Make new folder button should be disabled\n");
799 return E_FAIL;
802 /* Create new directory */
803 hr = SHGetDesktopFolder(&desktop);
804 if(FAILED(hr))
805 return hr;
806 hr = IShellFolder_BindToObject(desktop, info->pidlRet, 0, &IID_IShellFolder, (void**)&cur);
807 IShellFolder_Release(desktop);
808 if(FAILED(hr))
809 return hr;
811 hr = IShellFolder_QueryInterface(cur, &IID_ISFHelper, (void**)&sfhelper);
812 if(FAILED(hr))
813 return hr;
815 if(!SHGetPathFromIDListW(info->pidlRet, name)) {
816 hr = E_FAIL;
817 goto cleanup;
820 len = lstrlenW(name);
821 if(len<MAX_PATH)
822 name[len++] = '\\';
823 hr = ISFHelper_GetUniqueName(sfhelper, &name[len], MAX_PATH-len);
824 ISFHelper_Release(sfhelper);
825 if(FAILED(hr))
826 goto cleanup;
828 hr = E_FAIL;
829 if(!CreateDirectoryW(name, NULL))
830 goto cleanup;
832 /* Update parent of newly created directory */
833 parent = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CARET, 0);
834 if(!parent)
835 goto cleanup;
837 SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)parent);
839 memset(&item, 0, sizeof(TVITEMW));
840 item.mask = TVIF_PARAM|TVIF_STATE;
841 item.hItem = parent;
842 SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
843 item_data = (LPTV_ITEMDATA)item.lParam;
844 if(!item_data)
845 goto cleanup;
847 if(item_data->pEnumIL)
848 IEnumIDList_Release(item_data->pEnumIL);
849 hr = IShellFolder_EnumObjects(cur, info->hwndTreeView, flags, &item_data->pEnumIL);
850 if(FAILED(hr))
851 goto cleanup;
853 /* Update treeview */
854 if(!(item.state&TVIS_EXPANDEDONCE)) {
855 item.mask = TVIF_STATE;
856 item.state = TVIS_EXPANDEDONCE;
857 item.stateMask = TVIS_EXPANDEDONCE;
858 SendMessageW(info->hwndTreeView, TVM_SETITEMW, 0, (LPARAM)&item);
861 hr = IShellFolder_ParseDisplayName(cur, NULL, NULL, name+len, NULL, &new_item, NULL);
862 if(FAILED(hr))
863 goto cleanup;
865 added = InsertTreeViewItem(info, cur, new_item, item_data->lpifq, NULL, parent);
866 IShellFolder_Release(cur);
867 SHFree(new_item);
869 SendMessageW(info->hwndTreeView, TVM_SORTCHILDREN, FALSE, (LPARAM)parent);
870 return BrsFolder_Rename(info, added);
872 cleanup:
873 return hr;
876 static BOOL BrsFolder_OnCommand( browse_info *info, UINT id )
878 LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
880 switch (id)
882 case IDOK:
883 if (info->pidlRet == NULL) /* A null pidl would mean a cancel */
884 info->pidlRet = _ILCreateDesktop();
885 pdump( info->pidlRet );
886 if (lpBrowseInfo->pszDisplayName)
887 SHGetPathFromIDListW( info->pidlRet, lpBrowseInfo->pszDisplayName );
888 EndDialog( info->hWnd, 1 );
889 return TRUE;
891 case IDCANCEL:
892 EndDialog( info->hWnd, 0 );
893 return TRUE;
895 case IDD_MAKENEWFOLDER:
896 BrsFolder_NewFolder(info);
897 return TRUE;
899 return FALSE;
902 static BOOL BrsFolder_OnSetExpanded(browse_info *info, LPVOID selection,
903 BOOL is_str, HTREEITEM *pItem)
905 LPITEMIDLIST pidlSelection = selection;
906 LPCITEMIDLIST pidlCurrent, pidlRoot;
907 TVITEMEXW item;
908 BOOL bResult = FALSE;
910 memset(&item, 0, sizeof(item));
912 /* If 'selection' is a string, convert to a Shell ID List. */
913 if (is_str) {
914 IShellFolder *psfDesktop;
915 HRESULT hr;
917 hr = SHGetDesktopFolder(&psfDesktop);
918 if (FAILED(hr))
919 goto done;
921 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL,
922 selection, NULL, &pidlSelection, NULL);
923 IShellFolder_Release(psfDesktop);
924 if (FAILED(hr))
925 goto done;
928 /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
929 * the sub-tree currently displayed. */
930 pidlRoot = info->lpBrowseInfo->pidlRoot;
931 pidlCurrent = pidlSelection;
932 while (!_ILIsEmpty(pidlRoot) && _ILIsEqualSimple(pidlRoot, pidlCurrent)) {
933 pidlRoot = ILGetNext(pidlRoot);
934 pidlCurrent = ILGetNext(pidlCurrent);
937 /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */
938 if (!_ILIsEmpty(pidlRoot))
939 goto done;
941 /* Initialize item to point to the first child of the root folder. */
942 item.mask = TVIF_PARAM;
943 item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_ROOT, 0);
945 if (item.hItem)
946 item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CHILD,
947 (LPARAM)item.hItem);
949 /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */
950 while (item.hItem && !_ILIsEmpty(pidlCurrent)) {
951 LPTV_ITEMDATA pItemData;
953 SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
954 pItemData = (LPTV_ITEMDATA)item.lParam;
956 if (_ILIsEqualSimple(pItemData->lpi, pidlCurrent)) {
957 pidlCurrent = ILGetNext(pidlCurrent);
958 if (!_ILIsEmpty(pidlCurrent)) {
959 /* Only expand current node and move on to its first child,
960 * if we didn't already reach the last SHITEMID */
961 SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item.hItem);
962 item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CHILD,
963 (LPARAM)item.hItem);
965 } else {
966 item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_NEXT,
967 (LPARAM)item.hItem);
971 if (_ILIsEmpty(pidlCurrent) && item.hItem)
972 bResult = TRUE;
974 done:
975 if (pidlSelection && pidlSelection != selection)
976 ILFree(pidlSelection);
978 if (pItem)
979 *pItem = item.hItem;
981 return bResult;
984 static BOOL BrsFolder_OnSetSelectionW(browse_info *info, LPVOID selection, BOOL is_str) {
985 HTREEITEM hItem;
986 BOOL bResult;
988 if (!selection) return FALSE;
990 bResult = BrsFolder_OnSetExpanded(info, selection, is_str, &hItem);
991 if (bResult)
992 SendMessageW(info->hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem );
993 return bResult;
996 static BOOL BrsFolder_OnSetSelectionA(browse_info *info, LPVOID selection, BOOL is_str) {
997 LPWSTR selectionW = NULL;
998 BOOL result = FALSE;
999 int length;
1001 if (!is_str)
1002 return BrsFolder_OnSetSelectionW(info, selection, is_str);
1004 if ((length = MultiByteToWideChar(CP_ACP, 0, selection, -1, NULL, 0)) &&
1005 (selectionW = heap_alloc(length * sizeof(WCHAR))) &&
1006 MultiByteToWideChar(CP_ACP, 0, selection, -1, selectionW, length))
1008 result = BrsFolder_OnSetSelectionW(info, selectionW, is_str);
1011 heap_free(selectionW);
1012 return result;
1015 static LRESULT BrsFolder_OnWindowPosChanging(browse_info *info, WINDOWPOS *pos)
1017 if ((info->lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) && !(pos->flags & SWP_NOSIZE))
1019 if (pos->cx < info->szMin.cx)
1020 pos->cx = info->szMin.cx;
1021 if (pos->cy < info->szMin.cy)
1022 pos->cy = info->szMin.cy;
1024 return 0;
1027 static INT BrsFolder_OnDestroy(browse_info *info)
1029 if (info->layout)
1031 SHFree(info->layout);
1032 info->layout = NULL;
1035 SHChangeNotifyDeregister(info->hNotify);
1037 return 0;
1040 /* Find a treeview node by recursively walking the treeview */
1041 static HTREEITEM BrsFolder_FindItemByPidl(browse_info *info, LPCITEMIDLIST pidl, HTREEITEM hItem)
1043 TV_ITEMW item;
1044 TV_ITEMDATA *item_data;
1045 HRESULT hr;
1047 item.mask = TVIF_HANDLE | TVIF_PARAM;
1048 item.hItem = hItem;
1049 SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
1050 item_data = (TV_ITEMDATA *)item.lParam;
1052 hr = IShellFolder_CompareIDs(item_data->lpsfParent, 0, item_data->lpifq, pidl);
1053 if(SUCCEEDED(hr) && !HRESULT_CODE(hr))
1054 return hItem;
1056 hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
1058 while (hItem)
1060 HTREEITEM newItem = BrsFolder_FindItemByPidl(info, pidl, hItem);
1061 if (newItem)
1062 return newItem;
1063 hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
1065 return NULL;
1068 static LRESULT BrsFolder_OnChange(browse_info *info, const LPCITEMIDLIST *pidls, LONG event)
1070 BOOL ret = TRUE;
1072 TRACE("(%p)->(%p, %p, 0x%08lx)\n", info, pidls[0], pidls[1], event);
1074 switch (event)
1076 case SHCNE_RMDIR:
1077 case SHCNE_DELETE:
1079 HTREEITEM handle_root = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_ROOT, 0);
1080 HTREEITEM handle_item = BrsFolder_FindItemByPidl(info, pidls[0], handle_root);
1082 if (handle_item)
1083 SendMessageW(info->hwndTreeView, TVM_DELETEITEM, 0, (LPARAM)handle_item);
1085 break;
1088 return ret;
1091 /*************************************************************************
1092 * BrsFolderDlgProc32 (not an exported API function)
1094 static INT_PTR CALLBACK BrsFolderDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
1095 LPARAM lParam )
1097 browse_info *info;
1099 TRACE("hwnd=%p msg=%04x 0x%08Ix 0x%08Ix\n", hWnd, msg, wParam, lParam );
1101 if (msg == WM_INITDIALOG)
1102 return BrsFolder_OnCreate( hWnd, (browse_info*) lParam );
1104 info = GetPropW( hWnd, L"__WINE_BRSFOLDERDLG_INFO" );
1105 if (!info)
1106 return FALSE;
1108 switch (msg)
1110 case WM_NOTIFY:
1111 return BrsFolder_OnNotify( info, (UINT)wParam, (LPNMHDR)lParam);
1113 case WM_COMMAND:
1114 return BrsFolder_OnCommand( info, wParam );
1116 case WM_WINDOWPOSCHANGING:
1117 return BrsFolder_OnWindowPosChanging( info, (WINDOWPOS *)lParam);
1119 case WM_SIZE:
1120 if (info->layout) /* new style dialogs */
1121 LayoutUpdate(hWnd, info->layout, g_layout_info, ARRAY_SIZE(g_layout_info));
1122 return 0;
1124 case BFFM_SETSTATUSTEXTA:
1125 TRACE("Set status %s\n", debugstr_a((LPSTR)lParam));
1126 SetWindowTextA(GetDlgItem(hWnd, IDD_STATUS), (LPSTR)lParam);
1127 break;
1129 case BFFM_SETSTATUSTEXTW:
1130 TRACE("Set status %s\n", debugstr_w((LPWSTR)lParam));
1131 SetWindowTextW(GetDlgItem(hWnd, IDD_STATUS), (LPWSTR)lParam);
1132 break;
1134 case BFFM_ENABLEOK:
1135 TRACE("Enable %Id\n", lParam);
1136 EnableWindow(GetDlgItem(hWnd, 1), lParam != 0);
1137 break;
1139 case BFFM_SETOKTEXT: /* unicode only */
1140 TRACE("Set OK text %s\n", debugstr_w((LPWSTR)lParam));
1141 SetWindowTextW(GetDlgItem(hWnd, 1), (LPWSTR)lParam);
1142 break;
1144 case BFFM_SETSELECTIONA:
1145 return BrsFolder_OnSetSelectionA(info, (LPVOID)lParam, (BOOL)wParam);
1147 case BFFM_SETSELECTIONW:
1148 return BrsFolder_OnSetSelectionW(info, (LPVOID)lParam, (BOOL)wParam);
1150 case BFFM_SETEXPANDED: /* unicode only */
1151 return BrsFolder_OnSetExpanded(info, (LPVOID)lParam, (BOOL)wParam, NULL);
1153 case SHV_CHANGE_NOTIFY:
1154 return BrsFolder_OnChange(info, (const LPCITEMIDLIST*)wParam, (LONG)lParam);
1156 case WM_DESTROY:
1157 return BrsFolder_OnDestroy(info);
1159 return FALSE;
1162 /*************************************************************************
1163 * SHBrowseForFolderA [SHELL32.@]
1164 * SHBrowseForFolder [SHELL32.@]
1166 LPITEMIDLIST WINAPI SHBrowseForFolderA (LPBROWSEINFOA lpbi)
1168 BROWSEINFOW bi;
1169 LPITEMIDLIST lpid;
1170 INT len;
1171 LPWSTR title;
1173 TRACE("%p\n", lpbi);
1175 bi.hwndOwner = lpbi->hwndOwner;
1176 bi.pidlRoot = lpbi->pidlRoot;
1177 if (lpbi->pszDisplayName)
1178 bi.pszDisplayName = heap_alloc( MAX_PATH * sizeof(WCHAR) );
1179 else
1180 bi.pszDisplayName = NULL;
1182 if (lpbi->lpszTitle)
1184 len = MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, NULL, 0 );
1185 title = heap_alloc( len * sizeof(WCHAR) );
1186 MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, title, len );
1188 else
1189 title = NULL;
1191 bi.lpszTitle = title;
1192 bi.ulFlags = lpbi->ulFlags;
1193 bi.lpfn = lpbi->lpfn;
1194 bi.lParam = lpbi->lParam;
1195 bi.iImage = lpbi->iImage;
1196 lpid = SHBrowseForFolderW( &bi );
1197 if (bi.pszDisplayName)
1199 WideCharToMultiByte( CP_ACP, 0, bi.pszDisplayName, -1,
1200 lpbi->pszDisplayName, MAX_PATH, 0, NULL);
1201 heap_free( bi.pszDisplayName );
1203 heap_free(title);
1204 lpbi->iImage = bi.iImage;
1205 return lpid;
1209 /*************************************************************************
1210 * SHBrowseForFolderW [SHELL32.@]
1212 * NOTES
1213 * crashes when passed a null pointer
1215 LPITEMIDLIST WINAPI SHBrowseForFolderW (LPBROWSEINFOW lpbi)
1217 browse_info info;
1218 DWORD r;
1219 HRESULT hr;
1220 const WCHAR * templateName;
1221 INITCOMMONCONTROLSEX icex;
1223 info.hWnd = 0;
1224 info.pidlRet = NULL;
1225 info.lpBrowseInfo = lpbi;
1226 info.hwndTreeView = NULL;
1228 icex.dwSize = sizeof( icex );
1229 icex.dwICC = ICC_TREEVIEW_CLASSES;
1230 InitCommonControlsEx( &icex );
1232 hr = OleInitialize(NULL);
1234 if (lpbi->ulFlags & BIF_NEWDIALOGSTYLE)
1235 templateName = L"SHNEWBRSFORFOLDER_MSGBOX";
1236 else
1237 templateName = L"SHBRSFORFOLDER_MSGBOX";
1238 r = DialogBoxParamW( shell32_hInstance, templateName, lpbi->hwndOwner,
1239 BrsFolderDlgProc, (LPARAM)&info );
1240 if (SUCCEEDED(hr))
1241 OleUninitialize();
1242 if (!r)
1244 ILFree(info.pidlRet);
1245 return NULL;
1248 return info.pidlRet;