Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solved undo deleted item. #486

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Explorer++/Explorer++/DefaultAccelerators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
Binary file modified Explorer++/Explorer++/Explorer++.rc
Binary file not shown.
Binary file modified Explorer++/Explorer++/Explorer++VersionInfo.h
Binary file not shown.
8 changes: 8 additions & 0 deletions Explorer++/Explorer++/NoTranslationResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions Explorer++/Explorer++/ShellBrowser/ShellBrowserImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,8 +1160,8 @@ FolderSettings ShellBrowserImpl::GetFolderSettings() const

void ShellBrowserImpl::DeleteSelectedItems(bool permanent)
{
int item{ -1 };
std::vector<PCIDLIST_ABSOLUTE> pidls;
int item = -1;

while ((item = ListView_GetNextItem(m_hListView, item, LVNI_SELECTED)) != -1)
{
Expand All @@ -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.
Expand Down
4 changes: 1 addition & 3 deletions Explorer++/Explorer++/ShellTreeView/ShellTreeView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
12 changes: 9 additions & 3 deletions Explorer++/Helper/FileActionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions Explorer++/Helper/FileActionHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ class FileActionHandler
void UndoRenameOperation(const RenamedItems_t &renamedItemList);
void UndoDeleteOperation(const DeletedItems_t &deletedItemList);

private:
std::stack<UndoItem_t> m_stackFileActions;
};
147 changes: 118 additions & 29 deletions Explorer++/Helper/FileOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,30 @@ HRESULT FileOperations::RenameFile(IShellItem *item, const std::wstring &newName
return hr;
}

HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vector<PCIDLIST_ABSOLUTE> &pidls,
bool permanent, bool silent)
HRESULT FileOperations::DeleteFiles(HWND hwnd, std::vector<PCIDLIST_ABSOLUTE> &pidls, bool permanent, bool silent)
{
wil::com_ptr_nothrow<IFileOperation> fo;
HRESULT hr = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fo));
DWORD cookie{};
CComPtr<IFileOperation> pfo{};
CComPtr<IFileOperationProgressSink> 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))
{
Expand All @@ -82,39 +94,39 @@ HRESULT FileOperations::DeleteFiles(HWND hwnd, const std::vector<PCIDLIST_ABSOLU

if (flags != 0)
{
hr = fo->SetOperationFlags(flags);
hr = pfo->SetOperationFlags(flags);

if (FAILED(hr))
{
return hr;
}
}

wil::com_ptr_nothrow<IShellItemArray> shellItemArray;
hr = SHCreateShellItemArrayFromIDLists(static_cast<UINT>(pidls.size()), &pidls[0],
&shellItemArray);
wil::com_ptr_nothrow<IShellItemArray> shellItemArray{};
hr = SHCreateShellItemArrayFromIDLists(static_cast<UINT>(pidls.size()), &pidls[0], &shellItemArray);

if (FAILED(hr))
{
return hr;
}

wil::com_ptr_nothrow<IUnknown> unknown;
hr = shellItemArray->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&unknown));
hr = shellItemArray->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&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;
}
Expand Down Expand Up @@ -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))
{
Expand All @@ -448,6 +459,17 @@ HRESULT FileOperations::CreateLinkToFile(const std::wstring &strTargetFilename,
return hr;
}

HRESULT CreateFileOperationProgressSink(std::vector<PCIDLIST_ABSOLUTE> &pidls,
IFileOperationProgressSink **ppSink)
{
CFileOperationProgressSink* pfo = new (std::nothrow)CFileOperationProgressSink(pidls);
if (!pfo)
return E_OUTOFMEMORY;
const auto hr = pfo->QueryInterface(IID_IFileOperationProgressSink, reinterpret_cast<LPVOID*>(ppSink));
pfo->Release();
return hr;
}

HRESULT FileOperations::ResolveLink(HWND hwnd, DWORD fFlags, const TCHAR *szLinkFilename,
TCHAR *szResolvedPath, int nBufferSize)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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);

Expand All @@ -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)
{
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
Expand All @@ -649,3 +664,77 @@ void FileOperations::DeleteFileSecurely(const std::wstring &strFilename,

DeleteFile(strFilename.c_str());
}

HRESULT FileOperations::Undelete(const PCIDLIST_ABSOLUTE &pidl)
{
CComPtr<IShellFolder> pDesktop{};
HRESULT hr = SHGetDesktopFolder(&pDesktop);
if (SUCCEEDED(hr) && pDesktop)
{
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlbin{};
hr = SHGetKnownFolderIDList(FOLDERID_RecycleBinFolder, KF_FLAG_DEFAULT, NULL, &pidlbin);
if (SUCCEEDED(hr) && pidlbin)
{
CComPtr<IShellFolder> pShellFolder{};
hr = pDesktop->BindToObject(pidlbin, nullptr, IID_PPV_ARGS(&pShellFolder));
if (SUCCEEDED(hr) && pShellFolder)
{
CComPtr<IEnumIDList> 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<PCUIDLIST_RELATIVE>(pidl));
hr = pShellFolder->CompareIDs(SHCIDS_CANONICALONLY, pidlRelative, pidChild);
if (0 == static_cast<short>(HRESULT_CODE(hr)))
{
hr = PerformUndeleting(pShellFolder, pidChild);
break;
}
}
}
}
}
}

return hr;
}

HRESULT FileOperations::PerformUndeleting(CComPtr<IShellFolder>& shellFolder, const PITEMID_CHILD& pidChild)
{
PITEMID_CHILD* item = static_cast<PITEMID_CHILD*>(CoTaskMemAlloc(sizeof(PITEMID_CHILD)));
SecureZeroMemory(item, sizeof(PITEMID_CHILD));
item[0] = pidChild;

CComPtr<IContextMenu> pContextMenu{};
HRESULT hr = shellFolder->GetUIObjectOf(nullptr, 1, reinterpret_cast<PCUITEMID_CHILD_ARRAY>(item),
__uuidof(IContextMenu), nullptr, reinterpret_cast<void **>(&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;
}

Loading