2424
2525WINE_DEFAULT_DEBUG_CHANNEL (shell);
2626
27+ #define D_NONE DROPEFFECT_NONE
28+ #define D_COPY DROPEFFECT_COPY
29+ #define D_MOVE DROPEFFECT_MOVE
30+ #define D_LINK DROPEFFECT_LINK
31+
2732static void SHELL_StripIllegalFsNameCharacters (_Inout_ LPWSTR Buf)
2833{
2934 for (LPWSTR src = Buf, dst = src;;)
@@ -38,6 +43,17 @@ static void SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)
3843 }
3944}
4045
46+ static bool PathIsSameDrive (LPCWSTR Path1, LPCWSTR Path2)
47+ {
48+ int d1 = PathGetDriveNumberW (Path1), d2 = PathGetDriveNumberW (Path2);
49+ return d1 == d2 && d2 >= 0 ;
50+ }
51+
52+ static bool PathIsDriveRoot (LPCWSTR Path)
53+ {
54+ return PathIsRootW (Path) && PathGetDriveNumberW (Path) >= 0 ;
55+ }
56+
4157static HRESULT
4258SHELL_LimitDropEffectToItemAttributes (_In_ IDataObject *pDataObject, _Inout_ PDWORD pdwEffect)
4359{
@@ -134,7 +150,8 @@ CFSDropTarget::CFSDropTarget():
134150 m_fAcceptFmt(FALSE ),
135151 m_sPathTarget(NULL ),
136152 m_hwndSite(NULL ),
137- m_grfKeyState(0 )
153+ m_grfKeyState(0 ),
154+ m_AllowedEffects(0 )
138155{
139156}
140157
@@ -147,13 +164,7 @@ HRESULT CFSDropTarget::Initialize(LPWSTR PathTarget)
147164 if (!m_cfShellIDList)
148165 return E_FAIL;
149166
150- m_sPathTarget = (WCHAR *)SHAlloc ((wcslen (PathTarget) + 1 ) * sizeof (WCHAR));
151- if (!m_sPathTarget)
152- return E_OUTOFMEMORY;
153-
154- wcscpy (m_sPathTarget, PathTarget);
155-
156- return S_OK;
167+ return SHStrDupW (PathTarget, &m_sPathTarget);
157168}
158169
159170CFSDropTarget::~CFSDropTarget ()
@@ -202,7 +213,13 @@ BOOL CFSDropTarget::_QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
202213 *pdwEffect = DROPEFFECT_NONE;
203214
204215 if (m_fAcceptFmt) { /* Does our interpretation of the keystate ... */
205- *pdwEffect = KeyStateToDropEffect (dwKeyState);
216+ *pdwEffect = KeyStateToDropEffect (dwKeyState);
217+
218+ // Transform disallowed move to a copy
219+ if ((*pdwEffect & D_MOVE) && (m_AllowedEffects & (D_MOVE | D_COPY)) == D_COPY)
220+ *pdwEffect = D_COPY;
221+
222+ *pdwEffect &= m_AllowedEffects;
206223
207224 if (*pdwEffect == DROPEFFECT_NONE)
208225 *pdwEffect = dwEffect;
@@ -320,6 +337,9 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
320337{
321338 TRACE (" (%p)->(DataObject=%p)\n " , this , pDataObject);
322339
340+ const BOOL bAnyKeyMod = dwKeyState & (MK_SHIFT | MK_CONTROL);
341+ m_AllowedEffects = *pdwEffect;
342+
323343 if (*pdwEffect == DROPEFFECT_NONE)
324344 return S_OK;
325345
@@ -337,11 +357,9 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
337357
338358 m_grfKeyState = dwKeyState;
339359
340- #define D_NONE DROPEFFECT_NONE
341- #define D_COPY DROPEFFECT_COPY
342- #define D_MOVE DROPEFFECT_MOVE
343- #define D_LINK DROPEFFECT_LINK
344- m_dwDefaultEffect = *pdwEffect;
360+ SHELL_LimitDropEffectToItemAttributes (pDataObject, pdwEffect);
361+ m_AllowedEffects = *pdwEffect;
362+ m_dwDefaultEffect = m_AllowedEffects;
345363 switch (*pdwEffect & (D_COPY | D_MOVE | D_LINK))
346364 {
347365 case D_COPY | D_MOVE:
@@ -378,19 +396,24 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
378396 WCHAR wstrFirstFile[MAX_PATH];
379397 if (DragQueryFileW ((HDROP)medium.hGlobal , 0 , wstrFirstFile, _countof (wstrFirstFile)))
380398 {
381- /* Check if the drive letter is different */
382- if (wstrFirstFile[0 ] != m_sPathTarget[0 ])
399+ if (!PathIsSameDrive (wstrFirstFile, m_sPathTarget) && m_dwDefaultEffect != D_LINK)
383400 {
384401 m_dwDefaultEffect = DROPEFFECT_COPY;
385402 }
403+
404+ if (!bAnyKeyMod && PathIsDriveRoot (wstrFirstFile) && (m_AllowedEffects & DROPEFFECT_LINK))
405+ {
406+ m_dwDefaultEffect = DROPEFFECT_LINK; // Don't copy a drive by default
407+ }
386408 }
387409 ReleaseStgMedium (&medium);
388410 }
389411
390412 if (!m_fAcceptFmt)
391- *pdwEffect = DROPEFFECT_NONE;
413+ m_AllowedEffects = DROPEFFECT_NONE;
392414 else
393415 *pdwEffect = m_dwDefaultEffect;
416+ *pdwEffect &= m_AllowedEffects;
394417
395418 return S_OK;
396419}
@@ -471,7 +494,7 @@ HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
471494 data->pt = pt;
472495 // Need to dereference as pdweffect gets freed.
473496 data->pdwEffect = *pdwEffect;
474- SHCreateThread (CFSDropTarget::_DoDropThreadProc, data, NULL , NULL );
497+ SHCreateThread (CFSDropTarget::_DoDropThreadProc, data, CTF_COINIT | CTF_PROCESS_REF , NULL );
475498 return S_OK;
476499 }
477500 }
@@ -726,7 +749,6 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
726749
727750DWORD WINAPI CFSDropTarget::_DoDropThreadProc (LPVOID lpParameter)
728751{
729- CoInitialize (NULL );
730752 _DoDropData *data = static_cast <_DoDropData*>(lpParameter);
731753 CComPtr<IDataObject> pDataObject;
732754 HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream , IID_PPV_ARG (IDataObject, &pDataObject));
@@ -744,7 +766,6 @@ DWORD WINAPI CFSDropTarget::_DoDropThreadProc(LPVOID lpParameter)
744766 data->This ->Release ();
745767 // Release the parameter from the heap.
746768 HeapFree (GetProcessHeap (), 0 , data);
747- CoUninitialize ();
748769 return 0 ;
749770}
750771
0 commit comments