mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 09:25:10 +00:00
[SHELL32]
* Initial go at the Drag & Drop support. Work is still ongoing here. Brought to you by Huw Campbell. CORE-3760 svn path=/trunk/; revision=61294
This commit is contained in:
parent
e9a8c50011
commit
d6218793bb
7 changed files with 521 additions and 375 deletions
|
@ -58,8 +58,7 @@ class CDefaultContextMenu :
|
||||||
UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
||||||
UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
|
UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
|
||||||
UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
||||||
HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink);
|
||||||
HRESULT DoPasteLink(LPCMINVOKECOMMANDINFO lpcmi);
|
|
||||||
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
|
@ -947,7 +946,7 @@ NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
CDefaultContextMenu::DoPaste(
|
CDefaultContextMenu::DoPaste(
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
@ -956,56 +955,12 @@ CDefaultContextMenu::DoPaste(
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
STGMEDIUM medium;
|
|
||||||
FORMATETC formatetc;
|
|
||||||
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
||||||
hr = pda->GetData(&formatetc, &medium);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
/* lock the handle */
|
|
||||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
|
||||||
if (!lpcida)
|
|
||||||
{
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert the data into pidl */
|
|
||||||
LPITEMIDLIST pidl;
|
|
||||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
|
||||||
if (!apidl)
|
|
||||||
{
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CComPtr<IShellFolder> psfDesktop;
|
CComPtr<IShellFolder> psfDesktop;
|
||||||
CComPtr<IShellFolder> psfFrom = NULL;
|
|
||||||
CComPtr<IShellFolder> psfTarget = NULL;
|
CComPtr<IShellFolder> psfTarget = NULL;
|
||||||
CComPtr<ISFHelper> psfhlpdst;
|
|
||||||
CComPtr<ISFHelper> psfhlpsrc;
|
|
||||||
bool bCopy = TRUE;
|
|
||||||
|
|
||||||
hr = SHGetDesktopFolder(&psfDesktop);
|
hr = SHGetDesktopFolder(&psfDesktop);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
goto cleanup;
|
return hr;
|
||||||
|
|
||||||
/* Find source folder */
|
|
||||||
if (_ILIsDesktop(pidl))
|
|
||||||
{
|
|
||||||
/* use desktop shellfolder */
|
|
||||||
psfFrom = psfDesktop;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("no IShellFolder\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find target folder */
|
/* Find target folder */
|
||||||
if (m_Dcm.cidl)
|
if (m_Dcm.cidl)
|
||||||
|
@ -1043,269 +998,51 @@ CDefaultContextMenu::DoPaste(
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
ERR("no IShellFolder\n");
|
ERR("no IShellFolder\n");
|
||||||
goto cleanup;
|
return hr;
|
||||||
}
|
|
||||||
|
|
||||||
/* get source and destination shellfolder */
|
|
||||||
hr = psfTarget->QueryInterface(IID_PPV_ARG(ISFHelper, &psfhlpdst));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("no IID_ISFHelper for destination\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = psfFrom->QueryInterface(IID_PPV_ARG(ISFHelper, &psfhlpsrc));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("no IID_ISFHelper for source\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FORMATETC formatetc2;
|
FORMATETC formatetc2;
|
||||||
STGMEDIUM medium2;
|
STGMEDIUM medium2;
|
||||||
InitFormatEtc(formatetc2, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
|
InitFormatEtc(formatetc2, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
|
||||||
|
|
||||||
|
DWORD dwKey= 0;
|
||||||
|
|
||||||
if SUCCEEDED(pda->GetData(&formatetc2, &medium2))
|
if (SUCCEEDED(pda->GetData(&formatetc2, &medium2)))
|
||||||
{
|
{
|
||||||
DWORD * pdwFlag = (DWORD*)GlobalLock(medium2.hGlobal);
|
DWORD * pdwFlag = (DWORD*)GlobalLock(medium2.hGlobal);
|
||||||
if (pdwFlag)
|
if (pdwFlag)
|
||||||
{
|
{
|
||||||
TRACE("Current drop effect flag %i\n", *pdwFlag);
|
if (*pdwFlag == DROPEFFECT_COPY)
|
||||||
if (*pdwFlag & DROPEFFECT_MOVE)
|
dwKey = MK_CONTROL;
|
||||||
bCopy = FALSE;
|
else
|
||||||
|
dwKey = MK_SHIFT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ERR("No drop effect obtained");
|
||||||
}
|
}
|
||||||
GlobalUnlock(medium2.hGlobal);
|
GlobalUnlock(medium2.hGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
|
if (bLink)
|
||||||
|
{
|
||||||
|
dwKey = MK_CONTROL|MK_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDropTarget *pdrop;
|
||||||
|
hr = psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pdrop));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Error getting IDropTarget interface\n");
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
NotifyShellViewWindow(lpcmi, TRUE);
|
||||||
|
|
||||||
cleanup:
|
|
||||||
SHFree(pidl);
|
|
||||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
|
|
||||||
TRACE("CP result %x\n", hr);
|
TRACE("CP result %x\n", hr);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
|
||||||
GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
|
|
||||||
{
|
|
||||||
WCHAR wszLink[40];
|
|
||||||
|
|
||||||
if (!bShortcut)
|
|
||||||
{
|
|
||||||
if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
|
|
||||||
wszLink[0] = L'\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bShortcut)
|
|
||||||
swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
|
|
||||||
else
|
|
||||||
swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
|
|
||||||
|
|
||||||
for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
|
|
||||||
{
|
|
||||||
if (!bShortcut)
|
|
||||||
swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
|
|
||||||
else
|
|
||||||
swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT
|
|
||||||
CDefaultContextMenu::DoPasteLink(
|
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
WCHAR wszPath[MAX_PATH];
|
|
||||||
WCHAR wszTarget[MAX_PATH];
|
|
||||||
|
|
||||||
CComPtr<IDataObject> pda;
|
|
||||||
hr = OleGetClipboard(&pda);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
STGMEDIUM medium;
|
|
||||||
FORMATETC formatetc;
|
|
||||||
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
|
||||||
hr = pda->GetData(&formatetc, &medium);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
/* lock the handle */
|
|
||||||
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
|
||||||
if (!lpcida)
|
|
||||||
{
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert the clipboard data into pidl (pointer to id list) */
|
|
||||||
LPITEMIDLIST pidl;
|
|
||||||
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
|
||||||
if (!apidl)
|
|
||||||
{
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CComPtr<IShellFolder> psfDesktop;
|
|
||||||
CComPtr<IPersistFolder2> ppf2 = NULL;
|
|
||||||
CComPtr<IShellFolder> psfFrom = NULL;
|
|
||||||
|
|
||||||
/* Grab the desktop shell folder */
|
|
||||||
hr = SHGetDesktopFolder(&psfDesktop);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("SHGetDesktopFolder failed\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find source folder, this is where the clipboard data was copied from */
|
|
||||||
if (_ILIsDesktop(pidl))
|
|
||||||
{
|
|
||||||
/* use desktop shell folder */
|
|
||||||
psfFrom = psfDesktop;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("no IShellFolder\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the target path, where we will be saving the new links (where the user right clicked) */
|
|
||||||
STRRET strFile;
|
|
||||||
WCHAR wszTargetPath[MAX_PATH];
|
|
||||||
|
|
||||||
LPITEMIDLIST targetpidl;
|
|
||||||
|
|
||||||
hr = m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = ppf2->GetCurFolder(&targetpidl);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
|
|
||||||
ILFree(targetpidl);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("Error obtaining target path");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
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 */
|
|
||||||
for (UINT i = 0; i < lpcida->cidl; i++)
|
|
||||||
{
|
|
||||||
//Find out which file we're copying
|
|
||||||
STRRET strFile;
|
|
||||||
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("Error source obtaining path");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("Error putting source path into buffer");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TRACE("source path = %s", debugstr_w(wszPath));
|
|
||||||
|
|
||||||
// Creating a buffer to hold the combined path
|
|
||||||
WCHAR buffer_1[MAX_PATH] = L"";
|
|
||||||
WCHAR *lpStr1;
|
|
||||||
lpStr1 = buffer_1;
|
|
||||||
|
|
||||||
LPWSTR pwszFileName = PathFindFileNameW(wszPath);
|
|
||||||
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
|
||||||
LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, 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.
|
|
||||||
if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE))
|
|
||||||
{
|
|
||||||
ERR("Error getting unique file name");
|
|
||||||
hr = E_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
ERR("Error constructing link from file");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = ppf->Save(wszTarget, FALSE);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
ERR("Error instantiating IShellLinkW");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
|
||||||
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
|
||||||
if (pwszFile) pwszFile[0] = 0;
|
|
||||||
|
|
||||||
hr = pLink->SetPath(wszPath);
|
|
||||||
if(FAILED(hr))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hr = pLink->SetWorkingDirectory(szDirPath);
|
|
||||||
if(FAILED(hr))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
|
||||||
if(FAILED(hr))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hr = ppf->Save(wszTarget, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
SHFree(pidl);
|
|
||||||
_ILFreeaPidl(apidl, lpcida->cidl);
|
|
||||||
ReleaseStgMedium(&medium);
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
CDefaultContextMenu::DoOpenOrExplore(
|
CDefaultContextMenu::DoOpenOrExplore(
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
LPCMINVOKECOMMANDINFO lpcmi)
|
||||||
|
@ -1318,75 +1055,60 @@ HRESULT
|
||||||
CDefaultContextMenu::DoCreateLink(
|
CDefaultContextMenu::DoCreateLink(
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
LPCMINVOKECOMMANDINFO lpcmi)
|
||||||
{
|
{
|
||||||
WCHAR wszTarget[MAX_PATH];
|
LPDATAOBJECT pDataObj;
|
||||||
IPersistFile *ppf;
|
IDropTarget *pDT;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
STRRET strFile;
|
CComPtr<IPersistFolder2> ppf2 = NULL;
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
CComPtr<IShellFolder> psfDesktop;
|
||||||
|
CComPtr<IShellFolder> psfTarget = NULL;
|
||||||
|
|
||||||
hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
|
hr = SHGetDesktopFolder(&psfDesktop);
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
WCHAR wszPath[MAX_PATH];
|
|
||||||
hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath));
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
if (SUCCEEDED(hr = SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
|
||||||
|
|
||||||
if (!wcsicmp(pwszExt, L".lnk"))
|
|
||||||
{
|
{
|
||||||
if (!GetUniqueFileName(wszPath, pwszExt, wszTarget, TRUE))
|
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
IPersistFolder2 *ppf2 = NULL;
|
|
||||||
LPITEMIDLIST pidl;
|
|
||||||
hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
|
hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
hr = ppf2->GetCurFolder(&pidl);
|
hr = ppf2->GetCurFolder(&pidl);
|
||||||
ppf2->Release();
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, m_Dcm.apidl[0]), (LPVOID*)&ppf);
|
|
||||||
}
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
hr = ppf->Save(wszTarget, FALSE);
|
|
||||||
ppf->Release();
|
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!GetUniqueFileName(wszPath, L".lnk", wszTarget, TRUE))
|
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
IShellLinkW *pLink;
|
|
||||||
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
|
||||||
if (hr != S_OK)
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
|
||||||
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
|
||||||
if (pwszFile) pwszFile[0] = 0;
|
|
||||||
|
|
||||||
if (SUCCEEDED(pLink->SetPath(wszPath)) &&
|
|
||||||
SUCCEEDED(pLink->SetWorkingDirectory(szDirPath)))
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf))))
|
|
||||||
{
|
{
|
||||||
hr = ppf->Save(wszTarget, TRUE);
|
if (_ILIsDesktop(pidl))
|
||||||
ppf->Release();
|
{
|
||||||
|
/* use desktop shellfolder */
|
||||||
|
psfTarget = psfDesktop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* retrieve target desktop folder */
|
||||||
|
hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
|
||||||
|
}
|
||||||
|
TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
|
||||||
|
ILFree(pidl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pLink->Release();
|
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("no IShellFolder\n");
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pDT));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("no IDropTarget Interface\n");
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
DWORD link = DROPEFFECT_LINK;
|
||||||
|
SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
|
||||||
|
NotifyShellViewWindow(lpcmi, TRUE);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
@ -1843,9 +1565,9 @@ CDefaultContextMenu::InvokeCommand(
|
||||||
case FCIDM_SHVIEW_REFRESH:
|
case FCIDM_SHVIEW_REFRESH:
|
||||||
return NotifyShellViewWindow(lpcmi, FALSE);
|
return NotifyShellViewWindow(lpcmi, FALSE);
|
||||||
case FCIDM_SHVIEW_INSERT:
|
case FCIDM_SHVIEW_INSERT:
|
||||||
return DoPaste(lpcmi);
|
return DoPaste(lpcmi, FALSE);
|
||||||
case FCIDM_SHVIEW_INSERTLINK:
|
case FCIDM_SHVIEW_INSERTLINK:
|
||||||
return DoPasteLink(lpcmi);
|
return DoPaste(lpcmi, TRUE);
|
||||||
case FCIDM_SHVIEW_OPEN:
|
case FCIDM_SHVIEW_OPEN:
|
||||||
case FCIDM_SHVIEW_EXPLORE:
|
case FCIDM_SHVIEW_EXPLORE:
|
||||||
return DoOpenOrExplore(lpcmi);
|
return DoOpenOrExplore(lpcmi);
|
||||||
|
|
|
@ -254,10 +254,21 @@ HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWN
|
||||||
return ret ? S_OK : E_FAIL;
|
return ret ? S_OK : E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDesktopFolder::SF_RegisterClipFmt()
|
||||||
|
{
|
||||||
|
TRACE ("(%p)\n", this);
|
||||||
|
|
||||||
|
if (!cfShellIDList)
|
||||||
|
cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
|
||||||
|
}
|
||||||
|
|
||||||
CDesktopFolder::CDesktopFolder()
|
CDesktopFolder::CDesktopFolder()
|
||||||
{
|
{
|
||||||
pidlRoot = NULL;
|
pidlRoot = NULL;
|
||||||
sPathTarget = NULL;
|
sPathTarget = NULL;
|
||||||
|
cfShellIDList = 0;
|
||||||
|
SF_RegisterClipFmt();
|
||||||
|
fAcceptFmt = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDesktopFolder::~CDesktopFolder()
|
CDesktopFolder::~CDesktopFolder()
|
||||||
|
@ -512,8 +523,7 @@ HRESULT WINAPI CDesktopFolder::CreateViewObject(
|
||||||
|
|
||||||
if (IsEqualIID (riid, IID_IDropTarget))
|
if (IsEqualIID (riid, IID_IDropTarget))
|
||||||
{
|
{
|
||||||
WARN ("IDropTarget not implemented\n");
|
hr = this->QueryInterface (IID_IDropTarget, ppvOut);
|
||||||
hr = E_NOTIMPL;
|
|
||||||
}
|
}
|
||||||
else if (IsEqualIID (riid, IID_IContextMenu))
|
else if (IsEqualIID (riid, IID_IContextMenu))
|
||||||
{
|
{
|
||||||
|
@ -638,9 +648,12 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
|
||||||
SHFree (pidl);
|
SHFree (pidl);
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
}
|
}
|
||||||
else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
|
else if (IsEqualIID (riid, IID_IDropTarget))
|
||||||
{
|
{
|
||||||
hr = this->QueryInterface (IID_IDropTarget, (LPVOID *)&pObj);
|
/* only interested in attempting to bind to shell folders, not files, semicolon intentionate */
|
||||||
|
if (cidl == 1 && SUCCEEDED(this->BindToObject(apidl[0], NULL, IID_IDropTarget, (LPVOID*)&pObj)));
|
||||||
|
else
|
||||||
|
hr = this->QueryInterface(IID_IDropTarget, (LPVOID*)&pObj);
|
||||||
}
|
}
|
||||||
else if ((IsEqualIID(riid, IID_IShellLinkW) ||
|
else if ((IsEqualIID(riid, IID_IShellLinkW) ||
|
||||||
IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
|
IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
|
||||||
|
@ -1326,3 +1339,137 @@ HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCIT
|
||||||
}
|
}
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* IDropTarget implementation
|
||||||
|
*
|
||||||
|
* This should allow two somewhat separate things, copying files to the users directory,
|
||||||
|
* as well as allowing icons to be moved anywhere and updating the registry to save.
|
||||||
|
*
|
||||||
|
* The first thing I think is best done using fs.cpp to prevent WET code. So we'll simulate
|
||||||
|
* a drop to the user's home directory. The second will look at the pointer location and
|
||||||
|
* set sensible places for the icons to live.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
BOOL CDesktopFolder::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. */
|
||||||
|
|
||||||
|
DWORD dwEffect = DROPEFFECT_MOVE;
|
||||||
|
|
||||||
|
*pdwEffect = DROPEFFECT_NONE;
|
||||||
|
|
||||||
|
if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
|
||||||
|
*pdwEffect = KeyStateToDropEffect (dwKeyState);
|
||||||
|
|
||||||
|
if (*pdwEffect == DROPEFFECT_NONE)
|
||||||
|
*pdwEffect = dwEffect;
|
||||||
|
|
||||||
|
/* ... matches the desired effect ? */
|
||||||
|
if (dwEffect & *pdwEffect) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
|
||||||
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
FORMATETC fmt;
|
||||||
|
|
||||||
|
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||||
|
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ?
|
||||||
|
TRUE : FALSE;
|
||||||
|
|
||||||
|
QueryDrop(dwKeyState, pdwEffect);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CDesktopFolder::DragOver(DWORD dwKeyState, POINTL pt,
|
||||||
|
DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
TRACE("(%p)\n", this);
|
||||||
|
|
||||||
|
if (!pdwEffect)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
QueryDrop(dwKeyState, pdwEffect);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CDesktopFolder::DragLeave()
|
||||||
|
{
|
||||||
|
TRACE("(%p)\n", this);
|
||||||
|
fAcceptFmt = FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CDesktopFolder::Drop(IDataObject *pDataObject,
|
||||||
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
TRACE("(%p) object dropped desktop\n", this);
|
||||||
|
|
||||||
|
STGMEDIUM medium;
|
||||||
|
FORMATETC formatetc;
|
||||||
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
||||||
|
HRESULT hr = pDataObject->GetData(&formatetc, &medium);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
/* lock the handle */
|
||||||
|
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||||
|
if (!lpcida)
|
||||||
|
{
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert the clipboard data into pidl (pointer to id list) */
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||||
|
if (!apidl)
|
||||||
|
{
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only want to really move files around if they don't already
|
||||||
|
come from the desktop, or we're linking or copying */
|
||||||
|
if ((!_ILIsDesktop(pidl)) || (dwKeyState & MK_CONTROL))
|
||||||
|
{
|
||||||
|
LPITEMIDLIST pidl = NULL;
|
||||||
|
|
||||||
|
WCHAR szPath[MAX_PATH];
|
||||||
|
LPWSTR pathPtr;
|
||||||
|
|
||||||
|
/* build a complete path to create a simple pidl */
|
||||||
|
lstrcpynW(szPath, sPathTarget, MAX_PATH);
|
||||||
|
pathPtr = PathAddBackslashW(szPath);
|
||||||
|
//hr = _ILCreateFromPathW(szPath, &pidl);
|
||||||
|
hr = this->ParseDisplayName(NULL, NULL, szPath, NULL, &pidl, NULL);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IDropTarget *pDT;
|
||||||
|
hr = this->BindToObject(pidl, NULL, IID_IDropTarget, (LPVOID*)&pDT);
|
||||||
|
CoTaskMemFree(pidl);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
SHSimulateDrop(pDT, pDataObject, dwKeyState, NULL, pdwEffect);
|
||||||
|
else
|
||||||
|
ERR("Error Binding");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("Error creating from %s\n", debugstr_w(szPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Todo, rewrite the registry such that the icons are well placed.
|
||||||
|
Blocked by no bags implementation. */
|
||||||
|
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return hr;
|
||||||
|
}
|
|
@ -28,15 +28,19 @@ class CDesktopFolder :
|
||||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
public IShellFolder2,
|
public IShellFolder2,
|
||||||
public IPersistFolder2,
|
public IPersistFolder2,
|
||||||
|
public IDropTarget,
|
||||||
public ISFHelper
|
public ISFHelper
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/* both paths are parsible from the desktop */
|
/* both paths are parsible from the desktop */
|
||||||
LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
|
LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
|
||||||
LPITEMIDLIST pidlRoot; /* absolute pidl */
|
LPITEMIDLIST pidlRoot; /* absolute pidl */
|
||||||
|
|
||||||
|
UINT cfShellIDList; /* clipboardformat for IDropTarget */
|
||||||
|
BOOL fAcceptFmt; /* flag for pending Drop */
|
||||||
|
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
||||||
|
void SF_RegisterClipFmt();
|
||||||
|
|
||||||
// CComPtr<IShellFolder2> fDesktopFolder;
|
|
||||||
// CComPtr<IShellFolder2> fCommonDesktopFolder;
|
|
||||||
public:
|
public:
|
||||||
CDesktopFolder();
|
CDesktopFolder();
|
||||||
~CDesktopFolder();
|
~CDesktopFolder();
|
||||||
|
@ -72,6 +76,13 @@ class CDesktopFolder :
|
||||||
// *** IPersistFolder2 methods ***
|
// *** IPersistFolder2 methods ***
|
||||||
virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl);
|
virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl);
|
||||||
|
|
||||||
|
// IDropTarget
|
||||||
|
virtual HRESULT WINAPI DragEnter(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
|
||||||
|
virtual HRESULT WINAPI DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
|
||||||
|
virtual HRESULT WINAPI DragLeave();
|
||||||
|
virtual HRESULT WINAPI Drop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
|
||||||
|
|
||||||
|
|
||||||
// *** ISFHelper methods ***
|
// *** ISFHelper methods ***
|
||||||
virtual HRESULT WINAPI GetUniqueName(LPWSTR pwszName, UINT uLen);
|
virtual HRESULT WINAPI GetUniqueName(LPWSTR pwszName, UINT uLen);
|
||||||
virtual HRESULT WINAPI AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut);
|
virtual HRESULT WINAPI AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut);
|
||||||
|
@ -89,6 +100,7 @@ class CDesktopFolder :
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
|
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
|
||||||
END_COM_MAP()
|
END_COM_MAP()
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,6 +79,7 @@ CFSFolder::CFSFolder()
|
||||||
sPathTarget = NULL;
|
sPathTarget = NULL;
|
||||||
pidlRoot = NULL;
|
pidlRoot = NULL;
|
||||||
cfShellIDList = 0;
|
cfShellIDList = 0;
|
||||||
|
SF_RegisterClipFmt();
|
||||||
fAcceptFmt = FALSE;
|
fAcceptFmt = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,10 +499,15 @@ HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
|
||||||
SHFree (pidl);
|
SHFree (pidl);
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
}
|
}
|
||||||
else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
|
else if (IsEqualIID (riid, IID_IDropTarget))
|
||||||
hr = this->QueryInterface(IID_IDropTarget, (LPVOID*)&pObj);
|
{
|
||||||
|
/* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
|
||||||
|
if (cidl == 1 && SUCCEEDED(hr = this->BindToObject(apidl[0], NULL, IID_IDropTarget, (LPVOID*)&pObj)));
|
||||||
|
else
|
||||||
|
hr = this->QueryInterface(IID_IDropTarget, (LPVOID*)&pObj);
|
||||||
|
}
|
||||||
else if ((IsEqualIID(riid, IID_IShellLinkW) ||
|
else if ((IsEqualIID(riid, IID_IShellLinkW) ||
|
||||||
IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
|
IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
|
||||||
{
|
{
|
||||||
pidl = ILCombine (pidlRoot, apidl[0]);
|
pidl = ILCombine (pidlRoot, apidl[0]);
|
||||||
hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
|
hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
|
||||||
|
@ -571,9 +577,9 @@ void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
/*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
|
/*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
|
||||||
if (!(dwFlags & SHGDN_FORPARSING) &&
|
if (!(dwFlags & SHGDN_FORPARSING) &&
|
||||||
((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
|
((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
|
||||||
if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
|
if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
|
||||||
PathRemoveExtensionW(szPath);
|
PathRemoveExtensionW(szPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +814,7 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl,
|
||||||
{
|
{
|
||||||
case 0: /* name */
|
case 0: /* name */
|
||||||
hr = GetDisplayNameOf (pidl,
|
hr = GetDisplayNameOf (pidl,
|
||||||
SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
|
SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
|
||||||
break;
|
break;
|
||||||
case 1: /* size */
|
case 1: /* size */
|
||||||
_ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
|
_ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
|
||||||
|
@ -931,7 +937,7 @@ HRESULT WINAPI CFSFolder::AddFolder(HWND hwnd, LPCWSTR pwszName,
|
||||||
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
|
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
|
||||||
_countof(wszTempText));
|
_countof(wszTempText));
|
||||||
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
|
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
|
||||||
_countof(wszCaption));
|
_countof(wszCaption));
|
||||||
swprintf(wszText, wszTempText, wszNewDir);
|
swprintf(wszText, wszTempText, wszNewDir);
|
||||||
MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
|
MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
|
||||||
}
|
}
|
||||||
|
@ -1314,18 +1320,51 @@ HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CFSFolder::GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
|
||||||
|
{
|
||||||
|
WCHAR wszLink[40];
|
||||||
|
|
||||||
|
if (!bShortcut)
|
||||||
|
{
|
||||||
|
if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
|
||||||
|
wszLink[0] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bShortcut)
|
||||||
|
swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
|
||||||
|
else
|
||||||
|
swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
|
||||||
|
|
||||||
|
for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
|
||||||
|
{
|
||||||
|
if (!bShortcut)
|
||||||
|
swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
|
||||||
|
else
|
||||||
|
swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* ISFDropTarget implementation
|
* IDropTarget implementation
|
||||||
*/
|
*/
|
||||||
BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
||||||
{
|
{
|
||||||
DWORD dwEffect = *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. */
|
||||||
|
|
||||||
|
DWORD dwEffect = DROPEFFECT_MOVE;
|
||||||
|
|
||||||
*pdwEffect = DROPEFFECT_NONE;
|
*pdwEffect = DROPEFFECT_NONE;
|
||||||
|
|
||||||
if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
|
if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
|
||||||
*pdwEffect = KeyStateToDropEffect (dwKeyState);
|
*pdwEffect = KeyStateToDropEffect (dwKeyState);
|
||||||
|
|
||||||
|
if (*pdwEffect == DROPEFFECT_NONE)
|
||||||
|
*pdwEffect = dwEffect;
|
||||||
|
|
||||||
/* ... matches the desired effect ? */
|
/* ... matches the desired effect ? */
|
||||||
if (dwEffect & *pdwEffect) {
|
if (dwEffect & *pdwEffect) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1338,16 +1377,18 @@ HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
|
||||||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
{
|
{
|
||||||
FORMATETC fmt;
|
FORMATETC fmt;
|
||||||
|
|
||||||
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
|
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
|
||||||
|
|
||||||
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||||
|
|
||||||
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ?
|
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
|
||||||
TRUE : FALSE;
|
|
||||||
|
if (!fAcceptFmt)
|
||||||
|
{
|
||||||
|
InitFormatEtc(fmt, RegisterClipboardFormatW(CFSTR_FILEDESCRIPTOR), TYMED_HGLOBAL);
|
||||||
|
fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
QueryDrop(dwKeyState, pdwEffect);
|
QueryDrop(dwKeyState, pdwEffect);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1417,219 @@ HRESULT WINAPI CFSFolder::DragLeave()
|
||||||
HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
||||||
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
{
|
{
|
||||||
FIXME("(%p) object dropped\n", this);
|
TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
|
||||||
|
|
||||||
return E_NOTIMPL;
|
HRESULT hr;
|
||||||
|
bool bCopy = TRUE;
|
||||||
|
bool bLinking = FALSE;
|
||||||
|
|
||||||
|
STGMEDIUM medium;
|
||||||
|
FORMATETC formatetc;
|
||||||
|
InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
|
||||||
|
hr = pDataObject->GetData(&formatetc, &medium);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
/* lock the handle */
|
||||||
|
LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
|
||||||
|
if (!lpcida)
|
||||||
|
{
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert the data into pidl */
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
|
||||||
|
if (!apidl)
|
||||||
|
{
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Figure out what drop operation we're doing */
|
||||||
|
if (pdwEffect)
|
||||||
|
{
|
||||||
|
TRACE("Current drop effect flag %i\n", *pdwEffect);
|
||||||
|
if (*pdwEffect & DROPEFFECT_MOVE)
|
||||||
|
bCopy = FALSE;
|
||||||
|
if (*pdwEffect & DROPEFFECT_LINK)
|
||||||
|
bLinking = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CComPtr<IShellFolder> psfDesktop;
|
||||||
|
CComPtr<IShellFolder> psfFrom = NULL;
|
||||||
|
CComPtr<IShellFolder> psfTarget = NULL;
|
||||||
|
|
||||||
|
hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("psfTarget setting failed\n");
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab the desktop shell folder */
|
||||||
|
hr = SHGetDesktopFolder(&psfDesktop);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("SHGetDesktopFolder failed\n");
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find source folder, this is where the clipboard data was copied from */
|
||||||
|
if (_ILIsDesktop(pidl))
|
||||||
|
{
|
||||||
|
/* use desktop shell folder */
|
||||||
|
psfFrom = psfDesktop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("no IShellFolder\n");
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bLinking)
|
||||||
|
{
|
||||||
|
CComPtr<IPersistFolder2> ppf2 = NULL;
|
||||||
|
STRRET strFile;
|
||||||
|
WCHAR wszTargetPath[MAX_PATH];
|
||||||
|
LPITEMIDLIST targetpidl;
|
||||||
|
WCHAR wszPath[MAX_PATH];
|
||||||
|
WCHAR wszTarget[MAX_PATH];
|
||||||
|
|
||||||
|
hr = this->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = ppf2->GetCurFolder(&targetpidl);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
|
||||||
|
ILFree(targetpidl);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Error obtaining target path");
|
||||||
|
|
||||||
|
}
|
||||||
|
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 */
|
||||||
|
for (UINT i = 0; i < lpcida->cidl; i++)
|
||||||
|
{
|
||||||
|
//Find out which file we're copying
|
||||||
|
STRRET strFile;
|
||||||
|
hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Error source obtaining path");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Error putting source path into buffer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TRACE("source path = %s", debugstr_w(wszPath));
|
||||||
|
|
||||||
|
// Creating a buffer to hold the combined path
|
||||||
|
WCHAR buffer_1[MAX_PATH] = L"";
|
||||||
|
WCHAR *lpStr1;
|
||||||
|
lpStr1 = buffer_1;
|
||||||
|
|
||||||
|
LPWSTR pwszFileName = PathFindFileNameW(wszPath);
|
||||||
|
LPWSTR pwszExt = PathFindExtensionW(wszPath);
|
||||||
|
LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, 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.
|
||||||
|
if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE))
|
||||||
|
{
|
||||||
|
ERR("Error getting unique file name");
|
||||||
|
hr = E_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ERR("Error constructing link from file");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = ppf->Save(wszTarget, FALSE);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ERR("Error instantiating IShellLinkW");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR szDirPath[MAX_PATH], *pwszFile;
|
||||||
|
GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
|
||||||
|
if (pwszFile) pwszFile[0] = 0;
|
||||||
|
|
||||||
|
hr = pLink->SetPath(wszPath);
|
||||||
|
if(FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = pLink->SetWorkingDirectory(szDirPath);
|
||||||
|
if(FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
||||||
|
if(FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = ppf->Save(wszTarget, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -43,11 +43,15 @@ class CFSFolder :
|
||||||
|
|
||||||
UINT cfShellIDList; /* clipboardformat for IDropTarget */
|
UINT cfShellIDList; /* clipboardformat for IDropTarget */
|
||||||
BOOL fAcceptFmt; /* flag for pending Drop */
|
BOOL fAcceptFmt; /* flag for pending Drop */
|
||||||
|
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
||||||
|
void SF_RegisterClipFmt();
|
||||||
|
BOOL GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
|
||||||
|
DWORD _DoDropThreadProc(LPVOID lpParameter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFSFolder();
|
CFSFolder();
|
||||||
~CFSFolder();
|
~CFSFolder();
|
||||||
void SF_RegisterClipFmt();
|
|
||||||
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
|
||||||
|
|
||||||
// IShellFolder
|
// IShellFolder
|
||||||
virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
|
virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
|
||||||
|
@ -107,6 +111,7 @@ class CFSFolder :
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3)
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
|
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
|
||||||
END_COM_MAP()
|
END_COM_MAP()
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,8 +94,9 @@ LPEXTRACTICONW IExtractIconW_Constructor(LPCITEMIDLIST);
|
||||||
|
|
||||||
#define KeyStateToDropEffect(kst)\
|
#define KeyStateToDropEffect(kst)\
|
||||||
((((kst)&(MK_CONTROL|MK_SHIFT))==(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_LINK :\
|
((((kst)&(MK_CONTROL|MK_SHIFT))==(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_LINK :\
|
||||||
(((kst)&(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_COPY :\
|
(((kst)&(MK_CONTROL)) ? DROPEFFECT_COPY :\
|
||||||
DROPEFFECT_MOVE))
|
(((kst)&(MK_SHIFT)) ? DROPEFFECT_MOVE :\
|
||||||
|
DROPEFFECT_NONE)))
|
||||||
|
|
||||||
|
|
||||||
HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl);
|
HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl);
|
||||||
|
|
|
@ -937,7 +937,10 @@ LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
|
if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
|
||||||
RegisterDragDrop(m_hWnd, pdt);
|
{
|
||||||
|
if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
|
||||||
|
ERR("Registering Drag Drop Failed");
|
||||||
|
}
|
||||||
|
|
||||||
/* register for receiving notifications */
|
/* register for receiving notifications */
|
||||||
m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
|
m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
|
||||||
|
@ -1688,6 +1691,8 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
|
||||||
{
|
{
|
||||||
DWORD dwEffect2;
|
DWORD dwEffect2;
|
||||||
DoDragDrop(pda, pds, dwEffect, &dwEffect2);
|
DoDragDrop(pda, pds, dwEffect, &dwEffect2);
|
||||||
|
if ((dwEffect2 & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
|
||||||
|
this->Refresh();
|
||||||
}
|
}
|
||||||
pda->Release();
|
pda->Release();
|
||||||
}
|
}
|
||||||
|
@ -2482,10 +2487,11 @@ HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINT
|
||||||
{
|
{
|
||||||
m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
|
m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
|
||||||
m_pCurDropTarget.Release();
|
m_pCurDropTarget.Release();
|
||||||
|
|
||||||
|
this->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pCurDataObject.Release();
|
m_pCurDataObject.Release(); m_iDragOverItem = 0;
|
||||||
m_iDragOverItem = 0;
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue