mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:12:56 +00:00
[SHELL32]
* Move shell file operations to background threads to prevent the shell from hanging during long copies, deletes, and moves. * Improve drag and drop functionality. * Add a partial drop handler to the recycle bin. * Brought to you by Huw Campbell. CORE-3760 svn path=/trunk/; revision=61537
This commit is contained in:
parent
aa4d139a0c
commit
3ad827aa50
6 changed files with 293 additions and 69 deletions
|
@ -1037,7 +1037,6 @@ CDefaultContextMenu::DoPaste(
|
||||||
}
|
}
|
||||||
|
|
||||||
SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
|
SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
|
||||||
|
|
||||||
TRACE("CP result %x\n", hr);
|
TRACE("CP result %x\n", hr);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
@ -1104,73 +1103,24 @@ CDefaultContextMenu::DoCreateLink(
|
||||||
ERR("no IDropTarget Interface\n");
|
ERR("no IDropTarget Interface\n");
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
//DWORD link = DROPEFFECT_LINK;
|
|
||||||
SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
|
SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) {
|
||||||
CDefaultContextMenu::DoDelete(
|
TRACE("(%p) Deleting\n", this);
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
|
||||||
{
|
LPDATAOBJECT pDataObj;
|
||||||
STRRET strTemp;
|
|
||||||
HRESULT hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strTemp);
|
if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
|
||||||
if(hr != S_OK)
|
|
||||||
{
|
{
|
||||||
ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
|
pDataObj->AddRef();
|
||||||
return hr;
|
SHCreateThread(DoDeleteThreadProc, pDataObj, NULL, NULL);
|
||||||
|
pDataObj->Release();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
WCHAR wszPath[MAX_PATH];
|
|
||||||
hr = StrRetToBufW(&strTemp, m_Dcm.apidl[0], wszPath, _countof(wszPath));
|
|
||||||
if (hr != S_OK)
|
|
||||||
{
|
|
||||||
ERR("StrRetToBufW failed with %x\n", hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only keep the base path */
|
|
||||||
LPWSTR pwszFilename = PathFindFileNameW(wszPath);
|
|
||||||
*pwszFilename = L'\0';
|
|
||||||
|
|
||||||
/* Build paths list */
|
|
||||||
LPWSTR pwszPaths = BuildPathsList(wszPath, m_Dcm.cidl, m_Dcm.apidl);
|
|
||||||
if (!pwszPaths)
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
/* Delete them */
|
|
||||||
SHFILEOPSTRUCTW FileOp;
|
|
||||||
ZeroMemory(&FileOp, sizeof(FileOp));
|
|
||||||
FileOp.hwnd = GetActiveWindow();
|
|
||||||
FileOp.wFunc = FO_DELETE;
|
|
||||||
FileOp.pFrom = pwszPaths;
|
|
||||||
FileOp.fFlags = FOF_ALLOWUNDO;
|
|
||||||
|
|
||||||
if (SHFileOperationW(&FileOp) != 0)
|
|
||||||
{
|
|
||||||
ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the active IShellView */
|
|
||||||
LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
|
||||||
if (lpSB)
|
|
||||||
{
|
|
||||||
/* Is the treeview focused */
|
|
||||||
HWND hwnd;
|
|
||||||
if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
|
|
||||||
{
|
|
||||||
/* Remove selected items from treeview */
|
|
||||||
HTREEITEM hItem = TreeView_GetSelection(hwnd);
|
|
||||||
if (hItem)
|
|
||||||
(void)TreeView_DeleteItem(hwnd, hItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NotifyShellViewWindow(lpcmi, TRUE);
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, pwszPaths);
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1419,6 +1419,27 @@ HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
||||||
{
|
{
|
||||||
TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
|
TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
|
||||||
|
|
||||||
|
_DoDropData *data = reinterpret_cast<_DoDropData*> (HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
|
||||||
|
data->This = this;
|
||||||
|
// Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
|
||||||
|
data->This->AddRef();
|
||||||
|
data->pDataObject = pDataObject;
|
||||||
|
// Also keep the data object in case it gets freed elsewhere.
|
||||||
|
data->pDataObject->AddRef();
|
||||||
|
data->dwKeyState = dwKeyState;
|
||||||
|
data->pt = pt;
|
||||||
|
// Need to dereference as pdweffect is freed.
|
||||||
|
data->pdwEffect = *pdwEffect;
|
||||||
|
|
||||||
|
SHCreateThread(reinterpret_cast<LPTHREAD_START_ROUTINE> (CFSFolder::_DoDropThreadProc), reinterpret_cast<void *> (data), NULL, NULL);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
|
||||||
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
bool bCopy = TRUE;
|
bool bCopy = TRUE;
|
||||||
bool bLinking = FALSE;
|
bool bLinking = FALSE;
|
||||||
|
@ -1451,9 +1472,9 @@ HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
||||||
if (pdwEffect)
|
if (pdwEffect)
|
||||||
{
|
{
|
||||||
TRACE("Current drop effect flag %i\n", *pdwEffect);
|
TRACE("Current drop effect flag %i\n", *pdwEffect);
|
||||||
if (*pdwEffect & DROPEFFECT_MOVE)
|
if ((*pdwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
|
||||||
bCopy = FALSE;
|
bCopy = FALSE;
|
||||||
if (*pdwEffect & DROPEFFECT_LINK)
|
if ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
|
||||||
bLinking = TRUE;
|
bLinking = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,5 +1652,12 @@ HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
|
DWORD CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
|
||||||
|
_DoDropData *data = reinterpret_cast<_DoDropData*>(lpParameter);
|
||||||
|
data->This->_DoDrop(data->pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
|
||||||
|
//Release the CFSFolder and data object holds in the copying thread.
|
||||||
|
data->pDataObject->Release();
|
||||||
|
data->This->Release();
|
||||||
|
//Release the parameter from the heap.
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -46,7 +46,8 @@ class CFSFolder :
|
||||||
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
||||||
void SF_RegisterClipFmt();
|
void SF_RegisterClipFmt();
|
||||||
BOOL GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
|
BOOL GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
|
||||||
DWORD _DoDropThreadProc(LPVOID lpParameter);
|
static DWORD _DoDropThreadProc(LPVOID lpParameter);
|
||||||
|
virtual HRESULT WINAPI _DoDrop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFSFolder();
|
CFSFolder();
|
||||||
|
@ -116,4 +117,12 @@ class CFSFolder :
|
||||||
END_COM_MAP()
|
END_COM_MAP()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _DoDropData {
|
||||||
|
CFSFolder *This;
|
||||||
|
IDataObject *pDataObject;
|
||||||
|
DWORD dwKeyState;
|
||||||
|
POINTL pt;
|
||||||
|
DWORD pdwEffect;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // _CFSFOLDER_H_
|
#endif // _CFSFOLDER_H_
|
||||||
|
|
|
@ -429,10 +429,24 @@ static HRESULT WINAPI CRecycleBinItemContextMenuConstructor(REFIID riid, LPCITEM
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* registers clipboardformat once
|
||||||
|
*/
|
||||||
|
void CRecycleBin::SF_RegisterClipFmt()
|
||||||
|
{
|
||||||
|
TRACE ("(%p)\n", this);
|
||||||
|
|
||||||
|
if (!cfShellIDList)
|
||||||
|
cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
|
||||||
|
}
|
||||||
|
|
||||||
CRecycleBin::CRecycleBin()
|
CRecycleBin::CRecycleBin()
|
||||||
{
|
{
|
||||||
pidl = NULL;
|
pidl = NULL;
|
||||||
iIdEmpty = 0;
|
iIdEmpty = 0;
|
||||||
|
cfShellIDList = 0;
|
||||||
|
SF_RegisterClipFmt();
|
||||||
|
fAcceptFmt = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CRecycleBin::~CRecycleBin()
|
CRecycleBin::~CRecycleBin()
|
||||||
|
@ -556,8 +570,7 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void *
|
||||||
|
|
||||||
if (IsEqualIID (riid, IID_IDropTarget))
|
if (IsEqualIID (riid, IID_IDropTarget))
|
||||||
{
|
{
|
||||||
WARN ("IDropTarget not implemented\n");
|
hr = this->QueryInterface (IID_IDropTarget, ppv);
|
||||||
hr = E_NOTIMPL;
|
|
||||||
}
|
}
|
||||||
else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2))
|
else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2))
|
||||||
{
|
{
|
||||||
|
@ -605,7 +618,7 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLI
|
||||||
{
|
{
|
||||||
hr = CRecycleBinItemContextMenuConstructor(riid, apidl[0], (void **)&pObj);
|
hr = CRecycleBinItemContextMenuConstructor(riid, apidl[0], (void **)&pObj);
|
||||||
}
|
}
|
||||||
else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
|
else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
|
||||||
{
|
{
|
||||||
hr = this->QueryInterface(IID_IDropTarget, (LPVOID *) & pObj);
|
hr = this->QueryInterface(IID_IDropTarget, (LPVOID *) & pObj);
|
||||||
}
|
}
|
||||||
|
@ -1372,3 +1385,214 @@ EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void)
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* IDropTarget implementation
|
||||||
|
*/
|
||||||
|
BOOL CRecycleBin::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
||||||
|
{
|
||||||
|
/* TODO on shift we should delete, we should update the cursor manager to show this. */
|
||||||
|
|
||||||
|
DWORD dwEffect = DROPEFFECT_COPY;
|
||||||
|
|
||||||
|
*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 CRecycleBin::DragEnter(IDataObject *pDataObject,
|
||||||
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
FIXME("Recycle bin drag over (%p)\n", this);
|
||||||
|
/* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
|
||||||
|
fAcceptFmt = TRUE;
|
||||||
|
|
||||||
|
QueryDrop(dwKeyState, pdwEffect);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CRecycleBin::DragOver(DWORD dwKeyState, POINTL pt,
|
||||||
|
DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
TRACE("(%p)\n", this);
|
||||||
|
|
||||||
|
if (!pdwEffect)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
QueryDrop(dwKeyState, pdwEffect);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CRecycleBin::DragLeave()
|
||||||
|
{
|
||||||
|
TRACE("(%p)\n", this);
|
||||||
|
|
||||||
|
fAcceptFmt = FALSE;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI CRecycleBin::Drop(IDataObject *pDataObject,
|
||||||
|
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
|
||||||
|
{
|
||||||
|
FIXME("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect);
|
||||||
|
|
||||||
|
/* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */
|
||||||
|
|
||||||
|
FORMATETC fmt;
|
||||||
|
TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
|
||||||
|
InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
|
||||||
|
|
||||||
|
/* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */
|
||||||
|
if (SUCCEEDED(pDataObject->QueryGetData(&fmt))) {
|
||||||
|
pDataObject->AddRef();
|
||||||
|
SHCreateThread(DoDeleteThreadProc, pDataObject, NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* TODO call SetData on the data object with format CFSTR_TARGETCLSID
|
||||||
|
* set to the Recycle Bin's class identifier CLSID_RecycleBin.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter)
|
||||||
|
{
|
||||||
|
IDataObject *pda = (IDataObject*) lpParameter;
|
||||||
|
DoDeleteDataObject(pda);
|
||||||
|
//Release the data object
|
||||||
|
pda->Release();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
|
||||||
|
{
|
||||||
|
TRACE("performing delete");
|
||||||
|
HRESULT 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> psfFrom = NULL;
|
||||||
|
|
||||||
|
/* 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))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STRRET strTemp;
|
||||||
|
hr = psfFrom->GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strTemp);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR wszPath[MAX_PATH];
|
||||||
|
hr = StrRetToBufW(&strTemp, apidl[0], wszPath, _countof(wszPath));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("StrRetToBufW failed with %x\n", hr);
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only keep the base path */
|
||||||
|
LPWSTR pwszFilename = PathFindFileNameW(wszPath);
|
||||||
|
*pwszFilename = L'\0';
|
||||||
|
|
||||||
|
/* Build paths list */
|
||||||
|
LPWSTR pwszPaths = BuildPathsList(wszPath, lpcida->cidl, (LPCITEMIDLIST*) apidl);
|
||||||
|
if (!pwszPaths)
|
||||||
|
{
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete them */
|
||||||
|
SHFILEOPSTRUCTW FileOp;
|
||||||
|
ZeroMemory(&FileOp, sizeof(FileOp));
|
||||||
|
FileOp.wFunc = FO_DELETE;
|
||||||
|
FileOp.pFrom = pwszPaths;
|
||||||
|
FileOp.fFlags = FOF_ALLOWUNDO;
|
||||||
|
|
||||||
|
if (SHFileOperationW(&FileOp) != 0)
|
||||||
|
{
|
||||||
|
ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, pwszPaths);
|
||||||
|
SHFree(pidl);
|
||||||
|
_ILFreeaPidl(apidl, lpcida->cidl);
|
||||||
|
ReleaseStgMedium(&medium);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
|
@ -22,6 +22,9 @@
|
||||||
#ifndef _SHFLDR_RECYCLEBIN_H_
|
#ifndef _SHFLDR_RECYCLEBIN_H_
|
||||||
#define _SHFLDR_RECYCLEBIN_H_
|
#define _SHFLDR_RECYCLEBIN_H_
|
||||||
|
|
||||||
|
DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter);
|
||||||
|
HRESULT WINAPI DoDeleteDataObject(IDataObject *pda);
|
||||||
|
|
||||||
class CRecycleBin :
|
class CRecycleBin :
|
||||||
public CComCoClass<CRecycleBin, &CLSID_RecycleBin>,
|
public CComCoClass<CRecycleBin, &CLSID_RecycleBin>,
|
||||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
@ -29,11 +32,16 @@ class CRecycleBin :
|
||||||
public IPersistFolder2,
|
public IPersistFolder2,
|
||||||
public IContextMenu,
|
public IContextMenu,
|
||||||
public IShellPropSheetExt,
|
public IShellPropSheetExt,
|
||||||
|
public IDropTarget,
|
||||||
public IShellExtInit
|
public IShellExtInit
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
LPITEMIDLIST pidl;
|
LPITEMIDLIST pidl;
|
||||||
INT iIdEmpty;
|
INT iIdEmpty;
|
||||||
|
UINT cfShellIDList;
|
||||||
|
void SF_RegisterClipFmt();
|
||||||
|
BOOL fAcceptFmt; /* flag for pending Drop */
|
||||||
|
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRecycleBin();
|
CRecycleBin();
|
||||||
|
@ -76,6 +84,12 @@ class CRecycleBin :
|
||||||
virtual HRESULT WINAPI AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
|
virtual HRESULT WINAPI AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
|
||||||
virtual HRESULT WINAPI ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam);
|
virtual HRESULT WINAPI ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
// IShellExtInit
|
// IShellExtInit
|
||||||
virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
|
virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
|
||||||
|
|
||||||
|
@ -91,6 +105,7 @@ class CRecycleBin :
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt)
|
COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
|
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
|
||||||
END_COM_MAP()
|
END_COM_MAP()
|
||||||
};
|
};
|
||||||
|
|
|
@ -1691,8 +1691,6 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue