https://git.reactos.org/?p=reactos.git;a=commitdiff;h=aebaa14eba88056e15f46adbb30767a3889f2d1d

commit aebaa14eba88056e15f46adbb30767a3889f2d1d
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Sun Jan 19 21:00:55 2025 +0100
Commit:     GitHub <nore...@github.com>
CommitDate: Sun Jan 19 21:00:55 2025 +0100

    [SHELL32] Allow DnD to create shortcuts across different drives (#7607)
    
    CORE-17871 CORE-18271
---
 dll/win32/shell32/droptargets/CFSDropTarget.cpp | 61 +++++++++++++++++--------
 dll/win32/shell32/droptargets/CFSDropTarget.h   |  1 +
 dll/win32/shell32/folders/CDrivesFolder.cpp     |  9 ++--
 dll/win32/shell32/shldataobject.cpp             |  5 +-
 4 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/dll/win32/shell32/droptargets/CFSDropTarget.cpp 
b/dll/win32/shell32/droptargets/CFSDropTarget.cpp
index fce1a88d5b8..e7b5927500e 100644
--- a/dll/win32/shell32/droptargets/CFSDropTarget.cpp
+++ b/dll/win32/shell32/droptargets/CFSDropTarget.cpp
@@ -24,6 +24,11 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL (shell);
 
+#define D_NONE DROPEFFECT_NONE
+#define D_COPY DROPEFFECT_COPY
+#define D_MOVE DROPEFFECT_MOVE
+#define D_LINK DROPEFFECT_LINK
+
 static void SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)
 {
     for (LPWSTR src = Buf, dst = src;;)
@@ -38,6 +43,17 @@ static void SHELL_StripIllegalFsNameCharacters(_Inout_ 
LPWSTR Buf)
     }
 }
 
+static bool PathIsSameDrive(LPCWSTR Path1, LPCWSTR Path2)
+{
+    int d1 = PathGetDriveNumberW(Path1), d2 = PathGetDriveNumberW(Path2);
+    return d1 == d2 && d2 >= 0;
+}
+
+static bool PathIsDriveRoot(LPCWSTR Path)
+{
+    return PathIsRootW(Path) && PathGetDriveNumberW(Path) >= 0;
+}
+
 static HRESULT
 SHELL_LimitDropEffectToItemAttributes(_In_ IDataObject *pDataObject, _Inout_ 
PDWORD pdwEffect)
 {
@@ -134,7 +150,8 @@ CFSDropTarget::CFSDropTarget():
     m_fAcceptFmt(FALSE),
     m_sPathTarget(NULL),
     m_hwndSite(NULL),
-    m_grfKeyState(0)
+    m_grfKeyState(0),
+    m_AllowedEffects(0)
 {
 }
 
@@ -147,13 +164,7 @@ HRESULT CFSDropTarget::Initialize(LPWSTR PathTarget)
     if (!m_cfShellIDList)
         return E_FAIL;
 
-    m_sPathTarget = (WCHAR *)SHAlloc((wcslen(PathTarget) + 1) * sizeof(WCHAR));
-    if (!m_sPathTarget)
-        return E_OUTOFMEMORY;
-
-    wcscpy(m_sPathTarget, PathTarget);
-
-    return S_OK;
+    return SHStrDupW(PathTarget, &m_sPathTarget);
 }
 
 CFSDropTarget::~CFSDropTarget()
@@ -202,7 +213,13 @@ BOOL CFSDropTarget::_QueryDrop(DWORD dwKeyState, LPDWORD 
pdwEffect)
     *pdwEffect = DROPEFFECT_NONE;
 
     if (m_fAcceptFmt) { /* Does our interpretation of the keystate ... */
-        *pdwEffect = KeyStateToDropEffect (dwKeyState);
+        *pdwEffect = KeyStateToDropEffect(dwKeyState);
+
+        // Transform disallowed move to a copy
+        if ((*pdwEffect & D_MOVE) && (m_AllowedEffects & (D_MOVE | D_COPY)) == 
D_COPY)
+            *pdwEffect = D_COPY;
+
+        *pdwEffect &= m_AllowedEffects;
 
         if (*pdwEffect == DROPEFFECT_NONE)
             *pdwEffect = dwEffect;
@@ -320,6 +337,9 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject 
*pDataObject,
 {
     TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
 
+    const BOOL bAnyKeyMod = dwKeyState & (MK_SHIFT | MK_CONTROL);
+    m_AllowedEffects = *pdwEffect;
+
     if (*pdwEffect == DROPEFFECT_NONE)
         return S_OK;
 
@@ -337,11 +357,9 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject 
*pDataObject,
 
     m_grfKeyState = dwKeyState;
 
-#define D_NONE DROPEFFECT_NONE
-#define D_COPY DROPEFFECT_COPY
-#define D_MOVE DROPEFFECT_MOVE
-#define D_LINK DROPEFFECT_LINK
-    m_dwDefaultEffect = *pdwEffect;
+    SHELL_LimitDropEffectToItemAttributes(pDataObject, pdwEffect);
+    m_AllowedEffects = *pdwEffect;
+    m_dwDefaultEffect = m_AllowedEffects;
     switch (*pdwEffect & (D_COPY | D_MOVE | D_LINK))
     {
         case D_COPY | D_MOVE:
@@ -378,19 +396,24 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject 
*pDataObject,
         WCHAR wstrFirstFile[MAX_PATH];
         if (DragQueryFileW((HDROP)medium.hGlobal, 0, wstrFirstFile, 
_countof(wstrFirstFile)))
         {
-            /* Check if the drive letter is different */
-            if (wstrFirstFile[0] != m_sPathTarget[0])
+            if (!PathIsSameDrive(wstrFirstFile, m_sPathTarget) && 
m_dwDefaultEffect != D_LINK)
             {
                 m_dwDefaultEffect = DROPEFFECT_COPY;
             }
+
+            if (!bAnyKeyMod && PathIsDriveRoot(wstrFirstFile) && 
(m_AllowedEffects & DROPEFFECT_LINK))
+            {
+                m_dwDefaultEffect = DROPEFFECT_LINK; // Don't copy a drive by 
default
+            }
         }
         ReleaseStgMedium(&medium);
     }
 
     if (!m_fAcceptFmt)
-        *pdwEffect = DROPEFFECT_NONE;
+        m_AllowedEffects = DROPEFFECT_NONE;
     else
         *pdwEffect = m_dwDefaultEffect;
+    *pdwEffect &= m_AllowedEffects;
 
     return S_OK;
 }
@@ -471,7 +494,7 @@ HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
             data->pt = pt;
             // Need to dereference as pdweffect gets freed.
             data->pdwEffect = *pdwEffect;
-            SHCreateThread(CFSDropTarget::_DoDropThreadProc, data, NULL, NULL);
+            SHCreateThread(CFSDropTarget::_DoDropThreadProc, data, CTF_COINIT 
| CTF_PROCESS_REF, NULL);
             return S_OK;
         }
     }
