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
21 * - implement new dialog style "make new folder" button
23 * - implement new dialog style resizing
29 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
31 typedef struct tagbrowse_info
35 LPBROWSEINFOW lpBrowseInfo
;
39 typedef struct tagTV_ITEMDATA
41 LPSHELLFOLDER lpsfParent
; /* IShellFolder of the parent */
42 LPITEMIDLIST lpi
; /* PIDL relative to parent */
43 LPITEMIDLIST lpifq
; /* Fully qualified PIDL */
44 IEnumIDList
* pEnumIL
; /* Children iterator */
45 } TV_ITEMDATA
, *LPTV_ITEMDATA
;
47 #define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
48 BIF_BROWSEFORCOMPUTER | \
49 BIF_RETURNFSANCESTORS | \
50 BIF_RETURNONLYFSDIRS | \
51 BIF_NONEWFOLDERBUTTON | \
52 BIF_NEWDIALOGSTYLE | \
53 BIF_BROWSEINCLUDEFILES)
55 static void FillTreeView(browse_info
*, LPSHELLFOLDER
,
56 LPITEMIDLIST
, HTREEITEM
, IEnumIDList
*);
57 static HTREEITEM
InsertTreeViewItem( browse_info
*, IShellFolder
*,
58 LPCITEMIDLIST
, LPCITEMIDLIST
, IEnumIDList
*, HTREEITEM
);
60 static const WCHAR szBrowseFolderInfo
[] = {
61 '_','_','W','I','N','E','_',
62 'B','R','S','F','O','L','D','E','R','D','L','G','_',
66 static DWORD __inline
BrowseFlagsToSHCONTF(UINT ulFlags
)
68 return SHCONTF_FOLDERS
| (ulFlags
& BIF_BROWSEINCLUDEFILES
? SHCONTF_NONFOLDERS
: 0);
71 static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo
, HWND hWnd
,
72 UINT msg
, LPARAM param
)
74 if (!lpBrowseInfo
->lpfn
)
76 lpBrowseInfo
->lpfn( hWnd
, msg
, param
, lpBrowseInfo
->lParam
);
79 /******************************************************************************
80 * InitializeTreeView [Internal]
82 * Called from WM_INITDIALOG handler.
85 * hwndParent [I] The BrowseForFolder dialog
86 * root [I] ITEMIDLIST of the root shell folder
88 static void InitializeTreeView( browse_info
*info
)
90 LPITEMIDLIST pidlParent
, pidlChild
;
91 HIMAGELIST hImageList
;
93 IShellFolder
*lpsfParent
, *lpsfRoot
;
94 IEnumIDList
* pEnumChildren
= NULL
;
97 LPCITEMIDLIST root
= info
->lpBrowseInfo
->pidlRoot
;
101 Shell_GetImageLists(NULL
, &hImageList
);
104 SendMessageW( info
->hwndTreeView
, TVM_SETIMAGELIST
, 0, (LPARAM
)hImageList
);
106 /* We want to call InsertTreeViewItem down the code, in order to insert
107 * the root item of the treeview. Due to InsertTreeViewItem's signature,
108 * we need the following to do this:
110 * + An ITEMIDLIST corresponding to _the parent_ of root.
111 * + An ITEMIDLIST, which is a relative path from root's parent to root
112 * (containing a single SHITEMID).
113 * + An IShellFolder interface pointer of root's parent folder.
115 * If root is 'Desktop', then root's parent is also 'Desktop'.
118 pidlParent
= ILClone(root
);
119 ILRemoveLastID(pidlParent
);
120 pidlChild
= ILClone(ILFindLastID(root
));
122 if (_ILIsDesktop(pidlParent
)) {
123 hr
= SHGetDesktopFolder(&lpsfParent
);
125 IShellFolder
*lpsfDesktop
;
126 hr
= SHGetDesktopFolder(&lpsfDesktop
);
127 if (!SUCCEEDED(hr
)) {
128 WARN("SHGetDesktopFolder failed! hr = %08x\n", hr
);
131 hr
= lpsfDesktop
->BindToObject(pidlParent
, 0, IID_IShellFolder
, (LPVOID
*)&lpsfParent
);
132 lpsfDesktop
->Release();
135 if (!SUCCEEDED(hr
)) {
136 WARN("Could not bind to parent shell folder! hr = %08x\n", hr
);
140 if (pidlChild
&& pidlChild
->mkid
.cb
) {
141 hr
= lpsfParent
->BindToObject(pidlChild
, 0, IID_IShellFolder
, (LPVOID
*)&lpsfRoot
);
143 lpsfRoot
= lpsfParent
;
144 hr
= lpsfParent
->AddRef();
147 if (!SUCCEEDED(hr
)) {
148 WARN("Could not bind to root shell folder! hr = %08x\n", hr
);
149 lpsfParent
->Release();
153 flags
= BrowseFlagsToSHCONTF( info
->lpBrowseInfo
->ulFlags
);
154 hr
= lpsfRoot
->EnumObjects(info
->hWnd
, flags
, &pEnumChildren
);
155 if (!SUCCEEDED(hr
)) {
156 WARN("Could not get child iterator! hr = %08x\n", hr
);
157 lpsfParent
->Release();
162 SendMessageW( info
->hwndTreeView
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
163 item
= InsertTreeViewItem( info
, lpsfParent
, pidlChild
,
164 pidlParent
, pEnumChildren
, TVI_ROOT
);
165 SendMessageW( info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
);
168 lpsfParent
->Release();
171 static int GetIcon(LPCITEMIDLIST lpi
, UINT uFlags
)
174 SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), uFlags
);
178 static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq
, LPTVITEMW lpTV_ITEM
)
180 LPITEMIDLIST pidlDesktop
= NULL
;
183 TRACE("%p %p\n",lpifq
, lpTV_ITEM
);
187 pidlDesktop
= _ILCreateDesktop();
191 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
;
192 lpTV_ITEM
->iImage
= GetIcon( lpifq
, flags
);
194 flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
| SHGFI_OPENICON
;
195 lpTV_ITEM
->iSelectedImage
= GetIcon( lpifq
, flags
);
198 ILFree( pidlDesktop
);
201 /******************************************************************************
204 * Query a shell folder for the display name of one of it's children
207 * lpsf [I] IShellFolder interface of the folder to be queried.
208 * lpi [I] ITEMIDLIST of the child, relative to parent
209 * dwFlags [I] as in IShellFolder::GetDisplayNameOf
210 * lpFriendlyName [O] The desired display name in unicode
216 static BOOL
GetName(LPSHELLFOLDER lpsf
, LPCITEMIDLIST lpi
, DWORD dwFlags
, LPWSTR lpFriendlyName
)
221 TRACE("%p %p %x %p\n", lpsf
, lpi
, dwFlags
, lpFriendlyName
);
222 if (SUCCEEDED(lpsf
->GetDisplayNameOf(lpi
, dwFlags
, &str
)))
223 bSuccess
= StrRetToStrNW(lpFriendlyName
, MAX_PATH
, &str
, lpi
);
227 TRACE("-- %s\n", debugstr_w(lpFriendlyName
));
231 /******************************************************************************
232 * InsertTreeViewItem [Internal]
235 * info [I] data for the dialog
236 * lpsf [I] IShellFolder interface of the item's parent shell folder
237 * pidl [I] ITEMIDLIST of the child to insert, relative to parent
238 * pidlParent [I] ITEMIDLIST of the parent shell folder
239 * pEnumIL [I] Iterator for the children of the item to be inserted
240 * hParent [I] The treeview-item that represents the parent shell folder
243 * Success: Handle to the created and inserted treeview-item
246 static HTREEITEM
InsertTreeViewItem( browse_info
*info
, IShellFolder
* lpsf
,
247 LPCITEMIDLIST pidl
, LPCITEMIDLIST pidlParent
, IEnumIDList
* pEnumIL
,
251 TVINSERTSTRUCTW tvins
;
252 WCHAR szBuff
[MAX_PATH
];
253 LPTV_ITEMDATA lptvid
=0;
255 tvi
.mask
= TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
257 tvi
.cChildren
= pEnumIL
? 1 : 0;
258 tvi
.mask
|= TVIF_CHILDREN
;
260 lptvid
= (TV_ITEMDATA
*)SHAlloc( sizeof(TV_ITEMDATA
) );
264 if (!GetName(lpsf
, pidl
, SHGDN_NORMAL
, szBuff
))
267 tvi
.pszText
= szBuff
;
268 tvi
.cchTextMax
= MAX_PATH
;
269 tvi
.lParam
= (LPARAM
)lptvid
;
272 lptvid
->lpsfParent
= lpsf
;
273 lptvid
->lpi
= ILClone(pidl
);
274 lptvid
->lpifq
= pidlParent
? ILCombine(pidlParent
, pidl
) : ILClone(pidl
);
275 lptvid
->pEnumIL
= pEnumIL
;
276 GetNormalAndSelectedIcons(lptvid
->lpifq
, &tvi
);
279 tvins
.hInsertAfter
= NULL
;
280 tvins
.hParent
= hParent
;
282 return (HTREEITEM
)SendMessageW(info
->hwndTreeView
, TVM_INSERTITEM
, 0, (LPARAM
)&tvins
);
285 /******************************************************************************
286 * FillTreeView [Internal]
288 * For each child (given by lpe) of the parent shell folder, which is given by
289 * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
292 * info [I] data for the dialog
293 * lpsf [I] IShellFolder interface of the parent shell folder
294 * pidl [I] ITEMIDLIST of the parent shell folder
295 * hParent [I] The treeview item that represents the parent shell folder
296 * lpe [I] An iterator for the children of the parent shell folder
298 static void FillTreeView( browse_info
*info
, IShellFolder
* lpsf
,
299 LPITEMIDLIST pidl
, HTREEITEM hParent
, IEnumIDList
* lpe
)
302 LPITEMIDLIST pidlTemp
= 0;
305 HWND hwnd
= GetParent( info
->hwndTreeView
);
307 TRACE("%p %p %p %p\n",lpsf
, pidl
, hParent
, lpe
);
309 /* No IEnumIDList -> No children */
313 SetCursor( LoadCursorA( 0, (LPSTR
)IDC_WAIT
) );
315 while (NOERROR
== lpe
->Next(1,&pidlTemp
,&ulFetched
))
317 ULONG ulAttrs
= SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
;
318 IEnumIDList
* pEnumIL
= NULL
;
319 IShellFolder
* pSFChild
= NULL
;
320 lpsf
->GetAttributesOf(1, (LPCITEMIDLIST
*)&pidlTemp
, &ulAttrs
);
321 if (ulAttrs
& SFGAO_FOLDER
)
323 hr
= lpsf
->BindToObject(pidlTemp
, NULL
, IID_IShellFolder
, (LPVOID
*)&pSFChild
);
326 DWORD flags
= BrowseFlagsToSHCONTF(info
->lpBrowseInfo
->ulFlags
);
327 hr
= pSFChild
->EnumObjects(hwnd
, flags
, &pEnumIL
);
330 if ((pEnumIL
->Skip(1) != S_OK
) ||
331 FAILED(pEnumIL
->Reset()))
341 if (!(hPrev
= InsertTreeViewItem(info
, lpsf
, pidlTemp
, pidl
, pEnumIL
, hParent
)))
343 SHFree(pidlTemp
); /* Finally, free the pidl that the shell gave us... */
349 SetCursor(LoadCursorW(0, (LPWSTR
)IDC_ARROW
));
353 static BOOL __inline
PIDLIsType(LPCITEMIDLIST pidl
, PIDLTYPE type
)
355 LPPIDLDATA data
= _ILGetDataPointer(pidl
);
358 return (data
->type
== type
);
361 static void BrsFolder_CheckValidSelection( browse_info
*info
, LPTV_ITEMDATA lptvid
)
363 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
364 LPCITEMIDLIST pidl
= lptvid
->lpi
;
365 BOOL bEnabled
= TRUE
;
369 if ((lpBrowseInfo
->ulFlags
& BIF_BROWSEFORCOMPUTER
) &&
370 !PIDLIsType(pidl
, PT_COMP
))
372 if (lpBrowseInfo
->ulFlags
& BIF_RETURNFSANCESTORS
)
374 dwAttributes
= SFGAO_FILESYSANCESTOR
| SFGAO_FILESYSTEM
;
375 r
= lptvid
->lpsfParent
->GetAttributesOf(1,
376 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
377 if (FAILED(r
) || !(dwAttributes
& (SFGAO_FILESYSANCESTOR
|SFGAO_FILESYSTEM
)))
380 if (lpBrowseInfo
->ulFlags
& BIF_RETURNONLYFSDIRS
)
382 dwAttributes
= SFGAO_FOLDER
| SFGAO_FILESYSTEM
;
383 r
= lptvid
->lpsfParent
->GetAttributesOf(1,
384 (LPCITEMIDLIST
*)&lptvid
->lpi
, &dwAttributes
);
386 ((dwAttributes
& (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)) != (SFGAO_FOLDER
|SFGAO_FILESYSTEM
)))
391 SendMessageW(info
->hWnd
, BFFM_ENABLEOK
, 0, (LPARAM
)bEnabled
);
394 static LRESULT
BrsFolder_Treeview_Delete( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
396 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
)pnmtv
->itemOld
.lParam
;
398 TRACE("TVN_DELETEITEMA/W %p\n", lptvid
);
400 lptvid
->lpsfParent
->Release();
402 lptvid
->pEnumIL
->Release();
404 SHFree(lptvid
->lpifq
);
409 static LRESULT
BrsFolder_Treeview_Expand( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
411 IShellFolder
*lpsf2
= NULL
;
412 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
415 TRACE("TVN_ITEMEXPANDINGA/W\n");
417 if ((pnmtv
->itemNew
.state
& TVIS_EXPANDEDONCE
))
420 if (lptvid
->lpi
&& lptvid
->lpi
->mkid
.cb
) {
421 r
= lptvid
->lpsfParent
->BindToObject(lptvid
->lpi
, 0,
422 IID_IShellFolder
, (LPVOID
*)&lpsf2
);
424 lpsf2
= lptvid
->lpsfParent
;
429 FillTreeView( info
, lpsf2
, lptvid
->lpifq
, pnmtv
->itemNew
.hItem
, lptvid
->pEnumIL
);
431 /* My Computer is already sorted and trying to do a simple text
432 * sort will only mess things up */
433 if (!_ILIsMyComputer(lptvid
->lpi
))
434 SendMessageW( info
->hwndTreeView
, TVM_SORTCHILDREN
,
435 FALSE
, (LPARAM
)pnmtv
->itemNew
.hItem
);
440 static HRESULT
BrsFolder_Treeview_Changed( browse_info
*info
, NMTREEVIEWW
*pnmtv
)
442 LPTV_ITEMDATA lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
444 lptvid
= (LPTV_ITEMDATA
) pnmtv
->itemNew
.lParam
;
445 info
->pidlRet
= lptvid
->lpifq
;
446 browsefolder_callback( info
->lpBrowseInfo
, info
->hWnd
, BFFM_SELCHANGED
,
447 (LPARAM
)info
->pidlRet
);
448 BrsFolder_CheckValidSelection( info
, lptvid
);
452 static LRESULT
BrsFolder_OnNotify( browse_info
*info
, UINT CtlID
, LPNMHDR lpnmh
)
454 NMTREEVIEWW
*pnmtv
= (NMTREEVIEWW
*)lpnmh
;
456 TRACE("%p %x %p msg=%x\n", info
, CtlID
, lpnmh
, pnmtv
->hdr
.code
);
458 if (pnmtv
->hdr
.idFrom
!= IDD_TREEVIEW
)
461 switch (pnmtv
->hdr
.code
)
463 case TVN_DELETEITEMA
:
464 case TVN_DELETEITEMW
:
465 return BrsFolder_Treeview_Delete( info
, pnmtv
);
467 case TVN_ITEMEXPANDINGA
:
468 case TVN_ITEMEXPANDINGW
:
469 return BrsFolder_Treeview_Expand( info
, pnmtv
);
471 case TVN_SELCHANGEDA
:
472 case TVN_SELCHANGEDW
:
473 return BrsFolder_Treeview_Changed( info
, pnmtv
);
476 WARN("unhandled (%d)\n", pnmtv
->hdr
.code
);
484 static BOOL
BrsFolder_OnCreate( HWND hWnd
, browse_info
*info
)
486 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
489 SetPropW( hWnd
, szBrowseFolderInfo
, info
);
491 if (lpBrowseInfo
->ulFlags
& BIF_NEWDIALOGSTYLE
)
492 FIXME("flags BIF_NEWDIALOGSTYLE partially implemented\n");
493 if (lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
)
494 FIXME("flags %x not implemented\n", lpBrowseInfo
->ulFlags
& ~SUPPORTEDFLAGS
);
496 if (lpBrowseInfo
->lpszTitle
)
497 SetWindowTextW( GetDlgItem(hWnd
, IDD_TITLE
), lpBrowseInfo
->lpszTitle
);
499 ShowWindow( GetDlgItem(hWnd
, IDD_TITLE
), SW_HIDE
);
501 if (!(lpBrowseInfo
->ulFlags
& BIF_STATUSTEXT
)
502 || (lpBrowseInfo
->ulFlags
& BIF_NEWDIALOGSTYLE
))
503 ShowWindow( GetDlgItem(hWnd
, IDD_STATUS
), SW_HIDE
);
505 /* Hide "Make New Folder" Button? */
506 if ((lpBrowseInfo
->ulFlags
& BIF_NONEWFOLDERBUTTON
)
507 || !(lpBrowseInfo
->ulFlags
& BIF_NEWDIALOGSTYLE
))
508 ShowWindow( GetDlgItem(hWnd
, IDD_MAKENEWFOLDER
), SW_HIDE
);
510 /* Hide the editbox? */
511 if (!(lpBrowseInfo
->ulFlags
& BIF_EDITBOX
))
513 ShowWindow( GetDlgItem(hWnd
, IDD_FOLDER
), SW_HIDE
);
514 ShowWindow( GetDlgItem(hWnd
, IDD_FOLDERTEXT
), SW_HIDE
);
517 info
->hwndTreeView
= GetDlgItem( hWnd
, IDD_TREEVIEW
);
518 if (info
->hwndTreeView
)
520 InitializeTreeView( info
);
522 /* Resize the treeview if there's not editbox */
523 if ((lpBrowseInfo
->ulFlags
& BIF_NEWDIALOGSTYLE
)
524 && !(lpBrowseInfo
->ulFlags
& BIF_EDITBOX
))
527 GetClientRect(info
->hwndTreeView
, &rc
);
528 SetWindowPos(info
->hwndTreeView
, HWND_TOP
, 0, 0,
529 rc
.right
, rc
.bottom
+ 40, SWP_NOMOVE
);
533 ERR("treeview control missing!\n");
535 browsefolder_callback( info
->lpBrowseInfo
, hWnd
, BFFM_INITIALIZED
, 0 );
540 static BOOL
BrsFolder_OnCommand( browse_info
*info
, UINT id
)
542 LPBROWSEINFOW lpBrowseInfo
= info
->lpBrowseInfo
;
547 /* The original pidl is owned by the treeview and will be free'd. */
548 info
->pidlRet
= ILClone(info
->pidlRet
);
549 if (info
->pidlRet
== NULL
) /* A null pidl would mean a cancel */
550 info
->pidlRet
= _ILCreateDesktop();
551 pdump( info
->pidlRet
);
552 if (lpBrowseInfo
->pszDisplayName
)
553 SHGetPathFromIDListW( info
->pidlRet
, lpBrowseInfo
->pszDisplayName
);
554 EndDialog( info
->hWnd
, 1 );
558 EndDialog( info
->hWnd
, 0 );
561 case IDD_MAKENEWFOLDER
:
562 FIXME("make new folder not implemented\n");
568 static BOOL
BrsFolder_OnSetExpanded(browse_info
*info
, LPVOID selection
,
569 BOOL is_str
, HTREEITEM
*pItem
)
571 LPITEMIDLIST pidlSelection
= (LPITEMIDLIST
)selection
;
572 LPCITEMIDLIST pidlCurrent
, pidlRoot
;
574 BOOL bResult
= FALSE
;
576 /* If 'selection' is a string, convert to a Shell ID List. */
578 IShellFolder
*psfDesktop
;
581 hr
= SHGetDesktopFolder(&psfDesktop
);
585 hr
= psfDesktop
->ParseDisplayName(NULL
, NULL
,
586 (LPOLESTR
)selection
, NULL
, &pidlSelection
, NULL
);
587 psfDesktop
->Release();
592 /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
593 * the sub-tree currently displayed. */
594 pidlRoot
= info
->lpBrowseInfo
->pidlRoot
;
595 pidlCurrent
= pidlSelection
;
596 while (!_ILIsEmpty(pidlRoot
) && _ILIsEqualSimple(pidlRoot
, pidlCurrent
)) {
597 pidlRoot
= ILGetNext(pidlRoot
);
598 pidlCurrent
= ILGetNext(pidlCurrent
);
601 /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */
602 if (!_ILIsEmpty(pidlRoot
))
605 /* Initialize item to point to the first child of the root folder. */
606 memset(&item
, 0, sizeof(item
));
607 item
.mask
= TVIF_PARAM
;
608 item
.hItem
= TreeView_GetRoot(info
->hwndTreeView
);
610 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
612 /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */
613 while (item
.hItem
&& !_ILIsEmpty(pidlCurrent
)) {
614 LPTV_ITEMDATA pItemData
;
616 SendMessageW(info
->hwndTreeView
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
617 pItemData
= (LPTV_ITEMDATA
)item
.lParam
;
619 if (_ILIsEqualSimple(pItemData
->lpi
, pidlCurrent
)) {
620 pidlCurrent
= ILGetNext(pidlCurrent
);
621 if (!_ILIsEmpty(pidlCurrent
)) {
622 /* Only expand current node and move on to it's first child,
623 * if we didn't already reach the last SHITEMID */
624 SendMessageW(info
->hwndTreeView
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)item
.hItem
);
625 item
.hItem
= TreeView_GetChild(info
->hwndTreeView
, item
.hItem
);
628 item
.hItem
= TreeView_GetNextSibling(info
->hwndTreeView
, item
.hItem
);
632 if (_ILIsEmpty(pidlCurrent
) && item
.hItem
)
636 if (pidlSelection
&& pidlSelection
!= (LPITEMIDLIST
)selection
)
637 ILFree(pidlSelection
);
645 static BOOL
BrsFolder_OnSetSelectionW(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
649 bResult
= BrsFolder_OnSetExpanded(info
, selection
, is_str
, &hItem
);
651 SendMessageW(info
->hwndTreeView
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hItem
);
655 static BOOL
BrsFolder_OnSetSelectionA(browse_info
*info
, LPVOID selection
, BOOL is_str
) {
656 LPWSTR selectionW
= NULL
;
661 return BrsFolder_OnSetSelectionW(info
, selection
, is_str
);
663 if ((length
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, NULL
, 0)) &&
664 (selectionW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, length
* sizeof(WCHAR
))) &&
665 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)selection
, -1, selectionW
, length
))
667 result
= BrsFolder_OnSetSelectionW(info
, selectionW
, is_str
);
670 HeapFree(GetProcessHeap(), 0, selectionW
);
674 /*************************************************************************
675 * BrsFolderDlgProc32 (not an exported API function)
677 static INT_PTR CALLBACK
BrsFolderDlgProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
682 TRACE("hwnd=%p msg=%04x 0x%08lx 0x%08lx\n", hWnd
, msg
, wParam
, lParam
);
684 if (msg
== WM_INITDIALOG
)
685 return BrsFolder_OnCreate( hWnd
, (browse_info
*) lParam
);
687 info
= (browse_info
*) GetPropW( hWnd
, szBrowseFolderInfo
);
692 return BrsFolder_OnNotify( info
, (UINT
)wParam
, (LPNMHDR
)lParam
);
695 return BrsFolder_OnCommand( info
, wParam
);
697 case BFFM_SETSTATUSTEXTA
:
698 TRACE("Set status %s\n", debugstr_a((LPSTR
)lParam
));
699 SetWindowTextA(GetDlgItem(hWnd
, IDD_STATUS
), (LPSTR
)lParam
);
702 case BFFM_SETSTATUSTEXTW
:
703 TRACE("Set status %s\n", debugstr_w((LPWSTR
)lParam
));
704 SetWindowTextW(GetDlgItem(hWnd
, IDD_STATUS
), (LPWSTR
)lParam
);
708 TRACE("Enable %ld\n", lParam
);
709 EnableWindow(GetDlgItem(hWnd
, 1), (lParam
)?TRUE
:FALSE
);
712 case BFFM_SETOKTEXT
: /* unicode only */
713 TRACE("Set OK text %s\n", debugstr_w((LPWSTR
)wParam
));
714 SetWindowTextW(GetDlgItem(hWnd
, 1), (LPWSTR
)wParam
);
717 case BFFM_SETSELECTIONA
:
718 return BrsFolder_OnSetSelectionA(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
720 case BFFM_SETSELECTIONW
:
721 return BrsFolder_OnSetSelectionW(info
, (LPVOID
)lParam
, (BOOL
)wParam
);
723 case BFFM_SETEXPANDED
: /* unicode only */
724 return BrsFolder_OnSetExpanded(info
, (LPVOID
)lParam
, (BOOL
)wParam
, NULL
);
729 static const WCHAR swBrowseTemplateName
[] = {
730 'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
731 static const WCHAR swNewBrowseTemplateName
[] = {
732 'S','H','N','E','W','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0};
734 /*************************************************************************
735 * SHBrowseForFolderA [SHELL32.@]
736 * SHBrowseForFolder [SHELL32.@]
738 LPITEMIDLIST WINAPI
SHBrowseForFolderA (LPBROWSEINFOA lpbi
)
747 bi
.hwndOwner
= lpbi
->hwndOwner
;
748 bi
.pidlRoot
= lpbi
->pidlRoot
;
749 if (lpbi
->pszDisplayName
)
751 bi
.pszDisplayName
= (WCHAR
*)HeapAlloc( GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) );
752 MultiByteToWideChar( CP_ACP
, 0, lpbi
->pszDisplayName
, -1, bi
.pszDisplayName
, MAX_PATH
);
755 bi
.pszDisplayName
= NULL
;
759 len
= MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, NULL
, 0 );
760 title
= (WCHAR
*)HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
761 MultiByteToWideChar( CP_ACP
, 0, lpbi
->lpszTitle
, -1, title
, len
);
766 bi
.lpszTitle
= title
;
767 bi
.ulFlags
= lpbi
->ulFlags
;
768 bi
.lpfn
= lpbi
->lpfn
;
769 bi
.lParam
= lpbi
->lParam
;
770 bi
.iImage
= lpbi
->iImage
;
771 lpid
= SHBrowseForFolderW( &bi
);
772 if (bi
.pszDisplayName
)
774 WideCharToMultiByte( CP_ACP
, 0, bi
.pszDisplayName
, -1,
775 lpbi
->pszDisplayName
, MAX_PATH
, 0, NULL
);
776 HeapFree( GetProcessHeap(), 0, bi
.pszDisplayName
);
778 HeapFree(GetProcessHeap(), 0, title
);
779 lpbi
->iImage
= bi
.iImage
;
784 /*************************************************************************
785 * SHBrowseForFolderW [SHELL32.@]
788 * crashes when passed a null pointer
790 LPITEMIDLIST WINAPI
SHBrowseForFolderW (LPBROWSEINFOW lpbi
)
795 const WCHAR
* templateName
;
799 info
.lpBrowseInfo
= lpbi
;
800 info
.hwndTreeView
= NULL
;
802 hr
= OleInitialize(NULL
);
804 if (lpbi
->ulFlags
& BIF_NEWDIALOGSTYLE
)
805 templateName
= swNewBrowseTemplateName
;
807 templateName
= swBrowseTemplateName
;
808 r
= DialogBoxParamW( shell32_hInstance
, templateName
, lpbi
->hwndOwner
,
809 BrsFolderDlgProc
, (LPARAM
)&info
);