mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[SHELL32] Use correct PIDL and name when dropping to create a shortcut (#6999)
Ask for the editing name instead of the parsing name to get a suitable shortcut name for PIDL items.
This commit is contained in:
parent
089788a52a
commit
fa95a96e9b
3 changed files with 86 additions and 100 deletions
|
@ -900,7 +900,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::Save(IStream *stm, BOOL fClearDirty)
|
|||
|
||||
if (m_pPidl)
|
||||
m_Header.dwFlags |= SLDF_HAS_ID_LIST;
|
||||
if (m_sPath)
|
||||
if (m_sPath && *m_sPath && !(m_Header.dwFlags & SLDF_FORCE_NO_LINKINFO))
|
||||
m_Header.dwFlags |= SLDF_HAS_LINK_INFO;
|
||||
if (m_sDescription && *m_sDescription)
|
||||
m_Header.dwFlags |= SLDF_HAS_NAME;
|
||||
|
@ -936,7 +936,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::Save(IStream *stm, BOOL fClearDirty)
|
|||
}
|
||||
}
|
||||
|
||||
if (m_sPath)
|
||||
if (m_Header.dwFlags & SLDF_HAS_LINK_INFO)
|
||||
{
|
||||
hr = Stream_WriteLocationInfo(stm, m_sPath, &volume);
|
||||
if (FAILED(hr))
|
||||
|
|
|
@ -24,6 +24,35 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
||||
|
||||
static void SHELL_StripIllegalFsNameCharacters(_Inout_ LPWSTR Buf)
|
||||
{
|
||||
for (LPWSTR src = Buf, dst = src;;)
|
||||
{
|
||||
*dst = *src;
|
||||
if (!*dst)
|
||||
break;
|
||||
else if (wcschr(INVALID_FILETITLE_CHARACTERSW, *dst))
|
||||
src = CharNextW(src);
|
||||
else
|
||||
++src, ++dst;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
SHELL_LimitDropEffectToItemAttributes(_In_ IDataObject *pDataObject, _Inout_ PDWORD pdwEffect)
|
||||
{
|
||||
DWORD att = *pdwEffect & (SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK); // DROPEFFECT maps perfectly to these SFGAO bits
|
||||
HRESULT hr = SHGetAttributesFromDataObject(pDataObject, att, &att, NULL);
|
||||
if (FAILED(hr))
|
||||
return S_FALSE;
|
||||
*pdwEffect &= ~(SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK) | att;
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void GetDefaultCopyMoveEffect()
|
||||
{
|
||||
// FIXME: When the source is on a different volume than the target, change default from move to copy
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* CFSDropTarget::_CopyItems
|
||||
|
@ -166,6 +195,7 @@ BOOL CFSDropTarget::_QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
|||
{
|
||||
/* TODO Windows does different drop effects if dragging across drives.
|
||||
i.e., it will copy instead of move if the directories are on different disks. */
|
||||
GetDefaultCopyMoveEffect();
|
||||
|
||||
DWORD dwEffect = m_dwDefaultEffect;
|
||||
|
||||
|
@ -193,18 +223,20 @@ HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, D
|
|||
|
||||
HMENU hpopupmenu = GetSubMenu(hmenu, 0);
|
||||
|
||||
SHELL_LimitDropEffectToItemAttributes(pDataObject, &dwAvailableEffects);
|
||||
if ((dwAvailableEffects & DROPEFFECT_COPY) == 0)
|
||||
DeleteMenu(hpopupmenu, IDM_COPYHERE, MF_BYCOMMAND);
|
||||
else if ((dwAvailableEffects & DROPEFFECT_MOVE) == 0)
|
||||
if ((dwAvailableEffects & DROPEFFECT_MOVE) == 0)
|
||||
DeleteMenu(hpopupmenu, IDM_MOVEHERE, MF_BYCOMMAND);
|
||||
else if ((dwAvailableEffects & DROPEFFECT_LINK) == 0)
|
||||
if ((dwAvailableEffects & DROPEFFECT_LINK) == 0 && (dwAvailableEffects & (DROPEFFECT_COPY | DROPEFFECT_MOVE)))
|
||||
DeleteMenu(hpopupmenu, IDM_LINKHERE, MF_BYCOMMAND);
|
||||
|
||||
if ((*pdwEffect & DROPEFFECT_COPY))
|
||||
GetDefaultCopyMoveEffect();
|
||||
if (*pdwEffect & dwAvailableEffects & DROPEFFECT_COPY)
|
||||
SetMenuDefaultItem(hpopupmenu, IDM_COPYHERE, FALSE);
|
||||
else if ((*pdwEffect & DROPEFFECT_MOVE))
|
||||
else if (*pdwEffect & dwAvailableEffects & DROPEFFECT_MOVE)
|
||||
SetMenuDefaultItem(hpopupmenu, IDM_MOVEHERE, FALSE);
|
||||
else if ((*pdwEffect & DROPEFFECT_LINK))
|
||||
else if (dwAvailableEffects & DROPEFFECT_LINK)
|
||||
SetMenuDefaultItem(hpopupmenu, IDM_LINKHERE, FALSE);
|
||||
|
||||
/* FIXME: We need to support shell extensions here */
|
||||
|
@ -223,6 +255,7 @@ HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, D
|
|||
NULL,
|
||||
NULL);
|
||||
|
||||
SetForegroundWindow(hwndDummy); // Required for aborting by pressing Esc when dragging from Explorer to desktop
|
||||
UINT uCommand = TrackPopupMenu(hpopupmenu,
|
||||
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY,
|
||||
pt.x, pt.y, 0, hwndDummy, NULL);
|
||||
|
@ -548,125 +581,83 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
|
|||
|
||||
if (bLinking)
|
||||
{
|
||||
WCHAR wszPath[MAX_PATH];
|
||||
WCHAR wszTarget[MAX_PATH];
|
||||
WCHAR wszNewLnk[MAX_PATH];
|
||||
|
||||
TRACE("target path = %s\n", debugstr_w(m_sPathTarget));
|
||||
|
||||
/* 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++)
|
||||
{
|
||||
// Find out which file we're linking.
|
||||
STRRET strFile;
|
||||
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
|
||||
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlFull;
|
||||
hr = SHILCombine(pidl, apidl[i], &pidlFull);
|
||||
|
||||
WCHAR targetName[MAX_PATH];
|
||||
if (SUCCEEDED(hr))
|
||||
hr = Shell_DisplayNameOf(psfFrom, apidl[i], SHGDN_FOREDITING | SHGDN_INFOLDER, targetName, _countof(targetName));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
TRACE("source path = %s\n", debugstr_w(wszPath));
|
||||
|
||||
WCHAR wszDisplayName[MAX_PATH];
|
||||
LPWSTR pwszFileName = PathFindFileNameW(wszPath);
|
||||
if (PathIsRootW(wszPath)) // Drive?
|
||||
{
|
||||
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_NORMAL, &strFile);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
hr = StrRetToBufW(&strFile, apidl[i], wszDisplayName, _countof(wszDisplayName));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
// Delete a ':' in wszDisplayName.
|
||||
LPWSTR pch0 = wcschr(wszDisplayName, L':');
|
||||
if (pch0)
|
||||
{
|
||||
do
|
||||
{
|
||||
*pch0 = *(pch0 + 1);
|
||||
++pch0;
|
||||
} while (*pch0);
|
||||
}
|
||||
|
||||
pwszFileName = wszDisplayName; // Use wszDisplayName
|
||||
}
|
||||
else if (wszPath[0] == L':' && wszPath[1] == L':') // ::{GUID}?
|
||||
{
|
||||
CLSID clsid;
|
||||
hr = ::CLSIDFromString(&wszPath[2], &clsid);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
LPITEMIDLIST pidl = ILCreateFromPathW(wszPath);
|
||||
if (pidl)
|
||||
{
|
||||
SHFILEINFOW fi = { NULL };
|
||||
SHGetFileInfoW((LPCWSTR)pidl, 0, &fi, sizeof(fi),
|
||||
SHGFI_DISPLAYNAME | SHGFI_PIDL);
|
||||
if (fi.szDisplayName[0])
|
||||
{
|
||||
lstrcpynW(wszDisplayName, fi.szDisplayName, _countof(wszDisplayName));
|
||||
pwszFileName = wszDisplayName; // Use wszDisplayName
|
||||
}
|
||||
ILFree(pidl);
|
||||
}
|
||||
}
|
||||
SHELL_ErrorBox(m_hwndSite, hr);
|
||||
break;
|
||||
}
|
||||
SHELL_StripIllegalFsNameCharacters(targetName);
|
||||
|
||||
// Creating a buffer to hold the combined path.
|
||||
WCHAR wszCombined[MAX_PATH];
|
||||
PathCombineW(wszCombined, m_sPathTarget, pwszFileName);
|
||||
WCHAR wszCombined[MAX_PATH + _countof(targetName)];
|
||||
PathCombineW(wszCombined, m_sPathTarget, targetName);
|
||||
|
||||
// Check to see if the source is a link
|
||||
SFGAOF att = SHGetAttributes(psfFrom, apidl[i], SFGAO_FOLDER | SFGAO_STREAM | SFGAO_FILESYSTEM);
|
||||
BOOL fSourceIsLink = FALSE;
|
||||
if (!wcsicmp(PathFindExtensionW(wszPath), L".lnk"))
|
||||
if (!wcsicmp(PathFindExtensionW(targetName), L".lnk") && (att & (SFGAO_FOLDER | SFGAO_STREAM)) != SFGAO_FOLDER)
|
||||
{
|
||||
fSourceIsLink = TRUE;
|
||||
PathRemoveExtensionW(wszCombined);
|
||||
}
|
||||
|
||||
// Create a pathname to save the new link.
|
||||
_GetUniqueFileName(wszCombined, L".lnk", wszTarget, TRUE);
|
||||
_GetUniqueFileName(wszCombined, L".lnk", wszNewLnk, TRUE);
|
||||
|
||||
CComPtr<IPersistFile> ppf;
|
||||
if (fSourceIsLink)
|
||||
{
|
||||
hr = IShellLink_ConstructFromPath(wszPath, IID_PPV_ARG(IPersistFile, &ppf));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
PWSTR pwszTargetFull;
|
||||
hr = SHGetNameFromIDList(pidlFull, SIGDN_DESKTOPABSOLUTEPARSING, &pwszTargetFull);
|
||||
if (!FAILED_UNEXPECTEDLY(hr))
|
||||
{
|
||||
hr = IShellLink_ConstructFromPath(pwszTargetFull, IID_PPV_ARG(IPersistFile, &ppf));
|
||||
FAILED_UNEXPECTEDLY(hr);
|
||||
SHFree(pwszTargetFull);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CComPtr<IShellLinkW> pLink;
|
||||
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
if (!FAILED_UNEXPECTEDLY(hr))
|
||||
{
|
||||
hr = pLink->SetIDList(pidlFull);
|
||||
if (!FAILED_UNEXPECTEDLY(hr))
|
||||
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
||||
|
||||
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
||||
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
||||
if (pwszFile)
|
||||
pwszFile[0] = 0;
|
||||
|
||||
hr = pLink->SetPath(wszPath);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->SetWorkingDirectory(szDirPath);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
|
||||
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
break;
|
||||
PWSTR pwszPath, pSep;
|
||||
if ((att & SFGAO_FILESYSTEM) && SUCCEEDED(SHGetNameFromIDList(pidlFull, SIGDN_FILESYSPATH, &pwszPath)))
|
||||
{
|
||||
if ((pSep = PathFindFileNameW(pwszPath)) > pwszPath)
|
||||
{
|
||||
pSep[-1] = UNICODE_NULL;
|
||||
pLink->SetWorkingDirectory(pwszPath);
|
||||
}
|
||||
SHFree(pwszPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = ppf->Save(wszTarget, !fSourceIsLink);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = ppf->Save(wszNewLnk, !fSourceIsLink);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
{
|
||||
SHELL_ErrorBox(m_hwndSite, hr);
|
||||
break;
|
||||
|
||||
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
|
||||
}
|
||||
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszNewLnk, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -28,12 +28,7 @@ static_assert(sizeof(DataObjectAttributes) == 0xc, "Unexpected struct size!");
|
|||
static
|
||||
HRESULT _BindToObject(PCUIDLIST_ABSOLUTE pidl, CComPtr<IShellFolder>& spFolder)
|
||||
{
|
||||
CComPtr<IShellFolder> spDesktop;
|
||||
HRESULT hr = SHGetDesktopFolder(&spDesktop);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return spDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &spFolder));
|
||||
return SHBindToObject(NULL, pidl, IID_PPV_ARG(IShellFolder, &spFolder));
|
||||
}
|
||||
|
||||
EXTERN_C
|
||||
|
|
Loading…
Reference in a new issue