[SHELL32]
authorAmine Khaldi <amine.khaldi@reactos.org>
Thu, 9 Jan 2014 13:24:39 +0000 (13:24 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Thu, 9 Jan 2014 13:24:39 +0000 (13:24 +0000)
* 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

reactos/dll/win32/shell32/dataobject.cpp
reactos/dll/win32/shell32/folders/desktop.cpp
reactos/dll/win32/shell32/folders/fs.cpp
reactos/dll/win32/shell32/folders/fs.h
reactos/dll/win32/shell32/shlview.cpp

index 0bffd87..88f10fb 100644 (file)
@@ -163,7 +163,8 @@ HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMA
 
 class IDataObjectImpl :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
 
 class IDataObjectImpl :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IDataObject
+    public IDataObject,
+    public IAsyncOperation 
 {
 private:
     LPITEMIDLIST    pidl;
 {
 private:
     LPITEMIDLIST    pidl;
@@ -176,6 +177,7 @@ private:
     UINT        cfFileNameA;
     UINT        cfFileNameW;
     UINT        cfPreferredDropEffect;
     UINT        cfFileNameA;
     UINT        cfFileNameW;
     UINT        cfPreferredDropEffect;
+    BOOL        doasync;
 public:
     IDataObjectImpl();
     ~IDataObjectImpl();
 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 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)
 
 BEGIN_COM_MAP(IDataObjectImpl)
     COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
+    COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation,  IAsyncOperation)
 END_COM_MAP()
 };
 
 END_COM_MAP()
 };
 
@@ -207,6 +215,7 @@ IDataObjectImpl::IDataObjectImpl()
     cfFileNameA = 0;
     cfFileNameW = 0;
     cfPreferredDropEffect = 0;
     cfFileNameA = 0;
     cfFileNameW = 0;
     cfPreferredDropEffect = 0;
+    doasync = FALSE;
 }
 
 IDataObjectImpl::~IDataObjectImpl()
 }
 
 IDataObjectImpl::~IDataObjectImpl()
@@ -371,6 +380,37 @@ HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
     return E_NOTIMPL;
 }
 
     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
 */
 /**************************************************************************
 *  IDataObject_Constructor
 */
index 474bdd6..968bc35 100644 (file)
@@ -1377,11 +1377,18 @@ BOOL CDesktopFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
 HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
                                     DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
 {
 HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
                                     DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
 {
+    TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
     FORMATETC fmt;
     FORMATETC fmt;
+    FORMATETC fmt2;
+    fAcceptFmt = FALSE;
 
     InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
 
     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;
 
     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;
     TRACE("(%p) object dropped desktop\n", this);
 
     STGMEDIUM medium;
+    bool passthroughtofs = FALSE;
     FORMATETC formatetc;
     InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
     FORMATETC formatetc;
     InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
+    
     HRESULT hr = pDataObject->GetData(&formatetc, &medium);
     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))
     {
     {
+        /* 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)
+        {
+            ReleaseStgMedium(&medium);
+            return E_FAIL;
+        }
+        passthroughtofs = !_ILIsDesktop(pidl) || (dwKeyState & MK_CONTROL);
+        SHFree(pidl);
+        _ILFreeaPidl(apidl, lpcida->cidl);
         ReleaseStgMedium(&medium);
         ReleaseStgMedium(&medium);
-        return E_FAIL;
     }
     }
-
-    /* convert the clipboard data into pidl (pointer to id list) */
-    LPITEMIDLIST pidl;
-    LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
-    if (!apidl)
+    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 */
     /* 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;
 
     {
         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. */
 
     /* 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;
 }
\ No newline at end of file
     return hr;
 }
\ No newline at end of file
index 52ffbeb..da4b767 100644 (file)
@@ -1376,17 +1376,18 @@ BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
 HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
                                     DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
 {
 HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
                                     DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
 {
-    FORMATETC fmt;
     TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
     TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
-    InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+    FORMATETC fmt;
+    FORMATETC fmt2;
+    fAcceptFmt = FALSE;
 
 
-    fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
+    InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+    InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
 
 
-    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;
 
     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);
                                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);
 }
 
 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;
 
 
     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)
     {
     /* Figure out what drop operation we're doing */
     if (pdwEffect)
     {
@@ -1478,183 +1473,276 @@ HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
             bLinking = TRUE;
     }
 
             bLinking = TRUE;
     }
 
-    CComPtr<IShellFolder> psfDesktop;
-    CComPtr<IShellFolder> psfFrom = NULL;
-    CComPtr<IShellFolder> psfTarget = NULL;
-
-    hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
-    if (FAILED(hr))
+    if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
     {
     {
-        ERR("psfTarget setting failed\n");
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
-        return E_FAIL;
-    }
+        hr = pDataObject->GetData(&fmt, &medium);
+        TRACE("CFSTR_SHELLIDLIST.\n");
 
 
-    /* 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;
-    }
+        /* lock the handle */
+        LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
+        if (!lpcida)
+        {
+            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);
+        /* convert the data into pidl */
+        LPITEMIDLIST pidl;
+        LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
+        if (!apidl)
+        {
+            ReleaseStgMedium(&medium);
+            return E_FAIL;
+        }
+
+        CComPtr<IShellFolder> psfDesktop;
+        CComPtr<IShellFolder> psfFrom = NULL;
+        CComPtr<IShellFolder> psfTarget = NULL;
+
+        hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
         if (FAILED(hr))
         {
         if (FAILED(hr))
         {
-            ERR("no IShellFolder\n");
+            ERR("psfTarget setting failed\n");
             SHFree(pidl);
             _ILFreeaPidl(apidl, lpcida->cidl);
             ReleaseStgMedium(&medium);
             return E_FAIL;
         }
             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);
-            if (SUCCEEDED(hr))
-            {
-                hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
-                ILFree(targetpidl);
-                if (SUCCEEDED(hr)) 
-                {
-                    hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
-                }
-            }
+            ERR("SHGetDesktopFolder failed\n");
+            SHFree(pidl);
+            _ILFreeaPidl(apidl, lpcida->cidl);
+            ReleaseStgMedium(&medium);
+            return E_FAIL;
         }
 
         }
 
