mirror of
https://github.com/reactos/reactos.git
synced 2026-06-06 21:51:53 +08:00
[SHELL32] Implement Move To Folder (#3056)
- Add context menu item "Mo&ve to folder..." and implement the action. - Implement the "Mo&ve to folder..." menu item of "Edit" menu of Explorer. CORE-11132
This commit is contained in:
committed by
GitHub
parent
679c95597c
commit
46ff964e22
345
dll/win32/shell32/CMoveToMenu.cpp
Normal file
345
dll/win32/shell32/CMoveToMenu.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* PROJECT: shell32
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: MoveTo implementation
|
||||
* COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
|
||||
CMoveToMenu::CMoveToMenu() :
|
||||
m_idCmdFirst(0),
|
||||
m_idCmdLast(0),
|
||||
m_idCmdMoveTo(-1)
|
||||
{
|
||||
}
|
||||
|
||||
CMoveToMenu::~CMoveToMenu()
|
||||
{
|
||||
}
|
||||
|
||||
#define WM_ENABLEOK (WM_USER + 0x2000)
|
||||
|
||||
static LRESULT CALLBACK
|
||||
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CMoveToMenu *this_ =
|
||||
reinterpret_cast<CMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_ENABLEOK:
|
||||
SendMessageW(hwnd, BFFM_ENABLEOK, 0, (BOOL)lParam);
|
||||
return 0;
|
||||
}
|
||||
return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static int CALLBACK
|
||||
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
CMoveToMenu *this_ =
|
||||
reinterpret_cast<CMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case BFFM_INITIALIZED:
|
||||
{
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
|
||||
this_ = reinterpret_cast<CMoveToMenu *>(lpData);
|
||||
|
||||
// Select initial directory
|
||||
SendMessageW(hwnd, BFFM_SETSELECTION, FALSE,
|
||||
reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
|
||||
|
||||
// Set caption
|
||||
CString strCaption(MAKEINTRESOURCEW(IDS_MOVEITEMS));
|
||||
SetWindowTextW(hwnd, strCaption);
|
||||
|
||||
// Set OK button text
|
||||
CString strMove(MAKEINTRESOURCEW(IDS_MOVEBUTTON));
|
||||
SetDlgItemText(hwnd, IDOK, strMove);
|
||||
|
||||
// Subclassing
|
||||
this_->m_fnOldWndProc =
|
||||
reinterpret_cast<WNDPROC>(
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
|
||||
|
||||
// Disable OK
|
||||
PostMessageW(hwnd, WM_ENABLEOK, 0, FALSE);
|
||||
break;
|
||||
}
|
||||
case BFFM_SELCHANGED:
|
||||
{
|
||||
WCHAR szPath[MAX_PATH];
|
||||
LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
|
||||
|
||||
szPath[0] = 0;
|
||||
SHGetPathFromIDListW(pidl, szPath);
|
||||
|
||||
if (ILIsEqual(pidl, this_->m_pidlFolder))
|
||||
PostMessageW(hwnd, WM_ENABLEOK, 0, FALSE);
|
||||
else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
|
||||
PostMessageW(hwnd, WM_ENABLEOK, 0, TRUE);
|
||||
else
|
||||
PostMessageW(hwnd, WM_ENABLEOK, 0, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HRESULT CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
|
||||
{
|
||||
CComHeapPtr<CIDA> pCIDA;
|
||||
HRESULT hr = _GetCidlFromDataObject(m_pDataObject, &pCIDA);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
|
||||
if (!pidlParent)
|
||||
{
|
||||
ERR("HIDA_GetPIDLFolder failed\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
CStringW strFiles;
|
||||
WCHAR szPath[MAX_PATH];
|
||||
for (UINT n = 0; n < pCIDA->cidl; ++n)
|
||||
{
|
||||
PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, n);
|
||||
if (!pidlRelative)
|
||||
continue;
|
||||
|
||||
CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
|
||||
if (!pidl)
|
||||
return E_FAIL;
|
||||
|
||||
SHGetPathFromIDListW(pidlCombine, szPath);
|
||||
|
||||
if (n > 0)
|
||||
strFiles += L'|';
|
||||
strFiles += szPath;
|
||||
}
|
||||
|
||||
strFiles += L'|'; // double null-terminated
|
||||
strFiles.Replace(L'|', L'\0');
|
||||
|
||||
if (_ILIsDesktop(pidl))
|
||||
SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
|
||||
else
|
||||
SHGetPathFromIDListW(pidl, szPath);
|
||||
INT cchPath = lstrlenW(szPath);
|
||||
if (cchPath + 1 < MAX_PATH)
|
||||
{
|
||||
szPath[cchPath + 1] = 0; // double null-terminated
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Too long path\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
SHFILEOPSTRUCTW op = { lpici->hwnd };
|
||||
op.wFunc = FO_MOVE;
|
||||
op.pFrom = strFiles;
|
||||
op.pTo = szPath;
|
||||
op.fFlags = FOF_ALLOWUNDO;
|
||||
return ((SHFileOperation(&op) == 0) ? S_OK : E_FAIL);
|
||||
}
|
||||
|
||||
CStringW CMoveToMenu::DoGetFileTitle()
|
||||
{
|
||||
CStringW ret = L"(file)";
|
||||
|
||||
CComHeapPtr<CIDA> pCIDA;
|
||||
HRESULT hr = _GetCidlFromDataObject(m_pDataObject, &pCIDA);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return ret;
|
||||
|
||||
PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
|
||||
if (!pidlParent)
|
||||
{
|
||||
ERR("HIDA_GetPIDLFolder failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
WCHAR szPath[MAX_PATH];
|
||||
PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(pCIDA, 0);
|
||||
if (!pidlRelative)
|
||||
{
|
||||
ERR("HIDA_GetPIDLItem failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
|
||||
|
||||
if (SHGetPathFromIDListW(pidlCombine, szPath))
|
||||
ret = PathFindFileNameW(szPath);
|
||||
else
|
||||
ERR("Cannot get path\n");
|
||||
|
||||
if (pCIDA->cidl > 1)
|
||||
ret += L" ...";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HRESULT CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici)
|
||||
{
|
||||
WCHAR wszPath[MAX_PATH];
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
TRACE("DoMoveToFolder(%p)\n", lpici);
|
||||
|
||||
if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
|
||||
{
|
||||
ERR("SHGetPathFromIDListW failed\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
CStringW strFileTitle = DoGetFileTitle();
|
||||
CStringW strTitle;
|
||||
strTitle.Format(IDS_MOVETOTITLE, static_cast<LPCWSTR>(strFileTitle));
|
||||
|
||||
BROWSEINFOW info = { lpici->hwnd };
|
||||
info.pidlRoot = NULL;
|
||||
info.lpszTitle = strTitle;
|
||||
info.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
|
||||
info.lpfn = BrowseCallbackProc;
|
||||
info.lParam = reinterpret_cast<LPARAM>(this);
|
||||
CComHeapPtr<ITEMIDLIST> pidl(SHBrowseForFolder(&info));
|
||||
if (pidl)
|
||||
{
|
||||
hr = DoRealMove(lpici, pidl);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
CMoveToMenu::QueryContextMenu(HMENU hMenu,
|
||||
UINT indexMenu,
|
||||
UINT idCmdFirst,
|
||||
UINT idCmdLast,
|
||||
UINT uFlags)
|
||||
{
|
||||
MENUITEMINFOW mii;
|
||||
UINT Count = 0;
|
||||
|
||||
TRACE("CMoveToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
|
||||
hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
|
||||
|
||||
m_idCmdFirst = m_idCmdLast = idCmdFirst;
|
||||
|
||||
// insert separator if necessary
|
||||
CStringW strCopyTo(MAKEINTRESOURCEW(IDS_COPYTOMENU));
|
||||
WCHAR szBuff[128];
|
||||
ZeroMemory(&mii, sizeof(mii));
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_TYPE;
|
||||
mii.dwTypeData = szBuff;
|
||||
mii.cch = _countof(szBuff);
|
||||
if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
|
||||
mii.fType != MFT_SEPARATOR &&
|
||||
!(mii.fType == MFT_STRING && CStringW(szBuff) == strCopyTo))
|
||||
{
|
||||
ZeroMemory(&mii, sizeof(mii));
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_TYPE;
|
||||
mii.fType = MFT_SEPARATOR;
|
||||
if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
++indexMenu;
|
||||
++Count;
|
||||
}
|
||||
}
|
||||
|
||||
// insert "Move to folder..."
|
||||
CStringW strText(MAKEINTRESOURCEW(IDS_MOVETOMENU));
|
||||
ZeroMemory(&mii, sizeof(mii));
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_ID | MIIM_TYPE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = strText.GetBuffer();
|
||||
mii.cch = wcslen(mii.dwTypeData);
|
||||
mii.wID = m_idCmdLast;
|
||||
if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
m_idCmdMoveTo = m_idCmdLast++;
|
||||
++indexMenu;
|
||||
++Count;
|
||||
}
|
||||
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
CMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
TRACE("CMoveToMenu::InvokeCommand(%p)\n", lpici);
|
||||
|
||||
if (HIWORD(lpici->lpVerb) == 0)
|
||||
{
|
||||
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdMoveTo)
|
||||
{
|
||||
hr = DoMoveToFolder(lpici);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (::lstrcmpiA(lpici->lpVerb, "moveto") == 0)
|
||||
{
|
||||
hr = DoMoveToFolder(lpici);
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
CMoveToMenu::GetCommandString(UINT_PTR idCmd,
|
||||
UINT uType,
|
||||
UINT *pwReserved,
|
||||
LPSTR pszName,
|
||||
UINT cchMax)
|
||||
{
|
||||
FIXME("%p %lu %u %p %p %u\n", this,
|
||||
idCmd, uType, pwReserved, pszName, cchMax);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
CMoveToMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
TRACE("This %p uMsg %x\n", this, uMsg);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
CMoveToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder,
|
||||
IDataObject *pdtobj, HKEY hkeyProgID)
|
||||
{
|
||||
m_pidlFolder.Attach(ILClone(pidlFolder));
|
||||
m_pDataObject = pdtobj;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI CMoveToMenu::SetSite(IUnknown *pUnkSite)
|
||||
{
|
||||
m_pSite = pUnkSite;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI CMoveToMenu::GetSite(REFIID riid, void **ppvSite)
|
||||
{
|
||||
if (!m_pSite)
|
||||
return E_FAIL;
|
||||
|
||||
return m_pSite->QueryInterface(riid, ppvSite);
|
||||
}
|
||||
Reference in New Issue
Block a user