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 typedef struct tagbrowse_info
44 LPBROWSEINFOW lpBrowseInfo
;
48 typedef struct tagTV_ITEMDATA
50 LPSHELLFOLDER lpsfParent
; /* IShellFolder of the parent */
51 LPITEMIDLIST lpi
; /* PIDL relativ to parent */
52 LPITEMIDLIST lpifq
; /* Fully qualified PIDL */
53 IEnumIDList
* pEnumIL
; /* Children iterator */
54 } TV_ITEMDATA
, *LPTV_ITEMDATA
;
56 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
57 BIF_BROWSEFORCOMPUTER | \
58 BIF_RETURNFSANCESTORS | \
59 BIF_RETURNONLYFSDIRS | \
60 BIF_BROWSEINCLUDEFILES)
62 static void FillTreeView(browse_info
*, LPSHELLFOLDER
,
63 LPITEMIDLIST
, HTREEITEM
, IEnumIDList
*);
64 static HTREEITEM
InsertTreeViewItem( browse_info
*, IShellFolder
*,
65 LPCITEMIDLIST
, LPCITEMIDLIST
, IEnumIDList
*, HTREEITEM
);
67 const WCHAR szBrowseFolderInfo
[] = {
68 '_','_','W','I','N','E','_',
69 'B','R','S','F','O','L','D','E','R','D','L','G','_',
73 static inline DWORD
BrowseFlagsToSHCONTF(UINT ulFlags
)
75 return SHCONTF_FOLDERS
| (ulFlags
& BIF_BROWSEINCLUDEFILES
? SHCONTF_NONFOLDERS
: 0);
78 static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo
, HWND hWnd
,
79 UINT msg
, LPARAM param
)
81 if (!lpBrowseInfo
->lpfn
)
83 lpBrowseInfo
->lpfn( hWnd
, msg
, param
, lpBrowseInfo
->lParam
);
86 /******************************************************************************
87 * InitializeTreeView [Internal]
89 * Called from WM_INITDIALOG handler.
92 * hwndParent [I] The BrowseForFolder dialog
93 * root [I] ITEMIDLIST of the root shell folder
95 static void InitializeTreeView( browse_info
*info
)
97 LPITEMIDLIST pidlParent
, pidlChild
;
98 HIMAGELIST hImageList
;
100 IShellFolder
*lpsfParent
, *lpsfRoot
;
101 IEnumIDList
* pEnumChildren
= NULL
;
104 LPCITEMIDLIST root
= info
->lpBrowseInfo
->pidlRoot
;
106 TRACE("%p\n", info
);
108 Shell_GetImageList(NULL
, &hImageList
);
111 TreeView_SetImageList( info
->hwndTreeView
, hImageList
, 0 );
113 /* We want to call InsertTreeViewItem down the code, in order to insert
114 * the root item of the treeview. Due to InsertTreeViewItem's signature,
115 * we need the following to do this:
117 * + An ITEMIDLIST corresponding to _the parent_ of root.
118 * + An ITEMIDLIST, which is a relative path from root's parent to root
119 * (containing a single SHITEMID).
120 * + An IShellFolder interface pointer of root's parent folder.
122 * If root is 'Desktop', then root's parent is also 'Desktop'.
125 pidlParent
= ILClone(root
);
126 ILRemoveLastID(pidlParent
);
127 pidlChild
= ILClone(ILFindLastID(root
));
129 if (_ILIsDesktop(pidlParent
)) {
130 hr
= SHGetDesktopFolder(&lpsfParent
);
132 IShellFolder
*lpsfDesktop
;
133 hr
= SHGetDesktopFolder(&lpsfDesktop
);
134 if (!SUCCEEDED(hr
)) {
135 WARN("SHGetDesktopFolder failed! hr = %08lx\n", hr
);
138 hr
= IShellFolder_BindToObject(lpsfDesktop
, pidlParent
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfParent
);
139 IShellFolder_Release(lpsfDesktop
);
142 if (!SUCCEEDED(hr
)) {
143 WARN("Could not bind to parent shell folder! hr = %08lx\n", hr
);
147 if (pidlChild
&& pidlChild
->mkid
.cb
) {
148 hr
= IShellFolder_BindToObject(lpsfParent
, pidlChild
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfRoot
);
150 lpsfRoot
= lpsfParent
;
151 hr
= IShellFolder_AddRef(lpsfParent
);
154 if (!SUCCEEDED(hr
)) {
155 WARN("Could not bind to root shell folder! hr = %08lx\n", hr
);
156 IShellFolder_Release(lpsfParent
);
160 flags
= BrowseFlagsToSHCONTF( info
->lpBrowseInfo
->ulFlags
);
161 hr
= IShellFolder_EnumObjects( lpsfRoot
, info
->hWnd
, flags
, &pEnumChildren
);
162 if (!SUCCEEDED(hr
)) {
163 WARN("Could not get child iterator! hr = %08lx\n", hr
);
164 IShellFolder_Release(lpsfParent
);
165 IShellFolder_Release(lpsfRoot
);
169 TreeView_DeleteAllItems( info
->hwndTreeView
);
170 item
= InsertTreeViewItem( info
, lpsfParent
, pidlChild
,
171 pidlParent
, pEnumChildren
, TVI_ROOT
);
172 TreeView_Expand( info
->hwndTreeView
, item
, TVE_EXPAND
);
174 IShellFolder_Release(lpsfRoot
);
175 IShellFolder_Release(lpsfParent
);
178 static int GetIcon(LPITEMIDLIST lpi
, UINT uFlags
)
181 SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), uFlags
);
185 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq
, LPTVITEMW lpTV_ITEM
)
187 LPITEMIDLIST pidlDesktop
= NULL
;
190 TRACE("%p %p\n",lpifq
, lpTV_ITEM
);
194 pidlDesktop
= _ILCreateDesktop();
198 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
;
199 lpTV_ITEM
->iImage
= GetIcon( lpifq
, flags
);
201 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_OPENICON
;
202 lpTV_ITEM
->iSelectedImage
= GetIcon( lpifq
, flags
);
205 ILFree( pidlDesktop
);
208 /******************************************************************************
211 * Query a shell folder for the display name of one of it's children
214 * lpsf [I] IShellFolder interface of the folder to be queried.
215 * lpi [I] ITEMIDLIST of the child, relative to parent
216 * dwFlags [I] as in IShellFolder::GetDisplayNameOf
217 * lpFriendlyName [O] The desired display name in unicode
223 static BOOL
GetName(LPSHELLFOLDER lpsf
, LPCITEMIDLIST lpi
, DWORD dwFlags
, LPWSTR lpFriendlyName
)
228 TRACE("%p %p %lx %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
229 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf
, lpi
, dwFlags
, &str
)))
231 if (FAILED(StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
)))
239 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
243 /******************************************************************************
244 * InsertTreeViewItem [Internal]
247 * info [I] data for the dialog
248 * lpsf [I] IShellFolder interface of the item's parent shell folder
249 * pidl [I] ITEMIDLIST of the child to insert, relativ to parent
250 * pidlParent [I] ITEMIDLIST of the parent shell folder
251 * pEnumIL [I] Iterator for the children of the item to be inserted
252 * hParent [I] The treeview-item that represents the parent shell folder
255 * Success: Handle to the created and inserted treeview-item
258 static HTREEITEM
InsertTreeViewItem( browse_info
*info
, IShellFolder
* lpsf
,
259 LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
,
263 TVINSERTSTRUCTW tvins
;
264 WCHAR szBuff
[MAX_PATH
];
265 LPTV_ITEMDATA lptvid
=0;
267 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
269 tvi
.cChildren
= pEnumIL
? 1 : 0;
270 tvi
.mask
|= TVIF_CHILDREN
;
272 lptvid
= SHAlloc( sizeof(TV_ITEMDATA
) );
276 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
279 tvi
.pszText
= szBuff
;
280 tvi
.cchTextMax
= MAX_PATH
;
281 tvi
.lParam
= (LPARAM
)lptvid
;
283 IShellFolder_AddRef(lpsf
);
284 lptvid
->lpsfParent
= lpsf
;
285 lptvid
->lpi
= ILClone(pidl
);
286 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
287 lptvid
->pEnumIL
= pEnumIL
;
288 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
291 tvins
.hInsertAfter
= NULL
;
292 tvins
.hParent
= hParent
;
294 return (HTREEITEM
)TreeView_InsertItemW( info
->hwndTreeView
, &tvins
);
297 /******************************************************************************
298 * FillTreeView [Internal]
300 * For each child (given by lpe) of the parent shell folder, which is given by
301 * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
304 * info [I] data for the dialog
305 * lpsf [I] IShellFolder interface of the parent shell folder
306 * pidl [I] ITEMIDLIST of the parent shell folder
307 * hParent [I] The treeview item that represents the parent shell folder
308 * lpe [I] An iterator for the children of the parent shell folder
310 static void FillTreeView( browse_info
*info
, IShellFolder
* lpsf
,
311 LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
314 LPITEMIDLIST pidlTemp
= 0;
317 HWND hwnd
= GetParent( info
->hwndTreeView
);
319 TRACE("%p %p %p %p\n",lpsf
, pidl
, hParent
, lpe
);
321 /* No IEnumIDList -> No children */
325 SetCursor( LoadCursorA( 0, (LPSTR
)IDC_WAIT
) );
327 while (NOERROR
== IEnumIDList_Next(lpe
,1,&pidlTemp
,&ulFetched
))
329 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
330 IEnumIDList
* pEnumIL
= NULL
;
331 IShellFolder
* pSFChild
= NULL
;
332 IShellFolder_GetAttributesOf(lpsf
, 1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
333 if (ulAttrs
& SFGAO_FOLDER
)
335 hr
= IShellFolder_BindToObject(lpsf
,pidlTemp
,NULL
,&IID_IShellFolder
,(LPVOID
*)&pSFChild
);
338 DWORD flags
= BrowseFlagsToSHCONTF(info
->lpBrowseInfo
->ulFlags
);
339 hr
= IShellFolder_EnumObjects(pSFChild
, hwnd
, flags
, &pEnumIL
);
342 if ((IEnumIDList_Skip(pEnumIL
, 1) != S_OK
) ||
343 FAILED(IEnumIDList_Reset(pEnumIL
)))
345 IEnumIDList_Release(pEnumIL
);
349 IShellFolder_Release(pSFChild
);
353 if (!(hPrev
= InsertTreeViewItem(info
, lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
355 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
361 SetCursor(LoadCursorW(0, (LPWSTR
)IDC_ARROW
));
367 static inline BOOL
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
369 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
372 return (data
->type
== type
);
375 static void BrsFolder_CheckValidSelection( browse_info
*info
, LPTV_ITEMDATA lptvid
)
377 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
378 LPCITEMIDLIST pidl
= lptvid
->lpi
;
379 BOOL bEnabled
= TRUE
;
383 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
384 !PIDLIsType(pidl
, PT_COMP
))
386 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
388 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
389 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
390 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
391 if (FAILED(r
) || !dwAttributes
)
394 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
396 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
397 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
398 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
399 if (FAILED(r
) || (dwAttributes
!= (SFGAO_FOLDER
| SFGAO_FILESYSTEM
)))
402 SendMessageW(info
->hWnd
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
405 static LRESULT
BrsFolder_Treeview_Delete( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
407 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
409 TRACE("TVN_DELETEITEMA/W %p\n", lptvid
);
411 IShellFolder_Release(lptvid
->lpsfParent
);
413 IEnumIDList_Release(lptvid
->pEnumIL
);
415 SHFree(lptvid
->lpifq
);
420 static LRESULT
BrsFolder_Treeview_Expand( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
422 IShellFolder
*lpsf2
= NULL
;
423 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
426 TRACE("TVN_ITEMEXPANDINGA/W\n");
428 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
431 if (lptvid
->lpi
&& lptvid
->lpi
->mkid
.cb
) {
432 r
= IShellFolder_BindToObject( lptvid
->lpsfParent
, lptvid
->lpi
, 0,
433 (REFIID
)&IID_IShellFolder
, (LPVOID
*)&lpsf2
);
435 lpsf2
= lptvid
->lpsfParent
;
436 r
= IShellFolder_AddRef(lpsf2
);
440 FillTreeView( info
, lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
442 /* My Computer is already sorted and trying to do a simple text
443 * sort will only mess things up */
444 if (!_ILIsMyComputer(lptvid
->lpi
))
445 TreeView_SortChildren(info
->hwndTreeView
, pnmtv
->itemNew
.hItem
, FALSE
);
450 static HRESULT
BrsFolder_Treeview_Changed( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
452 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
454 lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
455 info
->pidlRet
= lptvid
->lpifq
;
456 browsefolder_callback( info
->lpBrowseInfo
, info
->hWnd
, BFFM_SELCHANGED
,
457 (LPARAM
)info
->pidlRet
);
458 BrsFolder_CheckValidSelection( info
, lptvid
);
462 static LRESULT
BrsFolder_OnNotify( browse_info
*info
, UINT CtlID
, LPNMHDR lpnmh
)
464 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
466 TRACE("%p %x %p msg=%x\n", info
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
468 if (pnmtv
->hdr
.idFrom
!= IDD_TREEVIEW
)
471 switch (pnmtv
->hdr
.code
)
473 case TVN_DELETEITEMA
:
474 case TVN_DELETEITEMW
:
475 return BrsFolder_Treeview_Delete( info
, pnmtv
);
477 case TVN_ITEMEXPANDINGA
:
478 case TVN_ITEMEXPANDINGW
:
479 return BrsFolder_Treeview_Expand( info
, pnmtv
);
481 case TVN_SELCHANGEDA
:
482 case TVN_SELCHANGEDW
:
483 return BrsFolder_Treeview_Changed( info
, pnmtv
);
486 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
494 static BOOL
BrsFolder_OnCreate( HWND hWnd
, browse_info
*info
)
496 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
499 SetPropW( hWnd
, szBrowseFolderInfo
, info
);
501 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
502 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
504 if (lpBrowseInfo
->lpszTitle
)
505 SetWindowTextW( GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
507 ShowWindow( GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
509 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
))
510 ShowWindow( GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
512 info
->hwndTreeView
= GetDlgItem( hWnd
, IDD_TREEVIEW
);
513 if (info
->hwndTreeView
)
514 InitializeTreeView( info
);
516 ERR("treeview control missing!\n");
518 browsefolder_callback( info
->lpBrowseInfo
, hWnd
, BFFM_INITIALIZED
, 0 );
523 static BOOL
BrsFolder_OnCommand( browse_info
*info
, UINT id
)
525 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
530 info
->pidlRet
= ILClone(info
->pidlRet
); /* The original pidl will be free'd. */
531 pdump( info
->pidlRet
);
532 if (lpBrowseInfo
->pszDisplayName
)
533 SHGetPathFromIDListW( info
->pidlRet
, lpBrowseInfo
->pszDisplayName
);
534 EndDialog( info
->hWnd
, 1 );
538 EndDialog( info
->hWnd
, 0 );
544 /*************************************************************************
545 * BrsFolderDlgProc32 (not an exported API function)
547 static INT_PTR CALLBACK
BrsFolderDlgProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
552 TRACE("hwnd=%p msg=%04x 0x%08x 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
554 if (msg
== WM_INITDIALOG
)
555 return BrsFolder_OnCreate( hWnd
, (browse_info
*) lParam
);
557 info
= (browse_info
*) GetPropW( hWnd
, szBrowseFolderInfo
);
562 return BrsFolder_OnNotify( info
, (UINT
)wParam
, (LPNMHDR
)lParam
);
565 return BrsFolder_OnCommand( info
, wParam
);
567 case BFFM_SETSTATUSTEXTA
:
568 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
569 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
572 case BFFM_SETSTATUSTEXTW
:
573 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
574 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
578 TRACE("Enable %ld\n", lParam
);
579 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
582 case BFFM_SETOKTEXT
: /* unicode only */
583 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
584 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
587 case BFFM_SETSELECTIONA
:
589 FIXME("Set selection %s\n", debugstr_a((LPSTR
)lParam
));
591 FIXME("Set selection %p\n", (void*)lParam
);
594 case BFFM_SETSELECTIONW
:
596 FIXME("Set selection %s\n", debugstr_w((LPWSTR
)lParam
));
598 FIXME("Set selection %p\n", (void*)lParam
);
601 case BFFM_SETEXPANDED
: /* unicode only */
603 FIXME("Set expanded %s\n", debugstr_w((LPWSTR
)lParam
));
605 FIXME("Set expanded %p\n", (void*)lParam
);
611 static const WCHAR swBrowseTemplateName
[] = {
612 'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
614 /*************************************************************************
615 * SHBrowseForFolderA [SHELL32.@]
616 * SHBrowseForFolder [SHELL32.@]
618 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
626 bi
.hwndOwner
= lpbi
->hwndOwner
;
627 bi
.pidlRoot
= lpbi
->pidlRoot
;
628 if (lpbi
->pszDisplayName
)
630 bi
.pszDisplayName
= HeapAlloc( GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) );
631 MultiByteToWideChar( CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, MAX_PATH
);
634 bi
.pszDisplayName
= NULL
;
638 len
= MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0 );
639 bi
.lpszTitle
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
640 MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, (LPWSTR
)bi
.lpszTitle
, len
);
645 bi
.ulFlags
= lpbi
->ulFlags
;
646 bi
.lpfn
= lpbi
->lpfn
;
647 bi
.lParam
= lpbi
->lParam
;
648 bi
.iImage
= lpbi
->iImage
;
649 lpid
= SHBrowseForFolderW( &bi
);
650 if (bi
.pszDisplayName
)
652 WideCharToMultiByte( CP_ACP
, 0, bi
.pszDisplayName
, -1,
653 lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
654 HeapFree( GetProcessHeap(), 0, bi
.pszDisplayName
);
656 HeapFree(GetProcessHeap(), 0, (LPVOID
)bi
.lpszTitle
);
657 lpbi
->iImage
= bi
.iImage
;
662 /*************************************************************************
663 * SHBrowseForFolderW [SHELL32.@]
666 * crashes when passed a null pointer
668 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
675 info
.lpBrowseInfo
= lpbi
;
676 info
.hwndTreeView
= NULL
;
678 r
= DialogBoxParamW( shell32_hInstance
, swBrowseTemplateName
, lpbi
->hwndOwner
,
679 BrsFolderDlgProc
, (LPARAM
)&info
);