mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 01:45:40 +00:00
[SHELL32] Improve CFSDropTarget::CopyItems logic (#5481)
The previous version resolved the path of the parent then did logic assuming simple pidls. This now resolves each source directly. This change addresses a longstanding TODO in copying and moving to shell folders. It's a simple change, but it removes a bit of code and makes things simpler. Corresponding Wine PR: https://gitlab.winehq.org/wine/wine/-/merge_requests/3360
This commit is contained in:
parent
9bc5b8357a
commit
1273bbe417
1 changed files with 46 additions and 63 deletions
|
@ -24,82 +24,65 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* BuildPathsList
|
|
||||||
*
|
|
||||||
* Builds a list of paths like the one used in SHFileOperation from a table of
|
|
||||||
* PIDLs relative to the given base folder
|
|
||||||
*/
|
|
||||||
static WCHAR* BuildPathsList(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls)
|
|
||||||
{
|
|
||||||
WCHAR *pwszPathsList = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
|
|
||||||
WCHAR *pwszListPos = pwszPathsList;
|
|
||||||
|
|
||||||
for (int i = 0; i < cidl; i++)
|
|
||||||
{
|
|
||||||
FileStructW* pDataW = _ILGetFileStructW(pidls[i]);
|
|
||||||
if (!pDataW)
|
|
||||||
{
|
|
||||||
ERR("Mistreating a pidl:\n");
|
|
||||||
pdump_always(pidls[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
PathCombineW(pwszListPos, wszBasePath, pDataW->wszName);
|
|
||||||
pwszListPos += wcslen(pwszListPos) + 1;
|
|
||||||
}
|
|
||||||
*pwszListPos = 0;
|
|
||||||
return pwszPathsList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* CFSDropTarget::_CopyItems
|
* CFSDropTarget::_CopyItems
|
||||||
*
|
*
|
||||||
* copies items to this folder
|
* copies or moves items to this folder
|
||||||
* FIXME: We should not ask the parent folder: 'What is your path', and then manually build paths assuming everything is a simple pidl!
|
|
||||||
* We should be asking the parent folder: Give me a full name for this pidl (for each child!)
|
|
||||||
*/
|
*/
|
||||||
HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
|
HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
|
||||||
LPCITEMIDLIST * apidl, BOOL bCopy)
|
LPCITEMIDLIST * apidl, BOOL bCopy)
|
||||||
{
|
{
|
||||||
LPWSTR pszSrcList;
|
HRESULT ret;
|
||||||
HRESULT hr;
|
WCHAR wszDstPath[MAX_PATH + 1] = {0};
|
||||||
WCHAR wszTargetPath[MAX_PATH + 1];
|
PWCHAR pwszSrcPathsList = (PWCHAR) HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
|
||||||
|
if (!pwszSrcPathsList)
|
||||||
wcscpy(wszTargetPath, m_sPathTarget);
|
|
||||||
//Double NULL terminate.
|
|
||||||
wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
|
|
||||||
|
|
||||||
TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
|
|
||||||
|
|
||||||
STRRET strretFrom;
|
|
||||||
hr = pSFFrom->GetDisplayNameOf(NULL, SHGDN_FORPARSING, &strretFrom);
|
|
||||||
if (hr != S_OK)
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
pszSrcList = BuildPathsList(strretFrom.pOleStr, cidl, apidl);
|
|
||||||
TRACE("Source file (just the first) = %s, target path = %s, bCopy: %d\n", debugstr_w(pszSrcList), debugstr_w(m_sPathTarget), bCopy);
|
|
||||||
CoTaskMemFree(strretFrom.pOleStr);
|
|
||||||
if (!pszSrcList)
|
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
SHFILEOPSTRUCTW op = {0};
|
PWCHAR pwszListPos = pwszSrcPathsList;
|
||||||
op.pFrom = pszSrcList;
|
STRRET strretFrom;
|
||||||
op.pTo = wszTargetPath;
|
SHFILEOPSTRUCTW fop;
|
||||||
op.hwnd = m_hwndSite;
|
|
||||||
op.wFunc = bCopy ? FO_COPY : FO_MOVE;
|
|
||||||
op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
|
|
||||||
|
|
||||||
int res = SHFileOperationW(&op);
|
/* Build a double null terminated list of C strings from source paths */
|
||||||
|
for (UINT i = 0; i < cidl; i++)
|
||||||
HeapFree(GetProcessHeap(), 0, pszSrcList);
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
{
|
{
|
||||||
ERR("SHFileOperationW failed with 0x%x\n", res);
|
ret = pSFFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strretFrom);
|
||||||
return E_FAIL;
|
if (FAILED(ret))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = StrRetToBufW(&strretFrom, NULL, pwszListPos, MAX_PATH);
|
||||||
|
if (FAILED(ret))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
pwszListPos += lstrlenW(pwszListPos) + 1;
|
||||||
}
|
}
|
||||||
return S_OK;
|
/* Append the final null. */
|
||||||
|
*pwszListPos = L'\0';
|
||||||
|
|
||||||
|
/* Build a double null terminated target (this path) */
|
||||||
|
ret = StringCchCopyW(wszDstPath, MAX_PATH, m_sPathTarget);
|
||||||
|
if (FAILED(ret))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
wszDstPath[lstrlenW(wszDstPath) + 1] = L'\0';
|
||||||
|
|
||||||
|
ZeroMemory(&fop, sizeof(fop));
|
||||||
|
fop.hwnd = m_hwndSite;
|
||||||
|
fop.wFunc = bCopy ? FO_COPY : FO_MOVE;
|
||||||
|
fop.pFrom = pwszSrcPathsList;
|
||||||
|
fop.pTo = wszDstPath;
|
||||||
|
fop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
|
||||||
|
ret = S_OK;
|
||||||
|
|
||||||
|
if (SHFileOperationW(&fop))
|
||||||
|
{
|
||||||
|
ERR("SHFileOperationW failed\n");
|
||||||
|
ret = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
HeapFree(GetProcessHeap(), 0, pwszSrcPathsList);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFSDropTarget::CFSDropTarget():
|
CFSDropTarget::CFSDropTarget():
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue