[SHELL32] Commonize CCopyToMenu and CMoveToMenu (#5873)

Reduce code. And correctly do the filename check.
CORE-18909
This commit is contained in:
Katayama Hirofumi MZ 2023-11-04 21:56:15 +09:00 committed by GitHub
parent d21def4819
commit a938d19714
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 234 additions and 564 deletions

View file

@ -1,33 +1,29 @@
/*
* PROJECT: shell32
* PROJECT: ReactOS 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)
* PURPOSE: CopyTo and MoveTo implementation
* COPYRIGHT: Copyright 2020-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
CMoveToMenu::CMoveToMenu() :
CCopyMoveToMenu::CCopyMoveToMenu() :
m_idCmdFirst(0),
m_idCmdLast(0),
m_idCmdMoveTo(-1),
m_idCmdAction(-1),
m_fnOldWndProc(NULL),
m_bIgnoreTextBoxChange(FALSE)
{
}
CMoveToMenu::~CMoveToMenu()
{
}
static LRESULT CALLBACK
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WCHAR szPath[MAX_PATH];
CMoveToMenu *this_ =
reinterpret_cast<CMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
CCopyMoveToMenu *this_ =
reinterpret_cast<CCopyMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg)
{
@ -64,30 +60,30 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
}
static int CALLBACK
static INT CALLBACK
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
CMoveToMenu *this_ =
reinterpret_cast<CMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
CCopyMoveToMenu *this_ =
reinterpret_cast<CCopyMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg)
{
case BFFM_INITIALIZED:
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
this_ = reinterpret_cast<CMoveToMenu *>(lpData);
this_ = reinterpret_cast<CCopyMoveToMenu *>(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));
CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID()));
SetWindowTextW(hwnd, strCaption);
// Set OK button text
CString strMove(MAKEINTRESOURCEW(IDS_MOVEBUTTON));
SetDlgItemText(hwnd, IDOK, strMove);
CString strCopyOrMove(MAKEINTRESOURCEW(this_->GetButtonStringID()));
SetDlgItemText(hwnd, IDOK, strCopyOrMove);
// Subclassing
this_->m_fnOldWndProc =
@ -125,7 +121,8 @@ BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
return FALSE;
}
HRESULT CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
HRESULT
CCopyMoveToMenu::DoRealFileOp(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
{
CDataObjectHIDA pCIDA(m_pDataObject);
if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
@ -175,10 +172,7 @@ HRESULT CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
return E_FAIL;
}
SHFILEOPSTRUCTW op = { lpici->hwnd };
op.wFunc = FO_MOVE;
op.pFrom = strFiles;
op.pTo = szPath;
SHFILEOPSTRUCTW op = { lpici->hwnd, GetFileOp(), strFiles, szPath };
op.fFlags = FOF_ALLOWUNDO;
int res = SHFileOperationW(&op);
if (res)
@ -189,19 +183,18 @@ HRESULT CMoveToMenu::DoRealMove(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
return S_OK;
}
CStringW CMoveToMenu::DoGetFileTitle()
static HRESULT
DoGetFileTitle(CStringW& strTitle, IDataObject *pDataObject)
{
CStringW ret = L"(file)";
CDataObjectHIDA pCIDA(m_pDataObject);
CDataObjectHIDA pCIDA(pDataObject);
if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
return ret;
return E_FAIL;
PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(pCIDA);
if (!pidlParent)
{
ERR("HIDA_GetPIDLFolder failed\n");
return ret;
return E_FAIL;
}
WCHAR szPath[MAX_PATH];
@ -209,28 +202,33 @@ CStringW CMoveToMenu::DoGetFileTitle()
if (!pidlRelative)
{
ERR("HIDA_GetPIDLItem failed\n");
return ret;
return E_FAIL;
}
CComHeapPtr<ITEMIDLIST> pidlCombine(ILCombine(pidlParent, pidlRelative));
if (SHGetPathFromIDListW(pidlCombine, szPath))
ret = PathFindFileNameW(szPath);
else
if (!SHGetPathFromIDListW(pidlCombine, szPath))
{
ERR("Cannot get path\n");
return E_FAIL;
}
strTitle = PathFindFileNameW(szPath);
if (strTitle.IsEmpty())
return E_FAIL;
if (pCIDA->cidl > 1)
ret += L" ...";
strTitle += L" ...";
return ret;
return S_OK;
}
HRESULT CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici)
HRESULT CCopyMoveToMenu::DoAction(LPCMINVOKECOMMANDINFO lpici)
{
WCHAR wszPath[MAX_PATH];
HRESULT hr = E_FAIL;
TRACE("DoMoveToFolder(%p)\n", lpici);
TRACE("(%p)\n", lpici);
if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
{
@ -238,9 +236,13 @@ HRESULT CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici)
return hr;
}
CStringW strFileTitle = DoGetFileTitle();
CStringW strFileTitle;
hr = DoGetFileTitle(strFileTitle, m_pDataObject);
if (FAILED(hr))
return hr;
CStringW strTitle;
strTitle.Format(IDS_MOVETOTITLE, static_cast<LPCWSTR>(strFileTitle));
strTitle.Format(GetActionTitleStringID(), static_cast<LPCWSTR>(strFileTitle));
BROWSEINFOW info = { lpici->hwnd };
info.pidlRoot = NULL;
@ -250,14 +252,67 @@ HRESULT CMoveToMenu::DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici)
info.lParam = reinterpret_cast<LPARAM>(this);
CComHeapPtr<ITEMIDLIST> pidl(SHBrowseForFolder(&info));
if (pidl)
{
hr = DoRealMove(lpici, pidl);
}
hr = DoRealFileOp(lpici, pidl);
return hr;
}
HRESULT WINAPI
STDMETHODIMP
CCopyToMenu::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
MENUITEMINFOW mii;
UINT Count = 0;
TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
m_idCmdFirst = m_idCmdLast = idCmdFirst;
// insert separator if necessary
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE;
if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
mii.fType != MFT_SEPARATOR)
{
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 "Copy to folder..."
CStringW strText(MAKEINTRESOURCEW(IDS_COPYTOMENU));
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_idCmdAction = m_idCmdLast++;
++indexMenu;
++Count;
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
}
STDMETHODIMP
CMoveToMenu::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
@ -309,7 +364,7 @@ CMoveToMenu::QueryContextMenu(HMENU hMenu,
mii.wID = m_idCmdLast;
if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
{
m_idCmdMoveTo = m_idCmdLast++;
m_idCmdAction = m_idCmdLast++;
++indexMenu;
++Count;
}
@ -317,36 +372,33 @@ CMoveToMenu::QueryContextMenu(HMENU hMenu,
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
}
HRESULT WINAPI
CMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
STDMETHODIMP
CCopyMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
HRESULT hr = E_FAIL;
TRACE("CMoveToMenu::InvokeCommand(%p)\n", lpici);
TRACE("CCopyMoveToMenu::InvokeCommand(%p)\n", lpici);
if (IS_INTRESOURCE(lpici->lpVerb))
{
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdMoveTo)
{
hr = DoMoveToFolder(lpici);
}
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdAction)
hr = DoAction(lpici);
}
else
{
if (::lstrcmpiA(lpici->lpVerb, "moveto") == 0)
{
hr = DoMoveToFolder(lpici);
}
if (::lstrcmpiA(lpici->lpVerb, GetVerb()) == 0)
hr = DoAction(lpici);
}
return hr;
}
HRESULT WINAPI
CMoveToMenu::GetCommandString(UINT_PTR idCmd,
UINT uType,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax)
STDMETHODIMP
CCopyMoveToMenu::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);
@ -354,29 +406,30 @@ CMoveToMenu::GetCommandString(UINT_PTR idCmd,
return E_NOTIMPL;
}
HRESULT WINAPI
CMoveToMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
STDMETHODIMP
CCopyMoveToMenu::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)
STDMETHODIMP
CCopyMoveToMenu::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)
STDMETHODIMP
CCopyMoveToMenu::SetSite(IUnknown *pUnkSite)
{
m_pSite = pUnkSite;
return S_OK;
}
HRESULT WINAPI CMoveToMenu::GetSite(REFIID riid, void **ppvSite)
STDMETHODIMP
CCopyMoveToMenu::GetSite(REFIID riid, void **ppvSite)
{
if (!m_pSite)
return E_FAIL;

View file

@ -0,0 +1,111 @@
/*
* PROJECT: ReactOS shell32
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: CopyTo and MoveTo implementation
* COPYRIGHT: Copyright 2020-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#pragma once
class CCopyMoveToMenu :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu2,
public IObjectWithSite,
public IShellExtInit
{
protected:
UINT m_idCmdFirst, m_idCmdLast, m_idCmdAction;
CComPtr<IDataObject> m_pDataObject;
CComPtr<IUnknown> m_pSite;
HRESULT DoRealFileOp(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl);
HRESULT DoAction(LPCMINVOKECOMMANDINFO lpici);
public:
CComHeapPtr<ITEMIDLIST> m_pidlFolder;
WNDPROC m_fnOldWndProc;
BOOL m_bIgnoreTextBoxChange;
CCopyMoveToMenu();
virtual UINT GetCaptionStringID() const = 0;
virtual UINT GetButtonStringID() const = 0;
virtual UINT GetActionTitleStringID() const = 0;
virtual UINT GetFileOp() const = 0;
virtual LPCSTR GetVerb() const = 0;
// IContextMenu
STDMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) override;
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) override;
// IContextMenu2
STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
// IShellExtInit
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) override;
// IObjectWithSite
STDMETHODIMP SetSite(IUnknown *pUnkSite) override;
STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override;
};
class CCopyToMenu
: public CComCoClass<CCopyToMenu, &CLSID_CopyToMenu>
, public CCopyMoveToMenu
{
public:
CComHeapPtr<ITEMIDLIST> m_pidlFolder;
WNDPROC m_fnOldWndProc;
BOOL m_bIgnoreTextBoxChange;
CCopyToMenu() { }
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override;
DECLARE_REGISTRY_RESOURCEID(IDR_COPYTOMENU)
DECLARE_NOT_AGGREGATABLE(CCopyToMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCopyToMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
END_COM_MAP()
UINT GetCaptionStringID() const override { return IDS_COPYITEMS; }
UINT GetButtonStringID() const override { return IDS_COPYBUTTON; }
UINT GetActionTitleStringID() const override { return IDS_COPYTOTITLE; }
UINT GetFileOp() const override { return FO_COPY; }
LPCSTR GetVerb() const override { return "copyto"; }
};
class CMoveToMenu
: public CComCoClass<CMoveToMenu, &CLSID_MoveToMenu>
, public CCopyMoveToMenu
{
public:
CMoveToMenu() { }
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override;
DECLARE_REGISTRY_RESOURCEID(IDR_MOVETOMENU)
DECLARE_NOT_AGGREGATABLE(CMoveToMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMoveToMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
END_COM_MAP()
UINT GetCaptionStringID() const override { return IDS_MOVEITEMS; }
UINT GetButtonStringID() const override { return IDS_MOVEBUTTON; }
UINT GetActionTitleStringID() const override { return IDS_MOVETOTITLE; }
UINT GetFileOp() const override { return FO_MOVE; }
LPCSTR GetVerb() const override { return "moveto"; }
};

View file

@ -1,381 +0,0 @@
/*
* PROJECT: shell32
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: CopyTo implementation
* COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
CCopyToMenu::CCopyToMenu() :
m_idCmdFirst(0),
m_idCmdLast(0),
m_idCmdCopyTo(-1),
m_fnOldWndProc(NULL),
m_bIgnoreTextBoxChange(FALSE)
{
}
CCopyToMenu::~CCopyToMenu()
{
}
static LRESULT CALLBACK
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WCHAR szPath[MAX_PATH];
CCopyToMenu *this_ =
reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT:
{
if (HIWORD(wParam) == EN_CHANGE)
{
if (!this_->m_bIgnoreTextBoxChange)
{
// get the text
GetDlgItemTextW(hwnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT, szPath, _countof(szPath));
StrTrimW(szPath, L" \t");
// update OK button
BOOL bValid = !PathIsRelative(szPath) && PathIsDirectoryW(szPath);
SendMessageW(hwnd, BFFM_ENABLEOK, 0, bValid);
return 0;
}
// reset flag
this_->m_bIgnoreTextBoxChange = FALSE;
}
break;
}
}
break;
}
}
return CallWindowProcW(this_->m_fnOldWndProc, hwnd, uMsg, wParam, lParam);
}
static int CALLBACK
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
CCopyToMenu *this_ =
reinterpret_cast<CCopyToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg)
{
case BFFM_INITIALIZED:
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
this_ = reinterpret_cast<CCopyToMenu *>(lpData);
// Select initial directory
SendMessageW(hwnd, BFFM_SETSELECTION, FALSE,
reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
// Set caption
CString strCaption(MAKEINTRESOURCEW(IDS_COPYITEMS));
SetWindowTextW(hwnd, strCaption);
// Set OK button text
CString strCopy(MAKEINTRESOURCEW(IDS_COPYBUTTON));
SetDlgItemText(hwnd, IDOK, strCopy);
// Subclassing
this_->m_fnOldWndProc =
reinterpret_cast<WNDPROC>(
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
// Disable OK
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE);
break;
}
case BFFM_SELCHANGED:
{
if (!this_)
break;
WCHAR szPath[MAX_PATH];
LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
szPath[0] = 0;
SHGetPathFromIDListW(pidl, szPath);
if (ILIsEqual(pidl, this_->m_pidlFolder))
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE);
else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
PostMessageW(hwnd, BFFM_ENABLEOK, 0, TRUE);
else
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE);
// the text box will be updated later soon, ignore it
this_->m_bIgnoreTextBoxChange = TRUE;
break;
}
}
return FALSE;
}
HRESULT CCopyToMenu::DoRealCopy(LPCMINVOKECOMMANDINFO lpici, LPCITEMIDLIST pidl)
{
CDataObjectHIDA pCIDA(m_pDataObject);
if (FAILED_UNEXPECTEDLY(pCIDA.hr()))
return pCIDA.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_COPY;
op.pFrom = strFiles;
op.pTo = szPath;
op.fFlags = FOF_ALLOWUNDO;
int res = SHFileOperationW(&op);
if (res)
{
ERR("SHFileOperationW failed with 0x%x\n", res);
return E_FAIL;
}
return S_OK;
}
CStringW CCopyToMenu::DoGetFileTitle()
{
CStringW ret = L"(file)";
CDataObjectHIDA pCIDA(m_pDataObject);
if (FAILED_UNEXPECTEDLY(pCIDA.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 CCopyToMenu::DoCopyToFolder(LPCMINVOKECOMMANDINFO lpici)
{
WCHAR wszPath[MAX_PATH];
HRESULT hr = E_FAIL;
TRACE("DoCopyToFolder(%p)\n", lpici);
if (!SHGetPathFromIDListW(m_pidlFolder, wszPath))
{
ERR("SHGetPathFromIDListW failed\n");
return hr;
}
CStringW strFileTitle = DoGetFileTitle();
CStringW strTitle;
strTitle.Format(IDS_COPYTOTITLE, 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 = DoRealCopy(lpici, pidl);
}
return hr;
}
HRESULT WINAPI
CCopyToMenu::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
MENUITEMINFOW mii;
UINT Count = 0;
TRACE("CCopyToMenu::QueryContextMenu(%p, %u, %u, %u, %u)\n",
hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
if (uFlags & (CMF_NOVERBS | CMF_VERBSONLY))
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
m_idCmdFirst = m_idCmdLast = idCmdFirst;
// insert separator if necessary
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE;
if (GetMenuItemInfoW(hMenu, indexMenu - 1, TRUE, &mii) &&
mii.fType != MFT_SEPARATOR)
{
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 "Copy to folder..."
CStringW strText(MAKEINTRESOURCEW(IDS_COPYTOMENU));
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_idCmdCopyTo = m_idCmdLast++;
++indexMenu;
++Count;
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst + Count);
}
HRESULT WINAPI
CCopyToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
HRESULT hr = E_FAIL;
TRACE("CCopyToMenu::InvokeCommand(%p)\n", lpici);
if (IS_INTRESOURCE(lpici->lpVerb))
{
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdCopyTo)
{
hr = DoCopyToFolder(lpici);
}
}
else
{
if (::lstrcmpiA(lpici->lpVerb, "copyto") == 0)
{
hr = DoCopyToFolder(lpici);
}
}
return hr;
}
HRESULT WINAPI
CCopyToMenu::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
CCopyToMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
TRACE("This %p uMsg %x\n", this, uMsg);
return E_NOTIMPL;
}
HRESULT WINAPI
CCopyToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder,
IDataObject *pdtobj, HKEY hkeyProgID)
{
m_pidlFolder.Attach(ILClone(pidlFolder));
m_pDataObject = pdtobj;
return S_OK;
}
HRESULT WINAPI CCopyToMenu::SetSite(IUnknown *pUnkSite)
{
m_pSite = pUnkSite;
return S_OK;
}
HRESULT WINAPI CCopyToMenu::GetSite(REFIID riid, void **ppvSite)
{
if (!m_pSite)
return E_FAIL;
return m_pSite->QueryInterface(riid, ppvSite);
}

View file

@ -1,112 +0,0 @@
/*
* PROJECT: shell32
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: CopyTo and MoveTo implementation
* COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#pragma once
class CCopyToMenu :
public CComCoClass<CCopyToMenu, &CLSID_CopyToMenu>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu2,
public IObjectWithSite,
public IShellExtInit
{
protected:
UINT m_idCmdFirst, m_idCmdLast, m_idCmdCopyTo;
CComPtr<IDataObject> m_pDataObject;
CComPtr<IUnknown> m_pSite;
HRESULT DoCopyToFolder(LPCMINVOKECOMMANDINFO lpici);
HRESULT DoRealCopy(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl);
CStringW DoGetFileTitle();
public:
CComHeapPtr<ITEMIDLIST> m_pidlFolder;
WNDPROC m_fnOldWndProc;
BOOL m_bIgnoreTextBoxChange;
CCopyToMenu();
~CCopyToMenu();
// IContextMenu
virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
// IContextMenu2
virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
// IShellExtInit
virtual HRESULT WINAPI Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
// IObjectWithSite
virtual HRESULT WINAPI SetSite(IUnknown *pUnkSite);
virtual HRESULT WINAPI GetSite(REFIID riid, void **ppvSite);
DECLARE_REGISTRY_RESOURCEID(IDR_COPYTOMENU)
DECLARE_NOT_AGGREGATABLE(CCopyToMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCopyToMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
END_COM_MAP()
};
class CMoveToMenu :
public CComCoClass<CMoveToMenu, &CLSID_MoveToMenu>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu2,
public IObjectWithSite,
public IShellExtInit
{
protected:
UINT m_idCmdFirst, m_idCmdLast, m_idCmdMoveTo;
CComPtr<IDataObject> m_pDataObject;
CComPtr<IUnknown> m_pSite;
HRESULT DoMoveToFolder(LPCMINVOKECOMMANDINFO lpici);
HRESULT DoRealMove(LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidl);
CStringW DoGetFileTitle();
public:
CComHeapPtr<ITEMIDLIST> m_pidlFolder;
WNDPROC m_fnOldWndProc;
BOOL m_bIgnoreTextBoxChange;
CMoveToMenu();
~CMoveToMenu();
// IContextMenu
virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
// IContextMenu2
virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
// IShellExtInit
virtual HRESULT WINAPI Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
// IObjectWithSite
virtual HRESULT WINAPI SetSite(IUnknown *pUnkSite);
virtual HRESULT WINAPI GetSite(REFIID riid, void **ppvSite);
DECLARE_REGISTRY_RESOURCEID(IDR_MOVETOMENU)
DECLARE_NOT_AGGREGATABLE(CMoveToMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMoveToMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
END_COM_MAP()
};

View file

@ -73,8 +73,7 @@ list(APPEND SOURCE
COpenWithMenu.cpp
CNewMenu.cpp
CSendToMenu.cpp
CCopyToMenu.cpp
CMoveToMenu.cpp
CCopyMoveToMenu.cpp
CShellDispatch.cpp
CFolder.cpp
CFolderItems.cpp

View file

@ -95,7 +95,7 @@
#include "COpenWithMenu.h"
#include "CNewMenu.h"
#include "CSendToMenu.h"
#include "CCopyToMoveToMenu.h"
#include "CCopyMoveToMenu.h"
#include "dialogs/filedefext.h"
#include "dialogs/drvdefext.h"
#include "CQueryAssociations.h"