2 * Copyright 2003, 2004, 2005, 2006 Martin Fuchs
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
25 // Martin Fuchs, 23.07.2003
31 // work around GCC's wide string constant bug
33 const LPCTSTR C_DRIVE
= C_DRIVE_STR
;
36 ShellBrowser::ShellBrowser(HWND hwnd
, HWND hwndFrame
, HWND left_hwnd
, WindowHandle
& right_hwnd
, ShellPathInfo
& create_info
,
37 BrowserCallback
* cb
, CtxMenuInterfaces
& cm_ifs
)
38 : super(IID_IShellFolderViewCB
),
40 _hwndFrame(hwndFrame
),
41 _left_hwnd(left_hwnd
),
42 _right_hwnd(right_hwnd
),
43 _create_info(create_info
),
53 HDC hDC
= GetDC(NULL
);
56 INT bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
75 _himl
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ilMask
, 2, 0);
76 ImageList_SetBkColor(_himl
, GetSysColor(COLOR_WINDOW
));
80 ShellBrowser::~ShellBrowser()
82 (void)TreeView_SetImageList(_left_hwnd
, _himl_old
, TVSIL_NORMAL
);
83 ImageList_Destroy(_himl
);
86 _pShellView
->Release();
89 _pDropTarget
->Release();
94 DestroyWindow(_right_hwnd
);
100 void ShellBrowser::Init()
102 CONTEXT("ShellBrowser::Init()");
104 const String
& root_name
= GetDesktopFolder().get_name(_create_info
._root_shell_path
, SHGDN_FORADDRESSBAR
);
106 _root
._drive_type
= DRIVE_UNKNOWN
;
107 lstrcpy(_root
._volname
, root_name
);
109 lstrcpy(_root
._fs
, TEXT("Desktop"));
111 _root
._entry
= new ShellDirectory(GetDesktopFolder(), _create_info
._root_shell_path
, _hwnd
);
113 _root
._entry
->read_directory(SCAN_DONT_ACCESS
|SCAN_NO_FILESYSTEM
); // avoid to handle desktop root folder as file system directory
120 jump_to(_create_info
._shell_path
);
122 /* already filled by ShellDirectory constructor
123 lstrcpy(_root._entry->_data.cFileName, TEXT("Desktop")); */
126 void ShellBrowser::jump_to(LPCITEMIDLIST pidl
)
131 _cur_dir
= static_cast<ShellDirectory
*>(_root
._entry
);
133 //LOG(FmtString(TEXT("ShellBrowser::jump_to(): pidl=%s"), (LPCTSTR)FileSysShellPath(pidl)));
135 // We could call read_tree() here to iterate through the hierarchy and open all folders
136 // from _create_info._root_shell_path (_cur_dir) to _create_info._shell_path (pidl).
137 // To make it easier we just use ILFindChild() instead.
139 static DynamicFct
<LPITEMIDLIST(WINAPI
*)(LPCITEMIDLIST
, LPCITEMIDLIST
)> ILFindChild(TEXT("SHELL32"), 24);
143 LPCITEMIDLIST child_pidl
= (*ILFindChild
)(_cur_dir
->create_absolute_pidl(), pidl
);
144 if (!child_pidl
|| !child_pidl
->mkid
.cb
)
147 _cur_dir
->smart_scan(SORT_NAME
, SCAN_DONT_ACCESS
);
149 entry
= _cur_dir
->find_entry(child_pidl
);
153 _cur_dir
= static_cast<ShellDirectory
*>(entry
);
154 _callback
->entry_selected(entry
);
157 _cur_dir
->smart_scan(SORT_NAME
, SCAN_DONT_ACCESS
);
159 entry
= _cur_dir
->find_entry(pidl
); // This is not correct in the common case, but works on the desktop level.
162 _cur_dir
= static_cast<ShellDirectory
*>(entry
);
163 _callback
->entry_selected(entry
);
168 // If not already called, now directly call UpdateFolderView() using pidl
170 UpdateFolderView(ShellFolder(pidl
));
174 void ShellBrowser::InitializeTree()
176 CONTEXT("ShellBrowserChild::InitializeTree()");
178 _himl_old
= TreeView_SetImageList(_left_hwnd
, _himl
, TVSIL_NORMAL
);
179 TreeView_SetScrollTime(_left_hwnd
, 100);
181 TV_INSERTSTRUCT tvInsert
;
182 TV_ITEM
& tvItem
= tvInsert
.item
;
184 tvInsert
.hParent
= 0;
185 tvInsert
.hInsertAfter
= TVI_LAST
;
187 tvItem
.mask
= TVIF_PARAM
| TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_CHILDREN
;
188 tvItem
.lParam
= (LPARAM
)_root
._entry
;
189 tvItem
.pszText
= _root
._volname
; //LPSTR_TEXTCALLBACK;
190 tvItem
.iImage
= tvItem
.iSelectedImage
= I_IMAGECALLBACK
;
191 tvItem
.cChildren
= 1;
193 HTREEITEM hItem
= TreeView_InsertItem(_left_hwnd
, &tvInsert
);
194 TreeView_SelectItem(_left_hwnd
, hItem
);
195 TreeView_Expand(_left_hwnd
, hItem
, TVE_EXPAND
);
198 bool ShellBrowser::InitDragDrop()
200 CONTEXT("ShellBrowser::InitDragDrop()");
202 _pDropTarget
= new TreeDropTarget(_left_hwnd
);
207 _pDropTarget
->AddRef();
209 if (FAILED(RegisterDragDrop(_left_hwnd
, _pDropTarget
))) {//calls addref
210 _pDropTarget
->Release(); // free TreeDropTarget
214 _pDropTarget
->Release();
218 ftetc
.dwAspect
= DVASPECT_CONTENT
;
220 ftetc
.tymed
= TYMED_HGLOBAL
;
221 ftetc
.cfFormat
= CF_HDROP
;
223 _pDropTarget
->AddSuportedFormat(ftetc
);
229 void ShellBrowser::OnTreeGetDispInfo(int idCtrl
, LPNMHDR pnmh
)
231 CONTEXT("ShellBrowser::OnTreeGetDispInfo()");
233 LPNMTVDISPINFO lpdi
= (LPNMTVDISPINFO
)pnmh
;
234 ShellEntry
* entry
= (ShellEntry
*)lpdi
->item
.lParam
;
237 if (lpdi
->item
.mask
& TVIF_TEXT
)
238 lpdi
->item
.pszText
= entry
->_display_name
;
240 if (lpdi
->item
.mask
& (TVIF_IMAGE
|TVIF_SELECTEDIMAGE
)) {
241 if (lpdi
->item
.mask
& TVIF_IMAGE
)
242 lpdi
->item
.iImage
= get_image_idx(
243 entry
->safe_extract_icon((ICONCACHE_FLAGS
)(ICF_HICON
|ICF_OVERLAYS
)));
245 if (lpdi
->item
.mask
& TVIF_SELECTEDIMAGE
)
246 lpdi
->item
.iSelectedImage
= get_image_idx(
247 entry
->safe_extract_icon((ICONCACHE_FLAGS
)(ICF_HICON
|ICF_OVERLAYS
|ICF_OPEN
)));
252 int ShellBrowser::get_image_idx(int icon_id
)
254 if (icon_id
!= ICID_NONE
) {
255 map
<int,int>::const_iterator found
= _image_map
.find(icon_id
);
257 if (found
!= _image_map
.end())
258 return found
->second
;
260 int idx
= ImageList_AddIcon(_himl
, g_Globals
._icon_cache
.get_icon(icon_id
).get_hicon());
262 _image_map
[icon_id
] = idx
;
269 void ShellBrowser::invalidate_cache()
271 (void)TreeView_SetImageList(_left_hwnd
, _himl_old
, TVSIL_NORMAL
);
272 ImageList_Destroy(_himl
);
274 _himl
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_MASK
|ILC_COLOR24
, 2, 0);
275 ImageList_SetBkColor(_himl
, GetSysColor(COLOR_WINDOW
));
277 _himl_old
= TreeView_SetImageList(_left_hwnd
, _himl
, TVSIL_NORMAL
);
279 for(map
<int,int>::const_iterator it
=_image_map
.begin(); it
!=_image_map
.end(); ++it
)
280 g_Globals
._icon_cache
.free_icon(it
->first
);
286 void ShellBrowser::OnTreeItemExpanding(int idCtrl
, LPNMTREEVIEW pnmtv
)
288 CONTEXT("ShellBrowser::OnTreeItemExpanding()");
290 if (pnmtv
->action
== TVE_COLLAPSE
)
291 TreeView_Expand(_left_hwnd
, pnmtv
->itemNew
.hItem
, TVE_COLLAPSE
|TVE_COLLAPSERESET
);
292 else if (pnmtv
->action
== TVE_EXPAND
) {
293 ShellDirectory
* entry
= (ShellDirectory
*)TreeView_GetItemData(_left_hwnd
, pnmtv
->itemNew
.hItem
);
296 if (!InsertSubitems(pnmtv
->itemNew
.hItem
, entry
, entry
->_folder
)) {
297 entry
->_shell_attribs
&= ~SFGAO_HASSUBFOLDER
;
299 // remove subitem "+"
302 tvItem
.mask
= TVIF_CHILDREN
;
303 tvItem
.hItem
= pnmtv
->itemNew
.hItem
;
304 tvItem
.cChildren
= 0;
306 TreeView_SetItem(_left_hwnd
, &tvItem
);
311 int ShellBrowser::InsertSubitems(HTREEITEM hParentItem
, Entry
* entry
, IShellFolder
* pParentFolder
)
313 CONTEXT("ShellBrowser::InsertSubitems()");
319 SendMessage(_left_hwnd
, WM_SETREDRAW
, FALSE
, 0);
322 entry
->smart_scan(SORT_NAME
, SCAN_DONT_ACCESS
);
323 } catch(COMException
& e
) {
324 HandleException(e
, g_Globals
._hMainWnd
);
327 // remove old children items
328 HTREEITEM hchild
, hnext
;
330 hnext
= TreeView_GetChild(_left_hwnd
, hParentItem
);
332 while((hchild
=hnext
) != 0) {
333 hnext
= TreeView_GetNextSibling(_left_hwnd
, hchild
);
334 TreeView_DeleteItem(_left_hwnd
, hchild
);
338 TV_INSERTSTRUCT tvInsert
;
340 for(entry
=entry
->_down
; entry
; entry
=entry
->_next
) {
342 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
345 // ignore hidden directories
346 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
349 // ignore directory entries "." and ".."
350 if (entry
->_data
.cFileName
[0]==TEXT('.') &&
351 (entry
->_data
.cFileName
[1]==TEXT('\0') ||
352 (entry
->_data
.cFileName
[1]==TEXT('.') && entry
->_data
.cFileName
[2]==TEXT('\0'))))
355 ZeroMemory(&tvItem
, sizeof(tvItem
));
357 tvItem
.mask
= TVIF_PARAM
| TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_CHILDREN
;
358 tvItem
.pszText
= LPSTR_TEXTCALLBACK
;
359 tvItem
.iImage
= tvItem
.iSelectedImage
= I_IMAGECALLBACK
;
360 tvItem
.lParam
= (LPARAM
)entry
;
361 tvItem
.cChildren
= entry
->_shell_attribs
& SFGAO_HASSUBFOLDER
? 1: 0;
363 if (entry
->_shell_attribs
& SFGAO_SHARE
) {
364 tvItem
.mask
|= TVIF_STATE
;
365 tvItem
.stateMask
|= TVIS_OVERLAYMASK
;
366 tvItem
.state
|= INDEXTOOVERLAYMASK(1);
369 tvInsert
.item
= tvItem
;
370 tvInsert
.hInsertAfter
= TVI_LAST
;
371 tvInsert
.hParent
= hParentItem
;
373 (void)TreeView_InsertItem(_left_hwnd
, &tvInsert
);
379 SendMessage(_left_hwnd
, WM_SETREDRAW
, TRUE
, 0);
385 void ShellBrowser::OnTreeItemSelected(int idCtrl
, LPNMTREEVIEW pnmtv
)
387 CONTEXT("ShellBrowser::OnTreeItemSelected()");
389 Entry
* entry
= (Entry
*)pnmtv
->itemNew
.lParam
;
391 _last_sel
= pnmtv
->itemNew
.hItem
;
394 _callback
->entry_selected(entry
);
398 void ShellBrowser::OnTreeItemRClick(int idCtrl
, LPNMHDR pnmh
)
400 CONTEXT("ShellBrowser::OnTreeItemRClick()");
404 GetCursorPos(&tvhti
.pt
);
405 ScreenToClient(_left_hwnd
, &tvhti
.pt
);
407 tvhti
.flags
= LVHT_NOWHERE
;
408 (void)TreeView_HitTest(_left_hwnd
, &tvhti
);
410 if (TVHT_ONITEM
& tvhti
.flags
) {
411 LPARAM itemData
= TreeView_GetItemData(_left_hwnd
, tvhti
.hItem
);
414 Entry
* entry
= (Entry
*)itemData
;
415 ClientToScreen(_left_hwnd
, &tvhti
.pt
);
417 HRESULT hr
= entry
->do_context_menu(_hwnd
, tvhti
.pt
, _cm_ifs
);
428 void ShellBrowser::UpdateFolderView(IShellFolder
* folder
)
430 CONTEXT("ShellBrowser::UpdateFolderView()");
433 IShellView
* pLastShellView
= _pShellView
;
438 pLastShellView
->GetCurrentInfo(&fs
);
440 fs
.ViewMode
= _create_info
._open_mode
&OWM_DETAILS
? FVM_DETAILS
: FVM_ICON
;
441 fs
.fFlags
= FWF_NOCLIENTEDGE
|FWF_BESTFITWINDOW
;
444 SFV_CREATE sfv_create
;
446 sfv_create
.cbSize
= sizeof(SFV_CREATE
);
447 sfv_create
.pshf
= folder
;
448 sfv_create
.psvOuter
= NULL
;
449 sfv_create
.psfvcb
= this;
451 HRESULT hr
= SHCreateShellFolderView(&sfv_create
, &_pShellView
);
458 RECT rect
= {CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
};
459 hr
= _pShellView
->CreateViewWindow(pLastShellView
, &fs
, static_cast<IShellBrowser
*>(this), &rect
, &_right_hwnd
/*&m_hWndListView*/);
461 if (pLastShellView
) {
462 pLastShellView
->GetCurrentInfo(&fs
);
463 pLastShellView
->UIActivate(SVUIA_DEACTIVATE
);
464 pLastShellView
->DestroyViewWindow();
465 pLastShellView
->Release();
468 _pShellView
->UIActivate(SVUIA_ACTIVATE_NOFOCUS
);
471 /// shell view callback
472 HRESULT STDMETHODCALLTYPE
ShellBrowser::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
474 if (uMsg
== SFVM_INITMENUPOPUP
) {
475 ///@todo never reached
476 InsertMenu((HMENU
)lParam
, 0, MF_BYPOSITION
, 12345, TEXT("TEST ENTRY"));
484 HRESULT
ShellBrowser::OnDefaultCommand(LPIDA pida
)
486 CONTEXT("ShellBrowser::OnDefaultCommand()");
488 if (pida
->cidl
>= 1) {
489 if (_left_hwnd
) { // explorer mode
491 ShellDirectory
* parent
= (ShellDirectory
*)TreeView_GetItemData(_left_hwnd
, _last_sel
);
495 parent
->smart_scan(SORT_NAME
, SCAN_DONT_ACCESS
);
496 } catch(COMException
& e
) {
500 UINT firstOffset
= pida
->aoffset
[1];
501 LPITEMIDLIST pidl
= (LPITEMIDLIST
)((LPBYTE
)pida
+firstOffset
);
503 Entry
* entry
= parent
->find_entry(pidl
);
505 if (entry
&& (entry
->_data
.dwFileAttributes
&FILE_ATTRIBUTE_DIRECTORY
))
506 if (entry
->_etype
== ET_SHELL
)
507 if (_last_sel
&& select_entry(_last_sel
, entry
))
510 ///@todo look for hidden or new subfolders and refresh/add new entry instead of opening a new window
514 } else { // no tree control
515 if (MainFrameBase::OpenShellFolders(pida
, _hwndFrame
))
518 /* create new Frame Window
519 if (MainFrame::OpenShellFolders(pida, 0))
529 HTREEITEM
ShellBrowser::select_entry(HTREEITEM hitem
, Entry
* entry
, bool expand
)
531 CONTEXT("ShellBrowser::select_entry()");
533 if (expand
&& !TreeView_Expand(_left_hwnd
, hitem
, TVE_EXPAND
))
536 for(hitem
=TreeView_GetChild(_left_hwnd
,hitem
); hitem
; hitem
=TreeView_GetNextSibling(_left_hwnd
,hitem
)) {
537 if ((Entry
*)TreeView_GetItemData(_left_hwnd
,hitem
) == entry
) {
538 if (TreeView_SelectItem(_left_hwnd
, hitem
)) {
540 TreeView_Expand(_left_hwnd
, hitem
, TVE_EXPAND
);
553 bool ShellBrowser::jump_to_pidl(LPCITEMIDLIST pidl
)
558 // iterate through the hierarchy and open all folders to reach pidl
561 HTREEITEM hitem
= TreeView_GetRoot(_left_hwnd
);
562 Entry
* entry
= _root
._entry
;
564 for(const void*p
=pidl
;;) {
568 if (!entry
|| !hitem
)
571 entry
->smart_scan(SORT_NAME
, SCAN_DONT_ACCESS
);
573 Entry
* found
= entry
->find_entry(p
);
574 p
= entry
->get_next_path_component(p
);
577 hitem
= select_entry(hitem
, found
);
585 bool ShellBrowser::TranslateAccelerator(LPMSG lpmsg
)
589 /* TranslateAccelerator is called for all explorer windows that are open
590 so we have to decide if this is the correct recipient */
598 hwnd
= GetParent(hwnd
);
602 return _pShellView
->TranslateAccelerator(lpmsg
) == S_OK
;
607 bool ShellBrowser::select_folder(Entry
* entry
, bool expand
)
609 CONTEXT("ShellBrowser::expand_folder()");
614 if (!TreeView_Expand(_left_hwnd
, _last_sel
, TVE_EXPAND
))
617 for(HTREEITEM hitem
=TreeView_GetChild(_left_hwnd
,_last_sel
); hitem
; hitem
=TreeView_GetNextSibling(_left_hwnd
,hitem
)) {
618 if ((ShellDirectory
*)TreeView_GetItemData(_left_hwnd
,hitem
) == entry
) {
619 if (TreeView_SelectItem(_left_hwnd
, hitem
)) {
621 if (!TreeView_Expand(_left_hwnd
, hitem
, TVE_EXPAND
))
635 void ShellBrowser::refresh()
643 MDIShellBrowserChild::MDIShellBrowserChild(HWND hwnd
, const ShellChildWndInfo
& info
)
646 _shellpath_info(info
) //@@ copies info -> no reference to _create_info !
648 /**todo Conversion of shell path into path string -> store into URL history
649 const String& path = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORADDRESSBAR);
650 const String& parsingpath = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORPARSING);
652 // store path into history
653 if (info._path && *info._path)
654 _url_history.push(info._path);
659 MDIShellBrowserChild
* MDIShellBrowserChild::create(const ShellChildWndInfo
& info
)
661 ChildWindow
* child
= ChildWindow::create(info
,
662 info
._pos
.rcNormalPosition
,
663 WINDOW_CREATOR_INFO(MDIShellBrowserChild
,ShellChildWndInfo
),
666 WS_CLIPCHILDREN
| (info
._pos
.showCmd
==SW_SHOWMAXIMIZED
? WS_MAXIMIZE
: 0));
668 return static_cast<MDIShellBrowserChild
*>(child
);
672 LRESULT
MDIShellBrowserChild::Init(LPCREATESTRUCT pcs
)
674 CONTEXT("MDIShellBrowserChild::Init()");
676 if (super::Init(pcs
))
679 update_shell_browser();
685 LRESULT
MDIShellBrowserChild::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
688 case PM_DISPATCH_COMMAND
: {
689 switch(LOWORD(wparam
)) {
690 case ID_WINDOW_NEW
: {CONTEXT("MDIShellBrowserChild PM_DISPATCH_COMMAND ID_WINDOW_NEW");
691 MDIShellBrowserChild::create(_create_info
);
695 ///@todo refresh shell child
696 _shellBrowser
->invalidate_cache();
700 MainFrameBase::Create(ExplorerCmd(_url
, false));
704 return super::WndProc(nmsg
, wparam
, lparam
);
708 case WM_SYSCOLORCHANGE
:
709 /* Forward WM_SYSCOLORCHANGE to common controls */
710 SendMessage(_left_hwnd
, WM_SYSCOLORCHANGE
, 0, 0);
711 SendMessage(_right_hwnd
, WM_SYSCOLORCHANGE
, 0, 0);
714 case PM_TRANSLATE_MSG
:
715 return _shellBrowser
->TranslateAccelerator((MSG
*)lparam
);
718 return super::WndProc(nmsg
, wparam
, lparam
);
724 void MDIShellBrowserChild::update_shell_browser()
726 int split_pos
= DEFAULT_SPLIT_POS
;
728 if (_shellBrowser
.get()) {
729 split_pos
= _split_pos
;
730 delete _shellBrowser
.release();
733 // create explorer treeview
734 if (_create_info
._open_mode
& OWM_EXPLORE
) {
736 ClientRect
rect(_hwnd
);
738 _left_hwnd
= CreateWindowEx(0, WC_TREEVIEW
, NULL
,
739 WS_CHILD
|WS_TABSTOP
|WS_VISIBLE
|TVS_HASLINES
|TVS_LINESATROOT
|TVS_HASBUTTONS
|TVS_SHOWSELALWAYS
,//|TVS_NOTOOLTIPS
740 0, rect
.top
, split_pos
-SPLIT_WIDTH
/2, rect
.bottom
-rect
.top
,
741 _hwnd
, (HMENU
)IDC_FILETREE
, g_Globals
._hInstance
, 0);
745 DestroyWindow(_left_hwnd
);
750 _shellBrowser
= auto_ptr
<ShellBrowser
>(new ShellBrowser(_hwnd
, _hwndFrame
, _left_hwnd
, _right_hwnd
,
751 _shellpath_info
, this, _cm_ifs
));
753 _shellBrowser
->Init();
757 String
MDIShellBrowserChild::jump_to_int(LPCTSTR url
)
761 if (!_tcsnicmp(url
, TEXT("shell://"), 8)) {
762 if (_shellBrowser
->jump_to_pidl(ShellPath(url
+8)))
766 if (SplitFileSysURL(url
, dir
, fname
)) {
770 if (_shellBrowser
->jump_to_pidl(ShellPath(dir
)))
771 return FmtString(TEXT("file://%s"), (LPCTSTR
)dir
);
778 void MDIShellBrowserChild::entry_selected(Entry
* entry
)
781 _shellBrowser
->select_folder(entry
, false);
783 _shellBrowser
->UpdateFolderView(entry
->get_shell_folder());
785 // set size of new created shell view windows
786 ClientRect
rt(_hwnd
);
787 resize_children(rt
.right
, rt
.bottom
);
790 TCHAR path
[MAX_PATH
];
792 if (entry
->get_path(path
, COUNTOF(path
))) {
796 url
.printf(TEXT("shell://%s"), path
);
798 url
.printf(TEXT("file://%s"), path
);