reactos/dll/shellext/sendmail/CDeskLinkDropHandler.cpp
Thamatip Chitpong 7c2b22c4de
[SENDMAIL] Fix Send To -> Desktop (create shortcut) behavior (#4913)
Several fixes and improvements to the CDeskLinkDropHandler:
- Set default working directory for shortcuts (except folders and zip files)
- Copy existing shortcut to the desktop if the source file is a shortcut
- Prevent destination file name collision

Verified on Windows XP SP3 and Windows 7 SP1.
2022-12-03 20:06:45 +03:00

206 lines
5.1 KiB
C++

/*
* PROJECT: sendmail
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
* PURPOSE: DeskLink implementation
* COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "precomp.hpp"
WINE_DEFAULT_DEBUG_CHANNEL(sendmail);
CDeskLinkDropHandler::CDeskLinkDropHandler()
{
InterlockedIncrement(&g_ModuleRefCnt);
}
CDeskLinkDropHandler::~CDeskLinkDropHandler()
{
InterlockedDecrement(&g_ModuleRefCnt);
}
// IDropTarget
STDMETHODIMP
CDeskLinkDropHandler::DragEnter(IDataObject *pDataObject, DWORD dwKeyState,
POINTL pt, DWORD *pdwEffect)
{
TRACE("(%p)\n", this);
*pdwEffect &= DROPEFFECT_LINK;
return S_OK;
}
STDMETHODIMP
CDeskLinkDropHandler::DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
{
TRACE("(%p)\n", this);
*pdwEffect &= DROPEFFECT_LINK;
return S_OK;
}
STDMETHODIMP CDeskLinkDropHandler::DragLeave()
{
TRACE("(%p)\n", this);
return S_OK;
}
STDMETHODIMP
CDeskLinkDropHandler::Drop(IDataObject *pDataObject, DWORD dwKeyState,
POINTL pt, DWORD *pdwEffect)
{
TRACE("(%p)\n", this);
if (!pDataObject)
{
ERR("pDataObject is NULL\n");
return E_POINTER;
}
WCHAR szDir[MAX_PATH], szDest[MAX_PATH], szSrc[MAX_PATH];
SHGetSpecialFolderPathW(NULL, szDir, CSIDL_DESKTOPDIRECTORY, FALSE);
CComPtr<IShellFolder> pDesktop;
HRESULT hr = SHGetDesktopFolder(&pDesktop);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CDataObjectHIDA pida(pDataObject);
if (FAILED_UNEXPECTEDLY(pida.hr()))
return pida.hr();
LPCITEMIDLIST pidlParent = HIDA_GetPIDLFolder(pida);
for (UINT i = 0; i < pida->cidl; ++i)
{
LPCITEMIDLIST pidlChild = HIDA_GetPIDLItem(pida, i);
CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlParent, pidlChild));
if (!pidl)
{
ERR("Out of memory\n");
break;
}
StringCbCopyW(szDest, sizeof(szDest), szDir);
if (SHGetPathFromIDListW(pidl, szSrc))
{
LPCWSTR pszSourceExt;
BOOL bIsLink;
pszSourceExt = PathFindExtensionW(szSrc);
bIsLink = ((_wcsicmp(pszSourceExt, L".lnk") == 0) ||
(_wcsicmp(pszSourceExt, L".url") == 0));
if (bIsLink)
{
PathAppendW(szDest, PathFindFileNameW(szSrc));
}
else
{
CStringW strTitle;
strTitle.Format(IDS_SHORTCUT, PathFindFileNameW(szSrc));
PathAppendW(szDest, strTitle);
PathRemoveExtensionW(szDest);
StringCbCatW(szDest, sizeof(szDest), L".lnk");
}
if (PathFileExistsW(szDest))
{
CStringW strName(PathFindFileNameW(szDest));
PathYetAnotherMakeUniqueName(szDest, szDir, NULL, strName);
}
if (bIsLink)
{
hr = (CopyFileW(szSrc, szDest, TRUE) ? S_OK : E_FAIL);
}
else if (PathIsDirectoryW(szSrc) || (_wcsicmp(pszSourceExt, L".zip") == 0))
{
hr = CreateShellLink(szDest, szSrc, NULL, NULL, NULL, NULL, -1, NULL);
}
else
{
/* Set default working directory for the shortcut */
CStringW strWorkingDir(szSrc);
PathRemoveFileSpecW(strWorkingDir.GetBuffer());
hr = CreateShellLink(szDest, szSrc, NULL, NULL, strWorkingDir, NULL, -1, NULL);
}
}
else
{
STRRET strret;
hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret);
if (FAILED_UNEXPECTEDLY(hr))
break;
hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc));
if (FAILED_UNEXPECTEDLY(hr))
break;
CStringW strTitle;
strTitle.Format(IDS_SHORTCUT, szSrc);
PathAppendW(szDest, strTitle);
PathRemoveExtensionW(szDest);
StringCbCatW(szDest, sizeof(szDest), L".lnk");
hr = CreateShellLink(szDest, NULL, pidl, NULL, NULL, NULL, -1, NULL);
}
if (FAILED_UNEXPECTEDLY(hr))
break;
}
return hr;
}
// IPersistFile
STDMETHODIMP CDeskLinkDropHandler::GetCurFile(LPOLESTR *ppszFileName)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
}
STDMETHODIMP CDeskLinkDropHandler::IsDirty()
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
}
STDMETHODIMP CDeskLinkDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode)
{
return S_OK;
}
STDMETHODIMP CDeskLinkDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
}
STDMETHODIMP CDeskLinkDropHandler::SaveCompleted(LPCOLESTR pszFileName)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
}
// IPersist
STDMETHODIMP CDeskLinkDropHandler::GetClassID(CLSID * lpClassId)
{
TRACE("(%p)\n", this);
if (!lpClassId)
{
ERR("lpClassId is NULL\n");
return E_POINTER;
}
*lpClassId = CLSID_DeskLinkDropHandler;
return S_OK;
}