[SHELL32] Drop a shortcut of the drive (#4072)

- If the Right-dropped item was a drive, then get the display name of the drive and use it.
- Use FAILED_UNEXPECTEDLY instead of FAILED macro.
- Accept ::{GUID}.
CORE-17813
This commit is contained in:
Katayama Hirofumi MZ 2021-11-18 17:11:24 +09:00 committed by GitHub
parent f8010947fe
commit 0f5fb4785b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 60 deletions

View file

@ -134,7 +134,7 @@ CFSDropTarget::~CFSDropTarget()
} }
BOOL BOOL
CFSDropTarget::_GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut) CFSDropTarget::_GetUniqueFileName(LPCWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
{ {
WCHAR wszLink[40]; WCHAR wszLink[40];
@ -549,104 +549,125 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
if (bLinking) if (bLinking)
{ {
WCHAR wszTargetPath[MAX_PATH];
WCHAR wszPath[MAX_PATH]; WCHAR wszPath[MAX_PATH];
WCHAR wszTarget[MAX_PATH]; WCHAR wszTarget[MAX_PATH];
wcscpy(wszTargetPath, m_sPathTarget); TRACE("target path = %s\n", debugstr_w(m_sPathTarget));
TRACE("target path = %s", debugstr_w(wszTargetPath));
/* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */ /* 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++) for (UINT i = 0; i < lpcida->cidl; i++)
{ {
//Find out which file we're copying // Find out which file we're linking.
STRRET strFile; STRRET strFile;
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile); hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
if (FAILED(hr)) if (FAILED_UNEXPECTEDLY(hr))
{
ERR("Error source obtaining path");
break; break;
}
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath)); hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
if (FAILED(hr)) if (FAILED_UNEXPECTEDLY(hr))
{
ERR("Error putting source path into buffer");
break; break;
}
TRACE("source path = %s", debugstr_w(wszPath));
// Creating a buffer to hold the combined path TRACE("source path = %s\n", debugstr_w(wszPath));
WCHAR buffer_1[MAX_PATH] = L"";
WCHAR *lpStr1;
lpStr1 = buffer_1;
WCHAR wszDisplayName[MAX_PATH];
LPWSTR pwszFileName = PathFindFileNameW(wszPath); LPWSTR pwszFileName = PathFindFileNameW(wszPath);
LPWSTR pwszExt = PathFindExtensionW(wszPath); if (PathIsRootW(wszPath)) // Drive?
LPWSTR placementPath = PathCombineW(lpStr1, m_sPathTarget, pwszFileName);
CComPtr<IPersistFile> ppf;
//Check to see if it's already a link.
if (!wcsicmp(pwszExt, L".lnk"))
{ {
//It's a link so, we create a new one which copies the old. hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_NORMAL, &strFile);
if(!_GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE)) 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)
{ {
ERR("Error getting unique file name"); do
hr = E_FAIL; {
break; *pch0 = *(pch0 + 1);
} ++pch0;
hr = IShellLink_ConstructFromPath(wszPath, IID_PPV_ARG(IPersistFile, &ppf)); } while (*pch0);
if (FAILED(hr)) {
ERR("Error constructing link from file");
break;
} }
hr = ppf->Save(wszTarget, FALSE); pwszFileName = wszDisplayName; // Use wszDisplayName
if (FAILED(hr)) }
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);
}
}
}
// Creating a buffer to hold the combined path.
WCHAR wszCombined[MAX_PATH];
PathCombineW(wszCombined, m_sPathTarget, pwszFileName);
// Check to see if the source is a link
BOOL fSourceIsLink = FALSE;
if (!wcsicmp(PathFindExtensionW(wszPath), L".lnk"))
{
fSourceIsLink = TRUE;
PathRemoveExtensionW(wszCombined);
}
// Create a pathname to save the new link.
_GetUniqueFileName(wszCombined, L".lnk", wszTarget, TRUE);
CComPtr<IPersistFile> ppf;
if (fSourceIsLink)
{
hr = IShellLink_ConstructFromPath(wszPath, IID_PPV_ARG(IPersistFile, &ppf));
if (FAILED_UNEXPECTEDLY(hr))
break; break;
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
} }
else else
{ {
//It's not a link, so build a new link using the creator class and fill it in.
//Create a file name for the link
if (!_GetUniqueFileName(placementPath, L".lnk", wszTarget, TRUE))
{
ERR("Error creating unique file name");
hr = E_FAIL;
break;
}
CComPtr<IShellLinkW> pLink; CComPtr<IShellLinkW> pLink;
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink)); hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
if (FAILED(hr)) { if (FAILED_UNEXPECTEDLY(hr))
ERR("Error instantiating IShellLinkW");
break; break;
}
WCHAR szDirPath[MAX_PATH], *pwszFile; WCHAR szDirPath[MAX_PATH], *pwszFile;
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile); GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
if (pwszFile) pwszFile[0] = 0; if (pwszFile)
pwszFile[0] = 0;
hr = pLink->SetPath(wszPath); hr = pLink->SetPath(wszPath);
if(FAILED(hr)) if (FAILED_UNEXPECTEDLY(hr))
break; break;
hr = pLink->SetWorkingDirectory(szDirPath); hr = pLink->SetWorkingDirectory(szDirPath);
if(FAILED(hr)) if (FAILED_UNEXPECTEDLY(hr))
break; break;
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf)); hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if(FAILED(hr)) if (FAILED_UNEXPECTEDLY(hr))
break; break;
hr = ppf->Save(wszTarget, TRUE);
if (FAILED(hr))
break;
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
} }
hr = ppf->Save(wszTarget, !fSourceIsLink);
if (FAILED_UNEXPECTEDLY(hr))
break;
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
} }
} }
else else

View file

@ -40,7 +40,7 @@ class CFSDropTarget :
BOOL _QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect); BOOL _QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
HRESULT _DoDrop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); HRESULT _DoDrop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT _CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy); HRESULT _CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy);
BOOL _GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut); BOOL _GetUniqueFileName(LPCWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
static DWORD WINAPI _DoDropThreadProc(LPVOID lpParameter); static DWORD WINAPI _DoDropThreadProc(LPVOID lpParameter);
HRESULT _GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect, DWORD dwAvailableEffects); HRESULT _GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect, DWORD dwAvailableEffects);
HRESULT _RepositionItems(IShellFolderView *psfv, IDataObject *pDataObject, POINTL pt); HRESULT _RepositionItems(IShellFolderView *psfv, IDataObject *pDataObject, POINTL pt);