[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:
Amine Khaldi 2014-01-09 13:24:39 +00:00
parent 0532456b81
commit 4adc3e9bbd
5 changed files with 360 additions and 209 deletions

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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.

View file

@ -120,6 +120,7 @@ class CFSFolder :
struct _DoDropData {
CFSFolder *This;
IDataObject *pDataObject;
IAsyncOperation *pAsyncOperation;
DWORD dwKeyState;
POINTL pt;
DWORD pdwEffect;

View file

@ -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();