[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:
Amine Khaldi 2013-12-19 12:51:32 +00:00
parent e9a8c50011
commit d6218793bb
7 changed files with 521 additions and 375 deletions

View file

@ -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);
if SUCCEEDED(pda->GetData(&formatetc2, &medium2)) DWORD dwKey= 0;
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);

View file

@ -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;
}

View file

@ -28,6 +28,7 @@ class CDesktopFolder :
public CComObjectRootEx<CComMultiThreadModelNoCS>, public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2, public IShellFolder2,
public IPersistFolder2, public IPersistFolder2,
public IDropTarget,
public ISFHelper public ISFHelper
{ {
private: private:
@ -35,8 +36,11 @@ class CDesktopFolder :
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 */
// CComPtr<IShellFolder2> fDesktopFolder; UINT cfShellIDList; /* clipboardformat for IDropTarget */
// CComPtr<IShellFolder2> fCommonDesktopFolder; BOOL fAcceptFmt; /* flag for pending Drop */
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
void SF_RegisterClipFmt();
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()
}; };

View file

@ -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;
} }

View file

@ -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()
}; };

View file

@ -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);

View file

@ -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;
} }