mirror of
https://github.com/reactos/reactos.git
synced 2025-04-03 20:21:17 +00:00
[SHELL32]
* Add support for the CF_HDROP format in the shell drop targets. * Implement IAsyncOperation for the shell data object implementation, which is how one checks to see if it's safe to perform a background copy. * Actually check for the IAsyncOperation interface in the drop targets. * 7-zip and WinRAR are now mostly working correctly in terms of drag and drop. * Brought to you by Huw Campbell. CORE-3760 svn path=/trunk/; revision=61576
This commit is contained in:
parent
0532456b81
commit
4adc3e9bbd
5 changed files with 360 additions and 209 deletions
|
@ -163,7 +163,8 @@ HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMA
|
|||
|
||||
class IDataObjectImpl :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public IDataObject
|
||||
public IDataObject,
|
||||
public IAsyncOperation
|
||||
{
|
||||
private:
|
||||
LPITEMIDLIST pidl;
|
||||
|
@ -176,6 +177,7 @@ private:
|
|||
UINT cfFileNameA;
|
||||
UINT cfFileNameW;
|
||||
UINT cfPreferredDropEffect;
|
||||
BOOL doasync;
|
||||
public:
|
||||
IDataObjectImpl();
|
||||
~IDataObjectImpl();
|
||||
|
@ -191,9 +193,15 @@ public:
|
|||
virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
|
||||
virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
|
||||
virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
|
||||
virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
|
||||
virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
|
||||
virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
|
||||
virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
|
||||
virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
|
||||
|
||||
BEGIN_COM_MAP(IDataObjectImpl)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation, IAsyncOperation)
|
||||
END_COM_MAP()
|
||||
};
|
||||
|
||||
|
@ -207,6 +215,7 @@ IDataObjectImpl::IDataObjectImpl()
|
|||
cfFileNameA = 0;
|
||||
cfFileNameW = 0;
|
||||
cfPreferredDropEffect = 0;
|
||||
doasync = FALSE;
|
||||
}
|
||||
|
||||
IDataObjectImpl::~IDataObjectImpl()
|
||||
|
@ -371,6 +380,37 @@ HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT WINAPI IDataObjectImpl::GetAsyncMode(BOOL *pfIsOpAsync)
|
||||
{
|
||||
TRACE("(%p)->()\n", this);
|
||||
*pfIsOpAsync = doasync;
|
||||
return S_OK;
|
||||
}
|
||||
HRESULT WINAPI IDataObjectImpl::InOperation(BOOL *pfInAsyncOp)
|
||||
{
|
||||
FIXME("(%p)->()\n", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
HRESULT WINAPI IDataObjectImpl::SetAsyncMode(BOOL fDoOpAsync)
|
||||
{
|
||||
TRACE("(%p)->()\n", this);
|
||||
doasync = fDoOpAsync;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI IDataObjectImpl::StartOperation(IBindCtx *pbcReserved)
|
||||
{
|
||||
FIXME("(%p)->()\n", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
HRESULT WINAPI IDataObjectImpl::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
|
||||
{
|
||||
FIXME("(%p)->()\n", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* IDataObject_Constructor
|
||||
*/
|
||||
|
|
|
@ -1377,11 +1377,18 @@ BOOL CDesktopFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
|||
HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
|
||||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
|
||||
FORMATETC fmt;
|
||||
FORMATETC fmt2;
|
||||
fAcceptFmt = FALSE;
|
||||
|
||||
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ?
|
||||
TRUE : FALSE;
|
||||
InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
|
||||
|
||||
if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
|
||||
fAcceptFmt = TRUE;
|
||||
else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
|
||||
fAcceptFmt = TRUE;
|
||||
|
||||
QueryDrop(dwKeyState, pdwEffect);
|
||||
return S_OK;
|
||||
|
@ -1413,32 +1420,45 @@ HRESULT WINAPI CDesktopFolder::Drop(IDataObject *pDataObject,
|
|||
TRACE("(%p) object dropped desktop\n", this);
|
||||
|
||||
STGMEDIUM medium;
|
||||
bool passthroughtofs = FALSE;
|
||||
FORMATETC formatetc;
|
||||
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
||||
|
||||
HRESULT hr = pDataObject->GetData(&formatetc, &medium);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
/* lock the handle */
|
||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||
if (!lpcida)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
/* lock the handle */
|
||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||
if (!lpcida)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* convert the clipboard data into pidl (pointer to id list) */
|
||||
LPITEMIDLIST pidl;
|
||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||
if (!apidl)
|
||||
/* convert the clipboard data into pidl (pointer to id list) */
|
||||
LPITEMIDLIST pidl;
|
||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||
if (!apidl)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
passthroughtofs = !_ILIsDesktop(pidl) || (dwKeyState & MK_CONTROL);
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL);
|
||||
if SUCCEEDED(pDataObject->QueryGetData(&formatetc));
|
||||
{
|
||||
passthroughtofs = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We only want to really move files around if they don't already
|
||||
come from the desktop, or we're linking or copying */
|
||||
if ((!_ILIsDesktop(pidl)) || (dwKeyState & MK_CONTROL))
|
||||
if (passthroughtofs)
|
||||
{
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
|
||||
|
@ -1467,9 +1487,5 @@ HRESULT WINAPI CDesktopFolder::Drop(IDataObject *pDataObject,
|
|||
|
||||
/* Todo, rewrite the registry such that the icons are well placed.
|
||||
Blocked by no bags implementation. */
|
||||
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return hr;
|
||||
}
|
|
@ -1376,17 +1376,18 @@ BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
|||
HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
|
||||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
FORMATETC fmt;
|
||||
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
|
||||
FORMATETC fmt;
|
||||
FORMATETC fmt2;
|
||||
fAcceptFmt = FALSE;
|
||||
|
||||
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||
InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
|
||||
|
||||
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
|
||||
|
||||
if (!fAcceptFmt)
|
||||
{
|
||||
InitFormatEtc(fmt, RegisterClipboardFormatW(CFSTR_FILEDESCRIPTOR), TYMED_HGLOBAL);
|
||||
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
|
||||
}
|
||||
if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
|
||||
fAcceptFmt = TRUE;
|
||||
else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
|
||||
fAcceptFmt = TRUE;
|
||||
|
||||
QueryDrop(dwKeyState, pdwEffect);
|
||||
return S_OK;
|
||||
|
@ -1418,56 +1419,50 @@ HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
|||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
|
||||
|
||||
BOOL fIsOpAsync = FALSE;
|
||||
CComPtr<IAsyncOperation> pAsyncOperation;
|
||||
|
||||
_DoDropData *data = reinterpret_cast<_DoDropData*> (HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
|
||||
data->This = this;
|
||||
// Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
|
||||
data->This->AddRef();
|
||||
data->pDataObject = pDataObject;
|
||||
// Also keep the data object in case it gets freed elsewhere.
|
||||
data->pDataObject->AddRef();
|
||||
data->dwKeyState = dwKeyState;
|
||||
data->pt = pt;
|
||||
// Need to dereference as pdweffect is freed.
|
||||
data->pdwEffect = *pdwEffect;
|
||||
|
||||
SHCreateThread(reinterpret_cast<LPTHREAD_START_ROUTINE> (CFSFolder::_DoDropThreadProc), reinterpret_cast<void *> (data), NULL, NULL);
|
||||
return S_OK;
|
||||
if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
|
||||
{
|
||||
if (SUCCEEDED(pAsyncOperation->GetAsyncMode(&fIsOpAsync)) && fIsOpAsync)
|
||||
{
|
||||
_DoDropData *data = reinterpret_cast<_DoDropData*> (HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
|
||||
data->This = this;
|
||||
// Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
|
||||
this->AddRef();
|
||||
data->pDataObject = pDataObject;
|
||||
data->pAsyncOperation = pAsyncOperation;
|
||||
data->dwKeyState = dwKeyState;
|
||||
data->pt = pt;
|
||||
// Need to dereference as pdweffect gets freed.
|
||||
data->pdwEffect = *pdwEffect;
|
||||
data->pDataObject->AddRef();
|
||||
data->pAsyncOperation->StartOperation(NULL);
|
||||
SHCreateThread(reinterpret_cast<LPTHREAD_START_ROUTINE> (CFSFolder::_DoDropThreadProc), reinterpret_cast<void *> (data), NULL, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
pAsyncOperation->Release();
|
||||
}
|
||||
return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
|
||||
}
|
||||
|
||||
HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
|
||||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
|
||||
FORMATETC fmt;
|
||||
FORMATETC fmt2;
|
||||
STGMEDIUM medium;
|
||||
|
||||
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||
InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
|
||||
|
||||
HRESULT hr;
|
||||
bool bCopy = TRUE;
|
||||
bool bLinking = FALSE;
|
||||
|
||||
STGMEDIUM medium;
|
||||
FORMATETC formatetc;
|
||||
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
||||
hr = pDataObject->GetData(&formatetc, &medium);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
/* lock the handle */
|
||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||
if (!lpcida)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* convert the data into pidl */
|
||||
LPITEMIDLIST pidl;
|
||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||
if (!apidl)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Figure out what drop operation we're doing */
|
||||
if (pdwEffect)
|
||||
{
|
||||
|
@ -1478,183 +1473,276 @@ HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
|
|||
bLinking = TRUE;
|
||||
}
|
||||
|
||||
CComPtr<IShellFolder> psfDesktop;
|
||||
CComPtr<IShellFolder> psfFrom = NULL;
|
||||
CComPtr<IShellFolder> psfTarget = NULL;
|
||||
if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
|
||||
{
|
||||
hr = pDataObject->GetData(&fmt, &medium);
|
||||
TRACE("CFSTR_SHELLIDLIST.\n");
|
||||
|
||||
hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("psfTarget setting failed\n");
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
/* lock the handle */
|
||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||
if (!lpcida)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Grab the desktop shell folder */
|
||||
hr = SHGetDesktopFolder(&psfDesktop);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("SHGetDesktopFolder failed\n");
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
/* convert the data into pidl */
|
||||
LPITEMIDLIST pidl;
|
||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||
if (!apidl)
|
||||
{
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Find source folder, this is where the clipboard data was copied from */
|
||||
if (_ILIsDesktop(pidl))
|
||||
{
|
||||
/* use desktop shell folder */
|
||||
psfFrom = psfDesktop;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom);
|
||||
CComPtr<IShellFolder> psfDesktop;
|
||||
CComPtr<IShellFolder> psfFrom = NULL;
|
||||
CComPtr<IShellFolder> psfTarget = NULL;
|
||||
|
||||
hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("no IShellFolder\n");
|
||||
ERR("psfTarget setting failed\n");
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (bLinking)
|
||||
{
|
||||
CComPtr<IPersistFolder2> ppf2 = NULL;
|
||||
STRRET strFile;
|
||||
WCHAR wszTargetPath[MAX_PATH];
|
||||
LPITEMIDLIST targetpidl;
|
||||
WCHAR wszPath[MAX_PATH];
|
||||
WCHAR wszTarget[MAX_PATH];
|
||||
|
||||
hr = this->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
||||
if (SUCCEEDED(hr))
|
||||
/* Grab the desktop shell folder */
|
||||
hr = SHGetDesktopFolder(&psfDesktop);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = ppf2->GetCurFolder(&targetpidl);
|
||||
ERR("SHGetDesktopFolder failed\n");
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Find source folder, this is where the clipboard data was copied from */
|
||||
if (_ILIsDesktop(pidl))
|
||||
{
|
||||
/* use desktop shell folder */
|
||||
psfFrom = psfDesktop;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("no IShellFolder\n");
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (bLinking)
|
||||
{
|
||||
CComPtr<IPersistFolder2> ppf2 = NULL;
|
||||
STRRET strFile;
|
||||
WCHAR wszTargetPath[MAX_PATH];
|
||||
LPITEMIDLIST targetpidl;
|
||||
WCHAR wszPath[MAX_PATH];
|
||||
WCHAR wszTarget[MAX_PATH];
|
||||
|
||||
hr = this->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
|
||||
ILFree(targetpidl);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = ppf2->GetCurFolder(&targetpidl);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
|
||||
hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
|
||||
ILFree(targetpidl);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("Error obtaining target path");
|
||||
}
|
||||
|
||||
TRACE("target path = %s", debugstr_w(wszTargetPath));
|
||||
|
||||
/* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
|
||||
for (UINT i = 0; i < lpcida->cidl; i++)
|
||||
{
|
||||
//Find out which file we're copying
|
||||
STRRET strFile;
|
||||
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("Error source obtaining path");
|
||||
break;
|
||||
}
|
||||
|
||||
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("Error putting source path into buffer");
|
||||
break;
|
||||
}
|
||||
TRACE("source path = %s", debugstr_w(wszPath));
|
||||
|
||||
// Creating a buffer to hold the combined path
|
||||
WCHAR buffer_1[MAX_PATH] = L"";
|
||||
WCHAR *lpStr1;
|
||||
lpStr1 = buffer_1;
|
||||
|
||||
LPWSTR pwszFileName = PathFindFileNameW(wszPath);
|
||||
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
||||
LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, pwszFileName);
|
||||
CComPtr<IPersistFile> ppf;
|
||||
|
||||
//Check to see if it's already a link.
|
||||
if (!wcsicmp(pwszExt, L".lnk"))
|
||||
{
|
||||
//It's a link so, we create a new one which copies the old.
|
||||
if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE))
|
||||
{
|
||||
ERR("Error getting unique file name");
|
||||
hr = E_FAIL;
|
||||
break;
|
||||
}
|
||||
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Error constructing link from file");
|
||||
break;
|
||||
}
|
||||
|
||||
hr = ppf->Save(wszTarget, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//It's not a link, so build a new link using the creator class and fill it in.
|
||||
//Create a file name for the link
|
||||
if (!GetUniqueFileName(placementPath, L".lnk", wszTarget, TRUE))
|
||||
{
|
||||
ERR("Error creating unique file name");
|
||||
hr = E_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
CComPtr<IShellLinkW> pLink;
|
||||
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
||||
if (FAILED(hr)) {
|
||||
ERR("Error instantiating IShellLinkW");
|
||||
break;
|
||||
}
|
||||
|
||||
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
||||
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
||||
if (pwszFile) pwszFile[0] = 0;
|
||||
|
||||
hr = pLink->SetPath(wszPath);
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->SetWorkingDirectory(szDirPath);
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = ppf->Save(wszTarget, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
else
|
||||
{
|
||||
ERR("Error obtaining target path");
|
||||
|
||||
hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
|
||||
}
|
||||
TRACE("target path = %s", debugstr_w(wszTargetPath));
|
||||
|
||||
/* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
|
||||
for (UINT i = 0; i < lpcida->cidl; i++)
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
}
|
||||
else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
|
||||
{
|
||||
FORMATETC fmt2;
|
||||
InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
|
||||
if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
|
||||
{
|
||||
//Find out which file we're copying
|
||||
CComPtr<IPersistFolder2> ppf2 = NULL;
|
||||
STRRET strFile;
|
||||
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
|
||||
WCHAR wszTargetPath[MAX_PATH + 1];
|
||||
LPWSTR pszSrcList;
|
||||
LPITEMIDLIST targetpidl;
|
||||
CComPtr<IShellFolder> psfDesktop = NULL;
|
||||
hr = SHGetDesktopFolder(&psfDesktop);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("SHGetDesktopFolder failed\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hr = this->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = ppf2->GetCurFolder(&targetpidl);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
|
||||
ILFree(targetpidl);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
|
||||
//Double NULL terminate.
|
||||
wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("Error source obtaining path");
|
||||
break;
|
||||
ERR("Error obtaining target path");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
|
||||
if (FAILED(hr))
|
||||
LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
|
||||
if (!lpdf)
|
||||
{
|
||||
ERR("Error putting source path into buffer");
|
||||
break;
|
||||
ERR("Error locking global\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
TRACE("source path = %s", debugstr_w(wszPath));
|
||||
pszSrcList = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);
|
||||
TRACE("Source file (just the first) = %s\n", debugstr_w(pszSrcList));
|
||||
TRACE("Target path = %s\n", debugstr_w(wszTargetPath));
|
||||
|
||||
// Creating a buffer to hold the combined path
|
||||
WCHAR buffer_1[MAX_PATH] = L"";
|
||||
WCHAR *lpStr1;
|
||||
lpStr1 = buffer_1;
|
||||
|
||||
LPWSTR pwszFileName = PathFindFileNameW(wszPath);
|
||||
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
||||
LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, pwszFileName);
|
||||
CComPtr<IPersistFile> ppf;
|
||||
|
||||
//Check to see if it's already a link.
|
||||
if (!wcsicmp(pwszExt, L".lnk"))
|
||||
{
|
||||
//It's a link so, we create a new one which copies the old.
|
||||
if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE))
|
||||
{
|
||||
ERR("Error getting unique file name");
|
||||
hr = E_FAIL;
|
||||
break;
|
||||
}
|
||||
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Error constructing link from file");
|
||||
break;
|
||||
}
|
||||
|
||||
hr = ppf->Save(wszTarget, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//It's not a link, so build a new link using the creator class and fill it in.
|
||||
//Create a file name for the link
|
||||
if (!GetUniqueFileName(placementPath, L".lnk", wszTarget, TRUE))
|
||||
{
|
||||
ERR("Error creating unique file name");
|
||||
hr = E_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
CComPtr<IShellLinkW> pLink;
|
||||
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
||||
if (FAILED(hr)) {
|
||||
ERR("Error instantiating IShellLinkW");
|
||||
break;
|
||||
}
|
||||
|
||||
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
||||
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
||||
if (pwszFile) pwszFile[0] = 0;
|
||||
|
||||
hr = pLink->SetPath(wszPath);
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->SetWorkingDirectory(szDirPath);
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
||||
if(FAILED(hr))
|
||||
break;
|
||||
|
||||
hr = ppf->Save(wszTarget, TRUE);
|
||||
}
|
||||
SHFILEOPSTRUCTW op;
|
||||
ZeroMemory(&op, sizeof(op));
|
||||
op.pFrom = pszSrcList;
|
||||
op.pTo = wszTargetPath;
|
||||
op.hwnd = GetActiveWindow();
|
||||
op.wFunc = bCopy ? FO_COPY : FO_MOVE;
|
||||
op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
|
||||
hr = SHFileOperationW(&op);
|
||||
return hr;
|
||||
}
|
||||
ERR("Error calling GetData\n");
|
||||
hr = E_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
|
||||
}
|
||||
|
||||
SHFree(pidl);
|
||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||
ReleaseStgMedium(&medium);
|
||||
|
||||
ERR("No viable drop format.\n");
|
||||
hr = E_FAIL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
DWORD CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
|
||||
_DoDropData *data = reinterpret_cast<_DoDropData*>(lpParameter);
|
||||
data->This->_DoDrop(data->pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
|
||||
HRESULT hr = data->This->_DoDrop(data->pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
|
||||
//Release the CFSFolder and data object holds in the copying thread.
|
||||
data->pAsyncOperation->EndOperation(hr, NULL, data->pdwEffect);
|
||||
data->pAsyncOperation->Release();
|
||||
data->pDataObject->Release();
|
||||
data->This->Release();
|
||||
//Release the parameter from the heap.
|
||||
|
|
|
@ -120,6 +120,7 @@ class CFSFolder :
|
|||
struct _DoDropData {
|
||||
CFSFolder *This;
|
||||
IDataObject *pDataObject;
|
||||
IAsyncOperation *pAsyncOperation;
|
||||
DWORD dwKeyState;
|
||||
POINTL pt;
|
||||
DWORD pdwEffect;
|
||||
|
|
|
@ -1686,10 +1686,16 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
|
|||
dwEffect |= DROPEFFECT_LINK;
|
||||
}
|
||||
}
|
||||
|
||||
CComPtr<IAsyncOperation> piaso;
|
||||
if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
|
||||
{
|
||||
piaso->SetAsyncMode(TRUE);
|
||||
piaso->Release();
|
||||
}
|
||||
|
||||
if (pds)
|
||||
{
|
||||
DWORD dwEffect2;
|
||||
{ DWORD dwEffect2;
|
||||
DoDragDrop(pda, pds, dwEffect, &dwEffect2);
|
||||
}
|
||||
pda->Release();
|
||||
|
|
Loading…
Reference in a new issue