[SHELL32] Separate CCopyAsPathMenu implementation from CCopyMoveToMenu

This commit is contained in:
Thamatip Chitpong 2024-04-09 12:28:26 +07:00
parent f9325370f5
commit d4ca55f65e
6 changed files with 195 additions and 174 deletions

View file

@ -0,0 +1,152 @@
/*
* PROJECT: ReactOS shell32
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Copy as Path Menu implementation
* COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks@proton.me>
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
static DWORD
SetClipboard(UINT cf, const void* data, SIZE_T size)
{
BOOL succ = FALSE;
HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
if (handle)
{
LPVOID clipdata = GlobalLock(handle);
if (clipdata)
{
CopyMemory(clipdata, data, size);
GlobalUnlock(handle);
if (OpenClipboard(NULL))
{
EmptyClipboard();
succ = SetClipboardData(cf, handle) != NULL;
CloseClipboard();
}
}
if (!succ)
{
GlobalFree(handle);
}
}
return succ ? ERROR_SUCCESS : GetLastError();
}
static DWORD
SetClipboardFromString(LPCWSTR str)
{
SIZE_T cch = lstrlenW(str) + 1, size = cch * sizeof(WCHAR);
if (size > cch)
return SetClipboard(CF_UNICODETEXT, str, size);
else
return ERROR_BUFFER_OVERFLOW;
}
static void
AppendToPathList(CStringW &paths, LPCWSTR path, DWORD index)
{
if (index)
paths += L"\r\n";
LPCWSTR quote = StrChrW(path, L' ');
if (quote)
paths += L'\"';
paths += path;
if (quote)
paths += L'\"';
}
STDMETHODIMP
CCopyAsPathMenu::Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
CStringW paths;
DWORD i, count;
#if 0
CComPtr<IShellItemArray> array;
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdto, IID_PPV_ARG(IShellItemArray, &array));
if (SUCCEEDED(hr))
{
for (i = 0, array->GetCount(&count); i < count && SUCCEEDED(hr); ++i)
{
CComPtr<IShellItem> item;
hr = array->GetItemAt(i, &item);
if (SUCCEEDED(hr))
{
CComHeapPtr<WCHAR> path;
hr = item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path);
if (SUCCEEDED(hr))
{
AppendToPathList(paths, path, i);
}
}
}
}
#else
FIXME("Implement and use SHCreateShellItemArrayFromDataObject\n");
CDataObjectHIDA pCIDA(pdto);
HRESULT hr = pCIDA.hr();
if (SUCCEEDED(hr))
{
for (i = 0, count = pCIDA->cidl; i < count && SUCCEEDED(hr); ++i)
{
PCUIDLIST_ABSOLUTE folder = HIDA_GetPIDLFolder(pCIDA);
PCUIDLIST_RELATIVE item = HIDA_GetPIDLItem(pCIDA, i);
CComHeapPtr<ITEMIDLIST> full;
hr = SHILCombine(folder, item, &full);
if (SUCCEEDED(hr))
{
PCUITEMID_CHILD child;
CComPtr<IShellFolder> sf;
hr = SHBindToParent(full, IID_PPV_ARG(IShellFolder, &sf), &child);
if (SUCCEEDED(hr))
{
STRRET strret;
hr = sf->GetDisplayNameOf(child, SHGDN_FORPARSING, &strret);
if (SUCCEEDED(hr))
{
CComHeapPtr<WCHAR> path;
hr = StrRetToStrW(&strret, child, &path);
if (SUCCEEDED(hr))
{
AppendToPathList(paths, path, i);
}
}
}
}
}
}
else
{
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgm;
hr = pdto->GetData(&fmte, &stgm);
if (SUCCEEDED(hr))
{
for (i = 0, count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0); i < count && SUCCEEDED(hr); ++i)
{
WCHAR path[MAX_PATH];
if (DragQueryFileW((HDROP)stgm.hGlobal, i, path, _countof(path)))
{
AppendToPathList(paths, path, i);
}
}
ReleaseStgMedium(&stgm);
}
}
#endif
if (SUCCEEDED(hr))
{
DWORD err = SetClipboardFromString(paths);
hr = HRESULT_FROM_WIN32(err);
}
if (SUCCEEDED(hr))
*pdwEffect &= DROPEFFECT_COPY;
else
*pdwEffect &= DROPEFFECT_NONE;
return hr;
}

View file

@ -0,0 +1,41 @@
/*
* PROJECT: ReactOS shell32
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Copy as Path Menu implementation
* COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks@proton.me>
*/
#pragma once
class CCopyAsPathMenu :
public CComCoClass<CCopyAsPathMenu, &CLSID_CopyAsPathMenu>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IDropTarget
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_COPYASPATHMENU)
DECLARE_NOT_AGGREGATABLE(CCopyAsPathMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCopyAsPathMenu)
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
END_COM_MAP()
// IDropTarget
STDMETHODIMP DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect &= DROPEFFECT_COPY;
return S_OK;
}
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect &= DROPEFFECT_COPY;
return S_OK;
}
STDMETHODIMP DragLeave()
{
return S_OK;
}
STDMETHODIMP Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect);
};

View file

