[BROWSEUI]

-CExplorerBand: Commit the last part of the work submitted by Sylvain Deverre. Sorry for not committing all this time. Unfortunately some parts were changed and some parts don't work well and we need to debug it a bit.
CORE-10838

svn path=/trunk/; revision=73706
This commit is contained in:
Giannis Adamopoulos 2017-02-05 13:41:45 +00:00
parent 2ee2be0a07
commit 1b634b38ec
2 changed files with 555 additions and 16 deletions

View file

@ -28,13 +28,148 @@
#define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__) #define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
#endif #endif
/*
* TODO:
* - Monitor correctly "external" shell interrupts (seems like we need to register/deregister them for each folder)
* - find and fix what cause explorer crashes sometimes (seems to be explorer that does more releases than addref)
* - TESTING
*/
typedef struct _PIDLDATA
{
BYTE type;
BYTE data[1];
} PIDLDATA, *LPPIDLDATA;
#define PT_GUID 0x1F
#define PT_SHELLEXT 0x2E
#define PT_YAGUID 0x70
static BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
{
LPPIDLDATA lpPData = (LPPIDLDATA)&pidl->mkid.abID;
return (pidl &&
((lpPData && (PT_GUID == lpPData->type || PT_SHELLEXT== lpPData->type ||
PT_YAGUID == lpPData->type)) || (pidl && pidl->mkid.cb == 0x00)));
}
static BOOL _ILIsDesktop (LPCITEMIDLIST pidl)
{
return (pidl && pidl->mkid.cb == 0x00);
}
HRESULT GetDisplayName(LPCITEMIDLIST pidlDirectory,TCHAR *szDisplayName,UINT cchMax,DWORD uFlags)
{
IShellFolder *pShellFolder = NULL;
LPCITEMIDLIST pidlRelative = NULL;
STRRET str;
HRESULT hr;
if (pidlDirectory == NULL || szDisplayName == NULL)
{
return E_FAIL;
}
hr = SHBindToParent(pidlDirectory, IID_PPV_ARG(IShellFolder, &pShellFolder), &pidlRelative);
if (SUCCEEDED(hr))
{
hr = pShellFolder->GetDisplayNameOf(pidlRelative,uFlags,&str);
if (SUCCEEDED(hr))
{
hr = StrRetToBuf(&str,pidlDirectory,szDisplayName,cchMax);
}
pShellFolder->Release();
}
return hr;
}
extern "C"
HRESULT WINAPI CExplorerBand_Constructor(REFIID riid, LPVOID *ppv)
{
#ifdef __REACTOS__
return ShellObjectCreator<CExplorerBand>(riid, ppv);
#else
return S_OK;
#endif
}
/*
This is a Windows hack, because shell event messages in Windows gives an
ill-formed PIDL stripped from useful data that parses incorrectly with SHGetFileInfo.
So we need to re-enumerate subfolders until we find one with the same name.
*/
HRESULT _ReparsePIDL(LPITEMIDLIST buggyPidl, LPITEMIDLIST *cleanPidl)
{
HRESULT hr;
CComPtr<IShellFolder> folder;
CComPtr<IPersistFolder2> persist;
CComPtr<IEnumIDList> pEnumIDList;
LPITEMIDLIST childPidl;
LPITEMIDLIST correctChild;
LPITEMIDLIST correctParent;
ULONG fetched;
DWORD EnumFlags;
EnumFlags = SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
hr = SHBindToParent(buggyPidl, IID_PPV_ARG(IShellFolder, &folder), (LPCITEMIDLIST*)&childPidl);
*cleanPidl = NULL;
if (!SUCCEEDED(hr))
{
ERR("Can't bind to parent folder\n");
return hr;
}
hr = folder->QueryInterface(IID_PPV_ARG(IPersistFolder2, &persist));
if (!SUCCEEDED(hr))
{
ERR("PIDL doesn't belong to the shell namespace, aborting\n");
return hr;
}
hr = persist->GetCurFolder(&correctParent);
if (!SUCCEEDED(hr))
{
ERR("Unable to get current folder\n");
return hr;
}
hr = folder->EnumObjects(NULL,EnumFlags,&pEnumIDList);
// avoid broken IShellFolder implementations that return null pointer with success
if (!SUCCEEDED(hr) || !pEnumIDList)
{
ERR("Can't enum the folder !\n");
return hr;
}
while(SUCCEEDED(pEnumIDList->Next(1, &correctChild, &fetched)) && correctChild && fetched)
{
if (!folder->CompareIDs(0, childPidl, correctChild))
{
*cleanPidl = ILCombine(correctParent, correctChild);
ILFree(correctChild);
goto Cleanup;
}
ILFree(correctChild);
}
Cleanup:
ILFree(correctParent);
return hr;
}
CExplorerBand::CExplorerBand() : CExplorerBand::CExplorerBand() :
pSite(NULL), fVisible(FALSE), bNavigating(FALSE), dwBandID(0) pSite(NULL), fVisible(FALSE), bNavigating(FALSE), dwBandID(0), pidlCurrent(NULL)
{ {
} }
CExplorerBand::~CExplorerBand() CExplorerBand::~CExplorerBand()
{ {
if(pidlCurrent)
{
ILFree(pidlCurrent);
}
} }
void CExplorerBand::InitializeExplorerBand() void CExplorerBand::InitializeExplorerBand()
@ -176,6 +311,11 @@ HRESULT CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto)
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
if(pidlCurrent)
{
ILFree(pidlCurrent);
pidlCurrent = ILClone(pidlGoto);
}
return hr; return hr;
} }
@ -214,6 +354,17 @@ BOOL CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv)
return FALSE; return FALSE;
} }
BOOL CExplorerBand::OnTreeItemDeleted(LPNMTREEVIEW pnmtv)
{
/* Destroy memory associated to our node */
NodeInfo* ptr = GetNodeInfo(pnmtv->itemNew.hItem);
ILFree(ptr->relativePidl);
ILFree(ptr->absolutePidl);
delete ptr;
return TRUE;
}
void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv) void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
{ {
NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem); NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
@ -229,6 +380,29 @@ void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
//TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND); //TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
} }
void CExplorerBand::OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick)
{
CComPtr<IShellFolder> pSrcFolder;
CComPtr<IDataObject> pObj;
LPCITEMIDLIST pLast;
HRESULT hr;
DWORD dwEffect;
DWORD dwEffect2;
dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
if (!pnmtv->itemNew.lParam)
return;
NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
hr = SHBindToParent(pNodeInfo->absolutePidl, IID_PPV_ARG(IShellFolder, &pSrcFolder), &pLast);
if (!SUCCEEDED(hr))
return;
hr = pSrcFolder->GetUIObjectOf(m_hWnd, 1, &pLast, IID_IDataObject, 0, reinterpret_cast<void**>(&pObj));
if (!SUCCEEDED(hr))
return;
DoDragDrop(pObj, this, dwEffect, &dwEffect2);
return;
}
// *** ATL event handlers *** // *** ATL event handlers ***
LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
@ -323,6 +497,64 @@ LRESULT CExplorerBand::ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam,
} }
return FALSE; /* let the wndproc process the message */ return FALSE; /* let the wndproc process the message */
} }
LRESULT CExplorerBand::OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
LPITEMIDLIST *dest;
LPITEMIDLIST clean;
HTREEITEM pItem;
dest = (LPITEMIDLIST*)wParam;
/* TODO: handle shell notifications */
switch(lParam & ~SHCNE_INTERRUPT)
{
case SHCNE_MKDIR:
if (!SUCCEEDED(_ReparsePIDL(dest[0], &clean)))
{
ERR("Can't reparse PIDL to a valid one\n");
return FALSE;
}
NavigateToPIDL(clean, &pItem, FALSE, TRUE, FALSE);
ILFree(clean);
break;
case SHCNE_RMDIR:
DeleteItem(dest[0]);
break;
case SHCNE_RENAMEFOLDER:
if (!SUCCEEDED(_ReparsePIDL(dest[1], &clean)))
{
ERR("Can't reparse PIDL to a valid one\n");
return FALSE;
}
if (NavigateToPIDL(dest[0], &pItem, FALSE, FALSE, FALSE))
RenameItem(pItem, clean);
ILFree(clean);
break;
case SHCNE_UPDATEDIR:
// We don't take care of this message
TRACE("Directory updated\n");
break;
default:
TRACE("Unhandled message\n");
}
return TRUE;
}
LRESULT CExplorerBand::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bFocused = TRUE;
IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), TRUE);
bHandled = FALSE;
return TRUE;
}
LRESULT CExplorerBand::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), FALSE);
bHandled = FALSE;
return TRUE;
}
// *** Helper functions *** // *** Helper functions ***
HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort) HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort)
{ {
@ -377,6 +609,15 @@ HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent,
htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert); htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert);
if (bSort)
{
TVSORTCB sortCallback;
sortCallback.hParent = hParent;
sortCallback.lpfnCompare = CompareTreeItems;
sortCallback.lParam = (LPARAM)this;
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
}
return htiCreated; return htiCreated;
} }
@ -401,6 +642,7 @@ BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
ULONG fetched; ULONG fetched;
ULONG uItemCount; ULONG uItemCount;
CComPtr<IShellFolder> pFolder; CComPtr<IShellFolder> pFolder;
TVSORTCB sortCallback;
entry = pNodeInfo->absolutePidl; entry = pNodeInfo->absolutePidl;
fetched = 1; fetched = 1;
@ -458,6 +700,11 @@ BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
ILFree(pidlSub); ILFree(pidlSub);
} }
pNodeInfo->expanded = TRUE; pNodeInfo->expanded = TRUE;
/* Let's do sorting */
sortCallback.hParent = hItem;
sortCallback.lpfnCompare = CompareTreeItems;
sortCallback.lParam = (LPARAM)this;
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
/* Now we can redraw */ /* Now we can redraw */
SendMessage(WM_SETREDRAW, TRUE, 0); SendMessage(WM_SETREDRAW, TRUE, 0);
@ -596,6 +843,184 @@ BOOL CExplorerBand::NavigateToCurrentFolder()
return result; return result;
} }
BOOL CExplorerBand::DeleteItem(LPITEMIDLIST idl)
{
HTREEITEM toDelete;
TVITEM tvItem;
HTREEITEM parentNode;
if (!NavigateToPIDL(idl, &toDelete, FALSE, FALSE, FALSE))
return FALSE;
// TODO: check that the treeview item is really deleted
parentNode = TreeView_GetParent(m_hWnd, toDelete);
// Navigate to parent when deleting child item
if (!pDesktop->CompareIDs(0, idl, pidlCurrent))
{
TreeView_SelectItem(m_hWnd, parentNode);
}
// Remove the child item
TreeView_DeleteItem(m_hWnd, toDelete);
// Probe parent to see if it has children
if (!TreeView_GetChild(m_hWnd, parentNode))
{
// Decrement parent's child count
ZeroMemory(&tvItem, sizeof(tvItem));
tvItem.mask = TVIF_CHILDREN;
tvItem.hItem = parentNode;
tvItem.cChildren = 0;
TreeView_SetItem(m_hWnd, &tvItem);
}
return TRUE;
}
BOOL CExplorerBand::RenameItem(HTREEITEM toRename, LPITEMIDLIST newPidl)
{
WCHAR wszDisplayName[MAX_PATH];
TVITEM itemInfo;
LPCITEMIDLIST relPidl;
NodeInfo *treeInfo;
TVSORTCB sortCallback;
HTREEITEM child;
ZeroMemory(&itemInfo, sizeof(itemInfo));
itemInfo.mask = TVIF_PARAM;
itemInfo.hItem = toRename;
// Change PIDL associated to the item
relPidl = ILFindLastID(newPidl);
TreeView_GetItem(m_hWnd, &itemInfo);
if (!itemInfo.lParam)
{
ERR("Unable to fetch lParam\n");
return FALSE;
}
SendMessage(WM_SETREDRAW, FALSE, 0);
treeInfo = (NodeInfo*)itemInfo.lParam;
ILFree(treeInfo->absolutePidl);
ILFree(treeInfo->relativePidl);
treeInfo->absolutePidl = ILClone(newPidl);
treeInfo->relativePidl = ILClone(relPidl);
// Change the display name
GetDisplayName(newPidl, wszDisplayName, MAX_PATH, SHGDN_INFOLDER);
ZeroMemory(&itemInfo, sizeof(itemInfo));
itemInfo.hItem = toRename;
itemInfo.mask = TVIF_TEXT;
itemInfo.pszText = wszDisplayName;
TreeView_SetItem(m_hWnd, &itemInfo);
if((child = TreeView_GetChild(m_hWnd, toRename)) != NULL)
{
RefreshTreePidl(child, newPidl);
}
// Sorting
sortCallback.hParent = TreeView_GetParent(m_hWnd, toRename);
sortCallback.lpfnCompare = CompareTreeItems;
sortCallback.lParam = (LPARAM)this;
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
SendMessage(WM_SETREDRAW, TRUE, 0);
return TRUE;
}
BOOL CExplorerBand::RefreshTreePidl(HTREEITEM tree, LPITEMIDLIST pidlParent)
{
HTREEITEM tmp;
NodeInfo *pInfo;
// Update our node data
pInfo = GetNodeInfo(tree);
if (!pInfo)
{
WARN("No tree info !\n");
return FALSE;
}
ILFree(pInfo->absolutePidl);
pInfo->absolutePidl = ILCombine(pidlParent, pInfo->relativePidl);
if (!pInfo->absolutePidl)
{
WARN("PIDL allocation failed\n");
return FALSE;
}
// Recursively update children
if ((tmp = TreeView_GetChild(m_hWnd, tree)) != NULL)
{
RefreshTreePidl(tmp, pInfo->absolutePidl);
}
tmp = TreeView_GetNextSibling(m_hWnd, tree);
while(tmp != NULL)
{
pInfo = GetNodeInfo(tmp);
if(!pInfo)
{
WARN("No tree info !\n");
continue;
}
ILFree(pInfo->absolutePidl);
pInfo->absolutePidl = ILCombine(pidlParent, pInfo->relativePidl);
tmp = TreeView_GetNextSibling(m_hWnd, tmp);
}
return TRUE;
}
// *** Tree item sorting callback ***
int CALLBACK CExplorerBand::CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3)
{
/*
* We first sort drive letters (Path root), then PIDLs and then regular folder
* display name.
* This is not how Windows sorts item, but it gives decent results.
*/
NodeInfo *info1;
NodeInfo *info2;
CExplorerBand *pThis;
WCHAR wszFolder1[MAX_PATH];
WCHAR wszFolder2[MAX_PATH];
info1 = (NodeInfo*)p1;
info2 = (NodeInfo*)p2;
pThis = (CExplorerBand*)p3;
GetDisplayName(info1->absolutePidl, wszFolder1, MAX_PATH, SHGDN_FORPARSING);
GetDisplayName(info2->absolutePidl, wszFolder2, MAX_PATH, SHGDN_FORPARSING);
if (PathIsRoot(wszFolder1) && PathIsRoot(wszFolder2))
{
return lstrcmpiW(wszFolder1,wszFolder2);
}
if (PathIsRoot(wszFolder1) && !PathIsRoot(wszFolder2))
{
return -1;
}
if (!PathIsRoot(wszFolder1) && PathIsRoot(wszFolder2))
{
return 1;
}
// Now, we compare non-root folders, grab display name
GetDisplayName(info1->absolutePidl, wszFolder1, MAX_PATH, SHGDN_INFOLDER);
GetDisplayName(info2->absolutePidl, wszFolder2, MAX_PATH, SHGDN_INFOLDER);
if (_ILIsSpecialFolder(info1->relativePidl) && !_ILIsSpecialFolder(info2->relativePidl))
{
return -1;
}
if (!_ILIsSpecialFolder(info1->relativePidl) && _ILIsSpecialFolder(info2->relativePidl))
{
return 1;
}
if (_ILIsSpecialFolder(info1->relativePidl) && !_ILIsSpecialFolder(info2->relativePidl))
{
HRESULT hr;
hr = pThis->pDesktop->CompareIDs(0, info1->absolutePidl, info2->absolutePidl);
if (!hr) return 0;
return (hr > 0) ? -1 : 1;
}
return StrCmpLogicalW(wszFolder1, wszFolder2);
}
// *** IOleWindow methods *** // *** IOleWindow methods ***
HRESULT STDMETHODCALLTYPE CExplorerBand::GetWindow(HWND *lphwnd) HRESULT STDMETHODCALLTYPE CExplorerBand::GetWindow(HWND *lphwnd)
{ {
@ -835,6 +1260,7 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::Save(IStream *pStm, BOOL fClearDirty)
HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize) HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
{ {
// TODO: calculate max size
UNIMPLEMENTED; UNIMPLEMENTED;
return E_NOTIMPL; return E_NOTIMPL;
} }
@ -855,10 +1281,16 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM
case TVN_SELCHANGED: case TVN_SELCHANGED:
OnSelectionChanged((LPNMTREEVIEW)lParam); OnSelectionChanged((LPNMTREEVIEW)lParam);
break; break;
case TVN_DELETEITEM:
OnTreeItemDeleted((LPNMTREEVIEW)lParam);
break;
case NM_RCLICK: case NM_RCLICK:
OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(), bHandled); OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(), bHandled);
*theResult = 1; *theResult = 1;
break; break;
case TVN_BEGINDRAG:
case TVN_BEGINRDRAG:
OnTreeItemDragging((LPNMTREEVIEW)lParam, pNotifyHeader->code == TVN_BEGINRDRAG);
case TVN_BEGINLABELEDITW: case TVN_BEGINLABELEDITW:
{ {
// TODO: put this in a function ? (mostly copypasta from CDefView) // TODO: put this in a function ? (mostly copypasta from CDefView)
@ -1009,37 +1441,120 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::Invoke(DISPID dispIdMember, REFIID riid
// *** IDropTarget methods *** // *** IDropTarget methods ***
HRESULT STDMETHODCALLTYPE CExplorerBand::DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect) HRESULT STDMETHODCALLTYPE CExplorerBand::DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
{ {
UNIMPLEMENTED; ERR("Entering drag\n");
return E_NOTIMPL; pCurObject = pObj;
oldSelected = TreeView_GetSelection(m_hWnd);
return DragOver(glfKeyState, pt, pdwEffect);
} }
HRESULT STDMETHODCALLTYPE CExplorerBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect) HRESULT STDMETHODCALLTYPE CExplorerBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
{ {
UNIMPLEMENTED; TVHITTESTINFO info;
return E_NOTIMPL; CComPtr<IShellFolder> pShellFldr;
NodeInfo *nodeInfo;
//LPCITEMIDLIST pChild;
HRESULT hr;
info.pt.x = pt.x;
info.pt.y = pt.y;
info.flags = TVHT_ONITEM;
info.hItem = NULL;
ScreenToClient(&info.pt);
// Move to the item selected by the treeview (don't change right pane)
TreeView_HitTest(m_hWnd, &info);
if (info.hItem)
{
bNavigating = TRUE;
TreeView_SelectItem(m_hWnd, info.hItem);
bNavigating = FALSE;
// Delegate to shell folder
if (pDropTarget && info.hItem != childTargetNode)
{
pDropTarget = NULL;
}
if (info.hItem != childTargetNode)
{
nodeInfo = GetNodeInfo(info.hItem);
if (!nodeInfo)
return E_FAIL;
#if 0
hr = SHBindToParent(nodeInfo->absolutePidl, IID_PPV_ARG(IShellFolder, &pShellFldr), &pChild);
if (!SUCCEEDED(hr))
return E_FAIL;
hr = pShellFldr->GetUIObjectOf(m_hWnd, 1, &pChild, IID_IDropTarget, NULL, reinterpret_cast<void**>(&pDropTarget));
if (!SUCCEEDED(hr))
return E_FAIL;
#endif
if(_ILIsDesktop(nodeInfo->absolutePidl))
pShellFldr = pDesktop;
else
{
hr = pDesktop->BindToObject(nodeInfo->absolutePidl, 0, IID_PPV_ARG(IShellFolder, &pShellFldr));
if (!SUCCEEDED(hr))
{
/* Don't allow dnd since we couldn't get our folder object */
ERR("Can't bind to folder object\n");
*pdwEffect = DROPEFFECT_NONE;
return E_FAIL;
}
}
hr = pShellFldr->CreateViewObject(m_hWnd, IID_PPV_ARG(IDropTarget, &pDropTarget));
if (!SUCCEEDED(hr))
{
/* Don't allow dnd since we couldn't get our drop target */
ERR("Can't get drop target for folder object\n");
*pdwEffect = DROPEFFECT_NONE;
return E_FAIL;
}
hr = pDropTarget->DragEnter(pCurObject, glfKeyState, pt, pdwEffect);
childTargetNode = info.hItem;
}
hr = pDropTarget->DragOver(glfKeyState, pt, pdwEffect);
}
else
{
childTargetNode = NULL;
pDropTarget = NULL;
*pdwEffect = DROPEFFECT_NONE;
}
return S_OK;
} }
HRESULT STDMETHODCALLTYPE CExplorerBand::DragLeave() HRESULT STDMETHODCALLTYPE CExplorerBand::DragLeave()
{ {
UNIMPLEMENTED; bNavigating = TRUE;
return E_NOTIMPL; TreeView_SelectItem(m_hWnd, oldSelected);
bNavigating = FALSE;
childTargetNode = NULL;
if (pCurObject)
{
pCurObject = NULL;
}
return S_OK;
} }
HRESULT STDMETHODCALLTYPE CExplorerBand::Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect) HRESULT STDMETHODCALLTYPE CExplorerBand::Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
{ {
UNIMPLEMENTED; if (!pDropTarget)
return E_NOTIMPL; return E_FAIL;
pDropTarget->Drop(pObj, glfKeyState, pt, pdwEffect);
DragLeave();
return S_OK;
} }
// *** IDropSource methods *** // *** IDropSource methods ***
HRESULT STDMETHODCALLTYPE CExplorerBand::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) HRESULT STDMETHODCALLTYPE CExplorerBand::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{ {
UNIMPLEMENTED; if (fEscapePressed)
return E_NOTIMPL; return DRAGDROP_S_CANCEL;
if ((grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
return S_OK;
return DRAGDROP_S_DROP;
} }
HRESULT STDMETHODCALLTYPE CExplorerBand::GiveFeedback(DWORD dwEffect) HRESULT STDMETHODCALLTYPE CExplorerBand::GiveFeedback(DWORD dwEffect)
{ {
UNIMPLEMENTED; return DRAGDROP_S_USEDEFAULTCURSORS;
return E_NOTIMPL;
} }

View file

@ -62,21 +62,33 @@ private:
HIMAGELIST hImageList; HIMAGELIST hImageList;
HTREEITEM hRoot; HTREEITEM hRoot;
HTREEITEM oldSelected; HTREEITEM oldSelected;
LPITEMIDLIST pidlCurrent;
// *** notification cookies *** // *** notification cookies ***
DWORD adviseCookie; DWORD adviseCookie;
ULONG shellRegID; ULONG shellRegID;
// *** Drop target information ***
CComPtr<IDropTarget> pDropTarget;
HTREEITEM childTargetNode;
CComPtr<IDataObject> pCurObject;
void InitializeExplorerBand(); void InitializeExplorerBand();
void DestroyExplorerBand(); void DestroyExplorerBand();
HRESULT ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd); HRESULT ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd);
// *** notifications handling ***
BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv); BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv);
void OnSelectionChanged(LPNMTREEVIEW pnmtv); void OnSelectionChanged(LPNMTREEVIEW pnmtv);
BOOL OnTreeItemDeleted(LPNMTREEVIEW pnmtv);
void OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick);
// *** ATL event handlers *** // *** ATL event handlers ***
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
// *** Helper functions *** // *** Helper functions ***
NodeInfo* GetNodeInfo(HTREEITEM hItem); NodeInfo* GetNodeInfo(HTREEITEM hItem);
@ -85,8 +97,14 @@ private:
HTREEITEM InsertItem(HTREEITEM hParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort); HTREEITEM InsertItem(HTREEITEM hParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort);
BOOL InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo); BOOL InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo);
BOOL NavigateToPIDL(LPITEMIDLIST dest, HTREEITEM *item, BOOL bExpand, BOOL bInsert, BOOL bSelect); BOOL NavigateToPIDL(LPITEMIDLIST dest, HTREEITEM *item, BOOL bExpand, BOOL bInsert, BOOL bSelect);
BOOL DeleteItem(LPITEMIDLIST toDelete);
BOOL RenameItem(HTREEITEM toRename, LPITEMIDLIST newPidl);
BOOL RefreshTreePidl(HTREEITEM tree, LPITEMIDLIST pidlParent);
BOOL NavigateToCurrentFolder(); BOOL NavigateToCurrentFolder();
// *** Tree item sorting callback ***
static int CALLBACK CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3);
public: public:
CExplorerBand(); CExplorerBand();
virtual ~CExplorerBand(); virtual ~CExplorerBand();
@ -181,6 +199,12 @@ public:
BEGIN_MSG_MAP(CExplorerBand) BEGIN_MSG_MAP(CExplorerBand)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_USER_SHELLEVENT, OnShellEvent)
MESSAGE_HANDLER(WM_RBUTTONDOWN, ContextMenuHack) MESSAGE_HANDLER(WM_RBUTTONDOWN, ContextMenuHack)
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
// MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
END_MSG_MAP() END_MSG_MAP()
}; };
extern "C"
HRESULT WINAPI CExplorerBand_Constructor(REFIID riid, LPVOID *ppv);