Author: akhaldi
Date: Thu Dec 19 12:51:32 2013
New Revision: 61294
URL:
http://svn.reactos.org/svn/reactos?rev=61294&view=rev
Log:
[SHELL32]
* Initial go at the Drag & Drop support. Work is still ongoing here. Brought to you by
Huw Campbell.
CORE-3760
Modified:
trunk/reactos/dll/win32/shell32/defcontextmenu.cpp
trunk/reactos/dll/win32/shell32/folders/desktop.cpp
trunk/reactos/dll/win32/shell32/folders/desktop.h
trunk/reactos/dll/win32/shell32/folders/fs.cpp
trunk/reactos/dll/win32/shell32/folders/fs.h
trunk/reactos/dll/win32/shell32/shell32_main.h
trunk/reactos/dll/win32/shell32/shlview.cpp
Modified: trunk/reactos/dll/win32/shell32/defcontextmenu.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/defconte…
==============================================================================
--- trunk/reactos/dll/win32/shell32/defcontextmenu.cpp [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/defcontextmenu.cpp [iso-8859-1] Thu Dec 19 12:51:32
2013
@@ -58,8 +58,7 @@
UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast,
UINT uFlags);
UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast,
UINT uFlags);
- HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi);
- HRESULT DoPasteLink(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink);
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
@@ -947,7 +946,7 @@
HRESULT
CDefaultContextMenu::DoPaste(
- LPCMINVOKECOMMANDINFO lpcmi)
+ LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
{
HRESULT hr;
@@ -956,56 +955,12 @@
if (FAILED(hr))
return hr;
- STGMEDIUM medium;
- FORMATETC formatetc;
- InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST),
TYMED_HGLOBAL);
- hr = pda->GetData(&formatetc, &medium);
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfTarget = NULL;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
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> psfFrom = NULL;
- CComPtr<IShellFolder> psfTarget = NULL;
- CComPtr<ISFHelper> psfhlpdst;
- CComPtr<ISFHelper> psfhlpsrc;
- bool bCopy = TRUE;
-
- hr = SHGetDesktopFolder(&psfDesktop);
- if (FAILED(hr))
- goto cleanup;
-
- /* 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 */
if (m_Dcm.cidl)
@@ -1043,350 +998,117 @@
if (FAILED(hr))
{
ERR("no IShellFolder\n");
- goto cleanup;
- }
-
- /* 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;
+ return hr;
}
FORMATETC formatetc2;
STGMEDIUM medium2;
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);
if (pdwFlag)
{
- TRACE("Current drop effect flag %i\n", *pdwFlag);
- if (*pdwFlag & DROPEFFECT_MOVE)
- bCopy = FALSE;
+ if (*pdwFlag == DROPEFFECT_COPY)
+ dwKey = MK_CONTROL;
+ else
+ dwKey = MK_SHIFT;
+ }
+ else {
+ ERR("No drop effect obtained");
}
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);
-
-cleanup:
- SHFree(pidl);
- _ILFreeaPidl(apidl, lpcida->cidl);
- ReleaseStgMedium(&medium);
TRACE("CP result %x\n", hr);
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(
+HRESULT
+CDefaultContextMenu::DoOpenOrExplore(
LPCMINVOKECOMMANDINFO lpcmi)
{
+ UNIMPLEMENTED;
+ return E_FAIL;
+}
+
+HRESULT
+CDefaultContextMenu::DoCreateLink(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ LPDATAOBJECT pDataObj;
+ IDropTarget *pDT;
HRESULT hr;
- WCHAR wszPath[MAX_PATH];
- WCHAR wszTarget[MAX_PATH];
-
- CComPtr<IDataObject> pda;
- hr = OleGetClipboard(&pda);
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ LPITEMIDLIST pidl;
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfTarget = NULL;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
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
-CDefaultContextMenu::DoOpenOrExplore(
- LPCMINVOKECOMMANDINFO lpcmi)
-{
- UNIMPLEMENTED;
- return E_FAIL;
-}
-
-HRESULT
-CDefaultContextMenu::DoCreateLink(
- LPCMINVOKECOMMANDINFO lpcmi)
-{
- WCHAR wszTarget[MAX_PATH];
- IPersistFile *ppf;
- HRESULT hr;
- STRRET strFile;
-
- hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
- 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))
- return hr;
-
- LPWSTR pwszExt = PathFindExtensionW(wszPath);
-
- if (!wcsicmp(pwszExt, L".lnk"))
- {
- if (!GetUniqueFileName(wszPath, pwszExt, wszTarget, TRUE))
- return E_FAIL;
-
- IPersistFolder2 *ppf2 = NULL;
- LPITEMIDLIST pidl;
+ if (SUCCEEDED(hr = SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl,
NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
+ {
hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
if (SUCCEEDED(hr))
{
hr = ppf2->GetCurFolder(&pidl);
- ppf2->Release();
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);
+ {
+ if (_ILIsDesktop(pidl))
+ {
+ /* 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);
+ }
+ }
+
+ }
+
+ if (FAILED(hr))
+ {
+ ERR("no IShellFolder\n");
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);
- ppf->Release();
- }
- }
- pLink->Release();
- NotifyShellViewWindow(lpcmi, TRUE);
+
+ 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
@@ -1843,9 +1565,9 @@
case FCIDM_SHVIEW_REFRESH:
return NotifyShellViewWindow(lpcmi, FALSE);
case FCIDM_SHVIEW_INSERT:
- return DoPaste(lpcmi);
+ return DoPaste(lpcmi, FALSE);
case FCIDM_SHVIEW_INSERTLINK:
- return DoPasteLink(lpcmi);
+ return DoPaste(lpcmi, TRUE);
case FCIDM_SHVIEW_OPEN:
case FCIDM_SHVIEW_EXPLORE:
return DoOpenOrExplore(lpcmi);
Modified: trunk/reactos/dll/win32/shell32/folders/desktop.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/…
==============================================================================
--- trunk/reactos/dll/win32/shell32/folders/desktop.cpp [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/folders/desktop.cpp [iso-8859-1] Thu Dec 19 12:51:32
2013
@@ -254,10 +254,21 @@
return ret ? S_OK : E_FAIL;
}
+void CDesktopFolder::SF_RegisterClipFmt()
+{
+ TRACE ("(%p)\n", this);
+
+ if (!cfShellIDList)
+ cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
+}
+
CDesktopFolder::CDesktopFolder()
{
pidlRoot = NULL;
sPathTarget = NULL;
+ cfShellIDList = 0;
+ SF_RegisterClipFmt();
+ fAcceptFmt = FALSE;
}
CDesktopFolder::~CDesktopFolder()
@@ -512,8 +523,7 @@
if (IsEqualIID (riid, IID_IDropTarget))
{
- WARN ("IDropTarget not implemented\n");
- hr = E_NOTIMPL;
+ hr = this->QueryInterface (IID_IDropTarget, ppvOut);
}
else if (IsEqualIID (riid, IID_IContextMenu))
{
@@ -638,9 +648,12 @@
SHFree (pidl);
hr = S_OK;
}
- else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
- {
- hr = this->QueryInterface (IID_IDropTarget, (LPVOID *)&pObj);
+ else if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ /* 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) ||
IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
@@ -1326,3 +1339,137 @@
}
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;
+}
Modified: trunk/reactos/dll/win32/shell32/folders/desktop.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/…
==============================================================================
--- trunk/reactos/dll/win32/shell32/folders/desktop.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/folders/desktop.h [iso-8859-1] Thu Dec 19 12:51:32
2013
@@ -28,15 +28,19 @@
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2,
public IPersistFolder2,
+ public IDropTarget,
public ISFHelper
{
private:
/* both paths are parsible from the desktop */
LPWSTR sPathTarget; /* complete path to target used for enumeration and
ChangeNotify */
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:
CDesktopFolder();
~CDesktopFolder();
@@ -72,6 +76,13 @@
// *** IPersistFolder2 methods ***
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 ***
virtual HRESULT WINAPI GetUniqueName(LPWSTR pwszName, UINT uLen);
virtual HRESULT WINAPI AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST
*ppidlOut);
@@ -89,6 +100,7 @@
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
END_COM_MAP()
};
Modified: trunk/reactos/dll/win32/shell32/folders/fs.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/…
==============================================================================
--- trunk/reactos/dll/win32/shell32/folders/fs.cpp [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/folders/fs.cpp [iso-8859-1] Thu Dec 19 12:51:32 2013
@@ -79,6 +79,7 @@
sPathTarget = NULL;
pidlRoot = NULL;
cfShellIDList = 0;
+ SF_RegisterClipFmt();
fAcceptFmt = FALSE;
}
@@ -498,10 +499,15 @@
SHFree (pidl);
hr = S_OK;
}
- else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
- hr = this->QueryInterface(IID_IDropTarget, (LPVOID*)&pObj);
+ else if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ /* 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) ||
- IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
+ IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
{
pidl = ILCombine (pidlRoot, apidl[0]);
hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
@@ -571,9 +577,9 @@
{
/*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
if (!(dwFlags & SHGDN_FORPARSING) &&
- ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
- if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
- PathRemoveExtensionW(szPath);
+ ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
+ if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
+ PathRemoveExtensionW(szPath);
}
}
@@ -808,7 +814,7 @@
{
case 0: /* name */
hr = GetDisplayNameOf (pidl,
- SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
break;
case 1: /* size */
_ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
@@ -931,7 +937,7 @@
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
_countof(wszTempText));
LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
- _countof(wszCaption));
+ _countof(wszCaption));
swprintf(wszText, wszTempText, wszNewDir);
MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
}
@@ -1314,17 +1320,50 @@
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)
{
- 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;
if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
*pdwEffect = KeyStateToDropEffect (dwKeyState);
+
+ if (*pdwEffect == DROPEFFECT_NONE)
+ *pdwEffect = dwEffect;
/* ... matches the desired effect ? */
if (dwEffect & *pdwEffect) {
@@ -1338,16 +1377,18 @@
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
{
FORMATETC fmt;
-
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
-
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
- fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ?
- TRUE : FALSE;
+ fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
+
+ if (!fAcceptFmt)
+ {
+ InitFormatEtc(fmt, RegisterClipboardFormatW(CFSTR_FILEDESCRIPTOR),
TYMED_HGLOBAL);
+ fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? TRUE : FALSE;
+ }
QueryDrop(dwKeyState, pdwEffect);
-
return S_OK;
}
@@ -1376,7 +1417,219 @@
HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
{
- FIXME("(%p) object dropped\n", this);
-
- return E_NOTIMPL;
-}
+ TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
+
+ 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;
+}
Modified: trunk/reactos/dll/win32/shell32/folders/fs.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/…
==============================================================================
--- trunk/reactos/dll/win32/shell32/folders/fs.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/folders/fs.h [iso-8859-1] Thu Dec 19 12:51:32 2013
@@ -43,11 +43,15 @@
UINT cfShellIDList; /* clipboardformat for IDropTarget */
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:
CFSFolder();
~CFSFolder();
- void SF_RegisterClipFmt();
- BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
+
// IShellFolder
virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR
lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
@@ -107,6 +111,7 @@
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3)
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper)
END_COM_MAP()
};
Modified: trunk/reactos/dll/win32/shell32/shell32_main.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/shell32_…
==============================================================================
--- trunk/reactos/dll/win32/shell32/shell32_main.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/shell32_main.h [iso-8859-1] Thu Dec 19 12:51:32 2013
@@ -94,8 +94,9 @@
#define KeyStateToDropEffect(kst)\
((((kst)&(MK_CONTROL|MK_SHIFT))==(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_LINK :\
- (((kst)&(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_COPY :\
- DROPEFFECT_MOVE))
+ (((kst)&(MK_CONTROL)) ? DROPEFFECT_COPY :\
+ (((kst)&(MK_SHIFT)) ? DROPEFFECT_MOVE :\
+ DROPEFFECT_NONE)))
HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl);
Modified: trunk/reactos/dll/win32/shell32/shlview.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/shlview.…
==============================================================================
--- trunk/reactos/dll/win32/shell32/shlview.cpp [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/shell32/shlview.cpp [iso-8859-1] Thu Dec 19 12:51:32 2013
@@ -937,7 +937,10 @@
}
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 */
m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
@@ -1688,6 +1691,8 @@
{
DWORD dwEffect2;
DoDragDrop(pda, pds, dwEffect, &dwEffect2);
+ if ((dwEffect2 & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
+ this->Refresh();
}
pda->Release();
}
@@ -2482,10 +2487,11 @@
{
m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
m_pCurDropTarget.Release();
- }
-
- m_pCurDataObject.Release();
- m_iDragOverItem = 0;
+
+ this->Refresh();
+ }
+
+ m_pCurDataObject.Release(); m_iDragOverItem = 0;
return S_OK;
}