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"
33 #include "shell32_main.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
39 typedef struct tagbrowse_info
43 LPBROWSEINFOW lpBrowseInfo
;
47 typedef struct tagTV_ITEMDATA
49 LPSHELLFOLDER lpsfParent
; /* IShellFolder of the parent */
50 LPITEMIDLIST lpi
; /* PIDL relativ to parent */
51 LPITEMIDLIST lpifq
; /* Fully qualified PIDL */
52 IEnumIDList
* pEnumIL
; /* Children iterator */
53 } TV_ITEMDATA
, *LPTV_ITEMDATA
;
55 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
56 BIF_BROWSEFORCOMPUTER | \
57 BIF_RETURNFSANCESTORS | \
58 BIF_RETURNONLYFSDIRS | \
59 BIF_BROWSEINCLUDEFILES)
61 static void FillTreeView(browse_info
*, LPSHELLFOLDER
,
62 LPITEMIDLIST
, HTREEITEM
, IEnumIDList
*);
63 static HTREEITEM
InsertTreeViewItem( browse_info
*, IShellFolder
*,
64 LPCITEMIDLIST
, LPCITEMIDLIST
, IEnumIDList
*, HTREEITEM
);
66 static const WCHAR szBrowseFolderInfo
[] = {
67 '_','_','W','I','N','E','_',
68 'B','R','S','F','O','L','D','E','R','D','L','G','_',
72 static inline DWORD
BrowseFlagsToSHCONTF(UINT ulFlags
)
74 return SHCONTF_FOLDERS
| (ulFlags
& BIF_BROWSEINCLUDEFILES
? SHCONTF_NONFOLDERS
: 0);
77 static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo
, HWND hWnd
,
78 UINT msg
, LPARAM param
)
80 if (!lpBrowseInfo
->lpfn
)
82 lpBrowseInfo
->lpfn( hWnd
, msg
, param
, lpBrowseInfo
->lParam
);
85 /******************************************************************************
86 * InitializeTreeView [Internal]
88 * Called from WM_INITDIALOG handler.
91 * hwndParent [I] The BrowseForFolder dialog
92 * root [I] ITEMIDLIST of the root shell folder
94 static void InitializeTreeView( browse_info
*info
)
96 LPITEMIDLIST pidlParent
, pidlChild
;
97 HIMAGELIST hImageList
;
99 IShellFolder
*lpsfParent
, *lpsfRoot
;
100 IEnumIDList
* pEnumChildren
= NULL
;
103 LPCITEMIDLIST root
= info
->lpBrowseInfo
->pidlRoot
;
105 TRACE("%p\n", info
);
107 Shell_GetImageList(NULL
, &hImageList
);
110 SendMessageW( info
->hwndTreeView
, TVM_SETIMAGELIST
, 0, (LPARAM
)hImageList
);
112 /* We want to call InsertTreeViewItem down the code, in order to insert
113 * the root item of the treeview. Due to InsertTreeViewItem's signature,
114 * we need the following to do this:
116 * + An ITEMIDLIST corresponding to _the parent_ of root.
117 * + An ITEMIDLIST, which is a relative path from root's parent to root
118 * (containing a single SHITEMID).
119 * + An IShellFolder interface pointer of root's parent folder.
121 * If root is 'Desktop', then root's parent is also 'Desktop'.
124 pidlParent
= ILClone(root
);
125 ILRemoveLastID(pidlParent
);
126 pidlChild
= ILClone(ILFindLastID(root
));
128 if (_ILIsDesktop(pidlParent
)) {
129 hr
= SHGetDesktopFolder(&lpsfParent
);
131 IShellFolder
*lpsfDesktop
;
132 hr
= SHGetDesktopFolder(&lpsfDesktop
);
133 if (!SUCCEEDED(hr
)) {
134 WARN("SHGetDesktopFolder failed! hr = %08x\n", hr
);
137 hr
= IShellFolder_BindToObject(lpsfDesktop
, pidlParent
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfParent
);
138 IShellFolder_Release(lpsfDesktop
);
141 if (!SUCCEEDED(hr
)) {
142 WARN("Could not bind to parent shell folder! hr = %08x\n", hr
);
146 if (pidlChild
&& pidlChild
->mkid
.cb
) {
147 hr
= IShellFolder_BindToObject(lpsfParent
, pidlChild
, 0, &IID_IShellFolder
, (LPVOID
*)&lpsfRoot
);
149 lpsfRoot
= lpsfParent
;
150 hr
= IShellFolder_AddRef(lpsfParent
);
153 if (!SUCCEEDED(hr
)) {
154 WARN("Could not bind to root shell folder! hr = %08x\n", hr
);
155 IShellFolder_Release(lpsfParent
);
159 flags
= BrowseFlagsToSHCONTF( info
->lpBrowseInfo
->ulFlags
);
160 hr
= IShellFolder_EnumObjects( lpsfRoot
, info
->hWnd
, flags
, &pEnumChildren
);
161 if (!SUCCEEDED(hr
)) {
162 WARN("Could not get child iterator! hr = %08x\n", hr
);
163 IShellFolder_Release(lpsfParent
);
164 IShellFolder_Release(lpsfRoot
);
168 SendMessageW( info
->hwndTreeView
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
169 item
= InsertTreeViewItem( info
, lpsfParent
, pidlChild
,
170 pidlParent
, pEnumChildren
, TVI_ROOT
);
171 SendMessageW( info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
);
173 IShellFolder_Release(lpsfRoot
);
174 IShellFolder_Release(lpsfParent
);
177 static int GetIcon(LPITEMIDLIST lpi
, UINT uFlags
)
180 SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), uFlags
);
184 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq
, LPTVITEMW lpTV_ITEM
)
186 LPITEMIDLIST pidlDesktop
= NULL
;
189 TRACE("%p %p\n",lpifq
, lpTV_ITEM
);
193 pidlDesktop
= _ILCreateDesktop();
197 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
;
198 lpTV_ITEM
->iImage
= GetIcon( lpifq
, flags
);
200 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_OPENICON
;
201 lpTV_ITEM
->iSelectedImage
= GetIcon( lpifq
, flags
);
204 ILFree( pidlDesktop
);
207 /******************************************************************************
210 * Query a shell folder for the display name of one of it's children
213 * lpsf [I] IShellFolder interface of the folder to be queried.
214 * lpi [I] ITEMIDLIST of the child, relative to parent
215 * dwFlags [I] as in IShellFolder::GetDisplayNameOf
216 * lpFriendlyName [O] The desired display name in unicode
222 static BOOL
GetName(LPSHELLFOLDER lpsf
, LPCITEMIDLIST lpi
, DWORD dwFlags
, LPWSTR lpFriendlyName
)
227 TRACE("%p %p %x %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
228 if (SUCCEEDED(IShellFolder_GetDisplayNameOf(lpsf
, lpi
, dwFlags
, &str
)))
229 bSuccess
= StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
);
233 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
237 /******************************************************************************
238 * InsertTreeViewItem [Internal]
241 * info [I] data for the dialog
242 * lpsf [I] IShellFolder interface of the item's parent shell folder
243 * pidl [I] ITEMIDLIST of the child to insert, relativ to parent
244 * pidlParent [I] ITEMIDLIST of the parent shell folder
245 * pEnumIL [I] Iterator for the children of the item to be inserted
246 * hParent [I] The treeview-item that represents the parent shell folder
249 * Success: Handle to the created and inserted treeview-item
252 static HTREEITEM
InsertTreeViewItem( browse_info
*info
, IShellFolder
* lpsf
,
253 LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
,
257 TVINSERTSTRUCTW tvins
;
258 WCHAR szBuff
[MAX_PATH
];
259 LPTV_ITEMDATA lptvid
=0;
261 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
263 tvi
.cChildren
= pEnumIL
? 1 : 0;
264 tvi
.mask
|= TVIF_CHILDREN
;
266 lptvid
= SHAlloc( sizeof(TV_ITEMDATA
) );
270 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
273 tvi
.pszText
= szBuff
;
274 tvi
.cchTextMax
= MAX_PATH
;
275 tvi
.lParam
= (LPARAM
)lptvid
;
277 IShellFolder_AddRef(lpsf
);
278 lptvid
->lpsfParent
= lpsf
;
279 lptvid
->lpi
= ILClone(pidl
);
280 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
281 lptvid
->pEnumIL
= pEnumIL
;
282 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
285 tvins
.hInsertAfter
= NULL
;
286 tvins
.hParent
= hParent
;
288 return (HTREEITEM
)TreeView_InsertItemW( info
->hwndTreeView
, &tvins
);
291 /******************************************************************************
292 * FillTreeView [Internal]
294 * For each child (given by lpe) of the parent shell folder, which is given by
295 * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
298 * info [I] data for the dialog
299 * lpsf [I] IShellFolder interface of the parent shell folder
300 * pidl [I] ITEMIDLIST of the parent shell folder
301 * hParent [I] The treeview item that represents the parent shell folder
302 * lpe [I] An iterator for the children of the parent shell folder
304 static void FillTreeView( browse_info
*info
, IShellFolder
* lpsf
,
305 LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
308 LPITEMIDLIST pidlTemp
= 0;
311 HWND hwnd
= GetParent( info
->hwndTreeView
);
313 TRACE("%p %p %p %p\n",lpsf
, pidl
, hParent
, lpe
);
315 /* No IEnumIDList -> No children */
319 SetCursor( LoadCursorA( 0, (LPSTR
)IDC_WAIT
) );
321 while (NOERROR
== IEnumIDList_Next(lpe
,1,&pidlTemp
,&ulFetched
))
323 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
324 IEnumIDList
* pEnumIL
= NULL
;
325 IShellFolder
* pSFChild
= NULL
;
326 IShellFolder_GetAttributesOf(lpsf
, 1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
327 if (ulAttrs
& SFGAO_FOLDER
)
329 hr
= IShellFolder_BindToObject(lpsf
,pidlTemp
,NULL
,&IID_IShellFolder
,(LPVOID
*)&pSFChild
);
332 DWORD flags
= BrowseFlagsToSHCONTF(info
->lpBrowseInfo
->ulFlags
);
333 hr
= IShellFolder_EnumObjects(pSFChild
, hwnd
, flags
, &pEnumIL
);
336 if ((IEnumIDList_Skip(pEnumIL
, 1) != S_OK
) ||
337 FAILED(IEnumIDList_Reset(pEnumIL
)))
339 IEnumIDList_Release(pEnumIL
);
343 IShellFolder_Release(pSFChild
);
347 if (!(hPrev
= InsertTreeViewItem(info
, lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
349 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
355 SetCursor(LoadCursorW(0, (LPWSTR
)IDC_ARROW
));
359 static inline BOOL
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
361 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
364 return (data
->type
== type
);
367 static void BrsFolder_CheckValidSelection( browse_info
*info
, LPTV_ITEMDATA lptvid
)
369 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
370 LPCITEMIDLIST pidl
= lptvid
->lpi
;
371 BOOL bEnabled
= TRUE
;
375 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
376 !PIDLIsType(pidl
, PT_COMP
))
378 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
380 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
381 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
382 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
383 if (FAILED(r
) || !(dwAttributes
& (SFGAO_FILESYSANCESTOR
|SFGAO_FILESYSTEM
)))
386 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
388 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
389 r
= IShellFolder_GetAttributesOf(lptvid
->lpsfParent
, 1,
390 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
392 ((dwAttributes
& (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)) != (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)))
397 SendMessageW(info
->hWnd
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
400 static LRESULT
BrsFolder_Treeview_Delete( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
402 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
404 TRACE("TVN_DELETEITEMA/W %p\n", lptvid
);
406 IShellFolder_Release(lptvid
->lpsfParent
);
408 IEnumIDList_Release(lptvid
->pEnumIL
);
410 SHFree(lptvid
->lpifq
);
415 static LRESULT
BrsFolder_Treeview_Expand( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
417 IShellFolder
*lpsf2
= NULL
;
418 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
421 TRACE("TVN_ITEMEXPANDINGA/W\n");
423 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
426 if (lptvid
->lpi
&& lptvid
->lpi
->mkid
.cb
) {
427 r
= IShellFolder_BindToObject( lptvid
->lpsfParent
, lptvid
->lpi
, 0,
428 (REFIID
)&IID_IShellFolder
, (LPVOID
*)&lpsf2
);
430 lpsf2
= lptvid
->lpsfParent
;
431 r
= IShellFolder_AddRef(lpsf2
);
435 FillTreeView( info
, lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
437 /* My Computer is already sorted and trying to do a simple text
438 * sort will only mess things up */
439 if (!_ILIsMyComputer(lptvid
->lpi
))
440 SendMessageW( info
->hwndTreeView
, TVM_SORTCHILDREN
,
441 FALSE
, (LPARAM
)pnmtv
->itemNew
.hItem
);
446 static HRESULT
BrsFolder_Treeview_Changed( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
448 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
450 lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
451 info
->pidlRet
= lptvid
->lpifq
;
452 browsefolder_callback( info
->lpBrowseInfo
, info
->hWnd
, BFFM_SELCHANGED
,
453 (LPARAM
)info
->pidlRet
);
454 BrsFolder_CheckValidSelection( info
, lptvid
);
458 static LRESULT
BrsFolder_OnNotify( browse_info
*info
, UINT CtlID
, LPNMHDR lpnmh
)
460 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
462 TRACE("%p %x %p msg=%x\n", info
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
464 if (pnmtv
->hdr
.idFrom
!= IDD_TREEVIEW
)
467 switch (pnmtv
->hdr
.code
)
469 case TVN_DELETEITEMA
:
470 case TVN_DELETEITEMW
:
471 return BrsFolder_Treeview_Delete( info
, pnmtv
);
473 case TVN_ITEMEXPANDINGA
:
474 case TVN_ITEMEXPANDINGW
:
475 return BrsFolder_Treeview_Expand( info
, pnmtv
);
477 case TVN_SELCHANGEDA
:
478 case TVN_SELCHANGEDW
:
479 return BrsFolder_Treeview_Changed( info
, pnmtv
);
482 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
490 static BOOL
BrsFolder_OnCreate( HWND hWnd
, browse_info
*info
)
492 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
495 SetPropW( hWnd
, szBrowseFolderInfo
, info
);
497 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
498 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
500 if (lpBrowseInfo
->lpszTitle
)
501 SetWindowTextW( GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
503 ShowWindow( GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
505 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
))
506 ShowWindow( GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
508 info
->hwndTreeView
= GetDlgItem( hWnd
, IDD_TREEVIEW
);
509 if (info
->hwndTreeView
)
510 InitializeTreeView( info
);
512 ERR("treeview control missing!\n");
514 browsefolder_callback( info
->lpBrowseInfo
, hWnd
, BFFM_INITIALIZED
, 0 );
519 static BOOL
BrsFolder_OnCommand( browse_info
*info
, UINT id
)
521 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
526 /* The original pidl is owned by the treeview and will be free'd. */
527 info
->pidlRet
= ILClone(info
->pidlRet
);
528 if (info
->pidlRet
== NULL
) /* A null pidl would mean a cancel */
529 info
->pidlRet
= _ILCreateDesktop();
530 pdump( info
->pidlRet
);
531 if (lpBrowseInfo
->pszDisplayName
)
532 SHGetPathFromIDListW( info
->pidlRet
, lpBrowseInfo
->pszDisplayName
);
533 EndDialog( info
->hWnd
, 1 );
537 EndDialog( info
->hWnd
, 0 );
543 static BOOL
BrsFolder_OnSetExpanded(browse_info
*info
, LPVOID selection
,
544 BOOL is_str
, HTREEITEM
*pItem
)
546 LPITEMIDLIST pidlSelection
= (LPITEMIDLIST
)selection
;
547 LPCITEMIDLIST pidlCurrent
, pidlRoot
;
549 BOOL bResult
= FALSE
;
551 /* If 'selection' is a string, convert to a Shell ID List. */
553 IShellFolder
*psfDesktop
;
556 hr
= SHGetDesktopFolder(&psfDesktop
);
560 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
,
561 (LPOLESTR
)selection
, NULL
, &pidlSelection
, NULL
);
562 IShellFolder_Release(psfDesktop
);
567 /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
568 * the sub-tree currently displayed. */
569 pidlRoot
= info
->lpBrowseInfo
->pidlRoot
;
570 pidlCurrent
= pidlSelection
;
571 while (!_ILIsEmpty(pidlRoot
) && _ILIsEqualSimple(pidlRoot
, pidlCurrent
)) {
572 pidlRoot
= ILGetNext(pidlRoot
);
573 pidlCurrent
= ILGetNext(pidlCurrent
);
576 /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */
577 if (!_ILIsEmpty(pidlRoot
))
580 /* Initialize item to point to the first child of the root folder. */
581 memset(&item
, 0, sizeof(item
));
582 item
.mask
= TVIF_PARAM
;
583 item
.hItem
= TreeView_GetRoot(info
->hwndTreeView
);
585 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
587 /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */
588 while (item
.hItem
&& !_ILIsEmpty(pidlCurrent
)) {
589 LPTV_ITEMDATA pItemData
;
591 SendMessageW(info
->hwndTreeView
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
592 pItemData
= (LPTV_ITEMDATA
)item
.lParam
;
594 if (_ILIsEqualSimple(pItemData
->lpi
, pidlCurrent
)) {
595 pidlCurrent
= ILGetNext(pidlCurrent
);
596 if (!_ILIsEmpty(pidlCurrent
)) {
597 /* Only expand current node and move on to it's first child,
598 * if we didn't already reach the last SHITEMID */
599 SendMessageW(info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
.hItem
);
600 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
603 item
.hItem
= TreeView_GetNextSibling(info
->hwndTreeView
, item
.hItem
);
607 if (_ILIsEmpty(pidlCurrent
) && item
.hItem
)
611 if (pidlSelection
&& pidlSelection
!= (LPITEMIDLIST
)selection
)
612 ILFree(pidlSelection
);
620 static BOOL
BrsFolder_OnSetSelectionW(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
624 bResult
= BrsFolder_OnSetExpanded(info
, selection
, is_str
, &hItem
);
626 SendMessageW(info
->hwndTreeView
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hItem
);
630 static BOOL
BrsFolder_OnSetSelectionA(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
631 LPWSTR selectionW
= NULL
;
636 return BrsFolder_OnSetSelectionW(info
, selection
, is_str
);
638 if ((length
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, NULL
, 0)) &&
639 (selectionW
= HeapAlloc(GetProcessHeap(), 0, length
* sizeof(WCHAR
))) &&
640 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, selectionW
, length
))
642 result
= BrsFolder_OnSetSelectionW(info
, selectionW
, is_str
);
645 HeapFree(GetProcessHeap(), 0, selectionW
);
649 /*************************************************************************
650 * BrsFolderDlgProc32 (not an exported API function)
652 static INT_PTR CALLBACK
BrsFolderDlgProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
657 TRACE("hwnd=%p msg=%04x 0x%08x 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
659 if (msg
== WM_INITDIALOG
)
660 return BrsFolder_OnCreate( hWnd
, (browse_info
*) lParam
);
662 info
= (browse_info
*) GetPropW( hWnd
, szBrowseFolderInfo
);
667 return BrsFolder_OnNotify( info
, (UINT
)wParam
, (LPNMHDR
)lParam
);
670 return BrsFolder_OnCommand( info
, wParam
);
672 case BFFM_SETSTATUSTEXTA
:
673 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
674 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
677 case BFFM_SETSTATUSTEXTW
:
678 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
679 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
683 TRACE("Enable %ld\n", lParam
);
684 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
687 case BFFM_SETOKTEXT
: /* unicode only */
688 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
689 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
692 case BFFM_SETSELECTIONA
:
693 return BrsFolder_OnSetSelectionA(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
695 case BFFM_SETSELECTIONW
:
696 return BrsFolder_OnSetSelectionW(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
698 case BFFM_SETEXPANDED
: /* unicode only */
699 return BrsFolder_OnSetExpanded(info
, (LPVOID
)lParam
, (BOOL
)wParam
, NULL
);
704 static const WCHAR swBrowseTemplateName
[] = {
705 'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
707 /*************************************************************************
708 * SHBrowseForFolderA [SHELL32.@]
709 * SHBrowseForFolder [SHELL32.@]
711 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
720 bi
.hwndOwner
= lpbi
->hwndOwner
;
721 bi
.pidlRoot
= lpbi
->pidlRoot
;
722 if (lpbi
->pszDisplayName
)
724 bi
.pszDisplayName
= HeapAlloc( GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) );
725 MultiByteToWideChar( CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, MAX_PATH
);
728 bi
.pszDisplayName
= NULL
;
732 len
= MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0 );
733 title
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
734 MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, title
, len
);
739 bi
.lpszTitle
= title
;
740 bi
.ulFlags
= lpbi
->ulFlags
;
741 bi
.lpfn
= lpbi
->lpfn
;
742 bi
.lParam
= lpbi
->lParam
;
743 bi
.iImage
= lpbi
->iImage
;
744 lpid
= SHBrowseForFolderW( &bi
);
745 if (bi
.pszDisplayName
)
747 WideCharToMultiByte( CP_ACP
, 0, bi
.pszDisplayName
, -1,
748 lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
749 HeapFree( GetProcessHeap(), 0, bi
.pszDisplayName
);
751 HeapFree(GetProcessHeap(), 0, title
);
752 lpbi
->iImage
= bi
.iImage
;
757 /*************************************************************************
758 * SHBrowseForFolderW [SHELL32.@]
761 * crashes when passed a null pointer
763 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
771 info
.lpBrowseInfo
= lpbi
;
772 info
.hwndTreeView
= NULL
;
774 hr
= OleInitialize(NULL
);
775 r
= DialogBoxParamW( shell32_hInstance
, swBrowseTemplateName
, lpbi
->hwndOwner
,
776 BrsFolderDlgProc
, (LPARAM
)&info
);