https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7ede53491013e6db1ac85…
commit 7ede53491013e6db1ac85dcfaa683dee3ef56084
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Aug 14 12:00:47 2024 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Aug 14 12:00:47 2024 +0900
[SHDOCVW][SDK] Support Favorites bar Part 2 (#7223)
Implement Favorites bar.
JIRA issue: CORE-19686
- Introduce CNSCBand class to commonize
some code of CFavBand and CExplorerBand
classes.
- Implement Favorites bar.
- Fix IBandNavigate and INamespaceProxy
interfaces.
---
dll/win32/shdocvw/CExplorerBand.cpp | 1625 ++++-------------------------------
dll/win32/shdocvw/CExplorerBand.h | 230 +----
dll/win32/shdocvw/CFavBand.cpp | 567 ++----------
dll/win32/shdocvw/CFavBand.h | 156 +---
dll/win32/shdocvw/CMakeLists.txt | 1 +
dll/win32/shdocvw/CNSCBand.cpp | 1487 ++++++++++++++++++++++++++++++++
dll/win32/shdocvw/CNSCBand.h | 231 +++++
sdk/include/reactos/shlobj_undoc.h | 4 +-
8 files changed, 2051 insertions(+), 2250 deletions(-)
diff --git a/dll/win32/shdocvw/CExplorerBand.cpp b/dll/win32/shdocvw/CExplorerBand.cpp
index 8a60321a706..aa70c06c5c2 100644
--- a/dll/win32/shdocvw/CExplorerBand.cpp
+++ b/dll/win32/shdocvw/CExplorerBand.cpp
@@ -7,8 +7,6 @@
*/
#include "objects.h"
-#include <commoncontrols.h>
-#include <undocshell.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
@@ -21,1545 +19,298 @@ WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
*/
CExplorerBand::CExplorerBand()
- : m_pSite(NULL)
- , m_fVisible(FALSE)
- , m_mtxBlockNavigate(0)
- , m_dwBandID(0)
- , m_isEditing(FALSE)
- , m_pidlCurrent(NULL)
{
}
CExplorerBand::~CExplorerBand()
{
- if (m_pidlCurrent)
- {
- ILFree(m_pidlCurrent);
- }
-}
-
-void CExplorerBand::InitializeExplorerBand()
-{
- // Init the treeview here
- HRESULT hr = SHGetDesktopFolder(&m_pDesktop);
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- LPITEMIDLIST pidl;
- hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidl);
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- IImageList * piml;
- hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- TreeView_SetImageList(m_hWnd, (HIMAGELIST)piml, TVSIL_NORMAL);
-
- // Insert the root node
- m_hRoot = InsertItem(NULL, m_pDesktop, pidl, pidl, FALSE);
- if (!m_hRoot)
- {
- ERR("Failed to create root item\n");
- return;
- }
-
- NodeInfo* pNodeInfo = GetNodeInfo(m_hRoot);
-
- // Insert child nodes
- InsertSubitems(m_hRoot, pNodeInfo);
- TreeView_Expand(m_hWnd, m_hRoot, TVE_EXPAND);
-
- // Navigate to current folder position
- NavigateToCurrentFolder();
-
-#define TARGET_EVENTS ( \
- SHCNE_DRIVEADD | SHCNE_MKDIR | SHCNE_CREATE | SHCNE_DRIVEREMOVED | SHCNE_RMDIR | \
- SHCNE_DELETE | SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEDIR | \
- SHCNE_UPDATEITEM | SHCNE_ASSOCCHANGED \
-)
- // Register shell notification
- SHChangeNotifyEntry shcne = { pidl, TRUE };
- m_shellRegID = SHChangeNotifyRegister(m_hWnd,
- SHCNRF_NewDelivery | SHCNRF_ShellLevel,
- TARGET_EVENTS,
- WM_USER_SHELLEVENT,
- 1, &shcne);
- if (!m_shellRegID)
- {
- ERR("Something went wrong, error %08x\n", GetLastError());
- }
-
- // Register browser connection endpoint
- CComPtr<IWebBrowser2> browserService;
- hr = IUnknown_QueryService(m_pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2,
&browserService));
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- hr = AtlAdvise(browserService, dynamic_cast<IDispatch*>(this),
DIID_DWebBrowserEvents, &m_adviseCookie);
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- ILFree(pidl);
-}
-
-void CExplorerBand::DestroyExplorerBand()
-{
- HRESULT hr;
- CComPtr <IWebBrowser2> browserService;
-
- TRACE("Cleaning up explorer band ...\n");
-
- hr = IUnknown_QueryService(m_pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2,
&browserService));
- if (FAILED_UNEXPECTEDLY(hr))
- return;
-
- hr = AtlUnadvise(browserService, DIID_DWebBrowserEvents, m_adviseCookie);
- /* Remove all items of the treeview */
- RevokeDragDrop(m_hWnd);
- TreeView_DeleteAllItems(m_hWnd);
- m_pDesktop = NULL;
- m_hRoot = NULL;
- TRACE("Cleanup done !\n");
-}
-
-CExplorerBand::NodeInfo* CExplorerBand::GetNodeInfo(HTREEITEM hItem)
-{
- TVITEM tvItem;
-
- tvItem.mask = TVIF_PARAM;
- tvItem.hItem = hItem;
-
- if (!TreeView_GetItem(m_hWnd, &tvItem))
- return 0;
-
- return reinterpret_cast<NodeInfo*>(tvItem.lParam);
-}
-
-static HRESULT GetCurrentLocationFromView(IShellView &View, PIDLIST_ABSOLUTE
&pidl)
-{
- CComPtr<IFolderView> pfv;
- CComPtr<IShellFolder> psf;
- HRESULT hr = View.QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
- if (SUCCEEDED(hr) && SUCCEEDED(hr =
pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf))))
- hr = SHELL_GetIDListFromObject(psf, &pidl);
- return hr;
-}
-
-HRESULT CExplorerBand::GetCurrentLocation(PIDLIST_ABSOLUTE &pidl)
-{
- pidl = NULL;
- CComPtr<IShellBrowser> psb;
- HRESULT hr = IUnknown_QueryService(m_pSite, SID_STopLevelBrowser,
IID_PPV_ARG(IShellBrowser, &psb));
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
-
- CComPtr<IBrowserService> pbs;
- if (SUCCEEDED(hr = psb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
- if (SUCCEEDED(hr = pbs->GetPidl(&pidl)) && pidl)
- return hr;
-
- CComPtr<IShellView> psv;
- if (!FAILED_UNEXPECTEDLY(hr = psb->QueryActiveShellView(&psv)))
- if (SUCCEEDED(hr = psv.p ? GetCurrentLocationFromView(*psv.p, pidl) : E_FAIL))
- return hr;
- return hr;
-}
-
-HRESULT CExplorerBand::IsCurrentLocation(PCIDLIST_ABSOLUTE pidl)
-{
- if (!pidl)
- return E_INVALIDARG;
- HRESULT hr = E_FAIL;
- PIDLIST_ABSOLUTE location = m_pidlCurrent;
- if (location || SUCCEEDED(hr = GetCurrentLocation(location)))
- hr = SHELL_IsEqualAbsoluteID(location, pidl) ? S_OK : S_FALSE;
- if (location != m_pidlCurrent)
- ILFree(location);
- return hr;
-}
-
-HRESULT CExplorerBand::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
-{
- CComPtr<IOleWindow> pBrowserOleWnd;
- CMINVOKECOMMANDINFO cmi;
- HWND browserWnd;
- HRESULT hr;
-
- hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IOleWindow,
&pBrowserOleWnd));
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
-
- hr = pBrowserOleWnd->GetWindow(&browserWnd);
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
-
- ZeroMemory(&cmi, sizeof(cmi));
- cmi.cbSize = sizeof(cmi);
- cmi.lpVerb = MAKEINTRESOURCEA(nCmd);
- cmi.hwnd = browserWnd;
- if (GetKeyState(VK_SHIFT) & 0x8000)
- cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
- if (GetKeyState(VK_CONTROL) & 0x8000)
- cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
-
- return menu->InvokeCommand(&cmi);
-}
-
-HRESULT CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto)
-{
- CComPtr<IShellBrowser> pBrowserService;
- HRESULT hr;
-
- hr = IUnknown_QueryService(m_pSite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser,
&pBrowserService));
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
-
- hr = pBrowserService->BrowseObject(pidlGoto, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
-
- ILFree(m_pidlCurrent);
- return SHILClone(pidlGoto, &m_pidlCurrent);
-}
-
-// *** notifications handling ***
-BOOL CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv)
-{
- NodeInfo *pNodeInfo;
-
- if (pnmtv->action == TVE_COLLAPSE) {
- if (pnmtv->itemNew.hItem == m_hRoot)
- {
- // Prenvent root from collapsing
- pnmtv->itemNew.mask |= TVIF_STATE;
- pnmtv->itemNew.stateMask |= TVIS_EXPANDED;
- pnmtv->itemNew.state &= ~TVIS_EXPANDED;
- pnmtv->action = TVE_EXPAND;
- return TRUE;
- }
- }
- if (pnmtv->action == TVE_EXPAND) {
- // Grab our directory PIDL
- pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
- // We have it, let's try
- if (pNodeInfo && !pNodeInfo->expanded)
- if (!InsertSubitems(pnmtv->itemNew.hItem, pNodeInfo)) {
- // remove subitem "+" since we failed to add subitems
- TV_ITEM tvItem;
-
- tvItem.mask = TVIF_CHILDREN;
- tvItem.hItem = pnmtv->itemNew.hItem;
- tvItem.cChildren = 0;
-
- TreeView_SetItem(m_hWnd, &tvItem);
- }
- }
- return FALSE;
-}
-
-BOOL CExplorerBand::OnTreeItemDeleted(LPNMTREEVIEW pnmtv)
-{
- // Navigate to parent when deleting selected item
- HTREEITEM hItem = pnmtv->itemOld.hItem;
- HTREEITEM hParent = TreeView_GetParent(m_hWnd, hItem);
- if (hParent && TreeView_GetSelection(m_hWnd) == hItem)
- TreeView_SelectItem(m_hWnd, hParent);
-
- /* Destroy memory associated to our node */
- NodeInfo* pNode = GetNodeInfo(hItem);
- if (!pNode)
- return FALSE;
-
- ILFree(pNode->relativePidl);
- ILFree(pNode->absolutePidl);
- delete pNode;
-
- return TRUE;
-}
-
-void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
-{
- NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
-
- /* Prevents navigation if selection is initiated inside the band */
- if (m_mtxBlockNavigate)
- return;
-
- UpdateBrowser(pNodeInfo->absolutePidl);
-
- SetFocus();
- // Expand the node
- //TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
-}
-
-void CExplorerBand::OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick)
-{
- if (!pnmtv->itemNew.lParam)
- return;
-
- NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
-
- HRESULT hr;
- CComPtr<IShellFolder> pSrcFolder;
- LPCITEMIDLIST pLast;
- hr = SHBindToParent(pNodeInfo->absolutePidl, IID_PPV_ARG(IShellFolder,
&pSrcFolder), &pLast);
- if (!SUCCEEDED(hr))
- return;
-
- SFGAOF attrs = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK;
- pSrcFolder->GetAttributesOf(1, &pLast, &attrs);
-
- DWORD dwEffect = 0;
- if (attrs & SFGAO_CANCOPY)
- dwEffect |= DROPEFFECT_COPY;
- if (attrs & SFGAO_CANMOVE)
- dwEffect |= DROPEFFECT_MOVE;
- if (attrs & SFGAO_CANLINK)
- dwEffect |= DROPEFFECT_LINK;
-
- CComPtr<IDataObject> pObj;
- hr = pSrcFolder->GetUIObjectOf(m_hWnd, 1, &pLast, IID_IDataObject, 0,
(LPVOID*)&pObj);
- if (!SUCCEEDED(hr))
- return;
-
- DoDragDrop(pObj, this, dwEffect, &dwEffect);
-}
-
-// *** ATL event handlers ***
-LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- HTREEITEM item;
- NodeInfo *info;
- HMENU treeMenu;
- POINT pt;
- CComPtr<IShellFolder> pFolder;
- CComPtr<IContextMenu> contextMenu;
- HRESULT hr;
- UINT uCommand;
- LPITEMIDLIST pidlChild;
- UINT cmdBase = max(FCIDM_SHVIEWFIRST, 1);
- UINT cmf = CMF_EXPLORE;
- SFGAOF attr = SFGAO_CANRENAME;
- BOOL startedRename = FALSE;
-
- treeMenu = NULL;
- item = TreeView_GetSelection(m_hWnd);
- bHandled = TRUE;
- if (!item)
- {
- goto Cleanup;
- }
-
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
- if ((UINT)lParam == (UINT)-1)
- {
- RECT r;
- if (TreeView_GetItemRect(m_hWnd, item, &r, TRUE))
- {
- pt.x = (r.left + r.right) / 2; // Center of
- pt.y = (r.top + r.bottom) / 2; // item rectangle
- }
- ClientToScreen(&pt);
- }
-
- info = GetNodeInfo(item);
- if (!info)
- {
- ERR("No node data, something has gone wrong !\n");
- goto Cleanup;
- }
- hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pFolder),
- (LPCITEMIDLIST*)&pidlChild);
- if (!SUCCEEDED(hr))
- {
- ERR("Can't bind to folder!\n");
- goto Cleanup;
- }
- hr = pFolder->GetUIObjectOf(m_hWnd, 1, (LPCITEMIDLIST*)&pidlChild,
IID_IContextMenu,
- NULL, reinterpret_cast<void**>(&contextMenu));
- if (!SUCCEEDED(hr))
- {
- ERR("Can't get IContextMenu interface\n");
- goto Cleanup;
- }
-
- IUnknown_SetSite(contextMenu, (IDeskBand *)this);
-
- if (SUCCEEDED(pFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlChild,
&attr)) && (attr & SFGAO_CANRENAME))
- cmf |= CMF_CANRENAME;
-
- treeMenu = CreatePopupMenu();
- hr = contextMenu->QueryContextMenu(treeMenu, 0, cmdBase, FCIDM_SHVIEWLAST, cmf);
- if (!SUCCEEDED(hr))
- {
- WARN("Can't get context menu for item\n");
- DestroyMenu(treeMenu);
- goto Cleanup;
- }
-
- uCommand = TrackPopupMenu(treeMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON |
TPM_RIGHTBUTTON,
- pt.x, pt.y, 0, m_hWnd, NULL);
- if (uCommand)
- {
- uCommand -= cmdBase;
-
- // Do DFM_CMD_RENAME in the treeview
- if ((cmf & CMF_CANRENAME) && SHELL_IsVerb(contextMenu, uCommand,
L"rename"))
- {
- HTREEITEM oldSelected = m_oldSelected;
- SetFocus();
- startedRename = TreeView_EditLabel(m_hWnd, item) != NULL;
- m_oldSelected = oldSelected; // Restore after TVN_BEGINLABELEDIT
- goto Cleanup;
- }
-
- hr = ExecuteCommand(contextMenu, uCommand);
- }
-
-Cleanup:
- if (contextMenu)
- IUnknown_SetSite(contextMenu, NULL);
- if (treeMenu)
- DestroyMenu(treeMenu);
- if (startedRename)
- {
- // The treeview disables drawing of the edited item so we must make sure
- // the correct item is selected (on right-click -> rename on not-current
folder).
- // TVN_ENDLABELEDIT becomes responsible for restoring the selection.
- }
- else
- {
- ++m_mtxBlockNavigate;
- TreeView_SelectItem(m_hWnd, m_oldSelected);
- --m_mtxBlockNavigate;
- }
- return TRUE;
-}
-
-LRESULT CExplorerBand::ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- bHandled = FALSE;
- if (uMsg == WM_RBUTTONDOWN)
- {
- TVHITTESTINFO info;
- info.pt.x = LOWORD(lParam);
- info.pt.y = HIWORD(lParam);
- info.flags = TVHT_ONITEM;
- info.hItem = NULL;
-
- // Save the current location
- m_oldSelected = TreeView_GetSelection(m_hWnd);
-
- // Move to the item selected by the treeview (don't change right pane)
- TreeView_HitTest(m_hWnd, &info);
- ++m_mtxBlockNavigate;
- TreeView_SelectItem(m_hWnd, info.hItem);
- --m_mtxBlockNavigate;
- }
- return FALSE; /* let the wndproc process the message */
-}
-
-// WM_USER_SHELLEVENT
-LRESULT CExplorerBand::OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- // We use SHCNRF_NewDelivery method
- HANDLE hChange = (HANDLE)wParam;
- DWORD dwProcID = (DWORD)lParam;
-
- PIDLIST_ABSOLUTE *ppidl = NULL;
- LONG lEvent;
- HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &ppidl,
&lEvent);
- if (hLock == NULL)
- {
- ERR("hLock == NULL\n");
- return 0;
- }
-
- OnChangeNotify(ppidl[0], ppidl[1], (lEvent & ~SHCNE_INTERRUPT));
-
- SHChangeNotification_Unlock(hLock);
- return 0;
-}
-
-BOOL
-CExplorerBand::IsTreeItemInEnum(
- _In_ HTREEITEM hItem,
- _In_ IEnumIDList *pEnum)
-{
- NodeInfo* pNodeInfo = GetNodeInfo(hItem);
- if (!pNodeInfo)
- return FALSE;
-
- pEnum->Reset();
-
- CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
- while (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
- {
- if (ILIsEqual(pidlTemp, pNodeInfo->relativePidl))
- return TRUE;
-
- pidlTemp.Free();
- }
-
- return FALSE;
-}
-
-BOOL
-CExplorerBand::TreeItemHasThisChild(
- _In_ HTREEITEM hItem,
- _In_ PCITEMID_CHILD pidlChild)
-{
- for (hItem = TreeView_GetChild(m_hWnd, hItem); hItem;
- hItem = TreeView_GetNextSibling(m_hWnd, hItem))
- {
- NodeInfo* pNodeInfo = GetNodeInfo(hItem);
- if (ILIsEqual(pNodeInfo->relativePidl, pidlChild))
- return TRUE;
- }
-
- return FALSE;
-}
-
-HRESULT
-CExplorerBand::GetItemEnum(
- _Out_ CComPtr<IEnumIDList>& pEnum,
- _In_ HTREEITEM hItem)
-{
- NodeInfo* pNodeInfo = GetNodeInfo(hItem);
-
- CComPtr<IShellFolder> psfDesktop;
- HRESULT hr = SHGetDesktopFolder(&psfDesktop);
- if (FAILED(hr))
- return hr;
-
- CComPtr<IShellFolder> pFolder;
- hr = psfDesktop->BindToObject(pNodeInfo->absolutePidl, NULL,
IID_PPV_ARG(IShellFolder, &pFolder));
- if (FAILED(hr))
- return hr;
-
- return pFolder->EnumObjects(NULL, SHCONTF_FOLDERS, &pEnum);
-}
-
-BOOL CExplorerBand::ItemHasAnyChild(_In_ HTREEITEM hItem)
-{
- CComPtr<IEnumIDList> pEnum;
- HRESULT hr = GetItemEnum(pEnum, hItem);
- if (FAILED(hr))
- return FALSE;
-
- CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
- hr = pEnum->Next(1, &pidlTemp, NULL);
- return SUCCEEDED(hr);
-}
-
-void CExplorerBand::RefreshRecurse(_In_ HTREEITEM hTarget)
-{
- NodeInfo* pNodeInfo = GetNodeInfo(hTarget);
-
- CComPtr<IEnumIDList> pEnum;
- HRESULT hrEnum = GetItemEnum(pEnum, hTarget);
-
- // Delete zombie items
- HTREEITEM hItem, hNextItem;
- for (hItem = TreeView_GetChild(m_hWnd, hTarget); hItem; hItem = hNextItem)
- {
- hNextItem = TreeView_GetNextSibling(m_hWnd, hItem);
-
- if (SUCCEEDED(hrEnum) && !IsTreeItemInEnum(hItem, pEnum))
- TreeView_DeleteItem(m_hWnd, hItem);
- }
-
- pEnum = NULL;
- hrEnum = GetItemEnum(pEnum, hTarget);
-
- // Insert new items and update items
- if (SUCCEEDED(hrEnum))
- {
- CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
- while (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
- {
- if (!TreeItemHasThisChild(hTarget, pidlTemp))
- {
- CComHeapPtr<ITEMIDLIST>
pidlAbsolute(ILCombine(pNodeInfo->absolutePidl, pidlTemp));
- InsertItem(hTarget, pidlAbsolute, pidlTemp, TRUE);
- }
- pidlTemp.Free();
- }
- }
-
- // Update children and recurse
- for (hItem = TreeView_GetChild(m_hWnd, hTarget); hItem; hItem = hNextItem)
- {
- hNextItem = TreeView_GetNextSibling(m_hWnd, hItem);
-
- TV_ITEMW item = { TVIF_HANDLE | TVIF_CHILDREN };
- item.hItem = hItem;
- item.cChildren = ItemHasAnyChild(hItem);
- TreeView_SetItem(m_hWnd, &item);
-
- if (TreeView_GetItemState(m_hWnd, hItem, TVIS_EXPANDEDONCE) &
TVIS_EXPANDEDONCE)
- RefreshRecurse(hItem);
- }
-}
-
-void CExplorerBand::Refresh()
-{
- SendMessage(WM_SETREDRAW, FALSE, 0);
- RefreshRecurse(m_hRoot);
- SendMessage(WM_SETREDRAW, TRUE, 0);
- InvalidateRect(NULL, TRUE);
-}
-
-#define TIMER_ID_REFRESH 9999
-
-LRESULT CExplorerBand::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- if (wParam != TIMER_ID_REFRESH)
- return 0;
-
- KillTimer(TIMER_ID_REFRESH);
-
- // FIXME: Avoid full refresh and optimize for speed
- Refresh();
-
- return 0;
-}
-
-void
-CExplorerBand::OnChangeNotify(
- _In_opt_ LPCITEMIDLIST pidl0,
- _In_opt_ LPCITEMIDLIST pidl1,
- _In_ LONG lEvent)
-{
- switch (lEvent)
- {
- case SHCNE_DRIVEADD:
- case SHCNE_MKDIR:
- case SHCNE_CREATE:
- case SHCNE_DRIVEREMOVED:
- case SHCNE_RMDIR:
- case SHCNE_DELETE:
- case SHCNE_RENAMEFOLDER:
- case SHCNE_RENAMEITEM:
- case SHCNE_UPDATEDIR:
- case SHCNE_UPDATEITEM:
- case SHCNE_ASSOCCHANGED:
- {
- KillTimer(TIMER_ID_REFRESH);
- SetTimer(TIMER_ID_REFRESH, 500, NULL);
- break;
- }
- default:
- {
- TRACE("lEvent: 0x%08lX\n", lEvent);
- break;
- }
- }
-}
-
-LRESULT CExplorerBand::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- m_bFocused = TRUE;
- IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), TRUE);
- bHandled = FALSE;
- return TRUE;
-}
-
-LRESULT CExplorerBand::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), FALSE);
- bHandled = FALSE;
- return TRUE;
-}
-
-// *** Helper functions ***
-HTREEITEM
-CExplorerBand::InsertItem(
- _In_opt_ HTREEITEM hParent,
- _Inout_ IShellFolder *psfParent,
- _In_ LPCITEMIDLIST pElt,
- _In_ LPCITEMIDLIST pEltRelative,
- _In_ BOOL bSort)
-{
- TV_INSERTSTRUCT tvInsert;
- HTREEITEM htiCreated;
-
- /* Get the attributes of the node */
- SFGAOF attrs = SFGAO_STREAM | SFGAO_HASSUBFOLDER;
- HRESULT hr = psfParent->GetAttributesOf(1, &pEltRelative, &attrs);
- if (FAILED_UNEXPECTEDLY(hr))
- return NULL;
-
- /* Ignore streams */
- if (attrs & SFGAO_STREAM)
- {
- TRACE("Ignoring stream\n");
- return NULL;
- }
-
- /* Get the name of the node */
- WCHAR wszDisplayName[MAX_PATH];
- STRRET strret;
- hr = psfParent->GetDisplayNameOf(pEltRelative, SHGDN_INFOLDER, &strret);
- if (FAILED_UNEXPECTEDLY(hr))
- return NULL;
-
- hr = StrRetToBufW(&strret, pEltRelative, wszDisplayName, MAX_PATH);
- if (FAILED_UNEXPECTEDLY(hr))
- return NULL;
-
- /* Get the icon of the node */
- INT iIcon = SHMapPIDLToSystemImageListIndex(psfParent, pEltRelative, NULL);
-
- NodeInfo* pChildInfo = new NodeInfo;
- if (!pChildInfo)
- {
- ERR("Failed to allocate NodeInfo\n");
- return FALSE;
- }
-
- // Store our node info
- pChildInfo->absolutePidl = ILClone(pElt);
- pChildInfo->relativePidl = ILClone(pEltRelative);
- pChildInfo->expanded = FALSE;
-
- // Set up our treeview template
- tvInsert.hParent = hParent;
- tvInsert.hInsertAfter = TVI_LAST;
- tvInsert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
TVIF_CHILDREN;
- tvInsert.item.cchTextMax = MAX_PATH;
- tvInsert.item.pszText = wszDisplayName;
- tvInsert.item.iImage = tvInsert.item.iSelectedImage = iIcon;
- tvInsert.item.cChildren = (attrs & SFGAO_HASSUBFOLDER) ? 1 : 0;
- tvInsert.item.lParam = (LPARAM)pChildInfo;
-
- htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert);
-
- if (bSort)
- {
- TVSORTCB sortCallback;
- sortCallback.hParent = hParent;
- sortCallback.lpfnCompare = CompareTreeItems;
- sortCallback.lParam = (LPARAM)(PVOID)m_pDesktop;
- SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
- }
-
- return htiCreated;
-}
-
-/* This is the slow version of the above method */
-HTREEITEM
-CExplorerBand::InsertItem(
- _In_opt_ HTREEITEM hParent,
- _In_ LPCITEMIDLIST pElt,
- _In_ LPCITEMIDLIST pEltRelative,
- _In_ BOOL bSort)
-{
- CComPtr<IShellFolder> psfFolder;
- HRESULT hr = SHBindToParent(pElt, IID_PPV_ARG(IShellFolder, &psfFolder), NULL);
- if (FAILED_UNEXPECTEDLY(hr))
- return NULL;
-
- return InsertItem(hParent, psfFolder, pElt, pEltRelative, bSort);
-}
-
-BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
-{
- CComPtr<IEnumIDList> pEnumIDList;
- LPITEMIDLIST pidlSub;
- LPITEMIDLIST entry;
- SHCONTF EnumFlags;
- HRESULT hr;
- ULONG fetched;
- ULONG uItemCount;
- CComPtr<IShellFolder> pFolder;
- TVSORTCB sortCallback;
-
- entry = pNodeInfo->absolutePidl;
- fetched = 1;
- uItemCount = 0;
- EnumFlags = SHCONTF_FOLDERS;
-
- hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidlSub);
- if (!SUCCEEDED(hr))
- {
- ERR("Can't get desktop PIDL !\n");
- return FALSE;
- }
-
- if (!m_pDesktop->CompareIDs(NULL, pidlSub, entry))
- {
- // We are the desktop, so use pDesktop as pFolder
- pFolder = m_pDesktop;
- }
- else
- {
- // Get an IShellFolder of our pidl
- hr = m_pDesktop->BindToObject(entry, NULL, IID_PPV_ARG(IShellFolder,
&pFolder));
- if (!SUCCEEDED(hr))
- {
- ILFree(pidlSub);
- ERR("Can't bind folder to desktop !\n");
- return FALSE;
- }
- }
- ILFree(pidlSub);
-
- // TODO: handle hidden folders according to settings !
- EnumFlags |= SHCONTF_INCLUDEHIDDEN;
-
- // Enum through objects
- hr = pFolder->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 FALSE;
- }
-
- /* Don't redraw while we add stuff into the tree */
- SendMessage(WM_SETREDRAW, FALSE, 0);
- while(SUCCEEDED(pEnumIDList->Next(1, &pidlSub, &fetched)) &&
pidlSub && fetched)
- {
- LPITEMIDLIST pidlSubComplete;
- pidlSubComplete = ILCombine(entry, pidlSub);
-
- if (InsertItem(hItem, pFolder, pidlSubComplete, pidlSub, FALSE))
- uItemCount++;
- ILFree(pidlSubComplete);
- ILFree(pidlSub);
- }
- pNodeInfo->expanded = TRUE;
- /* Let's do sorting */
- sortCallback.hParent = hItem;
- sortCallback.lpfnCompare = CompareTreeItems;
- sortCallback.lParam = (LPARAM)(PVOID)m_pDesktop;
- SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
-
- /* Now we can redraw */
- SendMessage(WM_SETREDRAW, TRUE, 0);
-
- return (uItemCount > 0) ? TRUE : FALSE;
-}
-
-/**
- * Navigate to a given PIDL in the treeview, and return matching tree item handle
- * - dest: The absolute PIDL we should navigate in the treeview
- * - item: Handle of the tree item matching the PIDL
- * - bExpand: expand collapsed nodes in order to find the right element
- * - bInsert: insert the element at the right place if we don't find it
- * - bSelect: select the item after we found it
- */
-BOOL CExplorerBand::NavigateToPIDL(LPCITEMIDLIST dest, HTREEITEM *item, BOOL bExpand,
BOOL bInsert,
- BOOL bSelect)
-{
- HTREEITEM current;
- HTREEITEM tmp;
- HTREEITEM parent;
- NodeInfo *nodeData;
- LPITEMIDLIST relativeChild;
- TVITEM tvItem;
-
- if (!item)
- return FALSE;
-
- current = m_hRoot;
- parent = NULL;
- while (TRUE)
- {
- nodeData = GetNodeInfo(current);
- if (!nodeData)
- {
- ERR("Something has gone wrong, no data associated to node !\n");
- *item = NULL;
- return FALSE;
- }
- // If we found our node, give it back
- if (!m_pDesktop->CompareIDs(0, nodeData->absolutePidl, dest))
- {
- if (bSelect)
- TreeView_SelectItem(m_hWnd, current);
- *item = current;
- return TRUE;
- }
-
- // Check if we are a parent of the requested item
- relativeChild = ILFindChild(nodeData->absolutePidl, dest);
- if (relativeChild != 0)
- {
- // Notify treeview we have children
- tvItem.mask = TVIF_CHILDREN;
- tvItem.hItem = current;
- tvItem.cChildren = 1;
- TreeView_SetItem(m_hWnd, &tvItem);
-
- // If we can expand and the node isn't expanded yet, do it
- if (bExpand)
- {
- if (!nodeData->expanded)
- InsertSubitems(current, nodeData);
- TreeView_Expand(m_hWnd, current, TVE_EXPAND);
- }
-
- // Try to get a child
- tmp = TreeView_GetChild(m_hWnd, current);
- if (tmp)
- {
- // We have a child, let's continue with it
- parent = current;
- current = tmp;
- continue;
- }
-
- if (bInsert && nodeData->expanded)
- {
- // Happens when we have to create a subchild inside a child
- current = InsertItem(current, dest, relativeChild, TRUE);
- }
- // We end up here, without any children, so we found nothing
- // Tell the parent node it has children
- ZeroMemory(&tvItem, sizeof(tvItem));
- *item = NULL;
- return FALSE;
- }
-
- // Find sibling
- tmp = TreeView_GetNextSibling(m_hWnd, current);
- if (tmp)
- {
- current = tmp;
- continue;
- }
- if (bInsert)
- {
- current = InsertItem(parent, dest, ILFindLastID(dest), TRUE);
- *item = current;
- return TRUE;
- }
- *item = NULL;
- return FALSE;
- }
- UNREACHABLE;
-}
-
-BOOL CExplorerBand::NavigateToCurrentFolder()
-{
- LPITEMIDLIST explorerPidl;
- HTREEITEM dummy;
- BOOL result;
-
- HRESULT hr = GetCurrentLocation(explorerPidl);
- if (FAILED_UNEXPECTEDLY(hr))
- {
- ERR("Unable to get browser PIDL !\n");
- return FALSE;
- }
- ++m_mtxBlockNavigate;
- /* find PIDL into our explorer */
- result = NavigateToPIDL(explorerPidl, &dummy, TRUE, FALSE, TRUE);
- --m_mtxBlockNavigate;
- ILFree(explorerPidl);
- return result;
-}
-
-// *** Tree item sorting callback ***
-int CALLBACK CExplorerBand::CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3)
-{
- NodeInfo *info1 = (NodeInfo*)p1;
- NodeInfo *info2 = (NodeInfo*)p2;
- IShellFolder *pDesktop = (IShellFolder *)p3;
-
- HRESULT hr = pDesktop->CompareIDs(0, info1->absolutePidl,
info2->absolutePidl);
- if (FAILED(hr))
- return 0;
-
- return (SHORT)HRESULT_CODE(hr);
-}
-
-// *** IOleWindow methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetWindow(HWND *lphwnd)
-{
- if (!lphwnd)
- return E_INVALIDARG;
- *lphwnd = m_hWnd;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::ContextSensitiveHelp(BOOL fEnterMode)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-
-// *** IDockingWindow methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::CloseDW(DWORD dwReserved)
-{
- // We do nothing, we don't have anything to save yet
- TRACE("CloseDW called\n");
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::ResizeBorderDW(const RECT *prcBorder, IUnknown
*punkToolbarSite, BOOL fReserved)
-{
- /* Must return E_NOTIMPL according to MSDN */
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::ShowDW(BOOL fShow)
-{
- m_fVisible = fShow;
- ShowWindow(fShow);
- return S_OK;
}
-
-// *** IDeskBand methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode,
DESKBANDINFO *pdbi)
+STDMETHODIMP CExplorerBand::GetClassID(CLSID *pClassID)
{
- if (!pdbi)
- {
- return E_INVALIDARG;
- }
- this->m_dwBandID = dwBandID;
-
- if (pdbi->dwMask & DBIM_MINSIZE)
- {
- pdbi->ptMinSize.x = 200;
- pdbi->ptMinSize.y = 30;
- }
-
- if (pdbi->dwMask & DBIM_MAXSIZE)
- {
- pdbi->ptMaxSize.y = -1;
- }
-
- if (pdbi->dwMask & DBIM_INTEGRAL)
- {
- pdbi->ptIntegral.y = 1;
- }
-
- if (pdbi->dwMask & DBIM_ACTUAL)
- {
- pdbi->ptActual.x = 200;
- pdbi->ptActual.y = 30;
- }
-
- if (pdbi->dwMask & DBIM_TITLE)
- {
- if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_FOLDERSLABEL,
pdbi->wszTitle, _countof(pdbi->wszTitle)))
- return HRESULT_FROM_WIN32(GetLastError());
- }
-
- if (pdbi->dwMask & DBIM_MODEFLAGS)
- {
- pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
- }
-
- if (pdbi->dwMask & DBIM_BKCOLOR)
- {
- pdbi->dwMask &= ~DBIM_BKCOLOR;
- }
+ if (!pClassID)
+ return E_POINTER;
+ *pClassID = CLSID_ExplorerBand;
return S_OK;
}
-
-// *** IObjectWithSite methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::SetSite(IUnknown *pUnkSite)
+INT CExplorerBand::_GetRootCsidl()
{
- HRESULT hr;
- HWND parentWnd;
-
- if (pUnkSite == m_pSite)
- return S_OK;
-
- TRACE("SetSite called \n");
- if (!pUnkSite)
- {
- DestroyExplorerBand();
- DestroyWindow();
- m_hWnd = NULL;
- }
-
- if (pUnkSite != m_pSite)
- {
- m_pSite = NULL;
- }
-
- if(!pUnkSite)
- return S_OK;
-
- hr = IUnknown_GetWindow(pUnkSite, &parentWnd);
- if (!SUCCEEDED(hr))
- {
- ERR("Could not get parent's window ! Status: %08lx\n", hr);
- return E_INVALIDARG;
- }
-
- m_pSite = pUnkSite;
-
- if (m_hWnd)
- {
- // Change its parent
- SetParent(parentWnd);
- }
- else
- {
- HWND wnd = CreateWindow(WC_TREEVIEW, NULL,
- 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
- 0, 0, 0, 0, parentWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
-
- // Subclass the window
- SubclassWindow(wnd);
-
- // Initialize our treeview now
- InitializeExplorerBand();
- RegisterDragDrop(m_hWnd, dynamic_cast<IDropTarget*>(this));
- }
- return S_OK;
+ return CSIDL_DESKTOP;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetSite(REFIID riid, void **ppvSite)
+DWORD CExplorerBand::_GetTVStyle()
{
- if (!ppvSite)
- return E_POINTER;
- *ppvSite = m_pSite;
- return S_OK;
+ // Remove TVS_SINGLEEXPAND for now since it has strange behaviour
+ return WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TVS_HASLINES |
+ TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_EDITLABELS /* | TVS_SINGLEEXPAND*/;
}
-
-// *** IOleCommandTarget methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::QueryStatus(const GUID *pguidCmdGroup, ULONG
cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
+DWORD CExplorerBand::_GetTVExStyle()
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ return 0;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
+DWORD CExplorerBand::_GetEnumFlags()
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ return SHCONTF_FOLDERS;
}
-
-// *** IServiceProvider methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::QueryService(REFGUID guidService, REFIID riid,
void **ppvObject)
+BOOL CExplorerBand::_GetTitle(LPWSTR pszTitle, INT cchTitle)
{
- /* FIXME: we probably want to handle more services here */
- return IUnknown_QueryService(m_pSite, SID_SShellBrowser, riid, ppvObject);
+ return ::LoadStringW(instance, IDS_FOLDERSLABEL, pszTitle, cchTitle);
}
-
-// *** IInputObject methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
+BOOL CExplorerBand::_WantsRootItem()
{
- if (fActivate)
- {
- //SetFocus();
- SetActiveWindow();
- }
- // TODO: handle message
- if(lpMsg)
- {
- TranslateMessage(lpMsg);
- DispatchMessage(lpMsg);
- }
- return S_OK;
+ return TRUE;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::HasFocusIO()
+// Called when the user has selected an item.
+STDMETHODIMP CExplorerBand::OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl)
{
- return m_bFocused ? S_OK : S_FALSE;
+ return Invoke(pidl);
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::TranslateAcceleratorIO(LPMSG lpMsg)
+// Handles a user action on an item.
+STDMETHODIMP CExplorerBand::Invoke(_In_ PCIDLIST_ABSOLUTE pidl)
{
- if (lpMsg->hwnd == m_hWnd ||
- (m_isEditing && IsChild(lpMsg->hwnd)))
- {
- TranslateMessage(lpMsg);
- DispatchMessage(lpMsg);
+ /* Prevents navigation if selection is initiated inside the band */
+ if (m_mtxBlockNavigate)
return S_OK;
- }
-
- return S_FALSE;
-}
-// *** IPersist methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetClassID(CLSID *pClassID)
-{
- if (!pClassID)
- return E_POINTER;
- memcpy(pClassID, &CLSID_ExplorerBand, sizeof(CLSID));
+ _UpdateBrowser(pidl);
+ m_hwndTreeView.SetFocus();
return S_OK;
}
-
-// *** IPersistStream methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::IsDirty()
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::Load(IStream *pStm)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::Save(IStream *pStm, BOOL fClearDirty)
+void CExplorerBand::_SortItems(HTREEITEM hParent)
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ TVSORTCB sortCallback;
+ sortCallback.hParent = hParent;
+ sortCallback.lpfnCompare = _CompareTreeItems;
+ sortCallback.lParam = (LPARAM)(PVOID)m_pDesktop; // m_pDesktop is not a pointer
+ TreeView_SortChildrenCB(m_hwndTreeView, &sortCallback, 0);
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
+INT CALLBACK CExplorerBand::_CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3)
{
- // TODO: calculate max size
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ CItemData *info1 = (CItemData*)p1;
+ CItemData *info2 = (CItemData*)p2;
+ IShellFolder *pDesktop = (IShellFolder *)p3;
+ HRESULT hr = pDesktop->CompareIDs(0, info1->absolutePidl,
info2->absolutePidl);
+ if (FAILED(hr))
+ return 0;
+ return (SHORT)HRESULT_CODE(hr);
}
-// *** IWinEventHandler methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, LRESULT *theResult)
+HRESULT CExplorerBand::_CreateTreeView(HWND hwndParent)
{
- BOOL bHandled;
- LRESULT result;
+ HRESULT hr = CNSCBand::_CreateTreeView(hwndParent);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- if (uMsg == WM_NOTIFY)
+ // Insert the root node
+ m_hRoot = _InsertItem(NULL, m_pDesktop, m_pidlRoot, m_pidlRoot, FALSE);
+ if (!m_hRoot)
{
- NMHDR *pNotifyHeader = (NMHDR*)lParam;
- switch (pNotifyHeader->code)
- {
- case TVN_ITEMEXPANDING:
- result = OnTreeItemExpanding((LPNMTREEVIEW)lParam);
- if (theResult)
- *theResult = result;
- break;
- case TVN_SELCHANGED:
- OnSelectionChanged((LPNMTREEVIEW)lParam);
- break;
- case TVN_DELETEITEM:
- OnTreeItemDeleted((LPNMTREEVIEW)lParam);
- break;
- case NM_RCLICK:
- OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(),
bHandled);
- if (theResult)
- *theResult = 1;
- break;
- case TVN_BEGINDRAG:
- case TVN_BEGINRDRAG:
- OnTreeItemDragging((LPNMTREEVIEW)lParam, pNotifyHeader->code ==
TVN_BEGINRDRAG);
- break;
- case TVN_BEGINLABELEDITW:
- {
- // TODO: put this in a function ? (mostly copypasta from CDefView)
- DWORD dwAttr = SFGAO_CANRENAME;
- LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
- CComPtr<IShellFolder> pParent;
- LPCITEMIDLIST pChild;
- HRESULT hr;
-
- if (theResult)
- *theResult = 1;
- NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
- if (!info)
- return E_FAIL;
- hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder,
&pParent), &pChild);
- if (!SUCCEEDED(hr) || !pParent.p)
- return E_FAIL;
-
- hr = pParent->GetAttributesOf(1, &pChild, &dwAttr);
- if (SUCCEEDED(hr) && (dwAttr & SFGAO_CANRENAME))
- {
- if (theResult)
- *theResult = 0;
- m_isEditing = TRUE;
- m_oldSelected = NULL;
- }
- return S_OK;
- }
- case TVN_ENDLABELEDITW:
- {
- LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
- NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
- HRESULT hr;
-
- m_isEditing = FALSE;
- if (m_oldSelected)
- {
- ++m_mtxBlockNavigate;
- TreeView_SelectItem(m_hWnd, m_oldSelected);
- --m_mtxBlockNavigate;
- }
-
- if (theResult)
- *theResult = 0;
- if (dispInfo->item.pszText)
- {
- LPITEMIDLIST pidlNew;
- CComPtr<IShellFolder> pParent;
- LPCITEMIDLIST pidlChild;
- BOOL RenamedCurrent = IsCurrentLocation(info->absolutePidl) ==
S_OK;
-
- hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder,
&pParent), &pidlChild);
- if (!SUCCEEDED(hr) || !pParent.p)
- return E_FAIL;
-
- hr = pParent->SetNameOf(m_hWnd, pidlChild,
dispInfo->item.pszText, SHGDN_INFOLDER, &pidlNew);
- if(SUCCEEDED(hr) && pidlNew)
- {
- CComPtr<IPersistFolder2> pPersist;
- LPITEMIDLIST pidlParent, pidlNewAbs;
-
- hr = pParent->QueryInterface(IID_PPV_ARG(IPersistFolder2,
&pPersist));
- if(!SUCCEEDED(hr))
- return E_FAIL;
-
- hr = pPersist->GetCurFolder(&pidlParent);
- if(!SUCCEEDED(hr))
- return E_FAIL;
- pidlNewAbs = ILCombine(pidlParent, pidlNew);
-
- if (RenamedCurrent)
- {
- // Navigate to our new location
- UpdateBrowser(pidlNewAbs);
- }
- else
- {
- // Tell everyone in case SetNameOf forgot, this causes
IShellView to update itself when we renamed a child
- SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_IDLIST,
info->absolutePidl, pidlNewAbs);
- }
-
- ILFree(pidlParent);
- ILFree(pidlNewAbs);
- ILFree(pidlNew);
- if (theResult)
- *theResult = 1;
- }
- return S_OK;
- }
- }
- default:
- break;
- }
+ ERR("Failed to create root item\n");
+ return E_FAIL;
}
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::IsWindowOwner(HWND hWnd)
-{
- return (hWnd == m_hWnd) ? S_OK : S_FALSE;
-}
+ TreeView_Expand(m_hwndTreeView, m_hRoot, TVE_EXPAND);
-// *** IBandNavigate methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::Select(long paramC)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
+ // Navigate to current folder position
+ _NavigateToCurrentFolder();
-// *** INamespaceProxy ***
+ // Register browser connection endpoint
+ CComPtr<IWebBrowser2> browserService;
+ hr = IUnknown_QueryService(m_pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2,
&browserService));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
-/// Returns the ITEMIDLIST that should be navigated when an item is invoked.
-STDMETHODIMP CExplorerBand::GetNavigateTarget(
- _In_ PCIDLIST_ABSOLUTE pidl,
- _Out_ PIDLIST_ABSOLUTE ppidlTarget,
- _Out_ ULONG *pulAttrib)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
+ // Communicate via IDispatch
+ hr = AtlAdvise(browserService, dynamic_cast<IDispatch*>(this),
DIID_DWebBrowserEvents, &m_adviseCookie);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
-/// Handles a user action on an item.
-STDMETHODIMP CExplorerBand::Invoke(_In_ PCIDLIST_ABSOLUTE pidl)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ return hr;
}
-/// Called when the user has selected an item.
-STDMETHODIMP CExplorerBand::OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl)
+void CExplorerBand::_DestroyTreeView()
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
+ CComPtr<IWebBrowser2> browserService;
+ HRESULT hr = IUnknown_QueryService(m_pSite, SID_SWebBrowserApp,
+ IID_PPV_ARG(IWebBrowser2, &browserService));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return;
-/// Returns flags used to update the tree control.
-STDMETHODIMP CExplorerBand::RefreshFlags(
- _Out_ DWORD *pdwStyle,
- _Out_ DWORD *pdwExStyle,
- _Out_ DWORD *dwEnum)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
+ AtlUnadvise(browserService, DIID_DWebBrowserEvents, m_adviseCookie);
-STDMETHODIMP CExplorerBand::CacheItem(_In_ PCIDLIST_ABSOLUTE pidl)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ CNSCBand::_DestroyTreeView();
}
// *** IDispatch methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetTypeInfoCount(UINT *pctinfo)
+
+STDMETHODIMP CExplorerBand::GetTypeInfoCount(UINT *pctinfo)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo
**ppTInfo)
+STDMETHODIMP CExplorerBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId)
+STDMETHODIMP CExplorerBand::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
-HRESULT STDMETHODCALLTYPE CExplorerBand::Invoke(DISPID dispIdMember, REFIID riid, LCID
lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
UINT *puArgErr)
+STDMETHODIMP
+CExplorerBand::Invoke(
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr)
{
switch (dispIdMember)
{
case DISPID_DOWNLOADCOMPLETE:
case DISPID_NAVIGATECOMPLETE2:
- TRACE("DISPID_NAVIGATECOMPLETE2 received\n");
- NavigateToCurrentFolder();
- return S_OK;
+ {
+ TRACE("dispId %d received\n", dispIdMember);
+ _NavigateToCurrentFolder();
+ return S_OK;
+ }
}
TRACE("Unknown dispid requested: %08x\n", dispIdMember);
return E_INVALIDARG;
}
-// *** IDropTarget methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::DragEnter(IDataObject *pObj, DWORD glfKeyState,
POINTL pt, DWORD *pdwEffect)
+BOOL CExplorerBand::_NavigateToCurrentFolder()
{
- ERR("Entering drag\n");
- m_pCurObject = pObj;
- m_oldSelected = TreeView_GetSelection(m_hWnd);
- return DragOver(glfKeyState, pt, pdwEffect);
-}
+ CComHeapPtr<ITEMIDLIST> pidl;
+ HRESULT hr = _GetCurrentLocation(&pidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
-HRESULT STDMETHODCALLTYPE CExplorerBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD
*pdwEffect)
-{
- TVHITTESTINFO info;
- CComPtr<IShellFolder> pShellFldr;
- NodeInfo *nodeInfo;
- //LPCITEMIDLIST pChild;
- HRESULT hr;
+ // Find PIDL into our explorer
+ ++m_mtxBlockNavigate;
+ HTREEITEM hItem;
+ BOOL result = _NavigateToPIDL(pidl, &hItem, TRUE, FALSE, TRUE);
+ --m_mtxBlockNavigate;
+
+ return result;
+}
- info.pt.x = pt.x;
- info.pt.y = pt.y;
- info.flags = TVHT_ONITEM;
- info.hItem = NULL;
- ScreenToClient(&info.pt);
+/**
+ * Navigate to a given PIDL in the treeview, and return matching tree item handle
+ * - dest: The absolute PIDL we should navigate in the treeview
+ * - item: Handle of the tree item matching the PIDL
+ * - bExpand: expand collapsed nodes in order to find the right element
+ * - bInsert: insert the element at the right place if we don't find it
+ * - bSelect: select the item after we found it
+ */
+BOOL
+CExplorerBand::_NavigateToPIDL(
+ _In_ LPCITEMIDLIST dest,
+ _Out_ HTREEITEM *phItem,
+ _In_ BOOL bExpand,
+ _In_ BOOL bInsert,
+ _In_ BOOL bSelect)
+{
+ if (!phItem)
+ return FALSE;
- // Move to the item selected by the treeview (don't change right pane)
- TreeView_HitTest(m_hWnd, &info);
+ *phItem = NULL;
- if (info.hItem)
+ HTREEITEM hItem = TreeView_GetFirstVisible(m_hwndTreeView);
+ HTREEITEM hParent = NULL, tmp;
+ while (TRUE)
{
- ++m_mtxBlockNavigate;
- TreeView_SelectItem(m_hWnd, info.hItem);
- --m_mtxBlockNavigate;
- // Delegate to shell folder
- if (m_pDropTarget && info.hItem != m_childTargetNode)
+ CItemData *pItemData = GetItemData(hItem);
+ if (!pItemData)
+ {
+ ERR("Something has gone wrong, no data associated to node\n");
+ return FALSE;
+ }
+
+ // If we found our node, give it back
+ if (!m_pDesktop->CompareIDs(0, pItemData->absolutePidl, dest))
{
- m_pDropTarget = NULL;
+ if (bSelect)
+ TreeView_SelectItem(m_hwndTreeView, hItem);
+ *phItem = hItem;
+ return TRUE;
}
- if (info.hItem != m_childTargetNode)
+
+ // Check if we are a parent of the requested item
+ TVITEMW tvItem;
+ LPITEMIDLIST relativeChild = ILFindChild(pItemData->absolutePidl, dest);
+ if (relativeChild)
{
- 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 = m_pDesktop;
- else
+ // Notify treeview we have children
+ tvItem.mask = TVIF_CHILDREN;
+ tvItem.hItem = hItem;
+ tvItem.cChildren = 1;
+ TreeView_SetItem(m_hwndTreeView, &tvItem);
+
+ // If we can expand and the node isn't expanded yet, do it
+ if (bExpand)
{
- hr = m_pDesktop->BindToObject(nodeInfo->absolutePidl, 0,
IID_PPV_ARG(IShellFolder, &pShellFldr));
- if (!SUCCEEDED(hr))
+ if (!pItemData->expanded)
{
- /* 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;
+ _InsertSubitems(hItem, pItemData->absolutePidl);
+ pItemData->expanded = TRUE;
}
+ TreeView_Expand(m_hwndTreeView, hItem, TVE_EXPAND);
+ }
+
+ // Try to get a child
+ tmp = TreeView_GetChild(m_hwndTreeView, hItem);
+ if (tmp)
+ {
+ // We have a child, let's continue with it
+ hParent = hItem;
+ hItem = tmp;
+ continue;
}
- hr = pShellFldr->CreateViewObject(m_hWnd, IID_PPV_ARG(IDropTarget,
&m_pDropTarget));
- if (!SUCCEEDED(hr))
+
+ if (bInsert && pItemData->expanded)
{
- /* 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;
+ // Happens when we have to create a subchild inside a child
+ hItem = _InsertItem(hItem, dest, relativeChild, TRUE);
}
- hr = m_pDropTarget->DragEnter(m_pCurObject, glfKeyState, pt, pdwEffect);
- m_childTargetNode = info.hItem;
+
+ // We end up here, without any children, so we found nothing
+ // Tell the parent node it has children
+ ZeroMemory(&tvItem, sizeof(tvItem));
+ return FALSE;
}
- if (m_pDropTarget)
+
+ // Find sibling
+ tmp = TreeView_GetNextSibling(m_hwndTreeView, hItem);
+ if (tmp)
{
- hr = m_pDropTarget->DragOver(glfKeyState, pt, pdwEffect);
+ hItem = tmp;
+ continue;
}
- }
- else
- {
- m_childTargetNode = NULL;
- m_pDropTarget = NULL;
- *pdwEffect = DROPEFFECT_NONE;
- }
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CExplorerBand::DragLeave()
-{
- ++m_mtxBlockNavigate;
- TreeView_SelectItem(m_hWnd, m_oldSelected);
- --m_mtxBlockNavigate;
- m_childTargetNode = NULL;
- if (m_pCurObject)
- {
- m_pCurObject = NULL;
- }
- return S_OK;
-}
-HRESULT STDMETHODCALLTYPE CExplorerBand::Drop(IDataObject *pObj, DWORD glfKeyState,
POINTL pt, DWORD *pdwEffect)
-{
- if (!m_pDropTarget)
- return E_FAIL;
- m_pDropTarget->Drop(pObj, glfKeyState, pt, pdwEffect);
- DragLeave();
- return S_OK;
-}
+ if (bInsert)
+ {
+ *phItem = hItem = _InsertItem(hParent, dest, ILFindLastID(dest), TRUE);
+ return TRUE;
+ }
-// *** IDropSource methods ***
-HRESULT STDMETHODCALLTYPE CExplorerBand::QueryContinueDrag(BOOL fEscapePressed, DWORD
grfKeyState)
-{
- if (fEscapePressed)
- return DRAGDROP_S_CANCEL;
- if ((grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
- return S_OK;
- return DRAGDROP_S_DROP;
-}
+ return FALSE;
+ }
-HRESULT STDMETHODCALLTYPE CExplorerBand::GiveFeedback(DWORD dwEffect)
-{
- return DRAGDROP_S_USEDEFAULTCURSORS;
+ UNREACHABLE;
}
diff --git a/dll/win32/shdocvw/CExplorerBand.h b/dll/win32/shdocvw/CExplorerBand.h
index 5c307deacce..6a2597605f8 100644
--- a/dll/win32/shdocvw/CExplorerBand.h
+++ b/dll/win32/shdocvw/CExplorerBand.h
@@ -8,185 +8,27 @@
#pragma once
-#define WM_USER_SHELLEVENT (WM_USER + 88)
+#include "CNSCBand.h"
-class CExplorerBand :
- public CComCoClass<CExplorerBand, &CLSID_ExplorerBand>,
- public CComObjectRootEx<CComMultiThreadModelNoCS>,
- public IDeskBand,
- public IObjectWithSite,
- public IInputObject,
- public IPersistStream,
- public IOleCommandTarget,
- public IServiceProvider,
- public IBandNavigate,
- public IWinEventHandler,
- public INamespaceProxy,
- public IDispatch,
- public IDropSource,
- public IDropTarget,
- public CWindowImpl<CExplorerBand, CWindow, CControlWinTraits>
+class CExplorerBand
+ : public CNSCBand
+ , public CComCoClass<CExplorerBand, &CLSID_ExplorerBand>
+ , public CComObjectRootEx<CComMultiThreadModelNoCS>
+ , public IDispatch
{
-private:
- class NodeInfo
- {
- public:
- LPITEMIDLIST absolutePidl;
- LPITEMIDLIST relativePidl;
- BOOL expanded;
- };
-
- // *** BaseBarSite information ***
- CComPtr<IUnknown> m_pSite;
- CComPtr<IShellFolder> m_pDesktop;
-
- // *** tree explorer band stuff ***
- BOOL m_fVisible;
- BYTE m_mtxBlockNavigate; // A "lock" that prevents internal selection
changes to initiate a navigation to the newly selected item.
- BOOL m_bFocused;
- DWORD m_dwBandID;
- BOOL m_isEditing;
- HIMAGELIST m_hImageList;
- HTREEITEM m_hRoot;
- HTREEITEM m_oldSelected;
- LPITEMIDLIST m_pidlCurrent; // Note: This is NULL until the first user navigation!
-
- // *** notification cookies ***
- DWORD m_adviseCookie;
- ULONG m_shellRegID;
-
- // *** Drop target information ***
- CComPtr<IDropTarget> m_pDropTarget;
- HTREEITEM m_childTargetNode;
- CComPtr<IDataObject> m_pCurObject;
-
- void InitializeExplorerBand();
- void DestroyExplorerBand();
- HRESULT ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd);
-
- // *** notifications handling ***
- BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv);
- void OnSelectionChanged(LPNMTREEVIEW pnmtv);
- BOOL OnTreeItemDeleted(LPNMTREEVIEW pnmtv);
- void OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick);
-
- // *** ATL event handlers ***
- LRESULT OnContextMenu(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);
- LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
-
- // *** Helper functions ***
- NodeInfo* GetNodeInfo(HTREEITEM hItem);
- HRESULT UpdateBrowser(LPITEMIDLIST pidlGoto);
- HTREEITEM InsertItem(
- _In_opt_ HTREEITEM hParent,
- _Inout_ IShellFolder *psfParent,
- _In_ LPCITEMIDLIST pElt,
- _In_ LPCITEMIDLIST pEltRelative,
- _In_ BOOL bSort);
- HTREEITEM InsertItem(
- _In_opt_ HTREEITEM hParent,
- _In_ LPCITEMIDLIST pElt,
- _In_ LPCITEMIDLIST pEltRelative,
- _In_ BOOL bSort);
- BOOL InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo);
- BOOL NavigateToPIDL(LPCITEMIDLIST dest, HTREEITEM *item, BOOL bExpand, BOOL bInsert,
BOOL bSelect);
- BOOL NavigateToCurrentFolder();
- HRESULT GetCurrentLocation(PIDLIST_ABSOLUTE &pidl);
- HRESULT IsCurrentLocation(PCIDLIST_ABSOLUTE pidl);
- void OnChangeNotify(
- _In_opt_ LPCITEMIDLIST pidl0,
- _In_opt_ LPCITEMIDLIST pidl1,
- _In_ LONG lEvent);
- void Refresh();
- void RefreshRecurse(_In_ HTREEITEM hItem);
- BOOL IsTreeItemInEnum(_In_ HTREEITEM hItem, _In_ IEnumIDList *pEnum);
- BOOL TreeItemHasThisChild(_In_ HTREEITEM hItem, _In_ PCITEMID_CHILD pidlChild);
- HRESULT GetItemEnum(_Out_ CComPtr<IEnumIDList>& pEnum, _In_ HTREEITEM
hItem);
- BOOL ItemHasAnyChild(_In_ HTREEITEM hItem);
-
- // *** Tree item sorting callback ***
- static int CALLBACK CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3);
-
public:
CExplorerBand();
virtual ~CExplorerBand();
- // *** IOleWindow methods ***
- STDMETHOD(GetWindow)(HWND *lphwnd) override;
- STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode) override;
-
- // *** IDockingWindow methods ***
- STDMETHOD(CloseDW)(DWORD dwReserved) override;
- STDMETHOD(ResizeBorderDW)(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL
fReserved) override;
- STDMETHOD(ShowDW)(BOOL fShow) override;
-
- // *** IDeskBand methods ***
- STDMETHOD(GetBandInfo)(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
override;
-
- // *** IObjectWithSite methods ***
- STDMETHOD(SetSite)(IUnknown *pUnkSite) override;
- STDMETHOD(GetSite)(REFIID riid, void **ppvSite) override;
-
- // *** IOleCommandTarget methods ***
- STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [],
OLECMDTEXT *pCmdText) override;
- STDMETHOD(Exec)(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT
*pvaIn, VARIANT *pvaOut) override;
-
- // *** IServiceProvider methods ***
- STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppvObject)
override;
-
- // *** IInputObject methods ***
- STDMETHOD(UIActivateIO)(BOOL fActivate, LPMSG lpMsg) override;
- STDMETHOD(HasFocusIO)() override;
- STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg) override;
-
- // *** IPersist methods ***
- STDMETHOD(GetClassID)(CLSID *pClassID) override;
-
- // *** IPersistStream methods ***
- STDMETHOD(IsDirty)() override;
- STDMETHOD(Load)(IStream *pStm) override;
- STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty) override;
- STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize) override;
-
- // *** IWinEventHandler methods ***
- STDMETHOD(OnWinEvent)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT
*theResult) override;
- STDMETHOD(IsWindowOwner)(HWND hWnd) override;
-
- // *** IBandNavigate methods ***
- STDMETHOD(Select)(long paramC) override;
-
- // *** INamespaceProxy ***
- STDMETHOD(GetNavigateTarget)(
- _In_ PCIDLIST_ABSOLUTE pidl,
- _Out_ PIDLIST_ABSOLUTE ppidlTarget,
- _Out_ ULONG *pulAttrib) override;
- STDMETHOD(Invoke)(_In_ PCIDLIST_ABSOLUTE pidl) override;
- STDMETHOD(OnSelectionChanged)(_In_ PCIDLIST_ABSOLUTE pidl) override;
- STDMETHOD(RefreshFlags)(
- _Out_ DWORD *pdwStyle,
- _Out_ DWORD *pdwExStyle,
- _Out_ DWORD *dwEnum) override;
- STDMETHOD(CacheItem)(_In_ PCIDLIST_ABSOLUTE pidl) override;
+ STDMETHODIMP GetClassID(CLSID *pClassID) override;
+ STDMETHODIMP OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl) override;
+ STDMETHODIMP Invoke(_In_ PCIDLIST_ABSOLUTE pidl) override;
// *** IDispatch methods ***
- STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) override;
- STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
- STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid,
DISPID *rgDispId) override;
- STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
override;
-
- // *** IDropTarget methods ***
- STDMETHOD(DragEnter)(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD
*pdwEffect) override;
- STDMETHOD(DragOver)(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect) override;
- STDMETHOD(DragLeave)() override;
- STDMETHOD(Drop)(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
override;
-
- // *** IDropSource methods ***
- STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState) override;
- STDMETHOD(GiveFeedback)(DWORD dwEffect) override;
+ STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override;
+ STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
+ STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid,
DISPID *rgDispId) override;
+ STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
override;
DECLARE_REGISTRY_RESOURCEID(IDR_EXPLORERBAND)
DECLARE_NOT_AGGREGATABLE(CExplorerBand)
@@ -194,27 +36,39 @@ public:
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CExplorerBand)
- COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
- COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
- COM_INTERFACE_ENTRY_IID(IID_IBandNavigate, IBandNavigate)
- COM_INTERFACE_ENTRY_IID(IID_INamespaceProxy, INamespaceProxy)
- COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
- COM_INTERFACE_ENTRY2_IID(IID_IDockingWindow, IDockingWindow, IDeskBand)
COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
+ COM_INTERFACE_ENTRY2_IID(IID_IDockingWindow, IDockingWindow, IDeskBand)
+ COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
- COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
- COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
- COM_INTERFACE_ENTRY2_IID(IID_IPersist, IPersist, IPersistStream)
COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
+ COM_INTERFACE_ENTRY2_IID(IID_IPersist, IPersist, IPersistStream)
+ COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
+ COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
+ COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
+ COM_INTERFACE_ENTRY_IID(IID_IBandNavigate, IBandNavigate)
+ COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
+ COM_INTERFACE_ENTRY_IID(IID_INamespaceProxy, INamespaceProxy)
+ COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
+ COM_INTERFACE_ENTRY2_IID(IID_IUnknown, IUnknown, IDispatch)
END_COM_MAP()
- BEGIN_MSG_MAP(CExplorerBand)
- MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
- MESSAGE_HANDLER(WM_USER_SHELLEVENT, OnShellEvent)
- MESSAGE_HANDLER(WM_RBUTTONDOWN, ContextMenuHack)
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
- MESSAGE_HANDLER(WM_TIMER, OnTimer)
- // MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
- END_MSG_MAP()
+protected:
+ INT _GetRootCsidl() override;
+ DWORD _GetTVStyle() override;
+ DWORD _GetTVExStyle() override;
+ DWORD _GetEnumFlags() override;
+ HRESULT _CreateTreeView(HWND hwndParent) override;
+ void _DestroyTreeView() override;
+ BOOL _WantsRootItem() override;
+ BOOL _GetTitle(LPWSTR pszTitle, INT cchTitle) override;
+ void _SortItems(HTREEITEM hParent) override;
+ BOOL _NavigateToCurrentFolder();
+ BOOL _NavigateToPIDL(
+ _In_ LPCITEMIDLIST dest,
+ _Out_ HTREEITEM *phItem,
+ _In_ BOOL bExpand,
+ _In_ BOOL bInsert,
+ _In_ BOOL bSelect);
+ static INT CALLBACK _CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3); // Used by
_SortItems
};
diff --git a/dll/win32/shdocvw/CFavBand.cpp b/dll/win32/shdocvw/CFavBand.cpp
index bc00c3943bb..b79f2e27be2 100644
--- a/dll/win32/shdocvw/CFavBand.cpp
+++ b/dll/win32/shdocvw/CFavBand.cpp
@@ -11,40 +11,64 @@
WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
CFavBand::CFavBand()
- : m_fVisible(FALSE)
- , m_bFocused(FALSE)
- , m_dwBandID(0)
- , m_hToolbarImageList(NULL)
- , m_hTreeViewImageList(NULL)
{
- SHDOCVW_LockModule();
- SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &m_pidlFav);
}
CFavBand::~CFavBand()
{
- if (m_hToolbarImageList)
- {
- ImageList_Destroy(m_hToolbarImageList);
- m_hToolbarImageList = NULL;
- }
- if (m_hTreeViewImageList)
+}
+
+STDMETHODIMP CFavBand::GetClassID(CLSID *pClassID)
+{
+ if (!pClassID)
+ return E_POINTER;
+ *pClassID = CLSID_SH_FavBand;
+ return S_OK;
+}
+
+INT CFavBand::_GetRootCsidl()
+{
+ return CSIDL_FAVORITES;
+}
+
+DWORD CFavBand::_GetTVStyle()
+{
+ // Remove TVS_SINGLEEXPAND for now since it has strange behaviour
+ return TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_FULLROWSELECT | TVS_INFOTIP |
+ /*TVS_SINGLEEXPAND | TVS_TRACKSELECT |*/ TVS_SHOWSELALWAYS | TVS_EDITLABELS |
+ WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP;
+}
+
+DWORD CFavBand::_GetTVExStyle()
+{
+ return WS_EX_CLIENTEDGE;
+}
+
+DWORD CFavBand::_GetEnumFlags()
+{
+ return SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
+}
+
+BOOL CFavBand::_GetTitle(LPWSTR pszTitle, INT cchTitle)
+{
+#define IDS_FAVORITES 47 // Borrowed from shell32.dll
+ HINSTANCE hShell32 = ::LoadLibraryExW(L"shell32.dll", NULL,
LOAD_LIBRARY_AS_DATAFILE);
+ if (hShell32)
{
- ImageList_Destroy(m_hTreeViewImageList);
- m_hTreeViewImageList = NULL;
+ ::LoadStringW(hShell32, IDS_FAVORITES, pszTitle, cchTitle);
+ ::FreeLibrary(hShell32);
+ return TRUE;
}
- SHDOCVW_UnlockModule();
+ return FALSE;
+#undef IDS_FAVORITES
}
-VOID CFavBand::OnFinalMessage(HWND)
+BOOL CFavBand::_WantsRootItem()
{
- // The message loop is finished, now we can safely destruct!
- Release();
+ return FALSE;
}
-// *** helper methods ***
-
-BOOL CFavBand::CreateToolbar()
+HRESULT CFavBand::_CreateToolbar(HWND hwndParent)
{
#define IDB_SHELL_EXPLORER_SM 216 // Borrowed from browseui.dll
HINSTANCE hinstBrowseUI = LoadLibraryExW(L"browseui.dll", NULL,
LOAD_LIBRARY_AS_DATAFILE);
@@ -58,23 +82,23 @@ BOOL CFavBand::CreateToolbar()
#undef IDB_SHELL_EXPLORER_SM
ATLASSERT(hbmToolbar);
if (!hbmToolbar)
- return FALSE;
+ return E_FAIL;
m_hToolbarImageList = ImageList_Create(16, 16, ILC_COLOR32, 0, 8);
ATLASSERT(m_hToolbarImageList);
if (!m_hToolbarImageList)
- return FALSE;
+ return E_FAIL;
ImageList_Add(m_hToolbarImageList, hbmToolbar, NULL);
DeleteObject(hbmToolbar);
DWORD style = WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_LIST | CCS_NODIVIDER |
TBSTYLE_WRAPABLE;
- HWND hwndTB = ::CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style, 0, 0, 0, 0,
m_hWnd,
- (HMENU)(LONG_PTR)IDW_TOOLBAR, instance, NULL);
+ HWND hwndTB = ::CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style, 0, 0, 0, 0,
hwndParent,
+ (HMENU)UlongToHandle(IDW_TOOLBAR), instance, NULL);
ATLASSERT(hwndTB);
if (!hwndTB)
- return FALSE;
+ return E_FAIL;
m_hwndToolbar.Attach(hwndTB);
m_hwndToolbar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
@@ -102,480 +126,57 @@ BOOL CFavBand::CreateToolbar()
tbb[iButton].iString = (INT)m_hwndToolbar.SendMessage(TB_ADDSTRING, 0,
(LPARAM)szzOrganize);
++iButton;
ATLASSERT(iButton == _countof(tbb));
+ m_hwndToolbar.SendMessage(TB_ADDBUTTONS, iButton, (LPARAM)&tbb);
- LRESULT ret = m_hwndToolbar.SendMessage(TB_ADDBUTTONS, iButton, (LPARAM)&tbb);
- ATLASSERT(ret);
-
- return ret;
-}
-
-BOOL CFavBand::CreateTreeView()
-{
- m_hTreeViewImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 64, 0);
- ATLASSERT(m_hTreeViewImageList);
- if (!m_hTreeViewImageList)
- return FALSE;
-
- DWORD style = TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_FULLROWSELECT | TVS_INFOTIP |
- TVS_SINGLEEXPAND | TVS_TRACKSELECT | TVS_SHOWSELALWAYS | TVS_EDITLABELS
|
- WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_TABSTOP;
- HWND hwndTV = ::CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, NULL, style, 0, 0, 0,
0,
- m_hWnd, (HMENU)(ULONG_PTR)IDW_TREEVIEW, instance,
NULL);
- ATLASSERT(hwndTV);
- if (!hwndTV)
- return FALSE;
-
- m_hwndTreeView.Attach(hwndTV);
- TreeView_SetImageList(m_hwndTreeView, m_hTreeViewImageList, TVSIL_NORMAL);
-
- return TRUE;
-}
-
-// *** message handlers ***
-
-LRESULT CFavBand::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-{
- INITCOMMONCONTROLSEX iccx = { sizeof(iccx), ICC_TREEVIEW_CLASSES | ICC_BAR_CLASSES
};
- if (!::InitCommonControlsEx(&iccx) || !CreateToolbar() || !CreateTreeView())
- return -1;
-
- return 0;
-}
-
-LRESULT CFavBand::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-{
- m_hwndTreeView.DestroyWindow();
- m_hwndToolbar.DestroyWindow();
- return 0;
-}
-
-LRESULT CFavBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-{
- if (!m_hwndTreeView)
- return 0;
-
- RECT rc;
- GetClientRect(&rc);
- LONG cx = rc.right, cy = rc.bottom;
-
- RECT rcTB;
- m_hwndToolbar.SendMessage(TB_AUTOSIZE, 0, 0);
- m_hwndToolbar.GetWindowRect(&rcTB);
-
- LONG cyTB = rcTB.bottom - rcTB.top;
- m_hwndTreeView.MoveWindow(0, cyTB, cx, cy - cyTB);
-
- return 0;
-}
-
-LRESULT CFavBand::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- m_bFocused = TRUE;
- IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), TRUE);
- return 0;
-}
-
-LRESULT CFavBand::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), FALSE);
- m_bFocused = FALSE;
- return 0;
-}
-
-LRESULT CFavBand::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
-{
- switch (LOWORD(wParam))
- {
- case ID_ADD:
- {
- UNIMPLEMENTED;
- SHELL_ErrorBox(m_hWnd, ERROR_NOT_SUPPORTED);
- break;
- }
- case ID_ORGANIZE:
- {
- SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_IDLIST };
- sei.hwnd = m_hWnd;
- sei.nShow = SW_SHOWNORMAL;
- sei.lpIDList = m_pidlFav;
- ::ShellExecuteExW(&sei);
- break;
- }
- }
- return 0;
-}
-
-// *** IOleWindow ***
-
-STDMETHODIMP CFavBand::GetWindow(HWND *lphwnd)
-{
- if (!lphwnd)
- return E_INVALIDARG;
- *lphwnd = m_hWnd;
return S_OK;
}
-STDMETHODIMP CFavBand::ContextSensitiveHelp(BOOL fEnterMode)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IDockingWindow ***
-
-STDMETHODIMP CFavBand::CloseDW(DWORD dwReserved)
-{
- // We do nothing, we don't have anything to save yet
- TRACE("CloseDW called\n");
- return S_OK;
-}
-
-STDMETHODIMP CFavBand::ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite,
BOOL fReserved)
-{
- /* Must return E_NOTIMPL according to MSDN */
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::ShowDW(BOOL fShow)
-{
- m_fVisible = fShow;
- ShowWindow(fShow ? SW_SHOW : SW_HIDE);
- return S_OK;
-}
-
-// *** IDeskBand ***
-
-STDMETHODIMP CFavBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
+// Called when the user has selected an item.
+STDMETHODIMP CFavBand::OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl)
{
- if (!pdbi)
- return E_INVALIDARG;
+ CComHeapPtr<ITEMIDLIST> pidlTarget;
+ DWORD attrs = SFGAO_FOLDER | SFGAO_LINK;
+ HRESULT hr = GetNavigateTarget(pidl, &pidlTarget, &attrs);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- m_dwBandID = dwBandID;
+ if ((attrs & (SFGAO_FOLDER | SFGAO_LINK)) == (SFGAO_FOLDER | SFGAO_LINK))
+ return _UpdateBrowser(pidlTarget);
- if (pdbi->dwMask & DBIM_MINSIZE)
+ if (attrs & SFGAO_FOLDER)
{
- pdbi->ptMinSize.x = 200;
- pdbi->ptMinSize.y = 30;
- }
-
- if (pdbi->dwMask & DBIM_MAXSIZE)
- pdbi->ptMaxSize.y = -1;
-
- if (pdbi->dwMask & DBIM_INTEGRAL)
- pdbi->ptIntegral.y = 1;
-
- if (pdbi->dwMask & DBIM_ACTUAL)
- {
- pdbi->ptActual.x = 200;
- pdbi->ptActual.y = 30;
- }
-
- if (pdbi->dwMask & DBIM_TITLE)
- {
-#define IDS_FAVORITES 47 // Borrowed from shell32.dll
- HINSTANCE hShell32 = LoadLibraryExW(L"shell32.dll", NULL,
LOAD_LIBRARY_AS_DATAFILE);
- if (hShell32)
+ HTREEITEM hItem = TreeView_GetSelection(m_hwndTreeView);
+ CItemData *pItemData = GetItemData(hItem);
+ if (pItemData && !pItemData->expanded)
{
- LoadStringW(hShell32, IDS_FAVORITES, pdbi->wszTitle,
_countof(pdbi->wszTitle));
- FreeLibrary(hShell32);
+ _InsertSubitems(hItem, pItemData->absolutePidl);
+ pItemData->expanded = TRUE;
}
-#undef IDS_FAVORITES
- }
-
- if (pdbi->dwMask & DBIM_MODEFLAGS)
- pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
-
- if (pdbi->dwMask & DBIM_BKCOLOR)
- pdbi->dwMask &= ~DBIM_BKCOLOR;
-
- return S_OK;
-}
-
-// *** IObjectWithSite ***
-
-STDMETHODIMP CFavBand::SetSite(IUnknown *pUnkSite)
-{
- HRESULT hr;
-
- if (pUnkSite == m_pSite)
- return S_OK;
-
- TRACE("SetSite called\n");
-
- if (!pUnkSite)
- {
- DestroyWindow();
- m_hWnd = NULL;
- }
-
- if (pUnkSite != m_pSite)
- m_pSite = NULL;
-
- if (!pUnkSite)
- return S_OK;
-
- HWND hwndParent;
- hr = IUnknown_GetWindow(pUnkSite, &hwndParent);
- if (!SUCCEEDED(hr))
- {
- ERR("Could not get parent's window! 0x%08lX\n", hr);
- return E_INVALIDARG;
- }
-
- m_pSite = pUnkSite;
-
- if (m_hWnd)
- {
- SetParent(hwndParent); // Change its parent
- }
- else
- {
- this->Create(hwndParent, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, (UINT)0,
NULL);
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CFavBand::GetSite(REFIID riid, void **ppvSite)
-{
- if (!ppvSite)
- return E_POINTER;
- *ppvSite = m_pSite;
- return S_OK;
-}
-
-// *** IOleCommandTarget ***
-
-STDMETHODIMP CFavBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds
[], OLECMDTEXT *pCmdText)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
VARIANT *pvaIn, VARIANT *pvaOut)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IServiceProvider ***
-
-STDMETHODIMP CFavBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IServiceProvider ***
-
-STDMETHODIMP CFavBand::QueryContextMenu(
- HMENU hmenu,
- UINT indexMenu,
- UINT idCmdFirst,
- UINT idCmdLast,
- UINT uFlags)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::InvokeCommand(
- LPCMINVOKECOMMANDINFO lpici)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::GetCommandString(
- UINT_PTR idCmd,
- UINT uType,
- UINT *pwReserved,
- LPSTR pszName,
- UINT cchMax)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IInputObject ***
-
-STDMETHODIMP CFavBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
-{
- if (fActivate)
- {
- //SetFocus();
- SetActiveWindow();
- }
-
- if (lpMsg)
- {
- TranslateMessage(lpMsg);
- DispatchMessage(lpMsg);
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CFavBand::HasFocusIO()
-{
- return m_bFocused ? S_OK : S_FALSE;
-}
-
-STDMETHODIMP CFavBand::TranslateAcceleratorIO(LPMSG lpMsg)
-{
- if (lpMsg->hwnd == m_hWnd)
- {
- TranslateMessage(lpMsg);
- DispatchMessage(lpMsg);
+ TreeView_Expand(m_hwndTreeView, hItem, TVE_EXPAND);
return S_OK;
}
- return S_FALSE;
-}
-
-// *** IPersist ***
-
-STDMETHODIMP CFavBand::GetClassID(CLSID *pClassID)
-{
- if (!pClassID)
- return E_POINTER;
- *pClassID = CLSID_SH_FavBand;
- return S_OK;
+ SHELLEXECUTEINFOW info = { sizeof(info) };
+ info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_IDLIST;
+ info.hwnd = m_hWnd;
+ info.nShow = SW_SHOWNORMAL;
+ info.lpIDList = pidlTarget;
+ ShellExecuteExW(&info);
+ return hr;
}
-
-// *** IPersistStream ***
-
-STDMETHODIMP CFavBand::IsDirty()
+void CFavBand::_SortItems(HTREEITEM hParent)
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
+ TreeView_SortChildren(m_hwndTreeView, hParent, 0); // Sort by name
}
-STDMETHODIMP CFavBand::Load(IStream *pStm)
+HRESULT CFavBand::_CreateTreeView(HWND hwndParent)
{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
+ HRESULT hr = CNSCBand::_CreateTreeView(hwndParent);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
-STDMETHODIMP CFavBand::Save(IStream *pStm, BOOL fClearDirty)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
-{
- // TODO: calculate max size
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IWinEventHandler ***
-
-STDMETHODIMP CFavBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
LRESULT *theResult)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::IsWindowOwner(HWND hWnd)
-{
- return (hWnd == m_hWnd) ? S_OK : S_FALSE;
-}
-
-// *** IBandNavigate ***
-
-STDMETHODIMP CFavBand::Select(long paramC)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** INamespaceProxy ***
-
-/// Returns the ITEMIDLIST that should be navigated when an item is invoked.
-STDMETHODIMP CFavBand::GetNavigateTarget(
- _In_ PCIDLIST_ABSOLUTE pidl,
- _Out_ PIDLIST_ABSOLUTE ppidlTarget,
- _Out_ ULONG *pulAttrib)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-/// Handles a user action on an item.
-STDMETHODIMP CFavBand::Invoke(_In_ PCIDLIST_ABSOLUTE pidl)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-/// Called when the user has selected an item.
-STDMETHODIMP CFavBand::OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-/// Returns flags used to update the tree control.
-STDMETHODIMP CFavBand::RefreshFlags(
- _Out_ DWORD *pdwStyle,
- _Out_ DWORD *pdwExStyle,
- _Out_ DWORD *dwEnum)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::CacheItem(
- _In_ PCIDLIST_ABSOLUTE pidl)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-// *** IDispatch ***
-
-STDMETHODIMP CFavBand::GetTypeInfoCount(UINT *pctinfo)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::GetIDsOfNames(
- REFIID riid,
- LPOLESTR *rgszNames,
- UINT cNames,
- LCID lcid,
- DISPID *rgDispId)
-{
- UNIMPLEMENTED;
- return E_NOTIMPL;
-}
-
-STDMETHODIMP CFavBand::Invoke(
- DISPID dispIdMember,
- REFIID riid,
- LCID lcid,
- WORD wFlags,
- DISPPARAMS *pDispParams,
- VARIANT *pVarResult,
- EXCEPINFO *pExcepInfo,
- UINT *puArgErr)
-{
- switch (dispIdMember)
- {
- case DISPID_DOWNLOADCOMPLETE:
- case DISPID_NAVIGATECOMPLETE2:
- // FIXME: Update current location
- return S_OK;
- }
- return E_INVALIDARG;
+ TreeView_SetItemHeight(m_hwndTreeView, 24);
+ _InsertSubitems(TVI_ROOT, m_pidlRoot);
+ return hr;
}
diff --git a/dll/win32/shdocvw/CFavBand.h b/dll/win32/shdocvw/CFavBand.h
index 1b91e04779c..62619096491 100644
--- a/dll/win32/shdocvw/CFavBand.h
+++ b/dll/win32/shdocvw/CFavBand.h
@@ -7,129 +7,27 @@
#pragma once
-#define FAVBANDCLASSNAME L"ReactOS Favorites Band"
-
#ifdef __cplusplus
+
+#include "CNSCBand.h"
+
class CFavBand
- : public CComCoClass<CFavBand, &CLSID_SH_FavBand>
+ : public CNSCBand
+ , public CComCoClass<CFavBand, &CLSID_SH_FavBand>
, public CComObjectRootEx<CComMultiThreadModelNoCS>
- , public CWindowImpl<CFavBand>
- , public IDispatch
- , public IDeskBand
- , public IObjectWithSite
- , public IInputObject
- , public IPersistStream
- , public IOleCommandTarget
- , public IServiceProvider
- , public IContextMenu
- , public IBandNavigate
- , public IWinEventHandler
- , public INamespaceProxy
{
public:
- DECLARE_WND_CLASS_EX(FAVBANDCLASSNAME, 0, COLOR_3DFACE)
- static LPCWSTR GetWndClassName() { return FAVBANDCLASSNAME; }
-
CFavBand();
virtual ~CFavBand();
- // *** IOleWindow methods ***
- STDMETHODIMP GetWindow(HWND *lphwnd) override;
- STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override;
-
- // *** IDockingWindow methods ***
- STDMETHODIMP CloseDW(DWORD dwReserved) override;
- STDMETHODIMP ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL
fReserved) override;
- STDMETHODIMP ShowDW(BOOL fShow) override;
-
- // *** IDeskBand methods ***
- STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
override;
-
- // *** IObjectWithSite methods ***
- STDMETHODIMP SetSite(IUnknown *pUnkSite) override;
- STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override;
-
- // *** IOleCommandTarget methods ***
- STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [],
OLECMDTEXT *pCmdText) override;
- STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT
*pvaIn, VARIANT *pvaOut) override;
-
- // *** IServiceProvider methods ***
- STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
override;
-
- // *** IContextMenu methods ***
- STDMETHODIMP QueryContextMenu(
- HMENU hmenu,
- UINT indexMenu,
- UINT idCmdFirst,
- UINT idCmdLast,
- UINT uFlags) override;
- STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici) override;
- STDMETHODIMP GetCommandString(
- UINT_PTR idCmd,
- UINT uType,
- UINT *pwReserved,
- LPSTR pszName,
- UINT cchMax) override;
-
- // *** IInputObject methods ***
- STDMETHODIMP UIActivateIO(BOOL fActivate, LPMSG lpMsg) override;
- STDMETHODIMP HasFocusIO() override;
- STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg) override;
-
- // *** IPersist methods ***
STDMETHODIMP GetClassID(CLSID *pClassID) override;
-
- // *** IPersistStream methods ***
- STDMETHODIMP IsDirty() override;
- STDMETHODIMP Load(IStream *pStm) override;
- STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty) override;
- STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize) override;
-
- // *** IWinEventHandler methods ***
- STDMETHODIMP OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT
*theResult) override;
- STDMETHODIMP IsWindowOwner(HWND hWnd) override;
-
- // *** IBandNavigate methods ***
- STDMETHODIMP Select(long paramC) override;
-
- // *** INamespaceProxy methods ***
- STDMETHODIMP GetNavigateTarget(
- _In_ PCIDLIST_ABSOLUTE pidl,
- _Out_ PIDLIST_ABSOLUTE ppidlTarget,
- _Out_ ULONG *pulAttrib) override;
- STDMETHODIMP Invoke(_In_ PCIDLIST_ABSOLUTE pidl) override;
- STDMETHODIMP OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl) override;
- STDMETHODIMP RefreshFlags(
- _Out_ DWORD *pdwStyle,
- _Out_ DWORD *pdwExStyle,
- _Out_ DWORD *dwEnum) override;
- STDMETHODIMP CacheItem(_In_ PCIDLIST_ABSOLUTE pidl) override;
-
- // *** IDispatch methods ***
- STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override;
- STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
- STDMETHODIMP GetIDsOfNames(
- REFIID riid,
- LPOLESTR *rgszNames,
- UINT cNames,
- LCID lcid,
- DISPID *rgDispId) override;
- STDMETHODIMP Invoke(
- DISPID dispIdMember,
- REFIID riid,
- LCID lcid,
- WORD wFlags,
- DISPPARAMS *pDispParams,
- VARIANT *pVarResult,
- EXCEPINFO *pExcepInfo,
- UINT *puArgErr) override;
+ STDMETHODIMP OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl);
DECLARE_REGISTRY_RESOURCEID(IDR_FAVBAND)
DECLARE_NOT_AGGREGATABLE(CFavBand)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CFavBand)
- COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
COM_INTERFACE_ENTRY2_IID(IID_IDockingWindow, IDockingWindow, IDeskBand)
COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
@@ -146,38 +44,16 @@ public:
COM_INTERFACE_ENTRY_IID(IID_INamespaceProxy, INamespaceProxy)
END_COM_MAP()
- BEGIN_MSG_MAP(CFavBand)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
- MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
- MESSAGE_HANDLER(WM_COMMAND, OnCommand)
- END_MSG_MAP()
-
protected:
- BOOL m_fVisible;
- BOOL m_bFocused;
- DWORD m_dwBandID;
- CComPtr<IUnknown> m_pSite;
- CComHeapPtr<ITEMIDLIST> m_pidlFav;
- HIMAGELIST m_hToolbarImageList;
- HIMAGELIST m_hTreeViewImageList;
- CToolbar<> m_hwndToolbar;
- CTreeView m_hwndTreeView;
-
- VOID OnFinalMessage(HWND) override;
-
- // *** helper methods ***
- BOOL CreateToolbar();
- BOOL CreateTreeView();
-
- // *** message handlers ***
- LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
- LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
- LRESULT OnSize(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);
- LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ INT _GetRootCsidl() override;
+ DWORD _GetTVStyle() override;
+ DWORD _GetTVExStyle() override;
+ DWORD _GetEnumFlags() override;
+ BOOL _GetTitle(LPWSTR pszTitle, INT cchTitle) override;
+ HRESULT _CreateTreeView(HWND hwndParent) override;
+ HRESULT _CreateToolbar(HWND hwndParent) override;
+ BOOL _WantsRootItem() override;
+ void _SortItems(HTREEITEM hParent) override;
};
+
#endif // def __cplusplus
diff --git a/dll/win32/shdocvw/CMakeLists.txt b/dll/win32/shdocvw/CMakeLists.txt
index 71ab7e8ddb3..764663a42ed 100644
--- a/dll/win32/shdocvw/CMakeLists.txt
+++ b/dll/win32/shdocvw/CMakeLists.txt
@@ -34,6 +34,7 @@ add_cd_file(TARGET shdocvw DESTINATION reactos/system32 FOR all)
add_library(shdocvw_sublib OBJECT
CExplorerBand.cpp
CFavBand.cpp
+ CNSCBand.cpp
mrulist.cpp
objects.cpp
utility.cpp)
diff --git a/dll/win32/shdocvw/CNSCBand.cpp b/dll/win32/shdocvw/CNSCBand.cpp
new file mode 100644
index 00000000000..976acb50a7d
--- /dev/null
+++ b/dll/win32/shdocvw/CNSCBand.cpp
@@ -0,0 +1,1487 @@
+/*
+ * PROJECT: ReactOS shdocvw
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: NameSpace Control Band
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "objects.h"
+#include <shlobj.h>
+#include <commoncontrols.h>
+#include <undocshell.h>
+
+#define TIMER_ID_REFRESH 9999
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
+
+HRESULT
+SHDOCVW_GetPathOfShortcut(
+ _In_opt_ HWND hWnd,
+ _In_ LPCWSTR pszLnkFile,
+ _Out_ LPWSTR pszPath)
+{
+ *pszPath = UNICODE_NULL;
+ CComPtr<IShellLink> pShellLink;
+ HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellLink, &pShellLink));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComPtr<IPersistFile> pPersistFile;
+ hr = pShellLink->QueryInterface(IID_PPV_ARG(IPersistFile, &pPersistFile));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = pPersistFile->Load(pszLnkFile, STGM_READ);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ WIN32_FIND_DATA find;
+ hr = pShellLink->GetPath(pszPath, MAX_PATH, &find, 0);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ return S_OK;
+}
+
+HRESULT
+SHDOCVW_CreateShortcut(
+ _In_ LPCWSTR pszLnkFileName,
+ _In_ PCIDLIST_ABSOLUTE pidlTarget,
+ _In_opt_ LPCWSTR pszDescription)
+{
+ HRESULT hr;
+
+ CComPtr<IShellLink> psl;
+ hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellLink, &psl));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ psl->SetIDList(pidlTarget);
+
+ if (pszDescription)
+ psl->SetDescription(pszDescription);
+
+ CComPtr<IPersistFile> ppf;
+ hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ return ppf->Save(pszLnkFileName, TRUE);
+}
+
+CNSCBand::CNSCBand()
+{
+ SHDOCVW_LockModule();
+
+ INITCOMMONCONTROLSEX iccx = { sizeof(iccx), ICC_TREEVIEW_CLASSES | ICC_BAR_CLASSES
};
+ ::InitCommonControlsEx(&iccx);
+}
+
+CNSCBand::~CNSCBand()
+{
+ if (m_hToolbarImageList)
+ {
+ ImageList_Destroy(m_hToolbarImageList);
+ m_hToolbarImageList = NULL;
+ }
+ SHDOCVW_UnlockModule();
+}
+
+VOID CNSCBand::OnFinalMessage(HWND)
+{
+ // The message loop is finished, now we can safely destruct!
+ static_cast<IDeskBand *>(this)->Release();
+}
+
+// *** helper methods ***
+
+CNSCBand::CItemData* CNSCBand::GetItemData(_In_ HTREEITEM hItem)
+{
+ if (hItem == TVI_ROOT)
+ return NULL;
+
+ TVITEMW tvItem = { TVIF_PARAM, hItem };
+ if (!TreeView_GetItem(m_hwndTreeView, &tvItem))
+ return NULL;
+
+ return reinterpret_cast<CItemData*>(tvItem.lParam);
+}
+
+static HRESULT
+SHDOCVW_GetCurrentLocationFromView(_In_ IShellView& View, _In_ PIDLIST_ABSOLUTE
*ppidl)
+{
+ CComPtr<IFolderView> pfv;
+ CComPtr<IShellFolder> psf;
+ HRESULT hr = View.QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
+ if (SUCCEEDED(hr) && SUCCEEDED(hr =
pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf))))
+ hr = SHELL_GetIDListFromObject(psf, ppidl);
+ return hr;
+}
+
+HRESULT CNSCBand::_GetCurrentLocation(_Out_ PIDLIST_ABSOLUTE *ppidl)
+{
+ *ppidl = NULL;
+ CComPtr<IShellBrowser> psb;
+ HRESULT hr = IUnknown_QueryService(m_pSite, SID_STopLevelBrowser,
IID_PPV_ARG(IShellBrowser, &psb));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComPtr<IBrowserService> pbs;
+ if (SUCCEEDED(hr = psb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
+ if (SUCCEEDED(hr = pbs->GetPidl(ppidl)) && *ppidl)
+ return hr;
+
+ CComPtr<IShellView> psv;
+ if (!FAILED_UNEXPECTEDLY(hr = psb->QueryActiveShellView(&psv)))
+ if (SUCCEEDED(hr = psv.p ? SHDOCVW_GetCurrentLocationFromView(*psv.p, ppidl) :
E_FAIL))
+ return hr;
+ return hr;
+}
+
+HRESULT CNSCBand::_IsCurrentLocation(_In_ PCIDLIST_ABSOLUTE pidl)
+{
+ if (!pidl)
+ return E_INVALIDARG;
+ HRESULT hr = E_FAIL;
+ PIDLIST_ABSOLUTE location = NULL;
+ hr = _GetCurrentLocation(&location);
+ if (SUCCEEDED(hr))
+ hr = SHELL_IsEqualAbsoluteID(location, pidl) ? S_OK : S_FALSE;
+ ILFree(location);
+ return hr;
+}
+
+HRESULT CNSCBand::_ExecuteCommand(_In_ CComPtr<IContextMenu>& menu, _In_ UINT
nCmd)
+{
+ CComPtr<IOleWindow> pBrowserOleWnd;
+ HRESULT hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser,
+ IID_PPV_ARG(IOleWindow, &pBrowserOleWnd));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ HWND browserWnd;
+ hr = pBrowserOleWnd->GetWindow(&browserWnd);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CMINVOKECOMMANDINFO cmi = { sizeof(cmi) };
+ cmi.lpVerb = MAKEINTRESOURCEA(nCmd);
+ cmi.hwnd = browserWnd;
+ if (::GetKeyState(VK_SHIFT) < 0)
+ cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
+ if (::GetKeyState(VK_CONTROL) < 0)
+ cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
+
+ return menu->InvokeCommand(&cmi);
+}
+
+void CNSCBand::_RegisterChangeNotify()
+{
+#define TARGET_EVENTS ( \
+ SHCNE_DRIVEADD | SHCNE_MKDIR | SHCNE_CREATE | SHCNE_DRIVEREMOVED | SHCNE_RMDIR | \
+ SHCNE_DELETE | SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEDIR | \
+ SHCNE_UPDATEITEM | SHCNE_ASSOCCHANGED \
+)
+ // Register shell notification
+ SHChangeNotifyEntry shcne = { m_pidlRoot, TRUE };
+ m_shellRegID = SHChangeNotifyRegister(m_hWnd,
+ SHCNRF_NewDelivery | SHCNRF_ShellLevel,
+ TARGET_EVENTS,
+ WM_USER_SHELLEVENT,
+ 1, &shcne);
+ if (!m_shellRegID)
+ {
+ ERR("Something went wrong, error %08x\n", GetLastError());
+ }
+}
+
+void CNSCBand::_UnregisterChangeNotify()
+{
+ SHChangeNotifyDeregister(m_shellRegID);
+ m_shellRegID = 0;
+}
+
+void CNSCBand::_DestroyTreeView()
+{
+ TRACE("Cleaning up treeview...\n");
+ /* Remove all items of the treeview */
+ ::RevokeDragDrop(m_hwndTreeView);
+ TreeView_DeleteAllItems(m_hwndTreeView);
+ m_hwndTreeView.DestroyWindow();
+ m_pDesktop = NULL;
+ m_hRoot = NULL;
+ TRACE("Cleanup ok\n");
+}
+
+void CNSCBand::_DestroyToolbar()
+{
+ m_hwndToolbar.DestroyWindow();
+}
+
+HRESULT CNSCBand::_CreateTreeView(HWND hwndParent)
+{
+ RefreshFlags(&m_dwTVStyle, &m_dwTVExStyle, &m_dwEnumFlags);
+ HWND hwndTV = ::CreateWindowExW(m_dwTVExStyle, WC_TREEVIEWW, NULL, m_dwTVStyle, 0, 0,
0, 0,
+ hwndParent, (HMENU)UlongToHandle(IDW_TREEVIEW),
instance, NULL);
+ ATLASSERT(hwndTV);
+ if (!hwndTV)
+ return E_FAIL;
+
+ m_hwndTreeView.Attach(hwndTV);
+ ::RegisterDragDrop(m_hwndTreeView, dynamic_cast<IDropTarget*>(this));
+
+ // Init the treeview here
+ HRESULT hr = SHGetDesktopFolder(&m_pDesktop);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ m_pidlRoot.Free();
+ hr = SHGetFolderLocation(m_hWnd, _GetRootCsidl(), NULL, 0, &m_pidlRoot);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ // Create image list and set
+ IImageList *piml;
+ hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ TreeView_SetImageList(m_hwndTreeView, (HIMAGELIST)piml, TVSIL_NORMAL);
+ return S_OK;
+}
+
+BOOL
+CNSCBand::_IsTreeItemInEnum(
+ _In_ HTREEITEM hItem,
+ _In_ IEnumIDList *pEnum)
+{
+ CItemData* pItemData = GetItemData(hItem);
+ if (!pItemData)
+ return FALSE;
+
+ pEnum->Reset();
+
+ CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
+ while (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
+ {
+ if (ILIsEqual(pidlTemp, pItemData->relativePidl))
+ return TRUE;
+
+ pidlTemp.Free();
+ }
+
+ return FALSE;
+}
+
+BOOL
+CNSCBand::_TreeItemHasThisChild(
+ _In_ HTREEITEM hItem,
+ _In_ PCITEMID_CHILD pidlChild)
+{
+ for (hItem = TreeView_GetChild(m_hwndTreeView, hItem); hItem;
+ hItem = TreeView_GetNextSibling(m_hwndTreeView, hItem))
+ {
+ CItemData* pItemData = GetItemData(hItem);
+ if (ILIsEqual(pItemData->relativePidl, pidlChild))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+HRESULT
+CNSCBand::_GetItemEnum(
+ _Out_ CComPtr<IEnumIDList>& pEnum,
+ _In_ HTREEITEM hItem,
+ _Out_opt_ IShellFolder **ppFolder)
+{
+ CComPtr<IShellFolder> psfDesktop;
+ HRESULT hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComPtr<IShellFolder> pFolder;
+ if (!ppFolder)
+ ppFolder = &pFolder;
+
+ if (hItem == m_hRoot && hItem)
+ {
+ *ppFolder = psfDesktop;
+ (*ppFolder)->AddRef();
+ }
+ else
+ {
+ CItemData* pItemData = GetItemData(hItem);
+ if (!pItemData && hItem == TVI_ROOT && !_WantsRootItem())
+ hr = psfDesktop->BindToObject(m_pidlRoot, NULL, IID_PPV_ARG(IShellFolder,
ppFolder));
+ else
+ hr = psfDesktop->BindToObject(pItemData->absolutePidl, NULL,
IID_PPV_ARG(IShellFolder, ppFolder));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ }
+
+ return (*ppFolder)->EnumObjects(NULL, _GetEnumFlags(), &pEnum);
+}
+
+BOOL CNSCBand::_ItemHasAnyChild(_In_ HTREEITEM hItem)
+{
+ CComPtr<IEnumIDList> pEnum;
+ HRESULT hr = _GetItemEnum(pEnum, hItem);
+ if (FAILED(hr))
+ return FALSE;
+
+ CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
+ hr = pEnum->Next(1, &pidlTemp, NULL);
+ return SUCCEEDED(hr);
+}
+
+void CNSCBand::_RefreshRecurse(_In_ HTREEITEM hTarget)
+{
+ CComPtr<IEnumIDList> pEnum;
+ HRESULT hrEnum = _GetItemEnum(pEnum, hTarget);
+
+ // Delete zombie items
+ HTREEITEM hItem, hNextItem;
+ for (hItem = TreeView_GetChild(m_hwndTreeView, hTarget); hItem; hItem = hNextItem)
+ {
+ hNextItem = TreeView_GetNextSibling(m_hwndTreeView, hItem);
+
+ if (SUCCEEDED(hrEnum) && !_IsTreeItemInEnum(hItem, pEnum))
+ TreeView_DeleteItem(m_hwndTreeView, hItem);
+ }
+
+ pEnum = NULL;
+ hrEnum = _GetItemEnum(pEnum, hTarget);
+
+ CItemData* pItemData = ((hTarget == TVI_ROOT) ? NULL : GetItemData(hTarget));
+
+ // Insert new items and update items
+ if (SUCCEEDED(hrEnum))
+ {
+ CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
+ while (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
+ {
+ if (!_TreeItemHasThisChild(hTarget, pidlTemp))
+ {
+ if (pItemData)
+ {
+ CComHeapPtr<ITEMIDLIST>
pidlAbsolute(ILCombine(pItemData->absolutePidl, pidlTemp));
+ _InsertItem(hTarget, pidlAbsolute, pidlTemp, TRUE);
+ }
+ else
+ {
+ CComHeapPtr<ITEMIDLIST> pidlAbsolute(ILCombine(m_pidlRoot,
pidlTemp));
+ _InsertItem(hTarget, pidlAbsolute, pidlTemp, TRUE);
+ }
+ }
+ pidlTemp.Free();
+ }
+ }
+
+ // Update children and recurse
+ for (hItem = TreeView_GetChild(m_hwndTreeView, hTarget); hItem; hItem = hNextItem)
+ {
+ hNextItem = TreeView_GetNextSibling(m_hwndTreeView, hItem);
+
+ TV_ITEMW item = { TVIF_HANDLE | TVIF_CHILDREN };
+ item.hItem = hItem;
+ item.cChildren = _ItemHasAnyChild(hItem);
+ TreeView_SetItem(m_hwndTreeView, &item);
+
+ if (TreeView_GetItemState(m_hwndTreeView, hItem, TVIS_EXPANDEDONCE) &
TVIS_EXPANDEDONCE)
+ _RefreshRecurse(hItem);
+ }
+}
+
+void CNSCBand::_Refresh()
+{
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, FALSE, 0);
+ _RefreshRecurse(_WantsRootItem() ? m_hRoot : TVI_ROOT);
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, TRUE, 0);
+}
+
+LRESULT CNSCBand::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ KillTimer(wParam);
+
+ if (wParam == TIMER_ID_REFRESH)
+ _Refresh();
+
+ return 0;
+}
+
+void
+CNSCBand::OnChangeNotify(
+ _In_opt_ LPCITEMIDLIST pidl0,
+ _In_opt_ LPCITEMIDLIST pidl1,
+ _In_ LONG lEvent)
+{
+ switch (lEvent)
+ {
+ case SHCNE_DRIVEADD:
+ case SHCNE_MKDIR:
+ case SHCNE_CREATE:
+ case SHCNE_DRIVEREMOVED:
+ case SHCNE_RMDIR:
+ case SHCNE_DELETE:
+ case SHCNE_RENAMEFOLDER:
+ case SHCNE_RENAMEITEM:
+ case SHCNE_UPDATEDIR:
+ case SHCNE_UPDATEITEM:
+ case SHCNE_ASSOCCHANGED:
+ {
+ KillTimer(TIMER_ID_REFRESH);
+ SetTimer(TIMER_ID_REFRESH, 500, NULL);
+ break;
+ }
+ default:
+ {
+ TRACE("lEvent: 0x%08lX\n", lEvent);
+ break;
+ }
+ }
+}
+
+HTREEITEM
+CNSCBand::_InsertItem(
+ _In_opt_ HTREEITEM hParent,
+ _Inout_ IShellFolder *psfParent,
+ _In_ LPCITEMIDLIST pElt,
+ _In_ LPCITEMIDLIST pEltRelative,
+ _In_ BOOL bSort)
+{
+ /* Get the attributes of the node */
+ SFGAOF attrs = SFGAO_STREAM | SFGAO_HASSUBFOLDER;
+ HRESULT hr = psfParent->GetAttributesOf(1, &pEltRelative, &attrs);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return NULL;
+
+ /* Get the name of the node */
+ WCHAR wszDisplayName[MAX_PATH];
+ STRRET strret;
+ hr = psfParent->GetDisplayNameOf(pEltRelative, SHGDN_INFOLDER, &strret);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return NULL;
+
+ hr = StrRetToBufW(&strret, pEltRelative, wszDisplayName, MAX_PATH);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return NULL;
+
+ /* Get the icon of the node */
+ INT iIcon = SHMapPIDLToSystemImageListIndex(psfParent, pEltRelative, NULL);
+
+ CItemData* pChildInfo = new CItemData;
+ if (!pChildInfo)
+ {
+ ERR("Failed to allocate CItemData\n");
+ return NULL;
+ }
+ pChildInfo->absolutePidl.Attach(ILClone(pElt));
+ pChildInfo->relativePidl.Attach(ILClone(pEltRelative));
+
+ // Set up our treeview template
+ TV_INSERTSTRUCT tvInsert = { hParent, TVI_LAST };
+ tvInsert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
TVIF_CHILDREN;
+ tvInsert.item.cchTextMax = MAX_PATH;
+ tvInsert.item.pszText = wszDisplayName;
+ tvInsert.item.iImage = tvInsert.item.iSelectedImage = iIcon;
+ tvInsert.item.lParam = (LPARAM)pChildInfo;
+
+ if (!(attrs & SFGAO_STREAM) && (attrs & SFGAO_HASSUBFOLDER))
+ tvInsert.item.cChildren = 1;
+
+ HTREEITEM htiCreated = TreeView_InsertItem(m_hwndTreeView, &tvInsert);
+
+ if (bSort)
+ _SortItems(hParent);
+
+ return htiCreated;
+}
+
+/* This is the slow version of the above method */
+HTREEITEM
+CNSCBand::_InsertItem(
+ _In_opt_ HTREEITEM hParent,
+ _In_ LPCITEMIDLIST pElt,
+ _In_ LPCITEMIDLIST pEltRelative,
+ _In_ BOOL bSort)
+{
+ CComPtr<IShellFolder> psfFolder;
+ HRESULT hr = SHBindToParent(pElt, IID_PPV_ARG(IShellFolder, &psfFolder), NULL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return NULL;
+
+ return _InsertItem(hParent, psfFolder, pElt, pEltRelative, bSort);
+}
+
+BOOL CNSCBand::_InsertSubitems(HTREEITEM hItem, LPCITEMIDLIST entry)
+{
+ ULONG fetched = 1, uItemCount = 0;
+
+ CComPtr<IEnumIDList> pEnum;
+ CComPtr<IShellFolder> pFolder;
+ HRESULT hr = _GetItemEnum(pEnum, hItem, &pFolder);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
+
+ /* Don't redraw while we add stuff into the tree */
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, FALSE, 0);
+
+ LPITEMIDLIST pidlSub;
+ while (SUCCEEDED(pEnum->Next(1, &pidlSub, &fetched)) && pidlSub
&& fetched)
+ {
+ LPITEMIDLIST pidlSubComplete;
+ pidlSubComplete = ILCombine(entry, pidlSub);
+
+ if (_InsertItem(hItem, pFolder, pidlSubComplete, pidlSub, FALSE))
+ ++uItemCount;
+
+ ILFree(pidlSubComplete);
+ ILFree(pidlSub);
+ }
+
+ /* Let's do sorting */
+ _SortItems(hItem);
+
+ /* Now we can redraw */
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, TRUE, 0);
+
+ return (uItemCount > 0);
+}
+
+// *** message handlers ***
+
+LRESULT CNSCBand::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+ if (FAILED_UNEXPECTEDLY(_CreateToolbar(m_hWnd)))
+ return -1;
+ if (FAILED_UNEXPECTEDLY(_CreateTreeView(m_hWnd)))
+ return -1;
+ return 0;
+}
+
+LRESULT CNSCBand::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+ _DestroyTreeView();
+ _DestroyToolbar();
+ _UnregisterChangeNotify();
+ return 0;
+}
+
+LRESULT CNSCBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+ if (!m_hwndTreeView)
+ return 0;
+
+ RECT rc;
+ GetClientRect(&rc);
+ LONG cx = rc.right, cy = rc.bottom;
+
+ RECT rcTB;
+ LONG cyTB = 0;
+ if (m_hwndToolbar)
+ {
+ m_hwndToolbar.SendMessage(TB_AUTOSIZE, 0, 0);
+ m_hwndToolbar.GetWindowRect(&rcTB);
+ cyTB = rcTB.bottom - rcTB.top;
+ }
+
+ m_hwndTreeView.MoveWindow(0, cyTB, cx, cy - cyTB);
+ return 0;
+}
+
+LRESULT CNSCBand::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
+{
+ m_bFocused = TRUE;
+ IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), TRUE);
+ bHandled = FALSE;
+ return 0;
+}
+
+LRESULT CNSCBand::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
+{
+ IUnknown_OnFocusChangeIS(m_pSite, reinterpret_cast<IUnknown*>(this), FALSE);
+ m_bFocused = FALSE;
+ return 0;
+}
+
+HRESULT CNSCBand::_AddFavorite()
+{
+ CComHeapPtr<ITEMIDLIST> pidlCurrent;
+ _GetCurrentLocation(&pidlCurrent);
+
+ WCHAR szCurDir[MAX_PATH];
+ if (!ILGetDisplayName(pidlCurrent, szCurDir))
+ {
+ FIXME("\n");
+ return E_FAIL;
+ }
+
+ WCHAR szPath[MAX_PATH], szSuffix[32];
+ SHGetSpecialFolderPathW(m_hWnd, szPath, CSIDL_FAVORITES, TRUE);
+ PathAppendW(szPath, PathFindFileNameW(szCurDir));
+
+ const INT ich = lstrlenW(szPath);
+ for (INT iTry = 2; iTry <= 9999; ++iTry)
+ {
+ PathAddExtensionW(szPath, L".lnk");
+ if (!PathFileExistsW(szPath))
+ break;
+ szPath[ich] = UNICODE_NULL;
+ wsprintfW(szSuffix, L" (%d)", iTry);
+ lstrcatW(szPath, szSuffix);
+ }
+
+ TRACE("%S, %S\n", szCurDir, szPath);
+
+ return SHDOCVW_CreateShortcut(szPath, pidlCurrent, NULL);
+}
+
+LRESULT CNSCBand::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ switch (LOWORD(wParam))
+ {
+ case ID_ADD:
+ {
+ _AddFavorite();
+ break;
+ }
+ case ID_ORGANIZE:
+ {
+ SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_INVOKEIDLIST };
+ sei.hwnd = m_hWnd;
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpIDList = m_pidlRoot;
+ ::ShellExecuteExW(&sei);
+ break;
+ }
+ }
+ return 0;
+}
+
+BOOL CNSCBand::OnTreeItemExpanding(_In_ LPNMTREEVIEW pnmtv)
+{
+ CItemData *pItemData;
+
+ if (pnmtv->action == TVE_COLLAPSE)
+ {
+ if (pnmtv->itemNew.hItem == m_hRoot)
+ {
+ // Prenvent root from collapsing
+ pnmtv->itemNew.mask |= TVIF_STATE;
+ pnmtv->itemNew.stateMask |= TVIS_EXPANDED;
+ pnmtv->itemNew.state &= ~TVIS_EXPANDED;
+ pnmtv->action = TVE_EXPAND;
+ return TRUE;
+ }
+ }
+
+ if (pnmtv->action == TVE_EXPAND)
+ {
+ // Grab our directory PIDL
+ pItemData = GetItemData(pnmtv->itemNew.hItem);
+ // We have it, let's try
+ if (pItemData && !pItemData->expanded)
+ {
+ if (_InsertSubitems(pnmtv->itemNew.hItem, pItemData->absolutePidl))
+ {
+ pItemData->expanded = TRUE;
+ }
+ else
+ {
+ // remove subitem "+" since we failed to add subitems
+ TVITEMW tvItem = { TVIF_CHILDREN, pnmtv->itemNew.hItem };
+ tvItem.cChildren = 0;
+ TreeView_SetItem(m_hwndTreeView, &tvItem);
+ }
+ }
+ }
+ return FALSE;
+}
+
+BOOL CNSCBand::OnTreeItemDeleted(_In_ LPNMTREEVIEW pnmtv)
+{
+ // Navigate to parent when deleting selected item
+ HTREEITEM hItem = pnmtv->itemOld.hItem;
+ HTREEITEM hParent = TreeView_GetParent(m_hwndTreeView, hItem);
+ if (hParent && TreeView_GetSelection(m_hwndTreeView) == hItem)
+ TreeView_SelectItem(m_hwndTreeView, hParent);
+
+ /* Destroy memory associated to our node */
+ CItemData* pItemData = GetItemData(hItem);
+ if (!pItemData)
+ return FALSE;
+
+ delete pItemData;
+
+ return TRUE;
+}
+
+void CNSCBand::_OnSelectionChanged(_In_ LPNMTREEVIEW pnmtv)
+{
+ HTREEITEM hItem = pnmtv->itemNew.hItem;
+ if (!hItem)
+ return;
+ CItemData* pItemData = GetItemData(hItem);
+ if (pItemData)
+ OnSelectionChanged(pItemData->absolutePidl);
+}
+
+void CNSCBand::OnTreeItemDragging(_In_ LPNMTREEVIEW pnmtv, _In_ BOOL isRightClick)
+{
+ CItemData* pItemData = GetItemData(pnmtv->itemNew.hItem);
+ if (!pItemData)
+ return;
+
+ HRESULT hr;
+ CComPtr<IShellFolder> pSrcFolder;
+ LPCITEMIDLIST pLast;
+ hr = SHBindToParent(pItemData->absolutePidl, IID_PPV_ARG(IShellFolder,
&pSrcFolder), &pLast);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return;
+
+ SFGAOF attrs = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK;
+ pSrcFolder->GetAttributesOf(1, &pLast, &attrs);
+
+ DWORD dwEffect = 0;
+ if (attrs & SFGAO_CANCOPY)
+ dwEffect |= DROPEFFECT_COPY;
+ if (attrs & SFGAO_CANMOVE)
+ dwEffect |= DROPEFFECT_MOVE;
+ if (attrs & SFGAO_CANLINK)
+ dwEffect |= DROPEFFECT_LINK;
+
+ CComPtr<IDataObject> pObj;
+ hr = pSrcFolder->GetUIObjectOf(m_hWnd, 1, &pLast, IID_IDataObject, 0,
(LPVOID*)&pObj);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return;
+
+ DoDragDrop(pObj, this, dwEffect, &dwEffect);
+}
+
+LRESULT CNSCBand::OnBeginLabelEdit(_In_ LPNMTVDISPINFO dispInfo)
+{
+ // TODO: put this in a function ? (mostly copypasta from CDefView)
+ DWORD dwAttr = SFGAO_CANRENAME;
+ CComPtr<IShellFolder> pParent;
+ LPCITEMIDLIST pChild;
+ HRESULT hr;
+
+ CItemData *info = GetItemData(dispInfo->item.hItem);
+ if (!info)
+ return FALSE;
+
+ hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent),
&pChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
+
+ hr = pParent->GetAttributesOf(1, &pChild, &dwAttr);
+ if (SUCCEEDED(hr) && (dwAttr & SFGAO_CANRENAME))
+ {
+ m_isEditing = TRUE;
+ m_oldSelected = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+HRESULT CNSCBand::_UpdateBrowser(LPCITEMIDLIST pidlGoto)
+{
+ CComPtr<IShellBrowser> pBrowserService;
+ HRESULT hr = IUnknown_QueryService(m_pSite, SID_STopLevelBrowser,
+ IID_PPV_ARG(IShellBrowser,
&pBrowserService));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = pBrowserService->BrowseObject(pidlGoto, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ return S_OK;
+}
+
+LRESULT CNSCBand::OnEndLabelEdit(_In_ LPNMTVDISPINFO dispInfo)
+{
+ CItemData *info = GetItemData(dispInfo->item.hItem);
+ HRESULT hr;
+
+ m_isEditing = FALSE;
+ if (m_oldSelected)
+ {
+ ++m_mtxBlockNavigate;
+ TreeView_SelectItem(m_hwndTreeView, m_oldSelected);
+ --m_mtxBlockNavigate;
+ }
+
+ if (!dispInfo->item.pszText)
+ return FALSE;
+
+ CComPtr<IShellFolder> pParent;
+ LPCITEMIDLIST pidlChild;
+ BOOL RenamedCurrent = _IsCurrentLocation(info->absolutePidl) == S_OK;
+
+ hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent),
&pidlChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
+
+ CComHeapPtr<ITEMIDLIST> pidlNew;
+ hr = pParent->SetNameOf(m_hWnd, pidlChild, dispInfo->item.pszText,
SHGDN_INFOLDER, &pidlNew);
+ if (SUCCEEDED(hr) && pidlNew)
+ {
+ CComPtr<IPersistFolder2> pPersist;
+ hr = pParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pPersist));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
+
+ CComHeapPtr<ITEMIDLIST> pidlParent;
+ hr = pPersist->GetCurFolder(&pidlParent);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return FALSE;
+
+ CComHeapPtr<ITEMIDLIST> pidlNewAbs(ILCombine(pidlParent, pidlNew));
+ if (RenamedCurrent)
+ {
+ _UpdateBrowser(pidlNewAbs);
+ }
+ else
+ {
+ // Tell everyone if SetNameOf forgot, this causes IShellView to update itself
when we rename a child
+ SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_IDLIST, info->absolutePidl,
pidlNewAbs);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+LRESULT CNSCBand::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ NMHDR *pnmhdr = (NMHDR*)lParam;
+ switch (pnmhdr->code)
+ {
+ case TVN_ITEMEXPANDING:
+ return OnTreeItemExpanding((LPNMTREEVIEW)lParam);
+ //case TVN_SINGLEEXPAND:
+ case TVN_SELCHANGED:
+ if (pnmhdr->hwndFrom == m_hwndTreeView)
+ _OnSelectionChanged((LPNMTREEVIEW)lParam);
+ break;
+ case TVN_DELETEITEM:
+ OnTreeItemDeleted((LPNMTREEVIEW)lParam);
+ break;
+ case NM_CLICK:
+ case NM_RCLICK:
+ if (pnmhdr->hwndFrom == m_hwndTreeView)
+ {
+ TVHITTESTINFO HitTest;
+ ::GetCursorPos(&HitTest.pt);
+ ::ScreenToClient(m_hwndTreeView, &HitTest.pt);
+ TreeView_HitTest(m_hwndTreeView, &HitTest);
+
+ if (HitTest.flags & (TVHT_ABOVE | TVHT_BELOW | TVHT_NOWHERE))
+ return TRUE; // Prevents click processing
+
+ if (HitTest.flags & TVHT_ONITEMBUTTON) // [+] / [-]
+ break; // Do default processing
+
+ // Generate selection notification even if same item
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, FALSE, 0);
+ TreeView_SelectItem(m_hwndTreeView, NULL);
+ TreeView_SelectItem(m_hwndTreeView, HitTest.hItem);
+ m_hwndTreeView.SendMessage(WM_SETREDRAW, TRUE, 0);
+
+ if (pnmhdr->code == NM_CLICK)
+ return TRUE; // Prevents click processing
+ }
+ break;
+ case TVN_BEGINDRAG:
+ case TVN_BEGINRDRAG:
+ OnTreeItemDragging((LPNMTREEVIEW)lParam, pnmhdr->code == TVN_BEGINRDRAG);
+ break;
+ case TVN_BEGINLABELEDITW:
+ return OnBeginLabelEdit((LPNMTVDISPINFO)lParam);
+ case TVN_ENDLABELEDITW:
+ return OnEndLabelEdit((LPNMTVDISPINFO)lParam);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+// Temporary menu
+struct CMenuTemp
+{
+ HMENU m_hMenu = NULL;
+ CMenuTemp(HMENU hMenu) : m_hMenu(hMenu)
+ {
+ }
+ ~CMenuTemp()
+ {
+ if (m_hMenu)
+ ::DestroyMenu(m_hMenu);
+ }
+ operator HMENU() const
+ {
+ return m_hMenu;
+ }
+};
+
+// *** ATL event handlers ***
+LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
+{
+ HWND hwndTarget = reinterpret_cast<HWND>(wParam);
+ if (hwndTarget && (hwndTarget == m_hwndToolbar || hwndTarget == m_hWnd))
+ {
+ FIXME("Show 'Close Toolbar' menu\n");
+ return 0;
+ }
+
+ HTREEITEM hItem = TreeView_GetSelection(m_hwndTreeView);
+ if (!hItem)
+ return 0;
+
+ POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) };
+ if ((UINT)lParam == (UINT)-1)
+ {
+ RECT rc;
+ if (TreeView_GetItemRect(m_hwndTreeView, hItem, &rc, TRUE))
+ {
+ // Center of item rectangle
+ pt.x = (rc.left + rc.right) / 2;
+ pt.y = (rc.top + rc.bottom) / 2;
+ }
+ ClientToScreen(&pt);
+ }
+
+ CItemData *info = GetItemData(hItem);
+ if (!info)
+ {
+ ERR("No node data, something has gone wrong\n");
+ return 0;
+ }
+
+ CComPtr<IShellFolder> pFolder;
+ LPCITEMIDLIST pidlChild;
+ HRESULT hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder,
&pFolder), &pidlChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return 0;
+
+ CComPtr<IContextMenu> contextMenu;
+ hr = pFolder->GetUIObjectOf(m_hWnd, 1, &pidlChild,
IID_NULL_PPV_ARG(IContextMenu, &contextMenu));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return 0;
+
+ IUnknown_SetSite(contextMenu, (IDeskBand *)this);
+
+ UINT cmf = CMF_EXPLORE;
+ SFGAOF attr = SFGAO_CANRENAME;
+ hr = pFolder->GetAttributesOf(1, &pidlChild, &attr);
+ if (SUCCEEDED(hr) && (attr & SFGAO_CANRENAME))
+ cmf |= CMF_CANRENAME;
+
+ CMenuTemp menuTemp(::CreatePopupMenu());
+ UINT idCmdFirst = max(FCIDM_SHVIEWFIRST, 1);
+ hr = contextMenu->QueryContextMenu(menuTemp, 0, idCmdFirst, FCIDM_SHVIEWLAST,
cmf);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return 0;
+
+ enum { flags = TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON };
+ UINT uCommand = ::TrackPopupMenu(menuTemp, flags, pt.x, pt.y, 0, m_hWnd, NULL);
+ if (uCommand)
+ {
+ uCommand -= idCmdFirst;
+
+ // Do DFM_CMD_RENAME in the treeview
+ if ((cmf & CMF_CANRENAME) && SHELL_IsVerb(contextMenu, uCommand,
L"rename"))
+ {
+ m_hwndTreeView.SetFocus();
+ if (TreeView_EditLabel(m_hwndTreeView, hItem))
+ m_oldSelected = hItem;
+ return 0;
+ }
+
+ hr = _ExecuteCommand(contextMenu, uCommand);
+ }
+
+ return TRUE;
+}
+
+// WM_USER_SHELLEVENT
+LRESULT CNSCBand::OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
+{
+ // We use SHCNRF_NewDelivery method
+ HANDLE hChange = (HANDLE)wParam;
+ DWORD dwProcID = (DWORD)lParam;
+
+ PIDLIST_ABSOLUTE *ppidl = NULL;
+ LONG lEvent;
+ HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &ppidl,
&lEvent);
+ if (!hLock)
+ {
+ ERR("!hLock\n");
+ return 0;
+ }
+
+ OnChangeNotify(ppidl[0], ppidl[1], (lEvent & ~SHCNE_INTERRUPT));
+
+ SHChangeNotification_Unlock(hLock);
+ return 0;
+}
+
+// *** IOleWindow ***
+
+STDMETHODIMP CNSCBand::GetWindow(HWND *lphwnd)
+{
+ if (!lphwnd)
+ return E_INVALIDARG;
+ *lphwnd = m_hWnd;
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** IDockingWindow ***
+
+STDMETHODIMP CNSCBand::CloseDW(DWORD dwReserved)
+{
+ // We do nothing, we don't have anything to save yet
+ TRACE("CloseDW called\n");
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite,
BOOL fReserved)
+{
+ /* Must return E_NOTIMPL according to MSDN */
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::ShowDW(BOOL fShow)
+{
+ m_fVisible = fShow;
+ ShowWindow(fShow ? SW_SHOW : SW_HIDE);
+ return S_OK;
+}
+
+// *** IDeskBand ***
+
+STDMETHODIMP CNSCBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
+{
+ if (!pdbi)
+ return E_INVALIDARG;
+
+ m_dwBandID = dwBandID;
+
+ if (pdbi->dwMask & DBIM_MINSIZE)
+ {
+ pdbi->ptMinSize.x = 200;
+ pdbi->ptMinSize.y = 30;
+ }
+
+ if (pdbi->dwMask & DBIM_MAXSIZE)
+ pdbi->ptMaxSize.y = -1;
+
+ if (pdbi->dwMask & DBIM_INTEGRAL)
+ pdbi->ptIntegral.y = 1;
+
+ if (pdbi->dwMask & DBIM_ACTUAL)
+ {
+ pdbi->ptActual.x = 200;
+ pdbi->ptActual.y = 30;
+ }
+
+ if (pdbi->dwMask & DBIM_TITLE)
+ {
+ _GetTitle(pdbi->wszTitle, _countof(pdbi->wszTitle));
+ }
+
+ if (pdbi->dwMask & DBIM_MODEFLAGS)
+ pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
+
+ if (pdbi->dwMask & DBIM_BKCOLOR)
+ pdbi->dwMask &= ~DBIM_BKCOLOR;
+
+ return S_OK;
+}
+
+// *** IObjectWithSite ***
+
+STDMETHODIMP CNSCBand::SetSite(IUnknown *pUnkSite)
+{
+ HRESULT hr;
+
+ if (pUnkSite == m_pSite)
+ return S_OK;
+
+ TRACE("SetSite called\n");
+
+ if (!pUnkSite)
+ {
+ DestroyWindow();
+ m_hWnd = NULL;
+ }
+
+ if (pUnkSite != m_pSite)
+ m_pSite = NULL;
+
+ if (!pUnkSite)
+ return S_OK;
+
+ HWND hwndParent;
+ hr = IUnknown_GetWindow(pUnkSite, &hwndParent);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return E_INVALIDARG;
+
+ m_pSite = pUnkSite;
+
+ if (m_hWnd)
+ {
+ SetParent(hwndParent); // Change its parent
+ }
+ else
+ {
+ enum { style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN };
+ this->Create(hwndParent, NULL, NULL, style, 0, 0U, NULL);
+ }
+
+ _RegisterChangeNotify();
+
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::GetSite(REFIID riid, void **ppvSite)
+{
+ if (!ppvSite)
+ return E_POINTER;
+ *ppvSite = m_pSite;
+ return S_OK;
+}
+
+// *** IOleCommandTarget ***
+
+STDMETHODIMP CNSCBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds
[], OLECMDTEXT *pCmdText)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
VARIANT *pvaIn, VARIANT *pvaOut)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** IServiceProvider ***
+
+STDMETHODIMP CNSCBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
+{
+ return IUnknown_QueryService(m_pSite, guidService, riid, ppvObject);
+}
+
+// *** IContextMenu ***
+
+STDMETHODIMP CNSCBand::QueryContextMenu(
+ HMENU hmenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::InvokeCommand(
+ LPCMINVOKECOMMANDINFO lpici)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::GetCommandString(
+ UINT_PTR idCmd,
+ UINT uType,
+ UINT *pwReserved,
+ LPSTR pszName,
+ UINT cchMax)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** IInputObject ***
+
+STDMETHODIMP CNSCBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
+{
+ if (fActivate)
+ {
+ m_hwndTreeView.SetFocus();
+ }
+
+ if (lpMsg)
+ {
+ TranslateMessage(lpMsg);
+ DispatchMessage(lpMsg);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::HasFocusIO()
+{
+ return m_bFocused ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg)
+{
+ if (lpMsg->hwnd == m_hWnd ||
+ (m_isEditing && IsChild(lpMsg->hwnd)))
+ {
+ TranslateMessage(lpMsg);
+ DispatchMessage(lpMsg);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+// *** IPersist ***
+
+STDMETHODIMP CNSCBand::GetClassID(CLSID *pClassID)
+{
+ return E_NOTIMPL;
+}
+
+// *** IPersistStream ***
+
+STDMETHODIMP CNSCBand::IsDirty()
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::Load(IStream *pStm)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::Save(IStream *pStm, BOOL fClearDirty)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CNSCBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** IWinEventHandler ***
+
+STDMETHODIMP CNSCBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
LRESULT *theResult)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::IsWindowOwner(HWND hWnd)
+{
+ return SHIsChildOrSelf(m_hWnd, hWnd);
+}
+
+// *** IBandNavigate ***
+
+STDMETHODIMP CNSCBand::Select(LPCITEMIDLIST pidl)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** INamespaceProxy ***
+
+// Returns the ITEMIDLIST that should be navigated when an item is invoked.
+STDMETHODIMP CNSCBand::GetNavigateTarget(
+ _In_ PCIDLIST_ABSOLUTE pidl,
+ _Out_ PIDLIST_ABSOLUTE *ppidlTarget,
+ _Out_ ULONG *pulAttrib)
+{
+ *pulAttrib = 0;
+ WCHAR szPath[MAX_PATH];
+ if (!SHGetPathFromIDListW(pidl, szPath))
+ return E_FAIL;
+
+ if (lstrcmpiW(PathFindExtensionW(szPath), L".lnk") == 0) // shortcut file?
+ {
+ WCHAR szTarget[MAX_PATH];
+ HRESULT hr = SHDOCVW_GetPathOfShortcut(m_hWnd, szPath, szTarget);
+ if (SUCCEEDED(hr))
+ {
+ lstrcpynW(szPath, szTarget, _countof(szPath));
+ *pulAttrib |= SFGAO_LINK;
+ }
+ }
+
+ if (PathIsDirectoryW(szPath) || PathIsRootW(szPath))
+ *pulAttrib |= SFGAO_FOLDER;
+
+ *ppidlTarget = ILCreateFromPathW(szPath);
+ return S_OK;
+}
+
+// Handles a user action on an item.
+STDMETHODIMP CNSCBand::Invoke(_In_ PCIDLIST_ABSOLUTE pidl)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// Called when the user has selected an item.
+STDMETHODIMP CNSCBand::OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl)
+{
+ return S_OK;
+}
+
+// Returns flags used to update the tree control.
+STDMETHODIMP CNSCBand::RefreshFlags(
+ _Out_ DWORD *pdwStyle,
+ _Out_ DWORD *pdwExStyle,
+ _Out_ DWORD *dwEnum)
+{
+ *pdwStyle = _GetTVStyle();
+ *pdwExStyle = _GetTVExStyle();
+ *dwEnum = _GetEnumFlags();
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::CacheItem(
+ _In_ PCIDLIST_ABSOLUTE pidl)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
+}
+
+// *** IDropTarget methods ***
+STDMETHODIMP CNSCBand::DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD
*pdwEffect)
+{
+ ERR("Entering drag\n");
+ m_pCurObject = pObj;
+ m_oldSelected = TreeView_GetSelection(m_hwndTreeView);
+ return DragOver(glfKeyState, pt, pdwEffect);
+}
+
+STDMETHODIMP CNSCBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TVHITTESTINFO info;
+ 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_hwndTreeView, &info);
+
+ HRESULT hr;
+ if (!info.hItem)
+ {
+ m_childTargetNode = NULL;
+ m_pDropTarget = NULL;
+ *pdwEffect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+
+ ++m_mtxBlockNavigate;
+ TreeView_SelectItem(m_hwndTreeView, info.hItem);
+ --m_mtxBlockNavigate;
+
+ // Delegate to shell folder
+ if (m_pDropTarget && info.hItem != m_childTargetNode)
+ m_pDropTarget = NULL;
+
+ if (info.hItem != m_childTargetNode)
+ {
+ CItemData *pItemData = GetItemData(info.hItem);
+ if (!pItemData)
+ return E_FAIL;
+
+ CComPtr<IShellFolder> pFolder;
+ if (_ILIsDesktop(pItemData->absolutePidl))
+ {
+ pFolder = m_pDesktop;
+ }
+ else
+ {
+ hr = m_pDesktop->BindToObject(pItemData->absolutePidl, 0,
IID_PPV_ARG(IShellFolder, &pFolder));
+ 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 = pFolder->CreateViewObject(m_hWnd, IID_PPV_ARG(IDropTarget,
&m_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 = m_pDropTarget->DragEnter(m_pCurObject, glfKeyState, pt, pdwEffect);
+ m_childTargetNode = info.hItem;
+ }
+
+ if (m_pDropTarget)
+ hr = m_pDropTarget->DragOver(glfKeyState, pt, pdwEffect);
+
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::DragLeave()
+{
+ ++m_mtxBlockNavigate;
+ TreeView_SelectItem(m_hwndTreeView, m_oldSelected);
+ --m_mtxBlockNavigate;
+ m_childTargetNode = NULL;
+ if (m_pCurObject)
+ m_pCurObject = NULL;
+ return S_OK;
+}
+
+STDMETHODIMP CNSCBand::Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD
*pdwEffect)
+{
+ if (!m_pDropTarget)
+ return E_FAIL;
+ m_pDropTarget->Drop(pObj, glfKeyState, pt, pdwEffect);
+ DragLeave();
+ return S_OK;
+}
+
+// *** IDropSource methods ***
+
+STDMETHODIMP CNSCBand::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
+{
+ if (fEscapePressed)
+ return DRAGDROP_S_CANCEL;
+ if ((grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
+ return S_OK;
+ return DRAGDROP_S_DROP;
+}
+
+STDMETHODIMP CNSCBand::GiveFeedback(DWORD dwEffect)
+{
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
diff --git a/dll/win32/shdocvw/CNSCBand.h b/dll/win32/shdocvw/CNSCBand.h
new file mode 100644
index 00000000000..f6c06afeb98
--- /dev/null
+++ b/dll/win32/shdocvw/CNSCBand.h
@@ -0,0 +1,231 @@
+/*
+ * PROJECT: ReactOS shdocvw
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: NameSpace Control Band
+ * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#pragma once
+
+#define NSCBANDCLASSNAME L"ReactOS NameSpace Control Band"
+
+#define WM_USER_SHELLEVENT (WM_USER + 88)
+
+#ifdef __cplusplus
+class CNSCBand
+ : public CWindowImpl<CNSCBand>
+ , public IDeskBand
+ , public IObjectWithSite
+ , public IInputObject
+ , public IPersistStream
+ , public IOleCommandTarget
+ , public IServiceProvider
+ , public IContextMenu
+ , public IBandNavigate
+ , public IWinEventHandler
+ , public INamespaceProxy
+ , public IDropTarget
+ , public IDropSource
+{
+public:
+ DECLARE_WND_CLASS_EX(NSCBANDCLASSNAME, 0, COLOR_3DFACE)
+ static LPCWSTR GetWndClassName() { return NSCBANDCLASSNAME; }
+
+ CNSCBand();
+ virtual ~CNSCBand();
+
+ // The node of TreeView
+ struct CItemData
+ {
+ CComHeapPtr<ITEMIDLIST> absolutePidl;
+ CComHeapPtr<ITEMIDLIST> relativePidl;
+ BOOL expanded = FALSE;
+ };
+ CItemData* GetItemData(_In_ HTREEITEM hItem);
+
+ // *** IOleWindow methods ***
+ STDMETHODIMP GetWindow(HWND *lphwnd) override;
+ STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override;
+
+ // *** IDockingWindow methods ***
+ STDMETHODIMP CloseDW(DWORD dwReserved) override;
+ STDMETHODIMP ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL
fReserved) override;
+ STDMETHODIMP ShowDW(BOOL fShow) override;
+
+ // *** IDeskBand methods ***
+ STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
override;
+
+ // *** IObjectWithSite methods ***
+ STDMETHODIMP SetSite(IUnknown *pUnkSite) override;
+ STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override;
+
+ // *** IOleCommandTarget methods ***
+ STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [],
OLECMDTEXT *pCmdText) override;
+ STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT
*pvaIn, VARIANT *pvaOut) override;
+
+ // *** IServiceProvider methods ***
+ STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
override;
+
+ // *** IContextMenu methods ***
+ STDMETHODIMP QueryContextMenu(
+ HMENU hmenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags) override;
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici) override;
+ STDMETHODIMP GetCommandString(
+ UINT_PTR idCmd,
+ UINT uType,
+ UINT *pwReserved,
+ LPSTR pszName,
+ UINT cchMax) override;
+
+ // *** IInputObject methods ***
+ STDMETHODIMP UIActivateIO(BOOL fActivate, LPMSG lpMsg) override;
+ STDMETHODIMP HasFocusIO() override;
+ STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg) override;
+
+ // *** IPersist methods ***
+ STDMETHODIMP GetClassID(CLSID *pClassID) override;
+
+ // *** IPersistStream methods ***
+ STDMETHODIMP IsDirty() override;
+ STDMETHODIMP Load(IStream *pStm) override;
+ STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty) override;
+ STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize) override;
+
+ // *** IWinEventHandler methods ***
+ STDMETHODIMP OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT
*theResult) override;
+ STDMETHODIMP IsWindowOwner(HWND hWnd) override;
+
+ // *** IBandNavigate methods ***
+ STDMETHODIMP Select(LPCITEMIDLIST pidl) override;
+
+ // *** INamespaceProxy methods ***
+ STDMETHODIMP GetNavigateTarget(
+ _In_ PCIDLIST_ABSOLUTE pidl,
+ _Out_ PIDLIST_ABSOLUTE *ppidlTarget,
+ _Out_ ULONG *pulAttrib) override;
+ STDMETHODIMP Invoke(_In_ PCIDLIST_ABSOLUTE pidl) override;
+ STDMETHODIMP OnSelectionChanged(_In_ PCIDLIST_ABSOLUTE pidl) override;
+ STDMETHODIMP RefreshFlags(
+ _Out_ DWORD *pdwStyle,
+ _Out_ DWORD *pdwExStyle,
+ _Out_ DWORD *dwEnum) override;
+ STDMETHODIMP CacheItem(_In_ PCIDLIST_ABSOLUTE pidl) override;
+
+ // *** IDropTarget methods ***
+ STDMETHODIMP DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD
*pdwEffect) override;
+ STDMETHODIMP DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect) override;
+ STDMETHODIMP DragLeave() override;
+ STDMETHODIMP Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
override;
+
+ // *** IDropSource methods ***
+ STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) override;
+ STDMETHODIMP GiveFeedback(DWORD dwEffect) override;
+
+protected:
+ DWORD m_dwTVStyle = 0;
+ DWORD m_dwTVExStyle = 0;
+ DWORD m_dwEnumFlags = 0;
+ BOOL m_fVisible = FALSE;
+ BOOL m_bFocused = FALSE;
+ DWORD m_dwBandID = 0;
+ CComPtr<IUnknown> m_pSite;
+ CComPtr<IShellFolder> m_pDesktop;
+ CComHeapPtr<ITEMIDLIST> m_pidlRoot;
+ HIMAGELIST m_hToolbarImageList = NULL;
+ CToolbar<> m_hwndToolbar;
+ CTreeView m_hwndTreeView;
+ LONG m_mtxBlockNavigate = 0; // A "lock" that prevents internal selection
changes to initiate a navigation to the newly selected item.
+ BOOL m_isEditing = FALSE;
+ HTREEITEM m_hRoot = NULL;
+ HTREEITEM m_oldSelected = NULL;
+ DWORD m_adviseCookie = 0;
+ ULONG m_shellRegID = 0;
+
+ // *** Drop target information ***
+ CComPtr<IDropTarget> m_pDropTarget;
+ HTREEITEM m_childTargetNode = NULL;
+ CComPtr<IDataObject> m_pCurObject;
+
+ VOID OnFinalMessage(HWND) override;
+
+ // *** helper methods ***
+ virtual INT _GetRootCsidl() = 0;
+ virtual HRESULT _CreateTreeView(HWND hwndParent);
+ virtual HRESULT _CreateToolbar(HWND hwndParent) { return S_OK; }
+ virtual void _DestroyTreeView();
+ virtual void _DestroyToolbar();
+ virtual DWORD _GetTVStyle() = 0;
+ virtual DWORD _GetTVExStyle() = 0;
+ virtual DWORD _GetEnumFlags() = 0;
+ virtual BOOL _GetTitle(LPWSTR pszTitle, INT cchTitle) = 0;
+ virtual BOOL _WantsRootItem() = 0;
+ virtual void _SortItems(HTREEITEM hParent) = 0;
+ void _RegisterChangeNotify();
+ void _UnregisterChangeNotify();
+ BOOL OnTreeItemExpanding(_In_ LPNMTREEVIEW pnmtv);
+ BOOL OnTreeItemDeleted(_In_ LPNMTREEVIEW pnmtv);
+ void _OnSelectionChanged(_In_ LPNMTREEVIEW pnmtv);
+ void OnTreeItemDragging(_In_ LPNMTREEVIEW pnmtv, _In_ BOOL isRightClick);
+ LRESULT OnBeginLabelEdit(_In_ LPNMTVDISPINFO dispInfo);
+ LRESULT OnEndLabelEdit(_In_ LPNMTVDISPINFO dispInfo);
+ void OnChangeNotify(
+ _In_opt_ LPCITEMIDLIST pidl0,
+ _In_opt_ LPCITEMIDLIST pidl1,
+ _In_ LONG lEvent);
+ HRESULT _ExecuteCommand(_In_ CComPtr<IContextMenu>& menu, _In_ UINT nCmd);
+ HTREEITEM _InsertItem(
+ _In_opt_ HTREEITEM hParent,
+ _Inout_ IShellFolder *psfParent,
+ _In_ LPCITEMIDLIST pElt,
+ _In_ LPCITEMIDLIST pEltRelative,
+ _In_ BOOL bSort);
+ HTREEITEM _InsertItem(
+ _In_opt_ HTREEITEM hParent,
+ _In_ LPCITEMIDLIST pElt,
+ _In_ LPCITEMIDLIST pEltRelative,
+ _In_ BOOL bSort);
+ BOOL _InsertSubitems(HTREEITEM hItem, LPCITEMIDLIST entry);
+ HRESULT _UpdateBrowser(LPCITEMIDLIST pidlGoto);
+ HRESULT _GetCurrentLocation(_Out_ PIDLIST_ABSOLUTE *ppidl);
+ HRESULT _IsCurrentLocation(_In_ PCIDLIST_ABSOLUTE pidl);
+ void _Refresh();
+ void _RefreshRecurse(_In_ HTREEITEM hItem);
+ BOOL _IsTreeItemInEnum(_In_ HTREEITEM hItem, _In_ IEnumIDList *pEnum);
+ BOOL _TreeItemHasThisChild(_In_ HTREEITEM hItem, _In_ PCITEMID_CHILD pidlChild);
+ HRESULT _GetItemEnum(
+ _Out_ CComPtr<IEnumIDList>& pEnum,
+ _In_ HTREEITEM hItem,
+ _Out_opt_ IShellFolder **ppFolder = NULL);
+ BOOL _ItemHasAnyChild(_In_ HTREEITEM hItem);
+ HRESULT _AddFavorite();
+
+ // *** ATL message handlers ***
+ LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+ LRESULT OnSize(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);
+ LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+
+ BEGIN_MSG_MAP(CNSCBand)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
+ MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
+ MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+ MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+ MESSAGE_HANDLER(WM_TIMER, OnTimer)
+ MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
+ MESSAGE_HANDLER(WM_USER_SHELLEVENT, OnShellEvent)
+ END_MSG_MAP()
+};
+#endif // def __cplusplus
diff --git a/sdk/include/reactos/shlobj_undoc.h b/sdk/include/reactos/shlobj_undoc.h
index c572dc36930..c9796909aa1 100644
--- a/sdk/include/reactos/shlobj_undoc.h
+++ b/sdk/include/reactos/shlobj_undoc.h
@@ -506,7 +506,7 @@ DECLARE_INTERFACE_(IBandNavigate, IUnknown)
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** IBandNavigate ***/
- STDMETHOD(Select)(THIS_ long paramC) PURE;
+ STDMETHOD(Select)(THIS_ LPCITEMIDLIST pidl) PURE;
};
#undef INTERFACE
@@ -528,7 +528,7 @@ DECLARE_INTERFACE_(INamespaceProxy, IUnknown)
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** INamespaceProxy ***/
- STDMETHOD(GetNavigateTarget)(THIS_ _In_ PCIDLIST_ABSOLUTE pidl, _Out_ PIDLIST_ABSOLUTE
ppidlTarget, _Out_ ULONG *pulAttrib) PURE;
+ STDMETHOD(GetNavigateTarget)(THIS_ _In_ PCIDLIST_ABSOLUTE pidl, _Out_ PIDLIST_ABSOLUTE
*ppidlTarget, _Out_ ULONG *pulAttrib) PURE;
STDMETHOD(Invoke)(THIS_ _In_ PCIDLIST_ABSOLUTE pidl) PURE;
STDMETHOD(OnSelectionChanged)(THIS_ _In_ PCIDLIST_ABSOLUTE pidl) PURE;
STDMETHOD(RefreshFlags)(THIS_ _Out_ DWORD *pdwStyle, _Out_ DWORD *pdwExStyle, _Out_
DWORD *dwEnum) PURE;