From 03799e9baa8cbaad09209fc35a3cd47410adcef7 Mon Sep 17 00:00:00 2001 From: flaviu22 Date: Thu, 26 Sep 2024 17:12:22 +0300 Subject: [PATCH] Solved undo deleted item. --- Explorer++/Explorer++/DefaultAccelerators.cpp | 1 + Explorer++/Explorer++/Explorer++.rc | Bin 186024 -> 186024 bytes Explorer++/Explorer++/Explorer++VersionInfo.h | Bin 1174 -> 1422 bytes Explorer++/Explorer++/NoTranslationResource.h | 8 + .../ShellBrowser/ShellBrowserImpl.cpp | 4 +- .../ShellTreeView/ShellTreeView.cpp | 4 +- Explorer++/Helper/FileActionHandler.cpp | 12 +- Explorer++/Helper/FileActionHandler.h | 1 + Explorer++/Helper/FileOperations.cpp | 147 ++++++++++++++---- Explorer++/Helper/FileOperations.h | 109 +++++++++++-- 10 files changed, 236 insertions(+), 50 deletions(-) diff --git a/Explorer++/Explorer++/DefaultAccelerators.cpp b/Explorer++/Explorer++/DefaultAccelerators.cpp index 653b6238c..cf9505c7a 100644 --- a/Explorer++/Explorer++/DefaultAccelerators.cpp +++ b/Explorer++/Explorer++/DefaultAccelerators.cpp @@ -54,6 +54,7 @@ constexpr ACCEL g_defaultAccelerators[] = { { FVIRTKEY | FCONTROL | FSHIFT, 'W', IDM_EDIT_WILDCARDDESELECT }, { FVIRTKEY | FCONTROL | FSHIFT, 'S', IDM_EDIT_WILDCARDSELECTION }, { FVIRTKEY | FCONTROL, 'W', IDM_FILE_CLOSETAB }, + { FVIRTKEY | FCONTROL, 'Q', IDM_FILE_EXIT }, { FVIRTKEY | FCONTROL, VK_F4, IDM_FILE_CLOSETAB }, { FVIRTKEY | FCONTROL | FSHIFT, 'P', IDM_FILE_COPYFOLDERPATH }, { FVIRTKEY | FSHIFT, VK_DELETE, IDM_FILE_DELETEPERMANENTLY }, diff --git a/Explorer++/Explorer++/Explorer++.rc b/Explorer++/Explorer++/Explorer++.rc index 30b23173fe71bcc58e4be1b1124b58e59e0b5b8d..1f69f5bcf36ae6bd164c8bb531c6a72b24a78ddf 100644 GIT binary patch delta 47 zcmZ3nmV3oo?uIRlTHgFI3?&TCKwQL-!=TL&IQ?NQqxN(KFGjBRJa5MBdEQJ`-2hy! B4gdfE delta 35 rcmZ3nmV3oo?uIRlTHe#Yv@ps|PEZh;-r&h7)Sli+QpbtJ35GW(zPa!(s!b&#+hl=?Va-x(QYQ diff --git a/Explorer++/Explorer++/NoTranslationResource.h b/Explorer++/Explorer++/NoTranslationResource.h index 70f830a5f..be568e033 100644 --- a/Explorer++/Explorer++/NoTranslationResource.h +++ b/Explorer++/Explorer++/NoTranslationResource.h @@ -473,9 +473,17 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS +#ifndef _APS_NEXT_RESOURCE_VALUE #define _APS_NEXT_RESOURCE_VALUE 40432 +#endif +#ifndef _APS_NEXT_COMMAND_VALUE #define _APS_NEXT_COMMAND_VALUE 32769 +#endif +#ifndef _APS_NEXT_CONTROL_VALUE #define _APS_NEXT_CONTROL_VALUE 1000 +#endif +#ifndef _APS_NEXT_SYMED_VALUE #define _APS_NEXT_SYMED_VALUE 40532 #endif #endif +#endif diff --git a/Explorer++/Explorer++/ShellBrowser/ShellBrowserImpl.cpp b/Explorer++/Explorer++/ShellBrowser/ShellBrowserImpl.cpp index 1cb6e26d0..c6c8e66aa 100644 --- a/Explorer++/Explorer++/ShellBrowser/ShellBrowserImpl.cpp +++ b/Explorer++/Explorer++/ShellBrowser/ShellBrowserImpl.cpp @@ -1160,8 +1160,8 @@ FolderSettings ShellBrowserImpl::GetFolderSettings() const void ShellBrowserImpl::DeleteSelectedItems(bool permanent) { + int item{ -1 }; std::vector pidls; - int item = -1; while ((item = ListView_GetNextItem(m_hListView, item, LVNI_SELECTED)) != -1) { @@ -1179,7 +1179,7 @@ void ShellBrowserImpl::DeleteSelectedItems(bool permanent) void ShellBrowserImpl::StartRenamingSelectedItems() { - int numSelected = ListView_GetSelectedCount(m_hListView); + const auto numSelected = ListView_GetSelectedCount(m_hListView); // If there is only item selected, start editing it in-place. If multiple items are selected, // show the mass rename dialog. diff --git a/Explorer++/Explorer++/ShellTreeView/ShellTreeView.cpp b/Explorer++/Explorer++/ShellTreeView/ShellTreeView.cpp index fe803d8b3..2770c8585 100644 --- a/Explorer++/Explorer++/ShellTreeView/ShellTreeView.cpp +++ b/Explorer++/Explorer++/ShellTreeView/ShellTreeView.cpp @@ -1362,9 +1362,7 @@ void ShellTreeView::ShowPropertiesOfSelectedItem() const void ShellTreeView::DeleteSelectedItem(bool permanent) { - HTREEITEM item = TreeView_GetSelection(m_hTreeView); - auto pidl = GetNodePidl(item); - + auto pidl = GetNodePidl(TreeView_GetSelection(m_hTreeView)); m_fileActionHandler->DeleteFiles(m_hTreeView, { pidl.get() }, permanent, false); } diff --git a/Explorer++/Helper/FileActionHandler.cpp b/Explorer++/Helper/FileActionHandler.cpp index 42223b71f..718ad200f 100644 --- a/Explorer++/Helper/FileActionHandler.cpp +++ b/Explorer++/Helper/FileActionHandler.cpp @@ -60,13 +60,14 @@ BOOL FileActionHandler::RenameFiles(const RenamedItems_t &itemList) HRESULT FileActionHandler::DeleteFiles(HWND hwnd, const DeletedItems_t &deletedItems, bool permanent, bool silent) { - HRESULT hr = FileOperations::DeleteFiles(hwnd, deletedItems, permanent, silent); + DeletedItems_t temp(deletedItems); + const HRESULT hr = FileOperations::DeleteFiles(hwnd, temp, permanent, silent); if (SUCCEEDED(hr)) { UndoItem_t undoItem; undoItem.type = UndoType::Deleted; - undoItem.deletedItems = deletedItems; + undoItem.deletedItems = temp; m_stackFileActions.push(undoItem); } @@ -77,7 +78,7 @@ void FileActionHandler::Undo() { if (!m_stackFileActions.empty()) { - UndoItem_t &undoItem = m_stackFileActions.top(); + UndoItem_t& undoItem = m_stackFileActions.top(); switch (undoItem.type) { @@ -127,6 +128,11 @@ void FileActionHandler::UndoDeleteOperation(const DeletedItems_t &deletedItemLis - Find the item in the recycle bin (probably need to read INFO2 file). - Restore it (context menu command). - Push delete action onto stack. */ + + for (const auto& item : deletedItemList) + { + FileOperations::Undelete(item); + } } BOOL FileActionHandler::CanUndo() const diff --git a/Explorer++/Helper/FileActionHandler.h b/Explorer++/Helper/FileActionHandler.h index cb8310c39..b90440a02 100644 --- a/Explorer++/Helper/FileActionHandler.h +++ b/Explorer++/Helper/FileActionHandler.h @@ -46,5 +46,6 @@ class FileActionHandler void UndoRenameOperation(const RenamedItems_t &renamedItemList); void UndoDeleteOperation(const DeletedItems_t &deletedItemList); +private: std::stack m_stackFileActions; }; diff --git a/Explorer++/Helper/FileOperations.cpp b/Explorer++/Helper/FileOperations.cpp index c92fde2ca..4e8492a56 100644 --- a/Explorer++/Helper/FileOperations.cpp +++ b/Explorer++/Helper/FileOperations.cpp @@ -46,18 +46,30 @@ HRESULT FileOperations::RenameFile(IShellItem *item, const std::wstring &newName return hr; } -HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vector &pidls, - bool permanent, bool silent) +HRESULT FileOperations::DeleteFiles(HWND hwnd, std::vector &pidls, bool permanent, bool silent) { - wil::com_ptr_nothrow fo; - HRESULT hr = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fo)); + DWORD cookie{}; + CComPtr pfo{}; + CComPtr pSink{}; + auto hr = pfo.CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_INPROC_SERVER); + if (FAILED(hr)) + { + return hr; + } + hr = CreateFileOperationProgressSink(pidls, &pSink); if (FAILED(hr)) { return hr; } - hr = fo->SetOwnerWindow(hwnd); + hr = pfo->Advise(pSink, &cookie); + if (FAILED(hr)) + { + return hr; + } + + hr = pfo->SetOwnerWindow(hwnd); if (FAILED(hr)) { @@ -82,7 +94,7 @@ HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vectorSetOperationFlags(flags); + hr = pfo->SetOperationFlags(flags); if (FAILED(hr)) { @@ -90,9 +102,8 @@ HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vector shellItemArray; - hr = SHCreateShellItemArrayFromIDLists(static_cast(pidls.size()), &pidls[0], - &shellItemArray); + wil::com_ptr_nothrow shellItemArray{}; + hr = SHCreateShellItemArrayFromIDLists(static_cast(pidls.size()), &pidls[0], &shellItemArray); if (FAILED(hr)) { @@ -100,21 +111,22 @@ HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vector unknown; - hr = shellItemArray->QueryInterface(IID_IUnknown, reinterpret_cast(&unknown)); + hr = shellItemArray->QueryInterface(IID_IUnknown, reinterpret_cast(&unknown)); if (FAILED(hr)) { return hr; } - hr = fo->DeleteItems(unknown.get()); + hr = pfo->DeleteItems(unknown.get()); if (FAILED(hr)) { return hr; } - hr = fo->PerformOperations(); + hr = pfo->PerformOperations(); + pfo->Unadvise(cookie); return hr; } @@ -425,8 +437,7 @@ HRESULT FileOperations::CreateLinkToFile(const std::wstring &strTargetFilename, const std::wstring &strLinkFilename, const std::wstring &strLinkDescription) { IShellLink *pShellLink = nullptr; - HRESULT hr = - CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink)); + HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink)); if (SUCCEEDED(hr)) { @@ -448,6 +459,17 @@ HRESULT FileOperations::CreateLinkToFile(const std::wstring &strTargetFilename, return hr; } +HRESULT CreateFileOperationProgressSink(std::vector &pidls, + IFileOperationProgressSink **ppSink) +{ + CFileOperationProgressSink* pfo = new (std::nothrow)CFileOperationProgressSink(pidls); + if (!pfo) + return E_OUTOFMEMORY; + const auto hr = pfo->QueryInterface(IID_IFileOperationProgressSink, reinterpret_cast(ppSink)); + pfo->Release(); + return hr; +} + HRESULT FileOperations::ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLinkFilename, TCHAR *szResolvedPath, int nBufferSize) { @@ -460,8 +482,7 @@ HRESULT FileOperations::ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLink } IShellLink *pShellLink = nullptr; - HRESULT hr = - CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink)); + HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink)); if (hr == S_OK) { @@ -492,8 +513,7 @@ HRESULT FileOperations::ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLink return hr; } -BOOL FileOperations::CreateBrowseDialog(HWND hOwner, const std::wstring &strTitle, - PIDLIST_ABSOLUTE *ppidl) +BOOL FileOperations::CreateBrowseDialog(HWND hOwner, const std::wstring &strTitle, PIDLIST_ABSOLUTE *ppidl) { TCHAR szDisplayName[MAX_PATH]; @@ -560,26 +580,22 @@ BOOL GetFileClusterSize(const std::wstring &strFilename, PLARGE_INTEGER lpRealFi void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, OverwriteMethod overwriteMethod) { - HANDLE hFile; WIN32_FIND_DATA wfd; - HANDLE hFindFile; HCRYPTPROV hProv; LARGE_INTEGER lRealFileSize; BYTE pass1Data; BYTE pass2Data; BYTE pass3Data; DWORD nBytesWritten; - BOOL bFolder; - int i = 0; - hFindFile = FindFirstFile(strFilename.c_str(), &wfd); + HANDLE hFindFile = FindFirstFile(strFilename.c_str(), &wfd); if (hFindFile == INVALID_HANDLE_VALUE) { return; } - bFolder = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; + BOOL bFolder = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; FindClose(hFindFile); @@ -594,8 +610,7 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, /* Open the file, block any sharing mode, to stop the file been opened while it is overwritten. */ - hFile = - CreateFile(strFilename.c_str(), FILE_WRITE_DATA, 0, nullptr, OPEN_EXISTING, NULL, nullptr); + HANDLE hFile = CreateFile(strFilename.c_str(), FILE_WRITE_DATA, 0, nullptr, OPEN_EXISTING, NULL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { @@ -612,7 +627,7 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, SetFilePointer(hFile, 0, nullptr, FILE_BEGIN); pass1Data = 0x00; - for (i = 0; i < lRealFileSize.QuadPart; i++) + for (int i = 0; i < lRealFileSize.QuadPart; i++) { WriteFile(hFile, (LPVOID) &pass1Data, 1, &nBytesWritten, nullptr); } @@ -625,7 +640,7 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, SetFilePointer(hFile, 0, nullptr, FILE_BEGIN); pass2Data = 0xFF; - for (i = 0; i < lRealFileSize.QuadPart; i++) + for (int i = 0; i < lRealFileSize.QuadPart; i++) { WriteFile(hFile, (LPVOID) &pass2Data, 1, &nBytesWritten, nullptr); } @@ -634,7 +649,7 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, CryptAcquireContext(&hProv, _T("SecureDelete"), nullptr, PROV_RSA_AES, CRYPT_NEWKEYSET); - for (i = 0; i < lRealFileSize.QuadPart; i++) + for (int i = 0; i < lRealFileSize.QuadPart; i++) { CryptGenRandom(hProv, 1, (LPBYTE) &pass3Data); WriteFile(hFile, (LPVOID) &pass3Data, 1, &nBytesWritten, nullptr); @@ -649,3 +664,77 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename, DeleteFile(strFilename.c_str()); } + +HRESULT FileOperations::Undelete(const PCIDLIST_ABSOLUTE &pidl) +{ + CComPtr pDesktop{}; + HRESULT hr = SHGetDesktopFolder(&pDesktop); + if (SUCCEEDED(hr) && pDesktop) + { + CComHeapPtr pidlbin{}; + hr = SHGetKnownFolderIDList(FOLDERID_RecycleBinFolder, KF_FLAG_DEFAULT, NULL, &pidlbin); + if (SUCCEEDED(hr) && pidlbin) + { + CComPtr pShellFolder{}; + hr = pDesktop->BindToObject(pidlbin, nullptr, IID_PPV_ARGS(&pShellFolder)); + if (SUCCEEDED(hr) && pShellFolder) + { + CComPtr pEnum{}; + hr = pShellFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum); + if (SUCCEEDED(hr) && pEnum) + { + ULONG fetched{}; + for (PITEMID_CHILD pidChild{}; pEnum->Next(1, &pidChild, &fetched) == S_OK; pidChild = nullptr) + { + const auto pidlRelative = ILFindLastID(static_cast(pidl)); + hr = pShellFolder->CompareIDs(SHCIDS_CANONICALONLY, pidlRelative, pidChild); + if (0 == static_cast(HRESULT_CODE(hr))) + { + hr = PerformUndeleting(pShellFolder, pidChild); + break; + } + } + } + } + } + } + + return hr; +} + +HRESULT FileOperations::PerformUndeleting(CComPtr& shellFolder, const PITEMID_CHILD& pidChild) +{ + PITEMID_CHILD* item = static_cast(CoTaskMemAlloc(sizeof(PITEMID_CHILD))); + SecureZeroMemory(item, sizeof(PITEMID_CHILD)); + item[0] = pidChild; + + CComPtr pContextMenu{}; + HRESULT hr = shellFolder->GetUIObjectOf(nullptr, 1, reinterpret_cast(item), + __uuidof(IContextMenu), nullptr, reinterpret_cast(&pContextMenu)); + if (SUCCEEDED(hr) && pContextMenu) + hr = InvokeVerb(pContextMenu, "undelete"); + + CoTaskMemFree(item); + + return hr; +} + +HRESULT FileOperations::InvokeVerb(IContextMenu* pContextMenu, PCSTR pszVerb) +{ + HRESULT hr{}; + const HMENU hmenu = CreatePopupMenu(); + if (pContextMenu && hmenu) + { + hr = pContextMenu->QueryContextMenu(hmenu, 0, 1, 0x7FFF, CMF_NORMAL); + if (SUCCEEDED(hr)) + { + CMINVOKECOMMANDINFO info = { 0 }; + info.cbSize = sizeof(info); + info.lpVerb = pszVerb; + hr = pContextMenu->InvokeCommand(&info); + } + DestroyMenu(hmenu); + } + return hr; +} + diff --git a/Explorer++/Helper/FileOperations.h b/Explorer++/Helper/FileOperations.h index f25d77291..13448f771 100644 --- a/Explorer++/Helper/FileOperations.h +++ b/Explorer++/Helper/FileOperations.h @@ -8,6 +8,92 @@ #include #include +#include + +class CFileOperationProgressSink : public IFileOperationProgressSink +{ +public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppv) + { + HRESULT hr{ E_NOINTERFACE }; + if (!ppv) + return E_POINTER; + + *ppv = nullptr; + if (iid == __uuidof(IUnknown)) + { + *ppv = static_cast(this); + AddRef(); + hr = S_OK; + } + else if (iid == __uuidof(IFileOperationProgressSink)) + { + *ppv = static_cast(this); + AddRef(); + hr = S_OK; + } + + return hr; + } + + STDMETHODIMP_(ULONG) AddRef() + { + ++m_cRef; + return m_cRef; + } + + STDMETHODIMP_(ULONG) Release() + { + ULONG cRef = --m_cRef; + if (0 == cRef) + delete this; + + return cRef; + } + + // IFileOperationProgressSink + STDMETHODIMP StartOperations() { return S_OK; } + STDMETHODIMP FinishOperations(HRESULT) { return S_OK; } + STDMETHODIMP PreRenameItem(DWORD, IShellItem *, LPCWSTR) { return S_OK; } + STDMETHODIMP PostRenameItem(DWORD, IShellItem *, LPCWSTR, HRESULT, IShellItem *) { return S_OK; } + STDMETHODIMP PreMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR) { return S_OK; } + STDMETHODIMP PostMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, IShellItem *) { return S_OK; } + STDMETHODIMP PreCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR) { return S_OK; } + STDMETHODIMP PostCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, IShellItem *) { return S_OK; } + STDMETHODIMP PreDeleteItem(DWORD, IShellItem *) { return S_OK; } + STDMETHODIMP PreNewItem(DWORD, IShellItem *, LPCWSTR) { return S_OK; } + STDMETHODIMP PostNewItem(DWORD, IShellItem *, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem *) { return S_OK; } + STDMETHODIMP UpdateProgress(UINT, UINT) { return S_OK; } + STDMETHODIMP ResetTimer() { return S_OK; } + STDMETHODIMP PauseTimer() { return S_OK; } + STDMETHODIMP ResumeTimer() { return S_OK; } + STDMETHODIMP PostDeleteItem(DWORD, IShellItem *, HRESULT, IShellItem *psiNewlyCreated) + { + HRESULT hr{ S_OK }; + if (psiNewlyCreated) + { + PIDLIST_ABSOLUTE pidlNewlyCreated{}; + hr = SHGetIDListFromObject(psiNewlyCreated, &pidlNewlyCreated); + if (SUCCEEDED(hr) && pidlNewlyCreated) + m_vPidls.emplace_back(pidlNewlyCreated); + } + return hr; + } + + CFileOperationProgressSink(std::vector &pidls) + :m_vPidls(pidls) + { + } + +private: + LONG m_cRef{ 1 }; + std::vector &m_vPidls; + ~CFileOperationProgressSink() + { + } +}; + namespace FileOperations { @@ -18,16 +104,12 @@ enum class OverwriteMethod }; HRESULT RenameFile(IShellItem *item, const std::wstring &newName); -HRESULT DeleteFiles(HWND hwnd, const std::vector &pidls, bool permanent, - bool silent); +HRESULT DeleteFiles(HWND hwnd, std::vector &pidls, bool permanent, bool silent); void DeleteFileSecurely(const std::wstring &strFilename, OverwriteMethod overwriteMethod); -HRESULT CopyFilesToFolder(HWND hOwner, const std::wstring &strTitle, - std::vector &pidls, bool move); -HRESULT CopyFiles(HWND hwnd, IShellItem *destinationFolder, std::vector &pidls, - bool move); +HRESULT CopyFilesToFolder(HWND hOwner, const std::wstring &strTitle, std::vector &pidls, bool move); +HRESULT CopyFiles(HWND hwnd, IShellItem *destinationFolder, std::vector &pidls, bool move); -HRESULT CreateNewFolder(IShellItem *destinationFolder, const std::wstring &newFolderName, - IFileOperationProgressSink *progressSink); +HRESULT CreateNewFolder(IShellItem *destinationFolder, const std::wstring &newFolderName, IFileOperationProgressSink *progressSink); TCHAR *BuildFilenameList(const std::list &FilenameList); @@ -35,14 +117,15 @@ BOOL SaveDirectoryListing(const std::wstring &strDirectory, const std::wstring & HRESULT CreateLinkToFile(const std::wstring &strTargetFilename, const std::wstring &strLinkFilename, const std::wstring &strLinkDescription); -HRESULT ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLinkFilename, TCHAR *szResolvedPath, - int nBufferSize); +HRESULT ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLinkFilename, TCHAR *szResolvedPath, int nBufferSize); BOOL CreateBrowseDialog(HWND hOwner, const std::wstring &strTitle, PIDLIST_ABSOLUTE *ppidl); - +HRESULT Undelete(const PCIDLIST_ABSOLUTE &pidl); +HRESULT PerformUndeleting(CComPtr &shellFolder, const PITEMID_CHILD &pidChild); +HRESULT InvokeVerb(IContextMenu *pContextMenu, PCSTR pszVerb); }; HRESULT CopyFiles(const std::vector &items, IDataObject **dataObjectOut); HRESULT CutFiles(const std::vector &items, IDataObject **dataObjectOut); -HRESULT CopyFilesToClipboard(const std::vector &items, bool move, - IDataObject **dataObjectOut); +HRESULT CopyFilesToClipboard(const std::vector &items, bool move, IDataObject **dataObjectOut); +HRESULT CreateFileOperationProgressSink(std::vector &pidls, IFileOperationProgressSink **ppSink);