4 * Copyright 2016 Sylvain Deverre <deverre dot sylv at gmail dot com>
5 * Copyright 2020 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <commoncontrols.h>
24 #include <undocshell.h>
29 #define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
34 * - Monitor correctly "external" shell interrupts (seems like we need to register/deregister them for each folder)
35 * - find and fix what cause explorer crashes sometimes (seems to be explorer that does more releases than addref)
39 typedef struct _PIDLDATA
43 } PIDLDATA
, *LPPIDLDATA
;
46 #define PT_SHELLEXT 0x2E
47 #define PT_YAGUID 0x70
49 static BOOL
_ILIsSpecialFolder (LPCITEMIDLIST pidl
)
51 LPPIDLDATA lpPData
= (LPPIDLDATA
)&pidl
->mkid
.abID
;
54 ((lpPData
&& (PT_GUID
== lpPData
->type
|| PT_SHELLEXT
== lpPData
->type
||
55 PT_YAGUID
== lpPData
->type
)) || (pidl
&& pidl
->mkid
.cb
== 0x00)));
58 HRESULT
GetDisplayName(LPCITEMIDLIST pidlDirectory
,TCHAR
*szDisplayName
,UINT cchMax
,DWORD uFlags
)
60 IShellFolder
*pShellFolder
= NULL
;
61 LPCITEMIDLIST pidlRelative
= NULL
;
65 if (pidlDirectory
== NULL
|| szDisplayName
== NULL
)
70 hr
= SHBindToParent(pidlDirectory
, IID_PPV_ARG(IShellFolder
, &pShellFolder
), &pidlRelative
);
74 hr
= pShellFolder
->GetDisplayNameOf(pidlRelative
,uFlags
,&str
);
77 hr
= StrRetToBuf(&str
,pidlDirectory
,szDisplayName
,cchMax
);
79 pShellFolder
->Release();
85 This is a Windows hack, because shell event messages in Windows gives an
86 ill-formed PIDL stripped from useful data that parses incorrectly with SHGetFileInfo.
87 So we need to re-enumerate subfolders until we find one with the same name.
89 HRESULT
_ReparsePIDL(LPITEMIDLIST buggyPidl
, LPITEMIDLIST
*cleanPidl
)
92 CComPtr
<IShellFolder
> folder
;
93 CComPtr
<IPersistFolder2
> persist
;
94 CComPtr
<IEnumIDList
> pEnumIDList
;
95 LPITEMIDLIST childPidl
;
96 LPITEMIDLIST correctChild
;
97 LPITEMIDLIST correctParent
;
102 EnumFlags
= SHCONTF_FOLDERS
| SHCONTF_INCLUDEHIDDEN
;
103 hr
= SHBindToParent(buggyPidl
, IID_PPV_ARG(IShellFolder
, &folder
), (LPCITEMIDLIST
*)&childPidl
);
107 ERR("Can't bind to parent folder\n");
110 hr
= folder
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &persist
));
113 ERR("PIDL doesn't belong to the shell namespace, aborting\n");
117 hr
= persist
->GetCurFolder(&correctParent
);
120 ERR("Unable to get current folder\n");
124 hr
= folder
->EnumObjects(NULL
,EnumFlags
,&pEnumIDList
);
125 // avoid broken IShellFolder implementations that return null pointer with success
126 if (!SUCCEEDED(hr
) || !pEnumIDList
)
128 ERR("Can't enum the folder !\n");
132 while(SUCCEEDED(pEnumIDList
->Next(1, &correctChild
, &fetched
)) && correctChild
&& fetched
)
134 if (!folder
->CompareIDs(0, childPidl
, correctChild
))
136 *cleanPidl
= ILCombine(correctParent
, correctChild
);
137 ILFree(correctChild
);
140 ILFree(correctChild
);
143 ILFree(correctParent
);
147 CExplorerBand::CExplorerBand()
150 , m_bNavigating(FALSE
)
152 , m_pidlCurrent(NULL
)
156 CExplorerBand::~CExplorerBand()
160 ILFree(m_pidlCurrent
);
164 void CExplorerBand::InitializeExplorerBand()
166 // Init the treeview here
169 CComPtr
<IWebBrowser2
> browserService
;
170 SHChangeNotifyEntry shcne
;
172 hr
= SHGetDesktopFolder(&m_pDesktop
);
173 if (FAILED_UNEXPECTEDLY(hr
))
176 hr
= SHGetFolderLocation(m_hWnd
, CSIDL_DESKTOP
, NULL
, 0, &pidl
);
177 if (FAILED_UNEXPECTEDLY(hr
))
181 hr
= SHGetImageList(SHIL_SMALL
, IID_PPV_ARG(IImageList
, &piml
));
182 if (FAILED_UNEXPECTEDLY(hr
))
185 TreeView_SetImageList(m_hWnd
, (HIMAGELIST
)piml
, TVSIL_NORMAL
);
187 // Insert the root node
188 m_hRoot
= InsertItem(0, m_pDesktop
, pidl
, pidl
, FALSE
);
191 ERR("Failed to create root item\n");
195 NodeInfo
* pNodeInfo
= GetNodeInfo(m_hRoot
);
197 // Insert child nodes
198 InsertSubitems(m_hRoot
, pNodeInfo
);
199 TreeView_Expand(m_hWnd
, m_hRoot
, TVE_EXPAND
);
201 // Navigate to current folder position
202 NavigateToCurrentFolder();
204 // Register shell notification
206 shcne
.fRecursive
= TRUE
;
207 m_shellRegID
= SHChangeNotifyRegister(
209 SHCNRF_ShellLevel
| SHCNRF_InterruptLevel
| SHCNRF_RecursiveInterrupt
,
210 SHCNE_DISKEVENTS
| SHCNE_RENAMEFOLDER
| SHCNE_RMDIR
| SHCNE_MKDIR
,
216 ERR("Something went wrong, error %08x\n", GetLastError());
218 // Register browser connection endpoint
219 hr
= IUnknown_QueryService(m_pSite
, SID_SWebBrowserApp
, IID_PPV_ARG(IWebBrowser2
, &browserService
));
220 if (FAILED_UNEXPECTEDLY(hr
))
223 hr
= AtlAdvise(browserService
, dynamic_cast<IDispatch
*>(this), DIID_DWebBrowserEvents
, &m_adviseCookie
);
224 if (FAILED_UNEXPECTEDLY(hr
))
230 void CExplorerBand::DestroyExplorerBand()
233 CComPtr
<IWebBrowser2
> browserService
;
235 TRACE("Cleaning up explorer band ...\n");
237 hr
= IUnknown_QueryService(m_pSite
, SID_SWebBrowserApp
, IID_PPV_ARG(IWebBrowser2
, &browserService
));
238 if (FAILED_UNEXPECTEDLY(hr
))
241 hr
= AtlUnadvise(browserService
, DIID_DWebBrowserEvents
, m_adviseCookie
);
242 /* Remove all items of the treeview */
243 RevokeDragDrop(m_hWnd
);
244 TreeView_DeleteAllItems(m_hWnd
);
247 TRACE("Cleanup done !\n");
250 CExplorerBand::NodeInfo
* CExplorerBand::GetNodeInfo(HTREEITEM hItem
)
254 tvItem
.mask
= TVIF_PARAM
;
255 tvItem
.hItem
= hItem
;
257 if (!TreeView_GetItem(m_hWnd
, &tvItem
))
260 return reinterpret_cast<NodeInfo
*>(tvItem
.lParam
);
263 HRESULT
CExplorerBand::ExecuteCommand(CComPtr
<IContextMenu
>& menu
, UINT nCmd
)
265 CComPtr
<IOleWindow
> pBrowserOleWnd
;
266 CMINVOKECOMMANDINFO cmi
;
270 hr
= IUnknown_QueryService(m_pSite
, SID_SShellBrowser
, IID_PPV_ARG(IOleWindow
, &pBrowserOleWnd
));
271 if (FAILED_UNEXPECTEDLY(hr
))
274 hr
= pBrowserOleWnd
->GetWindow(&browserWnd
);
275 if (FAILED_UNEXPECTEDLY(hr
))
278 ZeroMemory(&cmi
, sizeof(cmi
));
279 cmi
.cbSize
= sizeof(cmi
);
280 cmi
.lpVerb
= MAKEINTRESOURCEA(nCmd
);
281 cmi
.hwnd
= browserWnd
;
282 if (GetKeyState(VK_SHIFT
) & 0x8000)
283 cmi
.fMask
|= CMIC_MASK_SHIFT_DOWN
;
284 if (GetKeyState(VK_CONTROL
) & 0x8000)
285 cmi
.fMask
|= CMIC_MASK_CONTROL_DOWN
;
287 return menu
->InvokeCommand(&cmi
);
290 HRESULT
CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto
)
292 CComPtr
<IShellBrowser
> pBrowserService
;
295 hr
= IUnknown_QueryService(m_pSite
, SID_STopLevelBrowser
, IID_PPV_ARG(IShellBrowser
, &pBrowserService
));
296 if (FAILED_UNEXPECTEDLY(hr
))
299 hr
= pBrowserService
->BrowseObject(pidlGoto
, SBSP_SAMEBROWSER
| SBSP_ABSOLUTE
);
300 if (FAILED_UNEXPECTEDLY(hr
))
305 ILFree(m_pidlCurrent
);
306 m_pidlCurrent
= ILClone(pidlGoto
);
311 // *** notifications handling ***
312 BOOL
CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv
)
316 if (pnmtv
->action
== TVE_COLLAPSE
) {
317 if (pnmtv
->itemNew
.hItem
== m_hRoot
)
319 // Prenvent root from collapsing
320 pnmtv
->itemNew
.mask
|= TVIF_STATE
;
321 pnmtv
->itemNew
.stateMask
|= TVIS_EXPANDED
;
322 pnmtv
->itemNew
.state
&= ~TVIS_EXPANDED
;
323 pnmtv
->action
= TVE_EXPAND
;
327 if (pnmtv
->action
== TVE_EXPAND
) {
328 // Grab our directory PIDL
329 pNodeInfo
= GetNodeInfo(pnmtv
->itemNew
.hItem
);
330 // We have it, let's try
331 if (pNodeInfo
&& !pNodeInfo
->expanded
)
332 if (!InsertSubitems(pnmtv
->itemNew
.hItem
, pNodeInfo
)) {
333 // remove subitem "+" since we failed to add subitems
336 tvItem
.mask
= TVIF_CHILDREN
;
337 tvItem
.hItem
= pnmtv
->itemNew
.hItem
;
338 tvItem
.cChildren
= 0;
340 TreeView_SetItem(m_hWnd
, &tvItem
);
346 BOOL
CExplorerBand::OnTreeItemDeleted(LPNMTREEVIEW pnmtv
)
348 /* Destroy memory associated to our node */
349 NodeInfo
* ptr
= GetNodeInfo(pnmtv
->itemNew
.hItem
);
352 ILFree(ptr
->relativePidl
);
353 ILFree(ptr
->absolutePidl
);
359 void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv
)
361 NodeInfo
* pNodeInfo
= GetNodeInfo(pnmtv
->itemNew
.hItem
);
363 /* Prevents navigation if selection is initiated inside the band */
367 UpdateBrowser(pNodeInfo
->absolutePidl
);
371 //TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
374 void CExplorerBand::OnTreeItemDragging(LPNMTREEVIEW pnmtv
, BOOL isRightClick
)
376 CComPtr
<IShellFolder
> pSrcFolder
;
377 CComPtr
<IDataObject
> pObj
;
383 dwEffect
= DROPEFFECT_COPY
| DROPEFFECT_MOVE
;
384 if (!pnmtv
->itemNew
.lParam
)
386 NodeInfo
* pNodeInfo
= GetNodeInfo(pnmtv
->itemNew
.hItem
);
387 hr
= SHBindToParent(pNodeInfo
->absolutePidl
, IID_PPV_ARG(IShellFolder
, &pSrcFolder
), &pLast
);
390 hr
= pSrcFolder
->GetUIObjectOf(m_hWnd
, 1, &pLast
, IID_IDataObject
, 0, reinterpret_cast<void**>(&pObj
));
393 DoDragDrop(pObj
, this, dwEffect
, &dwEffect2
);
398 // *** ATL event handlers ***
399 LRESULT
CExplorerBand::OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
406 CComPtr
<IShellFolder
> pFolder
;
407 CComPtr
<IContextMenu
> contextMenu
;
410 LPITEMIDLIST pidlChild
;
413 item
= TreeView_GetSelection(m_hWnd
);
422 if (x
== -1 && y
== -1)
424 // TODO: grab position of tree item and position it correctly
427 info
= GetNodeInfo(item
);
430 ERR("No node data, something has gone wrong !\n");
433 hr
= SHBindToParent(info
->absolutePidl
, IID_PPV_ARG(IShellFolder
, &pFolder
),
434 (LPCITEMIDLIST
*)&pidlChild
);
437 ERR("Can't bind to folder!\n");
440 hr
= pFolder
->GetUIObjectOf(m_hWnd
, 1, (LPCITEMIDLIST
*)&pidlChild
, IID_IContextMenu
,
441 NULL
, reinterpret_cast<void**>(&contextMenu
));
444 ERR("Can't get IContextMenu interface\n");
448 IUnknown_SetSite(contextMenu
, (IDeskBand
*)this);
450 treeMenu
= CreatePopupMenu();
451 hr
= contextMenu
->QueryContextMenu(treeMenu
, 0, FCIDM_SHVIEWFIRST
, FCIDM_SHVIEWLAST
,
455 WARN("Can't get context menu for item\n");
456 DestroyMenu(treeMenu
);
459 uCommand
= TrackPopupMenu(treeMenu
, TPM_LEFTALIGN
| TPM_RETURNCMD
| TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
,
460 x
, y
, 0, m_hWnd
, NULL
);
462 ExecuteCommand(contextMenu
, uCommand
);
466 IUnknown_SetSite(contextMenu
, NULL
);
468 DestroyMenu(treeMenu
);
469 m_bNavigating
= TRUE
;
470 TreeView_SelectItem(m_hWnd
, m_oldSelected
);
471 m_bNavigating
= FALSE
;
475 LRESULT
CExplorerBand::ContextMenuHack(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
478 if (uMsg
== WM_RBUTTONDOWN
)
481 info
.pt
.x
= LOWORD(lParam
);
482 info
.pt
.y
= HIWORD(lParam
);
483 info
.flags
= TVHT_ONITEM
;
486 // Save the current location
487 m_oldSelected
= TreeView_GetSelection(m_hWnd
);
489 // Move to the item selected by the treeview (don't change right pane)
490 TreeView_HitTest(m_hWnd
, &info
);
491 m_bNavigating
= TRUE
;
492 TreeView_SelectItem(m_hWnd
, info
.hItem
);
493 m_bNavigating
= FALSE
;
495 return FALSE
; /* let the wndproc process the message */
498 LRESULT
CExplorerBand::OnShellEvent(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
504 dest
= (LPITEMIDLIST
*)wParam
;
505 /* TODO: handle shell notifications */
506 switch(lParam
& ~SHCNE_INTERRUPT
)
509 if (!SUCCEEDED(_ReparsePIDL(dest
[0], &clean
)))
511 ERR("Can't reparse PIDL to a valid one\n");
514 NavigateToPIDL(clean
, &pItem
, FALSE
, TRUE
, FALSE
);
520 case SHCNE_RENAMEFOLDER
:
521 if (!SUCCEEDED(_ReparsePIDL(dest
[1], &clean
)))
523 ERR("Can't reparse PIDL to a valid one\n");
526 if (NavigateToPIDL(dest
[0], &pItem
, FALSE
, FALSE
, FALSE
))
527 RenameItem(pItem
, clean
);
530 case SHCNE_UPDATEDIR
:
531 // We don't take care of this message
532 TRACE("Directory updated\n");
535 TRACE("Unhandled message\n");
540 LRESULT
CExplorerBand::OnSetFocus(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
543 IUnknown_OnFocusChangeIS(m_pSite
, reinterpret_cast<IUnknown
*>(this), TRUE
);
548 LRESULT
CExplorerBand::OnKillFocus(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
550 IUnknown_OnFocusChangeIS(m_pSite
, reinterpret_cast<IUnknown
*>(this), FALSE
);
555 // *** Helper functions ***
556 HTREEITEM
CExplorerBand::InsertItem(HTREEITEM hParent
, IShellFolder
*psfParent
, LPITEMIDLIST pElt
, LPITEMIDLIST pEltRelative
, BOOL bSort
)
558 TV_INSERTSTRUCT tvInsert
;
559 HTREEITEM htiCreated
;
561 /* Get the attributes of the node */
562 SFGAOF attrs
= SFGAO_STREAM
| SFGAO_HASSUBFOLDER
;
563 HRESULT hr
= psfParent
->GetAttributesOf(1, &pEltRelative
, &attrs
);
564 if (FAILED_UNEXPECTEDLY(hr
))
568 if ((attrs
& SFGAO_STREAM
))
570 TRACE("Ignoring stream\n");
574 /* Get the name of the node */
575 WCHAR wszDisplayName
[MAX_PATH
];
577 hr
= psfParent
->GetDisplayNameOf(pEltRelative
, SHGDN_INFOLDER
, &strret
);
578 if (FAILED_UNEXPECTEDLY(hr
))
581 hr
= StrRetToBufW(&strret
, pEltRelative
, wszDisplayName
, MAX_PATH
);
582 if (FAILED_UNEXPECTEDLY(hr
))
585 /* Get the icon of the node */
586 INT iIcon
= SHMapPIDLToSystemImageListIndex(psfParent
, pEltRelative
, NULL
);
588 NodeInfo
* pChildInfo
= new NodeInfo
;
591 ERR("Failed to allocate NodeInfo\n");
595 // Store our node info
596 pChildInfo
->absolutePidl
= ILClone(pElt
);
597 pChildInfo
->relativePidl
= ILClone(pEltRelative
);
598 pChildInfo
->expanded
= FALSE
;
600 // Set up our treeview template
601 tvInsert
.hParent
= hParent
;
602 tvInsert
.hInsertAfter
= TVI_LAST
;
603 tvInsert
.item
.mask
= TVIF_PARAM
| TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_CHILDREN
;
604 tvInsert
.item
.cchTextMax
= MAX_PATH
;
605 tvInsert
.item
.pszText
= wszDisplayName
;
606 tvInsert
.item
.iImage
= tvInsert
.item
.iSelectedImage
= iIcon
;
607 tvInsert
.item
.cChildren
= (attrs
& SFGAO_HASSUBFOLDER
) ? 1 : 0;
608 tvInsert
.item
.lParam
= (LPARAM
)pChildInfo
;
610 htiCreated
= TreeView_InsertItem(m_hWnd
, &tvInsert
);
614 TVSORTCB sortCallback
;
615 sortCallback
.hParent
= hParent
;
616 sortCallback
.lpfnCompare
= CompareTreeItems
;
617 sortCallback
.lParam
= (LPARAM
)this;
618 SendMessage(TVM_SORTCHILDRENCB
, 0, (LPARAM
)&sortCallback
);
624 /* This is the slow version of the above method */
625 HTREEITEM
CExplorerBand::InsertItem(HTREEITEM hParent
, LPITEMIDLIST pElt
, LPITEMIDLIST pEltRelative
, BOOL bSort
)
627 CComPtr
<IShellFolder
> psfFolder
;
628 HRESULT hr
= SHBindToParent(pElt
, IID_PPV_ARG(IShellFolder
, &psfFolder
), NULL
);
629 if (FAILED_UNEXPECTEDLY(hr
))
632 return InsertItem(hParent
, psfFolder
, pElt
, pEltRelative
, bSort
);
635 BOOL
CExplorerBand::InsertSubitems(HTREEITEM hItem
, NodeInfo
*pNodeInfo
)
637 CComPtr
<IEnumIDList
> pEnumIDList
;
638 LPITEMIDLIST pidlSub
;
644 CComPtr
<IShellFolder
> pFolder
;
645 TVSORTCB sortCallback
;
647 entry
= pNodeInfo
->absolutePidl
;
650 EnumFlags
= SHCONTF_FOLDERS
;
652 hr
= SHGetFolderLocation(m_hWnd
, CSIDL_DESKTOP
, NULL
, 0, &pidlSub
);
655 ERR("Can't get desktop PIDL !\n");
659 if (!m_pDesktop
->CompareIDs(NULL
, pidlSub
, entry
))
661 // We are the desktop, so use pDesktop as pFolder
662 pFolder
= m_pDesktop
;
666 // Get an IShellFolder of our pidl
667 hr
= m_pDesktop
->BindToObject(entry
, NULL
, IID_PPV_ARG(IShellFolder
, &pFolder
));
671 ERR("Can't bind folder to desktop !\n");
677 // TODO: handle hidden folders according to settings !
678 EnumFlags
|= SHCONTF_INCLUDEHIDDEN
;
680 // Enum through objects
681 hr
= pFolder
->EnumObjects(NULL
,EnumFlags
,&pEnumIDList
);
683 // avoid broken IShellFolder implementations that return null pointer with success
684 if (!SUCCEEDED(hr
) || !pEnumIDList
)
686 ERR("Can't enum the folder !\n");
690 /* Don't redraw while we add stuff into the tree */
691 SendMessage(WM_SETREDRAW
, FALSE
, 0);
692 while(SUCCEEDED(pEnumIDList
->Next(1, &pidlSub
, &fetched
)) && pidlSub
&& fetched
)
694 LPITEMIDLIST pidlSubComplete
;
695 pidlSubComplete
= ILCombine(entry
, pidlSub
);
697 if (InsertItem(hItem
, pFolder
, pidlSubComplete
, pidlSub
, FALSE
))
699 ILFree(pidlSubComplete
);
702 pNodeInfo
->expanded
= TRUE
;
703 /* Let's do sorting */
704 sortCallback
.hParent
= hItem
;
705 sortCallback
.lpfnCompare
= CompareTreeItems
;
706 sortCallback
.lParam
= (LPARAM
)this;
707 SendMessage(TVM_SORTCHILDRENCB
, 0, (LPARAM
)&sortCallback
);
709 /* Now we can redraw */
710 SendMessage(WM_SETREDRAW
, TRUE
, 0);
712 return (uItemCount
> 0) ? TRUE
: FALSE
;
716 * Navigate to a given PIDL in the treeview, and return matching tree item handle
717 * - dest: The absolute PIDL we should navigate in the treeview
718 * - item: Handle of the tree item matching the PIDL
719 * - bExpand: expand collapsed nodes in order to find the right element
720 * - bInsert: insert the element at the right place if we don't find it
721 * - bSelect: select the item after we found it
723 BOOL
CExplorerBand::NavigateToPIDL(LPITEMIDLIST dest
, HTREEITEM
*item
, BOOL bExpand
, BOOL bInsert
,
730 LPITEMIDLIST relativeChild
;
740 nodeData
= GetNodeInfo(current
);
743 ERR("Something has gone wrong, no data associated to node !\n");
747 // If we found our node, give it back
748 if (!m_pDesktop
->CompareIDs(0, nodeData
->absolutePidl
, dest
))
751 TreeView_SelectItem(m_hWnd
, current
);
756 // Check if we are a parent of the requested item
757 relativeChild
= ILFindChild(nodeData
->absolutePidl
, dest
);
758 if (relativeChild
!= 0)
760 // Notify treeview we have children
761 tvItem
.mask
= TVIF_CHILDREN
;
762 tvItem
.hItem
= current
;
763 tvItem
.cChildren
= 1;
764 TreeView_SetItem(m_hWnd
, &tvItem
);
766 // If we can expand and the node isn't expanded yet, do it
769 if (!nodeData
->expanded
)
770 InsertSubitems(current
, nodeData
);
771 TreeView_Expand(m_hWnd
, current
, TVE_EXPAND
);
774 // Try to get a child
775 tmp
= TreeView_GetChild(m_hWnd
, current
);
778 // We have a child, let's continue with it
784 if (bInsert
&& nodeData
->expanded
)
786 // Happens when we have to create a subchild inside a child
787 current
= InsertItem(current
, dest
, relativeChild
, TRUE
);
789 // We end up here, without any children, so we found nothing
790 // Tell the parent node it has children
791 ZeroMemory(&tvItem
, sizeof(tvItem
));
797 tmp
= TreeView_GetNextSibling(m_hWnd
, current
);
805 current
= InsertItem(parent
, dest
, ILFindLastID(dest
), TRUE
);
815 BOOL
CExplorerBand::NavigateToCurrentFolder()
817 LPITEMIDLIST explorerPidl
;
818 CComPtr
<IBrowserService
> pBrowserService
;
824 hr
= IUnknown_QueryService(m_pSite
, SID_STopLevelBrowser
, IID_PPV_ARG(IBrowserService
, &pBrowserService
));
827 ERR("Can't get IBrowserService !\n");
831 hr
= pBrowserService
->GetPidl(&explorerPidl
);
832 if (!SUCCEEDED(hr
) || !explorerPidl
)
834 ERR("Unable to get browser PIDL !\n");
837 m_bNavigating
= TRUE
;
838 /* find PIDL into our explorer */
839 result
= NavigateToPIDL(explorerPidl
, &dummy
, TRUE
, FALSE
, TRUE
);
840 m_bNavigating
= FALSE
;
844 BOOL
CExplorerBand::DeleteItem(LPITEMIDLIST idl
)
848 HTREEITEM parentNode
;
850 if (!NavigateToPIDL(idl
, &toDelete
, FALSE
, FALSE
, FALSE
))
853 // TODO: check that the treeview item is really deleted
855 parentNode
= TreeView_GetParent(m_hWnd
, toDelete
);
856 // Navigate to parent when deleting child item
857 if (!m_pDesktop
->CompareIDs(0, idl
, m_pidlCurrent
))
859 TreeView_SelectItem(m_hWnd
, parentNode
);
862 // Remove the child item
863 TreeView_DeleteItem(m_hWnd
, toDelete
);
864 // Probe parent to see if it has children
865 if (!TreeView_GetChild(m_hWnd
, parentNode
))
867 // Decrement parent's child count
868 ZeroMemory(&tvItem
, sizeof(tvItem
));
869 tvItem
.mask
= TVIF_CHILDREN
;
870 tvItem
.hItem
= parentNode
;
871 tvItem
.cChildren
= 0;
872 TreeView_SetItem(m_hWnd
, &tvItem
);
877 BOOL
CExplorerBand::RenameItem(HTREEITEM toRename
, LPITEMIDLIST newPidl
)
879 WCHAR wszDisplayName
[MAX_PATH
];
881 LPCITEMIDLIST relPidl
;
883 TVSORTCB sortCallback
;
886 ZeroMemory(&itemInfo
, sizeof(itemInfo
));
887 itemInfo
.mask
= TVIF_PARAM
;
888 itemInfo
.hItem
= toRename
;
890 // Change PIDL associated to the item
891 relPidl
= ILFindLastID(newPidl
);
892 TreeView_GetItem(m_hWnd
, &itemInfo
);
893 if (!itemInfo
.lParam
)
895 ERR("Unable to fetch lParam\n");
898 SendMessage(WM_SETREDRAW
, FALSE
, 0);
899 treeInfo
= (NodeInfo
*)itemInfo
.lParam
;
900 ILFree(treeInfo
->absolutePidl
);
901 ILFree(treeInfo
->relativePidl
);
902 treeInfo
->absolutePidl
= ILClone(newPidl
);
903 treeInfo
->relativePidl
= ILClone(relPidl
);
905 // Change the display name
906 GetDisplayName(newPidl
, wszDisplayName
, MAX_PATH
, SHGDN_INFOLDER
);
907 ZeroMemory(&itemInfo
, sizeof(itemInfo
));
908 itemInfo
.hItem
= toRename
;
909 itemInfo
.mask
= TVIF_TEXT
;
910 itemInfo
.pszText
= wszDisplayName
;
911 TreeView_SetItem(m_hWnd
, &itemInfo
);
913 if((child
= TreeView_GetChild(m_hWnd
, toRename
)) != NULL
)
915 RefreshTreePidl(child
, newPidl
);
919 sortCallback
.hParent
= TreeView_GetParent(m_hWnd
, toRename
);
920 sortCallback
.lpfnCompare
= CompareTreeItems
;
921 sortCallback
.lParam
= (LPARAM
)this;
922 SendMessage(TVM_SORTCHILDRENCB
, 0, (LPARAM
)&sortCallback
);
923 SendMessage(WM_SETREDRAW
, TRUE
, 0);
927 BOOL
CExplorerBand::RefreshTreePidl(HTREEITEM tree
, LPITEMIDLIST pidlParent
)
932 // Update our node data
933 pInfo
= GetNodeInfo(tree
);
936 WARN("No tree info !\n");
939 ILFree(pInfo
->absolutePidl
);
940 pInfo
->absolutePidl
= ILCombine(pidlParent
, pInfo
->relativePidl
);
941 if (!pInfo
->absolutePidl
)
943 WARN("PIDL allocation failed\n");
946 // Recursively update children
947 if ((tmp
= TreeView_GetChild(m_hWnd
, tree
)) != NULL
)
949 RefreshTreePidl(tmp
, pInfo
->absolutePidl
);
952 tmp
= TreeView_GetNextSibling(m_hWnd
, tree
);
955 pInfo
= GetNodeInfo(tmp
);
958 WARN("No tree info !\n");
961 ILFree(pInfo
->absolutePidl
);
962 pInfo
->absolutePidl
= ILCombine(pidlParent
, pInfo
->relativePidl
);
963 tmp
= TreeView_GetNextSibling(m_hWnd
, tmp
);
968 // *** Tree item sorting callback ***
969 int CALLBACK
CExplorerBand::CompareTreeItems(LPARAM p1
, LPARAM p2
, LPARAM p3
)
972 * We first sort drive letters (Path root), then PIDLs and then regular folder
974 * This is not how Windows sorts item, but it gives decent results.
978 CExplorerBand
*pThis
;
979 WCHAR wszFolder1
[MAX_PATH
];
980 WCHAR wszFolder2
[MAX_PATH
];
982 info1
= (NodeInfo
*)p1
;
983 info2
= (NodeInfo
*)p2
;
984 pThis
= (CExplorerBand
*)p3
;
986 GetDisplayName(info1
->absolutePidl
, wszFolder1
, MAX_PATH
, SHGDN_FORPARSING
);
987 GetDisplayName(info2
->absolutePidl
, wszFolder2
, MAX_PATH
, SHGDN_FORPARSING
);
988 if (PathIsRoot(wszFolder1
) && PathIsRoot(wszFolder2
))
990 return lstrcmpiW(wszFolder1
,wszFolder2
);
992 if (PathIsRoot(wszFolder1
) && !PathIsRoot(wszFolder2
))
996 if (!PathIsRoot(wszFolder1
) && PathIsRoot(wszFolder2
))
1000 // Now, we compare non-root folders, grab display name
1001 GetDisplayName(info1
->absolutePidl
, wszFolder1
, MAX_PATH
, SHGDN_INFOLDER
);
1002 GetDisplayName(info2
->absolutePidl
, wszFolder2
, MAX_PATH
, SHGDN_INFOLDER
);
1004 if (_ILIsSpecialFolder(info1
->relativePidl
) && !_ILIsSpecialFolder(info2
->relativePidl
))
1008 if (!_ILIsSpecialFolder(info1
->relativePidl
) && _ILIsSpecialFolder(info2
->relativePidl
))
1012 if (_ILIsSpecialFolder(info1
->relativePidl
) && !_ILIsSpecialFolder(info2
->relativePidl
))
1015 hr
= pThis
->m_pDesktop
->CompareIDs(0, info1
->absolutePidl
, info2
->absolutePidl
);
1017 return (hr
> 0) ? -1 : 1;
1019 return StrCmpLogicalW(wszFolder1
, wszFolder2
);
1022 // *** IOleWindow methods ***
1023 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetWindow(HWND
*lphwnd
)
1026 return E_INVALIDARG
;
1031 HRESULT STDMETHODCALLTYPE
CExplorerBand::ContextSensitiveHelp(BOOL fEnterMode
)
1038 // *** IDockingWindow methods ***
1039 HRESULT STDMETHODCALLTYPE
CExplorerBand::CloseDW(DWORD dwReserved
)
1041 // We do nothing, we don't have anything to save yet
1042 TRACE("CloseDW called\n");
1046 HRESULT STDMETHODCALLTYPE
CExplorerBand::ResizeBorderDW(const RECT
*prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
1048 /* Must return E_NOTIMPL according to MSDN */
1052 HRESULT STDMETHODCALLTYPE
CExplorerBand::ShowDW(BOOL fShow
)
1060 // *** IDeskBand methods ***
1061 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetBandInfo(DWORD dwBandID
, DWORD dwViewMode
, DESKBANDINFO
*pdbi
)
1065 return E_INVALIDARG
;
1067 this->m_dwBandID
= dwBandID
;
1069 if (pdbi
->dwMask
& DBIM_MINSIZE
)
1071 pdbi
->ptMinSize
.x
= 200;
1072 pdbi
->ptMinSize
.y
= 30;
1075 if (pdbi
->dwMask
& DBIM_MAXSIZE
)
1077 pdbi
->ptMaxSize
.y
= -1;
1080 if (pdbi
->dwMask
& DBIM_INTEGRAL
)
1082 pdbi
->ptIntegral
.y
= 1;
1085 if (pdbi
->dwMask
& DBIM_ACTUAL
)
1087 pdbi
->ptActual
.x
= 200;
1088 pdbi
->ptActual
.y
= 30;
1091 if (pdbi
->dwMask
& DBIM_TITLE
)
1093 if (!LoadStringW(_AtlBaseModule
.GetResourceInstance(), IDS_FOLDERSLABEL
, pdbi
->wszTitle
, _countof(pdbi
->wszTitle
)))
1094 return HRESULT_FROM_WIN32(GetLastError());
1097 if (pdbi
->dwMask
& DBIM_MODEFLAGS
)
1099 pdbi
->dwModeFlags
= DBIMF_NORMAL
| DBIMF_VARIABLEHEIGHT
;
1102 if (pdbi
->dwMask
& DBIM_BKCOLOR
)
1104 pdbi
->dwMask
&= ~DBIM_BKCOLOR
;
1110 // *** IObjectWithSite methods ***
1111 HRESULT STDMETHODCALLTYPE
CExplorerBand::SetSite(IUnknown
*pUnkSite
)
1116 if (pUnkSite
== m_pSite
)
1119 TRACE("SetSite called \n");
1122 DestroyExplorerBand();
1127 if (pUnkSite
!= m_pSite
)
1135 hr
= IUnknown_GetWindow(pUnkSite
, &parentWnd
);
1138 ERR("Could not get parent's window ! Status: %08lx\n", hr
);
1139 return E_INVALIDARG
;
1146 // Change its parent
1147 SetParent(parentWnd
);
1151 HWND wnd
= CreateWindow(WC_TREEVIEW
, NULL
,
1152 WS_CHILD
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| TVS_HASLINES
| TVS_HASBUTTONS
| TVS_SHOWSELALWAYS
| TVS_EDITLABELS
/* | TVS_SINGLEEXPAND*/ , // remove TVS_SINGLEEXPAND for now since it has strange behaviour
1153 0, 0, 0, 0, parentWnd
, NULL
, _AtlBaseModule
.GetModuleInstance(), NULL
);
1155 // Subclass the window
1156 SubclassWindow(wnd
);
1158 // Initialize our treeview now
1159 InitializeExplorerBand();
1160 RegisterDragDrop(m_hWnd
, dynamic_cast<IDropTarget
*>(this));
1165 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetSite(REFIID riid
, void **ppvSite
)
1174 // *** IOleCommandTarget methods ***
1175 HRESULT STDMETHODCALLTYPE
CExplorerBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
1181 HRESULT STDMETHODCALLTYPE
CExplorerBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
1188 // *** IServiceProvider methods ***
1189 HRESULT STDMETHODCALLTYPE
CExplorerBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
1191 /* FIXME: we probably want to handle more services here */
1192 return IUnknown_QueryService(m_pSite
, SID_SShellBrowser
, riid
, ppvObject
);
1196 // *** IInputObject methods ***
1197 HRESULT STDMETHODCALLTYPE
CExplorerBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
1204 // TODO: handle message
1207 TranslateMessage(lpMsg
);
1208 DispatchMessage(lpMsg
);
1213 HRESULT STDMETHODCALLTYPE
CExplorerBand::HasFocusIO()
1215 return m_bFocused
? S_OK
: S_FALSE
;
1218 HRESULT STDMETHODCALLTYPE
CExplorerBand::TranslateAcceleratorIO(LPMSG lpMsg
)
1220 if (lpMsg
->hwnd
== m_hWnd
)
1222 TranslateMessage(lpMsg
);
1223 DispatchMessage(lpMsg
);
1230 // *** IPersist methods ***
1231 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetClassID(CLSID
*pClassID
)
1235 memcpy(pClassID
, &CLSID_ExplorerBand
, sizeof(CLSID
));
1240 // *** IPersistStream methods ***
1241 HRESULT STDMETHODCALLTYPE
CExplorerBand::IsDirty()
1247 HRESULT STDMETHODCALLTYPE
CExplorerBand::Load(IStream
*pStm
)
1253 HRESULT STDMETHODCALLTYPE
CExplorerBand::Save(IStream
*pStm
, BOOL fClearDirty
)
1259 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
1261 // TODO: calculate max size
1267 // *** IWinEventHandler methods ***
1268 HRESULT STDMETHODCALLTYPE
CExplorerBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1273 if (uMsg
== WM_NOTIFY
)
1275 NMHDR
*pNotifyHeader
= (NMHDR
*)lParam
;
1276 switch (pNotifyHeader
->code
)
1278 case TVN_ITEMEXPANDING
:
1279 result
= OnTreeItemExpanding((LPNMTREEVIEW
)lParam
);
1281 *theResult
= result
;
1283 case TVN_SELCHANGED
:
1284 OnSelectionChanged((LPNMTREEVIEW
)lParam
);
1286 case TVN_DELETEITEM
:
1287 OnTreeItemDeleted((LPNMTREEVIEW
)lParam
);
1290 OnContextMenu(WM_CONTEXTMENU
, (WPARAM
)m_hWnd
, GetMessagePos(), bHandled
);
1295 case TVN_BEGINRDRAG
:
1296 OnTreeItemDragging((LPNMTREEVIEW
)lParam
, pNotifyHeader
->code
== TVN_BEGINRDRAG
);
1297 case TVN_BEGINLABELEDITW
:
1299 // TODO: put this in a function ? (mostly copypasta from CDefView)
1300 DWORD dwAttr
= SFGAO_CANRENAME
;
1301 LPNMTVDISPINFO dispInfo
= (LPNMTVDISPINFO
)lParam
;
1302 CComPtr
<IShellFolder
> pParent
;
1303 LPCITEMIDLIST pChild
;
1308 NodeInfo
*info
= GetNodeInfo(dispInfo
->item
.hItem
);
1311 hr
= SHBindToParent(info
->absolutePidl
, IID_PPV_ARG(IShellFolder
, &pParent
), &pChild
);
1312 if (!SUCCEEDED(hr
) || !pParent
.p
)
1315 hr
= pParent
->GetAttributesOf(1, &pChild
, &dwAttr
);
1316 if (SUCCEEDED(hr
) && (dwAttr
& SFGAO_CANRENAME
) && theResult
)
1320 case TVN_ENDLABELEDITW
:
1322 LPNMTVDISPINFO dispInfo
= (LPNMTVDISPINFO
)lParam
;
1323 NodeInfo
*info
= GetNodeInfo(dispInfo
->item
.hItem
);
1328 if (dispInfo
->item
.pszText
)
1330 LPITEMIDLIST pidlNew
;
1331 CComPtr
<IShellFolder
> pParent
;
1332 LPCITEMIDLIST pidlChild
;
1334 hr
= SHBindToParent(info
->absolutePidl
, IID_PPV_ARG(IShellFolder
, &pParent
), &pidlChild
);
1335 if (!SUCCEEDED(hr
) || !pParent
.p
)
1338 hr
= pParent
->SetNameOf(0, pidlChild
, dispInfo
->item
.pszText
, SHGDN_INFOLDER
, &pidlNew
);
1339 if(SUCCEEDED(hr
) && pidlNew
)
1341 CComPtr
<IPersistFolder2
> pPersist
;
1342 LPITEMIDLIST pidlParent
, pidlNewAbs
;
1344 hr
= pParent
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pPersist
));
1348 hr
= pPersist
->GetCurFolder(&pidlParent
);
1351 pidlNewAbs
= ILCombine(pidlParent
, pidlNew
);
1353 // Navigate to our new location
1354 UpdateBrowser(pidlNewAbs
);
1372 HRESULT STDMETHODCALLTYPE
CExplorerBand::IsWindowOwner(HWND hWnd
)
1374 return (hWnd
== m_hWnd
) ? S_OK
: S_FALSE
;
1377 // *** IBandNavigate methods ***
1378 HRESULT STDMETHODCALLTYPE
CExplorerBand::Select(long paramC
)
1384 // *** INamespaceProxy ***
1385 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetNavigateTarget(long paramC
, long param10
, long param14
)
1391 HRESULT STDMETHODCALLTYPE
CExplorerBand::Invoke(long paramC
)
1397 HRESULT STDMETHODCALLTYPE
CExplorerBand::OnSelectionChanged(long paramC
)
1403 HRESULT STDMETHODCALLTYPE
CExplorerBand::RefreshFlags(long paramC
, long param10
, long param14
)
1409 HRESULT STDMETHODCALLTYPE
CExplorerBand::CacheItem(long paramC
)
1415 // *** IDispatch methods ***
1416 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetTypeInfoCount(UINT
*pctinfo
)
1422 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetTypeInfo(UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
1428 HRESULT STDMETHODCALLTYPE
CExplorerBand::GetIDsOfNames(REFIID riid
, LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1434 HRESULT STDMETHODCALLTYPE
CExplorerBand::Invoke(DISPID dispIdMember
, REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1436 switch (dispIdMember
)
1438 case DISPID_DOWNLOADCOMPLETE
:
1439 case DISPID_NAVIGATECOMPLETE2
:
1440 TRACE("DISPID_NAVIGATECOMPLETE2 received\n");
1441 NavigateToCurrentFolder();
1444 TRACE("Unknown dispid requested: %08x\n", dispIdMember
);
1445 return E_INVALIDARG
;
1448 // *** IDropTarget methods ***
1449 HRESULT STDMETHODCALLTYPE
CExplorerBand::DragEnter(IDataObject
*pObj
, DWORD glfKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1451 ERR("Entering drag\n");
1452 m_pCurObject
= pObj
;
1453 m_oldSelected
= TreeView_GetSelection(m_hWnd
);
1454 return DragOver(glfKeyState
, pt
, pdwEffect
);
1457 HRESULT STDMETHODCALLTYPE
CExplorerBand::DragOver(DWORD glfKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1460 CComPtr
<IShellFolder
> pShellFldr
;
1462 //LPCITEMIDLIST pChild;
1467 info
.flags
= TVHT_ONITEM
;
1469 ScreenToClient(&info
.pt
);
1471 // Move to the item selected by the treeview (don't change right pane)
1472 TreeView_HitTest(m_hWnd
, &info
);
1476 m_bNavigating
= TRUE
;
1477 TreeView_SelectItem(m_hWnd
, info
.hItem
);
1478 m_bNavigating
= FALSE
;
1479 // Delegate to shell folder
1480 if (m_pDropTarget
&& info
.hItem
!= m_childTargetNode
)
1482 m_pDropTarget
= NULL
;
1484 if (info
.hItem
!= m_childTargetNode
)
1486 nodeInfo
= GetNodeInfo(info
.hItem
);
1490 hr
= SHBindToParent(nodeInfo
->absolutePidl
, IID_PPV_ARG(IShellFolder
, &pShellFldr
), &pChild
);
1493 hr
= pShellFldr
->GetUIObjectOf(m_hWnd
, 1, &pChild
, IID_IDropTarget
, NULL
, reinterpret_cast<void**>(&pDropTarget
));
1497 if(_ILIsDesktop(nodeInfo
->absolutePidl
))
1498 pShellFldr
= m_pDesktop
;
1501 hr
= m_pDesktop
->BindToObject(nodeInfo
->absolutePidl
, 0, IID_PPV_ARG(IShellFolder
, &pShellFldr
));
1504 /* Don't allow dnd since we couldn't get our folder object */
1505 ERR("Can't bind to folder object\n");
1506 *pdwEffect
= DROPEFFECT_NONE
;
1510 hr
= pShellFldr
->CreateViewObject(m_hWnd
, IID_PPV_ARG(IDropTarget
, &m_pDropTarget
));
1513 /* Don't allow dnd since we couldn't get our drop target */
1514 ERR("Can't get drop target for folder object\n");
1515 *pdwEffect
= DROPEFFECT_NONE
;
1518 hr
= m_pDropTarget
->DragEnter(m_pCurObject
, glfKeyState
, pt
, pdwEffect
);
1519 m_childTargetNode
= info
.hItem
;
1523 hr
= m_pDropTarget
->DragOver(glfKeyState
, pt
, pdwEffect
);
1528 m_childTargetNode
= NULL
;
1529 m_pDropTarget
= NULL
;
1530 *pdwEffect
= DROPEFFECT_NONE
;
1535 HRESULT STDMETHODCALLTYPE
CExplorerBand::DragLeave()
1537 m_bNavigating
= TRUE
;
1538 TreeView_SelectItem(m_hWnd
, m_oldSelected
);
1539 m_bNavigating
= FALSE
;
1540 m_childTargetNode
= NULL
;
1543 m_pCurObject
= NULL
;
1548 HRESULT STDMETHODCALLTYPE
CExplorerBand::Drop(IDataObject
*pObj
, DWORD glfKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1552 m_pDropTarget
->Drop(pObj
, glfKeyState
, pt
, pdwEffect
);
1557 // *** IDropSource methods ***
1558 HRESULT STDMETHODCALLTYPE
CExplorerBand::QueryContinueDrag(BOOL fEscapePressed
, DWORD grfKeyState
)
1561 return DRAGDROP_S_CANCEL
;
1562 if ((grfKeyState
& MK_LBUTTON
) || (grfKeyState
& MK_RBUTTON
))
1564 return DRAGDROP_S_DROP
;
1567 HRESULT STDMETHODCALLTYPE
CExplorerBand::GiveFeedback(DWORD dwEffect
)
1569 return DRAGDROP_S_USEDEFAULTCURSORS
;