Skip to content

Commit aebaa14

Browse files
authored
[SHELL32] Allow DnD to create shortcuts across different drives (reactos#7607)
CORE-17871 CORE-18271
1 parent 17eff53 commit aebaa14

File tree

4 files changed

+49
-27
lines changed

4 files changed

+49
-27
lines changed

dll/win32/shell32/droptargets/CFSDropTarget.cpp

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424

2525
WINE_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+
2732
static 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+
4157
static HRESULT
4258
SHELL_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

159170
CFSDropTarget::~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

727750
DWORD 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

dll/win32/shell32/droptargets/CFSDropTarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CFSDropTarget :
3535
HWND m_hwndSite;
3636
DWORD m_grfKeyState;
3737
DWORD m_dwDefaultEffect;
38+
DWORD m_AllowedEffects;
3839
CComPtr<IUnknown> m_site;
3940

4041
BOOL _QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);

dll/win32/shell32/folders/CDrivesFolder.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ static const DWORD dwControlPanelAttributes =
557557
SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
558558
static const DWORD dwDriveAttributes =
559559
SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
560-
SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
560+
SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANCOPY;
561561

562562
CDrivesFolder::CDrivesFolder()
563563
{
@@ -611,10 +611,9 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
611611
pdwAttributes);
612612
}
613613

614-
if (lpszDisplayName[0] &&
615-
((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') ||
614+
if (((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') ||
616615
(L'a' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'z')) &&
617-
lpszDisplayName[1] == L':' && lpszDisplayName[2] == L'\\')
616+
lpszDisplayName[1] == L':' && (lpszDisplayName[2] == L'\\' || !lpszDisplayName[2]))
618617
{
619618
// "C:\..."
620619
WCHAR szRoot[8];
@@ -630,7 +629,7 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
630629
if (!pidlTemp)
631630
return E_OUTOFMEMORY;
632631

633-
if (lpszDisplayName[3])
632+
if (lpszDisplayName[2] && lpszDisplayName[3])
634633
{
635634
CComPtr<IShellFolder> pChildFolder;
636635
hr = BindToObject(pidlTemp, pbc, IID_PPV_ARG(IShellFolder, &pChildFolder));

dll/win32/shell32/shldataobject.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ HRESULT WINAPI SHGetAttributesFromDataObject(IDataObject* pDataObject, DWORD dwA
7777
data.dwAttributes = rgfInOut & dwQueryAttributes;
7878
data.cItems = apidl.GetSize();
7979

80-
hr = DataObject_SetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data));
81-
FAILED_UNEXPECTEDLY(hr);
80+
HRESULT hr2;
81+
hr2 = DataObject_SetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data));
82+
FAILED_UNEXPECTEDLY(hr2); // Report cache failure but don't fail the function
8283
}
8384
}
8485
}

0 commit comments

Comments
 (0)