@ -436,145 +436,3 @@ CCopyMoveToMenu::GetSite(REFIID riid, void **ppvSite)
return m_pSite->QueryInterface(riid, ppvSite);
}
static DWORD
SetClipboard(UINT cf, const void* data, SIZE_T size)
{
BOOL succ = FALSE;
HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
if (handle)
{
LPVOID clipdata = GlobalLock(handle);
if (clipdata)
{
CopyMemory(clipdata, data, size);
GlobalUnlock(handle);
if (OpenClipboard(NULL))
{
EmptyClipboard();
succ = SetClipboardData(cf, handle) != NULL;
CloseClipboard();
}
}
if (!succ)
{
GlobalFree(handle);
}
}
return succ ? ERROR_SUCCESS : GetLastError();
}
static DWORD
SetClipboardFromString(LPCWSTR str)
{
SIZE_T cch = lstrlenW(str) + 1, size = cch * sizeof(WCHAR);
if (size > cch)
return SetClipboard(CF_UNICODETEXT, str, size);
else
return ERROR_BUFFER_OVERFLOW;
}
static void
AppendToPathList(CStringW &paths, LPCWSTR path, DWORD index)
{
if (index)
paths += L"\r\n";
LPCWSTR quote = StrChrW(path, L' ');
if (quote)
paths += L'\"';
paths += path;
if (quote)
paths += L'\"';
}
STDMETHODIMP
CCopyAsPathMenu::Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
CStringW paths;
DWORD i, count;
#if 0
CComPtr<IShellItemArray> array;
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdto, IID_PPV_ARG(IShellItemArray, &array));
if (SUCCEEDED(hr))
{
for (i = 0, array->GetCount(&count); i < count && SUCCEEDED(hr); ++i)
{
CComPtr<IShellItem> item;
hr = array->GetItemAt(i, &item);
if (SUCCEEDED(hr))
{
CComHeapPtr<WCHAR> path;
hr = item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path);
if (SUCCEEDED(hr))
{
AppendToPathList(paths, path, i);
}
}
}
}
#else
FIXME("Implement and use SHCreateShellItemArrayFromDataObject\n");
CDataObjectHIDA pCIDA(pdto);
HRESULT hr = pCIDA.hr();
if (SUCCEEDED(hr))
{
for (i = 0, count = pCIDA->cidl; i < count && SUCCEEDED(hr); ++i)
{
PCUIDLIST_ABSOLUTE folder = HIDA_GetPIDLFolder(pCIDA);
PCUIDLIST_RELATIVE item = HIDA_GetPIDLItem(pCIDA, i);
CComHeapPtr<ITEMIDLIST> full;
hr = SHILCombine(folder, item, &full);
if (SUCCEEDED(hr))
{
PCUITEMID_CHILD child;
CComPtr<IShellFolder> sf;
hr = SHBindToParent(full, IID_PPV_ARG(IShellFolder, &sf), &child);
if (SUCCEEDED(hr))
{
STRRET strret;
hr = sf->GetDisplayNameOf(child, SHGDN_FORPARSING, &strret);
if (SUCCEEDED(hr))
{
CComHeapPtr<WCHAR> path;
hr = StrRetToStrW(&strret, child, &path);
if (SUCCEEDED(hr))
{
AppendToPathList(paths, path, i);
}
}
}
}
}
}
else
{
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgm;
hr = pdto->GetData(&fmte, &stgm);
if (SUCCEEDED(hr))
{
for (i = 0, count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0); i < count && SUCCEEDED(hr); ++i)
{
WCHAR path[MAX_PATH];
if (DragQueryFileW((HDROP)stgm.hGlobal, i, path, _countof(path)))
{
AppendToPathList(paths, path, i);
}
}
ReleaseStgMedium(&stgm);
}
}
#endif
if (SUCCEEDED(hr))
{
DWORD err = SetClipboardFromString(paths);
hr = HRESULT_FROM_WIN32(err);
}
if (SUCCEEDED(hr))
*pdwEffect &= DROPEFFECT_COPY;
else
*pdwEffect &= DROPEFFECT_NONE;
return hr;
}

View file

@ -109,35 +109,3 @@ public:
UINT GetFileOp() const override { return FO_MOVE; }
LPCSTR GetVerb() const override { return "moveto"; }
};
class CCopyAsPathMenu
: public CComCoClass<CCopyAsPathMenu, &CLSID_CopyAsPathMenu>
, public CComObjectRootEx<CComMultiThreadModelNoCS>
, public IDropTarget
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_COPYASPATHMENU)
DECLARE_NOT_AGGREGATABLE(CCopyAsPathMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCopyAsPathMenu)
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
END_COM_MAP()
// IDropTarget
STDMETHODIMP DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect &= DROPEFFECT_COPY;
return S_OK;
}
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect &= DROPEFFECT_COPY;
return S_OK;
}
STDMETHODIMP DragLeave()
{
return S_OK;
}
STDMETHODIMP Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect);
};

View file

@ -74,6 +74,7 @@ list(APPEND SOURCE
CNewMenu.cpp
CSendToMenu.cpp
CCopyMoveToMenu.cpp
CCopyAsPathMenu.cpp
CShellDispatch.cpp
CFolder.cpp
CFolderItems.cpp

View file

@ -96,6 +96,7 @@
#include "CNewMenu.h"
#include "CSendToMenu.h"
#include "CCopyMoveToMenu.h"
#include "CCopyAsPathMenu.h"
#include "dialogs/filedefext.h"
#include "dialogs/drvdefext.h"
#include "CQueryAssociations.h"