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
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 static 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 SendMessageW( info
->hwndTreeView
, TVM_SETIMAGELIST
, 0, (LPARAM
)hImageList
);
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 = %08x\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 = %08x\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 = %08x\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 = %08x\n", hr
);
164 IShellFolder_Release(lpsfParent
);
165 IShellFolder_Release(lpsfRoot
);
169 SendMessageW( info
->hwndTreeView
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
170 item
= InsertTreeViewItem( info
, lpsfParent
, pidlChild
,
171 pidlParent
, pEnumChildren
, TVI_ROOT
);
172 SendMessageW( info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
);
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 %x %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
229 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf
, lpi
, dwFlags
, &str
)))
230 bSuccess
= StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
);
234 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
238 /******************************************************************************
239 * InsertTreeViewItem [Internal]
242 * info [I] data for the dialog
243 * lpsf [I] IShellFolder interface of the item's parent shell folder
244 * pidl [I] ITEMIDLIST of the child to insert, relativ to parent
245 * pidlParent [I] ITEMIDLIST of the parent shell folder
246 * pEnumIL [I] Iterator for the children of the item to be inserted
247 * hParent [I] The treeview-item that represents the parent shell folder
250 * Success: Handle to the created and inserted treeview-item
253 static HTREEITEM
InsertTreeViewItem( browse_info
*info
, IShellFolder
* lpsf
,
254 LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
,
258 TVINSERTSTRUCTW tvins
;
259 WCHAR szBuff
[MAX_PATH
];
260 LPTV_ITEMDATA lptvid
=0;
262 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
264 tvi
.cChildren
= pEnumIL
? 1 : 0;
265 tvi
.mask
|= TVIF_CHILDREN
;
267 lptvid
= SHAlloc( sizeof(TV_ITEMDATA
) );
271 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
274 tvi
.pszText
= szBuff
;
275 tvi
.cchTextMax
= MAX_PATH
;
276 tvi
.lParam
= (LPARAM
)lptvid
;
278 IShellFolder_AddRef(lpsf
);
279 lptvid
->lpsfParent
= lpsf
;
280 lptvid
->lpi
= ILClone(pidl
);
281 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
282 lptvid
->pEnumIL
= pEnumIL
;
283 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
286 tvins
.hInsertAfter
= NULL
;
287 tvins
.hParent
= hParent
;
289 return (HTREEITEM
)TreeView_InsertItemW( info
->hwndTreeView
, &tvins
);
292 /******************************************************************************
293 * FillTreeView [Internal]
295 * For each child (given by lpe) of the parent shell folder, which is given by
296 * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
299 * info [I] data for the dialog
300 * lpsf [I] IShellFolder interface of the parent shell folder
301 * pidl [I] ITEMIDLIST of the parent shell folder
302 * hParent [I] The treeview item that represents the parent shell folder
303 * lpe [I] An iterator for the children of the parent shell folder
305 static void FillTreeView( browse_info
*info
, IShellFolder
* lpsf
,
306 LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
309 LPITEMIDLIST pidlTemp
= 0;
312 HWND hwnd
= GetParent( info
->hwndTreeView
);
314 TRACE("%p %p %p %p\n",lpsf
, pidl
, hParent
, lpe
);
316 /* No IEnumIDList -> No children */
320 SetCursor( LoadCursorA( 0, (LPSTR
)IDC_WAIT
) );
322 while (NOERROR
== IEnumIDList_Next(lpe
,1,&pidlTemp
,&ulFetched
))
324 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
325 IEnumIDList
* pEnumIL
= NULL
;
326 IShellFolder
* pSFChild
= NULL
;
327 IShellFolder_GetAttributesOf(lpsf
, 1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
328 if (ulAttrs
& SFGAO_FOLDER
)
330 hr
= IShellFolder_BindToObject(lpsf
,pidlTemp
,NULL
,&IID_IShellFolder
,(LPVOID
*)&pSFChild
);
333 DWORD flags
= BrowseFlagsToSHCONTF(info
->lpBrowseInfo
->ulFlags
);
334 hr
= IShellFolder_EnumObjects(pSFChild
, hwnd
, flags
, &pEnumIL
);
337 if ((IEnumIDList_Skip(pEnumIL
, 1) != S_OK
) ||
338 FAILED(IEnumIDList_Reset(pEnumIL
)))
340 IEnumIDList_Release(pEnumIL
);
344 IShellFolder_Release(pSFChild
);
348 if (!(hPrev
= InsertTreeViewItem(info
, lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
350 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
356 SetCursor(LoadCursorW(0, (LPWSTR
)IDC_ARROW
));
360 static inline BOOL
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
362 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
365 return (data
->type
== type
);
368 static void BrsFolder_CheckValidSelection( browse_info
*info
, LPTV_ITEMDATA lptvid
)
370 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
371 LPCITEMIDLIST pidl
= lptvid
->lpi
;
372 BOOL bEnabled
= TRUE
;
376 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
377 !PIDLIsType(pidl
, PT_COMP
))
379 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
381 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
382 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
383 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
384 if (FAILED(r
) || !(dwAttributes
& (SFGAO_FILESYSANCESTOR
|SFGAO_FILESYSTEM
)))
387 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
389 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
390 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
391 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
393 ((dwAttributes
& (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)) != (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)))
398 SendMessageW(info
->hWnd
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
401 static LRESULT
BrsFolder_Treeview_Delete( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
403 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
405 TRACE("TVN_DELETEITEMA/W %p\n", lptvid
);
407 IShellFolder_Release(lptvid
->lpsfParent
);
409 IEnumIDList_Release(lptvid
->pEnumIL
);
411 SHFree(lptvid
->lpifq
);
416 static LRESULT
BrsFolder_Treeview_Expand( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
418 IShellFolder
*lpsf2
= NULL
;
419 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
422 TRACE("TVN_ITEMEXPANDINGA/W\n");
424 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
427 if (lptvid
->lpi
&& lptvid
->lpi
->mkid
.cb
) {
428 r
= IShellFolder_BindToObject( lptvid
->lpsfParent
, lptvid
->lpi
, 0,
429 (REFIID
)&IID_IShellFolder
, (LPVOID
*)&lpsf2
);
431 lpsf2
= lptvid
->lpsfParent
;
432 r
= IShellFolder_AddRef(lpsf2
);
436 FillTreeView( info
, lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
438 /* My Computer is already sorted and trying to do a simple text
439 * sort will only mess things up */
440 if (!_ILIsMyComputer(lptvid
->lpi
))
441 SendMessageW( info
->hwndTreeView
, TVM_SORTCHILDREN
,
442 FALSE
, (LPARAM
)pnmtv
->itemNew
.hItem
);
447 static HRESULT
BrsFolder_Treeview_Changed( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
449 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
451 lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
452 info
->pidlRet
= lptvid
->lpifq
;
453 browsefolder_callback( info
->lpBrowseInfo
, info
->hWnd
, BFFM_SELCHANGED
,
454 (LPARAM
)info
->pidlRet
);
455 BrsFolder_CheckValidSelection( info
, lptvid
);
459 static LRESULT
BrsFolder_OnNotify( browse_info
*info
, UINT CtlID
, LPNMHDR lpnmh
)
461 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
463 TRACE("%p %x %p msg=%x\n", info
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
465 if (pnmtv
->hdr
.idFrom
!= IDD_TREEVIEW
)
468 switch (pnmtv
->hdr
.code
)
470 case TVN_DELETEITEMA
:
471 case TVN_DELETEITEMW
:
472 return BrsFolder_Treeview_Delete( info
, pnmtv
);
474 case TVN_ITEMEXPANDINGA
:
475 case TVN_ITEMEXPANDINGW
:
476 return BrsFolder_Treeview_Expand( info
, pnmtv
);
478 case TVN_SELCHANGEDA
:
479 case TVN_SELCHANGEDW
:
480 return BrsFolder_Treeview_Changed( info
, pnmtv
);
483 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
491 static BOOL
BrsFolder_OnCreate( HWND hWnd
, browse_info
*info
)
493 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
496 SetPropW( hWnd
, szBrowseFolderInfo
, info
);
498 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
499 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
501 if (lpBrowseInfo
->lpszTitle
)
502 SetWindowTextW( GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
504 ShowWindow( GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
506 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
))
507 ShowWindow( GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
509 info
->hwndTreeView
= GetDlgItem( hWnd
, IDD_TREEVIEW
);
510 if (info
->hwndTreeView
)
511 InitializeTreeView( info
);
513 ERR("treeview control missing!\n");
515 browsefolder_callback( info
->lpBrowseInfo
, hWnd
, BFFM_INITIALIZED
, 0 );
520 static BOOL
BrsFolder_OnCommand( browse_info
*info
, UINT id
)
522 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
527 /* The original pidl is owned by the treeview and will be free'd. */
528 info
->pidlRet
= ILClone(info
->pidlRet
);
529 if (info
->pidlRet
== NULL
) /* A null pidl would mean a cancel */
530 info
->pidlRet
= _ILCreateDesktop();
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 static BOOL
BrsFolder_OnSetExpanded(browse_info
*info
, LPVOID selection
,
545 BOOL is_str
, HTREEITEM
*pItem
)
547 LPITEMIDLIST pidlSelection
= (LPITEMIDLIST
)selection
;
548 LPCITEMIDLIST pidlCurrent
, pidlRoot
;
550 BOOL bResult
= FALSE
;
552 /* If 'selection' is a string, convert to a Shell ID List. */
554 IShellFolder
*psfDesktop
;
557 hr
= SHGetDesktopFolder(&psfDesktop
);
561 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
,
562 (LPOLESTR
)selection
, NULL
, &pidlSelection
, NULL
);
563 IShellFolder_Release(psfDesktop
);
568 /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
569 * the sub-tree currently displayed. */
570 pidlRoot
= info
->lpBrowseInfo
->pidlRoot
;
571 pidlCurrent
= pidlSelection
;
572 while (!_ILIsEmpty(pidlRoot
) && _ILIsEqualSimple(pidlRoot
, pidlCurrent
)) {
573 pidlRoot
= ILGetNext(pidlRoot
);
574 pidlCurrent
= ILGetNext(pidlCurrent
);
577 /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */
578 if (!_ILIsEmpty(pidlRoot
))
581 /* Initialize item to point to the first child of the root folder. */
582 memset(&item
, 0, sizeof(item
));
583 item
.mask
= TVIF_PARAM
;
584 item
.hItem
= TreeView_GetRoot(info
->hwndTreeView
);
586 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
588 /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */
589 while (item
.hItem
&& !_ILIsEmpty(pidlCurrent
)) {
590 LPTV_ITEMDATA pItemData
;
592 SendMessageW(info
->hwndTreeView
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
593 pItemData
= (LPTV_ITEMDATA
)item
.lParam
;
595 if (_ILIsEqualSimple(pItemData
->lpi
, pidlCurrent
)) {
596 pidlCurrent
= ILGetNext(pidlCurrent
);
597 if (!_ILIsEmpty(pidlCurrent
)) {
598 /* Only expand current node and move on to it's first child,
599 * if we didn't already reach the last SHITEMID */
600 SendMessageW(info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
.hItem
);
601 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
604 item
.hItem
= TreeView_GetNextSibling(info
->hwndTreeView
, item
.hItem
);
608 if (_ILIsEmpty(pidlCurrent
) && item
.hItem
)
612 if (pidlSelection
&& pidlSelection
!= (LPITEMIDLIST
)selection
)
613 ILFree(pidlSelection
);
621 static BOOL
BrsFolder_OnSetSelectionW(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
625 bResult
= BrsFolder_OnSetExpanded(info
, selection
, is_str
, &hItem
);
627 SendMessageW(info
->hwndTreeView
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hItem
);
631 static BOOL
BrsFolder_OnSetSelectionA(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
632 LPWSTR selectionW
= NULL
;
637 return BrsFolder_OnSetSelectionW(info
, selection
, is_str
);
639 if ((length
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, NULL
, 0)) &&
640 (selectionW
= HeapAlloc(GetProcessHeap(), 0, length
* sizeof(WCHAR
))) &&
641 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, selectionW
, length
))
643 result
= BrsFolder_OnSetSelectionW(info
, selectionW
, is_str
);
646 HeapFree(GetProcessHeap(), 0, selectionW
);
650 /*************************************************************************
651 * BrsFolderDlgProc32 (not an exported API function)
653 static INT_PTR CALLBACK
BrsFolderDlgProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
658 TRACE("hwnd=%p msg=%04x 0x%08x 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
660 if (msg
== WM_INITDIALOG
)
661 return BrsFolder_OnCreate( hWnd
, (browse_info
*) lParam
);
663 info
= (browse_info
*) GetPropW( hWnd
, szBrowseFolderInfo
);
668 return BrsFolder_OnNotify( info
, (UINT
)wParam
, (LPNMHDR
)lParam
);
671 return BrsFolder_OnCommand( info
, wParam
);
673 case BFFM_SETSTATUSTEXTA
:
674 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
675 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
678 case BFFM_SETSTATUSTEXTW
:
679 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
680 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
684 TRACE("Enable %ld\n", lParam
);
685 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
688 case BFFM_SETOKTEXT
: /* unicode only */
689 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
690 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
693 case BFFM_SETSELECTIONA
:
694 return BrsFolder_OnSetSelectionA(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
696 case BFFM_SETSELECTIONW
:
697 return BrsFolder_OnSetSelectionW(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
699 case BFFM_SETEXPANDED
: /* unicode only */
700 return BrsFolder_OnSetExpanded(info
, (LPVOID
)lParam
, (BOOL
)wParam
, NULL
);
705 static const WCHAR swBrowseTemplateName
[] = {
706 'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
708 /*************************************************************************
709 * SHBrowseForFolderA [SHELL32.@]
710 * SHBrowseForFolder [SHELL32.@]
712 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
721 bi
.hwndOwner
= lpbi
->hwndOwner
;
722 bi
.pidlRoot
= lpbi
->pidlRoot
;
723 if (lpbi
->pszDisplayName
)
725 bi
.pszDisplayName
= HeapAlloc( GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) );
726 MultiByteToWideChar( CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, MAX_PATH
);
729 bi
.pszDisplayName
= NULL
;
733 len
= MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0 );
734 title
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
735 MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, title
, len
);
740 bi
.lpszTitle
= title
;
741 bi
.ulFlags
= lpbi
->ulFlags
;
742 bi
.lpfn
= lpbi
->lpfn
;
743 bi
.lParam
= lpbi
->lParam
;
744 bi
.iImage
= lpbi
->iImage
;
745 lpid
= SHBrowseForFolderW( &bi
);
746 if (bi
.pszDisplayName
)
748 WideCharToMultiByte( CP_ACP
, 0, bi
.pszDisplayName
, -1,
749 lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
750 HeapFree( GetProcessHeap(), 0, bi
.pszDisplayName
);
752 HeapFree(GetProcessHeap(), 0, title
);
753 lpbi
->iImage
= bi
.iImage
;
758 /*************************************************************************
759 * SHBrowseForFolderW [SHELL32.@]
762 * crashes when passed a null pointer
764 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
772 info
.lpBrowseInfo
= lpbi
;
773 info
.hwndTreeView
= NULL
;
775 hr
= OleInitialize(NULL
);
776 r
= DialogBoxParamW( shell32_hInstance
, swBrowseTemplateName
, lpbi
->hwndOwner
,
777 BrsFolderDlgProc
, (LPARAM
)&info
);