-        if (FAILED(hr)) 
+        /* Find source folder, this is where the clipboard data was copied from */
+        if (_ILIsDesktop(pidl))
+        {
+            /* use desktop shell folder */
+            psfFrom = psfDesktop;
+        }
+        else 
         {
         {
-            ERR("Error obtaining target path");
-            
+            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;
+            }
         }
         }
-        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++)
+        if (bLinking)
         {
         {
-            //Find out which file we're copying
+            CComPtr<IPersistFolder2> ppf2 = NULL;
             STRRET strFile;
             STRRET strFile;
-            hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
-            if (FAILED(hr)) 
+            WCHAR wszTargetPath[MAX_PATH];
+            LPITEMIDLIST targetpidl;
+            WCHAR wszPath[MAX_PATH];
+            WCHAR wszTarget[MAX_PATH];
+
+            hr = this->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
+            if (SUCCEEDED(hr))
             {
             {
-                ERR("Error source obtaining path");
-                break;
+                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));
+                    }
+                }
             }
 
             }
 
-            hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
             if (FAILED(hr)) 
             {
             if (FAILED(hr)) 
             {
-                ERR("Error putting source path into buffer");
-                break;
+                ERR("Error obtaining target path");
             }
             }
-            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;
+            TRACE("target path = %s", debugstr_w(wszTargetPath));
 
 
-            //Check to see if it's already a link. 
-            if (!wcsicmp(pwszExt, L".lnk"))
+            /* 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++)
             {
             {
-                //It's a link so, we create a new one which copies the old.
-                if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE)) 
+                //Find out which file we're copying
+                STRRET strFile;
+                hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
+                if (FAILED(hr)) 
                 {
                 {
-                    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");
+                    ERR("Error source obtaining path");
                     break;
                 }
 
                     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))
+                hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
+                if (FAILED(hr)) 
                 {
                 {
-                    ERR("Error creating unique file name");
-                    hr = E_FAIL;
+                    ERR("Error putting source path into buffer");
                     break;
                 }
                     break;
                 }
+                TRACE("source path = %s", debugstr_w(wszPath));
 
 
-                CComPtr<IShellLinkW> pLink;
-                hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
-                if (FAILED(hr)) {
-                    ERR("Error instantiating IShellLinkW");
-                    break;
-                }
+                // Creating a buffer to hold the combined path
+                WCHAR buffer_1[MAX_PATH] = L"";
+                WCHAR *lpStr1;
+                lpStr1 = buffer_1;
 
 
-                WCHAR szDirPath[MAX_PATH], *pwszFile;
-                GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
-                if (pwszFile) pwszFile[0] = 0;
+                LPWSTR pwszFileName = PathFindFileNameW(wszPath);
+                LPWSTR pwszExt = PathFindExtensionW(wszPath);
+                LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, pwszFileName);
+                CComPtr<IPersistFile> ppf;
 
 
-                hr = pLink->SetPath(wszPath);
-                if(FAILED(hr))
-                    break;
+                //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);
+                }
+            }
+        }
+        else 
+        {
+            hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
+        }
 
 
-                hr = pLink->SetWorkingDirectory(szDirPath);
-                if(FAILED(hr))
-                    break;
+        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))*/)
+        {
+            CComPtr<IPersistFolder2> ppf2 = NULL;
+            STRRET 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 = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
-                if(FAILED(hr))
-                    break;
+            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 obtaining target path");
+                return E_FAIL;
+            }
 
 
-                hr = ppf->Save(wszTarget, TRUE);
+            LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
+            if (!lpdf)
+            {
+                ERR("Error locking global\n");
+                return E_FAIL;
             }
             }
+            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));
+
+            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 
     {
     }
     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);
     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.
     //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.
     data->pDataObject->Release();
     data->This->Release();
     //Release the parameter from the heap.
index a613a1f..8b687c3 100644 (file)
@@ -120,6 +120,7 @@ class CFSFolder :
 struct _DoDropData {
     CFSFolder *This;
     IDataObject *pDataObject;
 struct _DoDropData {
     CFSFolder *This;
     IDataObject *pDataObject;
+    IAsyncOperation *pAsyncOperation;
     DWORD dwKeyState;
     POINTL pt; 
     DWORD pdwEffect;
     DWORD dwKeyState;
     POINTL pt; 
     DWORD pdwEffect;
index 0c2a0c4..5d8f4b2 100644 (file)
@@ -1686,10 +1686,16 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
                             dwEffect |= DROPEFFECT_LINK;
                         }
                     }
                             dwEffect |= DROPEFFECT_LINK;
                         }
                     }
+                    
+                    CComPtr<IAsyncOperation> piaso;
+                    if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
+                    {
+                        piaso->SetAsyncMode(TRUE);
+                        piaso->Release();
+                    }
 
                     if (pds)
 
                     if (pds)
-                    {
-                        DWORD dwEffect2;
+                    {                        DWORD dwEffect2;
                         DoDragDrop(pda, pds, dwEffect, &dwEffect2);
                     }
                     pda->Release();
                         DoDragDrop(pda, pds, dwEffect, &dwEffect2);
                     }
                     pda->Release();