@@ -726,7 +749,6 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
 
 DWORD WINAPI CFSDropTarget::_DoDropThreadProc(LPVOID lpParameter)
 {
-    CoInitialize(NULL);
     _DoDropData *data = static_cast<_DoDropData*>(lpParameter);
     CComPtr<IDataObject> pDataObject;
     HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream, 
IID_PPV_ARG(IDataObject, &pDataObject));
@@ -744,7 +766,6 @@ DWORD WINAPI CFSDropTarget::_DoDropThreadProc(LPVOID 
lpParameter)
     data->This->Release();
     //Release the parameter from the heap.
     HeapFree(GetProcessHeap(), 0, data);
-    CoUninitialize();
     return 0;
 }
 
diff --git a/dll/win32/shell32/droptargets/CFSDropTarget.h 
b/dll/win32/shell32/droptargets/CFSDropTarget.h
index 706164d8f6d..bde59979c24 100644
--- a/dll/win32/shell32/droptargets/CFSDropTarget.h
+++ b/dll/win32/shell32/droptargets/CFSDropTarget.h
@@ -35,6 +35,7 @@ class CFSDropTarget :
         HWND m_hwndSite;
         DWORD m_grfKeyState;
         DWORD m_dwDefaultEffect;
+        DWORD m_AllowedEffects;
         CComPtr<IUnknown> m_site;
 
         BOOL _QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
diff --git a/dll/win32/shell32/folders/CDrivesFolder.cpp 
b/dll/win32/shell32/folders/CDrivesFolder.cpp
index 040511f03e9..df2f591b8bc 100644
--- a/dll/win32/shell32/folders/CDrivesFolder.cpp
+++ b/dll/win32/shell32/folders/CDrivesFolder.cpp
@@ -557,7 +557,7 @@ static const DWORD dwControlPanelAttributes =
     SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
 static const DWORD dwDriveAttributes =
     SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | 
SFGAO_FILESYSANCESTOR |
-    SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
+    SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK | 
SFGAO_CANCOPY;
 
 CDrivesFolder::CDrivesFolder()
 {
@@ -611,10 +611,9 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND 
hwndOwner, LPBC pbc, LPOLEST
                                              pdwAttributes);
     }
 
-    if (lpszDisplayName[0] &&
-        ((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') ||
+    if (((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') ||
          (L'a' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'z')) &&
-        lpszDisplayName[1] == L':' && lpszDisplayName[2] == L'\\')
+        lpszDisplayName[1] == L':' && (lpszDisplayName[2] == L'\\' || 
!lpszDisplayName[2]))
     {
         // "C:\..."
         WCHAR szRoot[8];
@@ -630,7 +629,7 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND 
hwndOwner, LPBC pbc, LPOLEST
         if (!pidlTemp)
             return E_OUTOFMEMORY;
 
-        if (lpszDisplayName[3])
+        if (lpszDisplayName[2] && lpszDisplayName[3])
         {
             CComPtr<IShellFolder> pChildFolder;
             hr = BindToObject(pidlTemp, pbc, IID_PPV_ARG(IShellFolder, 
&pChildFolder));
diff --git a/dll/win32/shell32/shldataobject.cpp 
b/dll/win32/shell32/shldataobject.cpp
index 728cca0dbf3..04126e930b9 100644
--- a/dll/win32/shell32/shldataobject.cpp
+++ b/dll/win32/shell32/shldataobject.cpp
@@ -77,8 +77,9 @@ HRESULT WINAPI SHGetAttributesFromDataObject(IDataObject* 
pDataObject, DWORD dwA
                     data.dwAttributes = rgfInOut & dwQueryAttributes;
                     data.cItems = apidl.GetSize();
 
-                    hr = DataObject_SetData(pDataObject, 
g_DataObjectAttributes, &data, sizeof(data));
-                    FAILED_UNEXPECTEDLY(hr);
+                    HRESULT hr2;
+                    hr2 = DataObject_SetData(pDataObject, 
g_DataObjectAttributes, &data, sizeof(data));
+                    FAILED_UNEXPECTEDLY(hr2); // Report cache failure but 
don't fail the function
                 }
             }
         }

Reply via email to