1760 lines
45 KiB
C++
1760 lines
45 KiB
C++
/*
|
|
* Copyright 2004-2020 Sandboxie Holdings, LLC
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Quick Recover
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "QuickRecover.h"
|
|
|
|
#include <shlobj.h>
|
|
#include "common/win32_ntddk.h"
|
|
#include "UserSettings.h"
|
|
#include "Boxes.h"
|
|
#include "apps/common/MyGdi.h"
|
|
#include "apps/common/CommonUtils.h"
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Variables
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
static const CString _RecoverTarget(L"RecoverTarget");
|
|
static const CString _SaveRecoverTargets(L"SaveRecoverTargets");
|
|
|
|
static const CString _LongPathPrefix(L"\\\\?\\");
|
|
|
|
ULONG CQuickRecover::m_TempFolderCounter = 0;
|
|
|
|
CStringList CQuickRecover::m_past_files;
|
|
|
|
const WCHAR *CQuickRecover::ReplaceButtonText = NULL;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Message Map
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CQuickRecover, CBaseDialog)
|
|
|
|
ON_WM_VKEYTOITEM()
|
|
ON_CONTROL(LBN_SELCHANGE, ID_RECOVER_FOLDERS, OnListSelect)
|
|
ON_CONTROL(LBN_DBLCLK, ID_RECOVER_FOLDERS, OnListSelect)
|
|
ON_COMMAND(ID_RECOVER_SELECT_ALL, OnSelectAll)
|
|
ON_COMMAND(ID_RECOVER_DISABLE, OnCheckBoxClick)
|
|
ON_COMMAND(ID_RECOVER_REMOVE, OnRemoveFolders)
|
|
ON_COMMAND(ID_RECOVER_CYCLE, OnCycleRecover)
|
|
ON_WM_CONTEXTMENU()
|
|
ON_WM_DESTROY()
|
|
ON_WM_ACTIVATE()
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Constructor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
CQuickRecover::CQuickRecover(
|
|
CWnd *pParentWnd, const CString &BoxName,
|
|
const CString &SrcPath, int qrMode)
|
|
: CBaseDialog(pParentWnd)
|
|
{
|
|
m_BoxName = BoxName;
|
|
m_SrcPath = SrcPath;
|
|
|
|
m_ready = FALSE;
|
|
m_log = FALSE;
|
|
m_replace = FALSE;
|
|
m_recover_mode = 0;
|
|
|
|
if (qrMode == QR_SAME)
|
|
RecoverToSameFolder();
|
|
else if (qrMode == QR_ANY)
|
|
RecoverToAnyFolder();
|
|
else if (qrMode == QR_AUTO)
|
|
AutoRecover();
|
|
else if (qrMode == QR_LOG)
|
|
RecoveryLog();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Constructor
|
|
//---------------------------------------------------------------------------
|
|
|
|
CQuickRecover::CQuickRecover(
|
|
CWnd *pParentWnd, const CString &BoxName,
|
|
CStringList &SrcPaths, int qrMode)
|
|
: CBaseDialog(pParentWnd)
|
|
{
|
|
m_BoxName = BoxName;
|
|
|
|
m_ready = FALSE;
|
|
m_log = FALSE;
|
|
m_replace = FALSE;
|
|
m_recover_mode = 0;
|
|
|
|
bool first = true;
|
|
BOOL ok;
|
|
CString SaveDstPath;
|
|
|
|
POSITION pos = SrcPaths.GetHeadPosition();
|
|
while (pos) {
|
|
|
|
CString RelativePath;
|
|
m_SrcPath = SrcPaths.GetNext(pos);
|
|
int index = m_SrcPath.ReverseFind(L'|');
|
|
if (index != -1) {
|
|
RelativePath = m_SrcPath.Mid(index + 1);
|
|
m_SrcPath = m_SrcPath.Left(index);
|
|
}
|
|
|
|
if (qrMode == QR_SAME)
|
|
ok = RecoverToSameFolder();
|
|
else if (first) {
|
|
ok = RecoverToAnyFolder(RelativePath);
|
|
SaveDstPath = m_DstPath;
|
|
first = false;
|
|
} else
|
|
ok = RecoverFile(GetDestPlusRelative(SaveDstPath, RelativePath));
|
|
if ((! ok) || m_DstPath.IsEmpty())
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Destructor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
CQuickRecover::~CQuickRecover()
|
|
{
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnDestroy
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnDestroy()
|
|
{
|
|
if (m_static.m_hWnd)
|
|
m_static.UnsubclassWindow();
|
|
if (m_listbox.m_hWnd)
|
|
m_listbox.UnsubclassWindow();
|
|
if (m_checkbox.m_hWnd)
|
|
m_checkbox.UnsubclassWindow();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnListSelect
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnListSelect()
|
|
{
|
|
if (m_ready) {
|
|
|
|
POSITION pos = 0;
|
|
int index = m_listbox.GetCurSel();
|
|
if (index != LB_ERR)
|
|
pos = m_list.FindIndex(index);
|
|
if (pos) {
|
|
|
|
if (m_hwndTree) {
|
|
|
|
//
|
|
// SHBrowseForFolder dialog
|
|
//
|
|
|
|
CString &path = m_list.GetAt(pos);
|
|
SendMessage(
|
|
BFFM_SETSELECTION, TRUE, (LPARAM)(const WCHAR *)path);
|
|
|
|
const MSG *msg = GetCurrentMessage();
|
|
if (HIWORD(msg->wParam) == LBN_DBLCLK)
|
|
SendMessage(WM_COMMAND, IDOK, 0);
|
|
else
|
|
::SetFocus(m_hwndTree);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Immediate Recovery dialog
|
|
//
|
|
|
|
if (m_log)
|
|
GetDlgItem(IDOK)->EnableWindow(TRUE);
|
|
|
|
const MSG *msg = GetCurrentMessage();
|
|
if (HIWORD(msg->wParam) == LBN_DBLCLK && (! m_check))
|
|
SendMessage(WM_COMMAND, IDOK, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnVKeyToItem
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
int CQuickRecover::OnVKeyToItem(UINT nKey, CListBox *pListBox, UINT nIndex)
|
|
{
|
|
if (m_log || m_hwndTree || pListBox->GetDlgCtrlID() != ID_RECOVER_ITEMS)
|
|
return -1;
|
|
if (nKey != L'A' || (GetKeyState(VK_CONTROL) & 0x8000) == 0)
|
|
return -1;
|
|
|
|
pListBox->SelItemRange(TRUE, 0, pListBox->GetCount());
|
|
return -2;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnSelectAll
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnSelectAll()
|
|
{
|
|
CListBox *pListBox = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
pListBox->SelItemRange(TRUE, 0, pListBox->GetCount());
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnContextMenu
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnContextMenu(CWnd *pWnd, CPoint pt)
|
|
{
|
|
//
|
|
// display a context menu to remove items from the list of folders
|
|
//
|
|
|
|
if (m_hwndTree)
|
|
return;
|
|
if (pWnd->GetDlgCtrlID() != ID_RECOVER_FOLDERS)
|
|
return;
|
|
CListBox *pListBox = (CListBox *)GetDlgItem(ID_RECOVER_FOLDERS);
|
|
|
|
CPoint ptListBox = pt;
|
|
pListBox->ScreenToClient(&ptListBox);
|
|
|
|
BOOL outside = FALSE;
|
|
ULONG FolderIndex = pListBox->ItemFromPoint(ptListBox, outside);
|
|
if (outside)
|
|
return;
|
|
pListBox->SetCurSel(FolderIndex);
|
|
if (m_hwndTree)
|
|
OnListSelect();
|
|
|
|
ULONG gray = 0;
|
|
if ((! m_hwndTree) && (FolderIndex <= 1))
|
|
gray = MF_GRAYED;
|
|
|
|
CString msg3981 = CMyMsg(MSG_3981);
|
|
msg3981.Remove(L'&');
|
|
|
|
CMenu menu;
|
|
menu.CreatePopupMenu();
|
|
menu.AppendMenu(MF_STRING | gray, 3981, msg3981);
|
|
menu.AppendMenu(MF_STRING | gray, 3982, CMyMsg(MSG_3982));
|
|
menu.AppendMenu(MF_STRING, 3983, CMyMsg(MSG_3983));
|
|
ULONG menucmd = menu.TrackPopupMenu(
|
|
TPM_NONOTIFY | TPM_RETURNCMD | TPM_TOPALIGN, pt.x, pt.y, this);
|
|
|
|
//
|
|
// process menu selection
|
|
//
|
|
|
|
bool UpdateList = false;
|
|
|
|
if (menucmd == 3981) {
|
|
|
|
CString path = m_list.GetAt(m_list.FindIndex(FolderIndex));
|
|
ShellExecute(m_hWnd, NULL, path, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
} else if (menucmd == 3982) {
|
|
|
|
//
|
|
// delete the selected item
|
|
//
|
|
|
|
POSITION pos = m_list.FindIndex(FolderIndex);
|
|
m_list.RemoveAt(pos);
|
|
pListBox->DeleteString(FolderIndex);
|
|
UpdateList = true;
|
|
|
|
} else if (menucmd == 3983) {
|
|
|
|
//
|
|
// delete everything, except the items Recovery to Same/Any Folder
|
|
//
|
|
|
|
ULONG FolderCount = (m_hwndTree) ? 0 : 2;
|
|
while (m_list.GetCount() != FolderCount) {
|
|
POSITION pos = m_list.FindIndex(FolderCount);
|
|
m_list.RemoveAt(pos);
|
|
pListBox->DeleteString(FolderCount);
|
|
}
|
|
UpdateList = true;
|
|
}
|
|
|
|
//
|
|
// store the new list, except the items Recovery Same/Any Folder
|
|
//
|
|
|
|
if (UpdateList) {
|
|
|
|
if (! gray)
|
|
pListBox->SetCurSel(0);
|
|
|
|
CUserSettings &ini = CUserSettings::GetInstance();
|
|
|
|
POSITION pos = m_list.GetHeadPosition();
|
|
if (! m_hwndTree) {
|
|
m_list.GetNext(pos); // Recover to Same Folder
|
|
m_list.GetNext(pos); // Recover to Any Folder
|
|
}
|
|
|
|
CString value;
|
|
while (pos) {
|
|
if (! value.IsEmpty())
|
|
value += L"\n";
|
|
value += m_list.GetNext(pos);
|
|
}
|
|
|
|
ini.SetText(_RecoverTarget, value);
|
|
|
|
int FolderCount = (m_hwndTree) ? 0 : 2;
|
|
GetDlgItem(ID_RECOVER_RIGHT_CLICK)->ShowWindow(
|
|
(m_list.GetCount() > FolderCount) ? SW_SHOW : SW_HIDE);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnCheckBoxClick
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnCheckBoxClick()
|
|
{
|
|
m_check = ! m_check;
|
|
|
|
CButton *pCheckBox = (CButton *)GetDlgItem(ID_RECOVER_DISABLE);
|
|
pCheckBox->SetCheck(m_check ? BST_CHECKED : BST_UNCHECKED);
|
|
|
|
if (! m_hwndTree) {
|
|
GetDlgItem(IDOK)->EnableWindow(! m_check);
|
|
CBox &box = CBoxes::GetInstance().GetBox(m_BoxName);
|
|
box.SetImmediateRecoveryState(! m_check, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnCycleRecover
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnCycleRecover()
|
|
{
|
|
ULONG msgid1, msgid2;
|
|
++m_recover_mode;
|
|
if (m_recover_mode == 3) {
|
|
msgid1 = 3718;
|
|
msgid2 = 3736;
|
|
m_recover_mode = 0;
|
|
} else if (m_recover_mode == 2) {
|
|
msgid1 = 3737;
|
|
msgid2 = 3718;
|
|
} else if (m_recover_mode == 1) {
|
|
msgid1 = 3736;
|
|
msgid2 = 3737;
|
|
}
|
|
GetDlgItem(IDOK)->SetWindowText(CMyMsg(msgid1));
|
|
if (CycleRecoverButton.m_hWnd)
|
|
CycleRecoverButton.SetText(CMyMsg(msgid2));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// InitFolderList
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::InitFolderList(bool AddHead, int SelectIndex)
|
|
{
|
|
//
|
|
// ReadFolderList
|
|
//
|
|
|
|
m_list.RemoveAll();
|
|
m_listbox.ResetContent();
|
|
|
|
CUserSettings &ini = CUserSettings::GetInstance();
|
|
ini.GetBool(_SaveRecoverTargets, m_check, TRUE);
|
|
if (m_check) {
|
|
ini.GetTextList(_RecoverTarget, m_list);
|
|
while (m_list.GetCount() > 10)
|
|
m_list.RemoveTail();
|
|
}
|
|
|
|
if (AddHead) {
|
|
|
|
AddHeadFolderList(MSG_3721);
|
|
AddHeadFolderList(MSG_3720);
|
|
}
|
|
|
|
//
|
|
// ShowFolderList
|
|
//
|
|
|
|
POSITION pos = m_list.GetHeadPosition();
|
|
while (pos) {
|
|
CString text = m_list.GetNext(pos);
|
|
int index = 0;
|
|
while (text.GetLength() - index > 45) {
|
|
int index2 = text.Find(L'\\', index);
|
|
if (index2 == -1)
|
|
break;
|
|
index = index2 + 1;
|
|
}
|
|
if (index)
|
|
text = CString(L"...\\") + text.Mid(index);
|
|
m_listbox.AddString(text);
|
|
}
|
|
|
|
m_listbox.SetCurSel(SelectIndex);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// AddHeadFolderList
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::AddHeadFolderList(ULONG msgid)
|
|
{
|
|
CString text = CMyMsg(msgid);
|
|
|
|
int index = text.Find(L'(');
|
|
if (index != -1)
|
|
text = text.Left(index);
|
|
text.Remove(L'&');
|
|
text.Remove(L'\r');
|
|
text.Replace(L'\n', L' ');
|
|
text.TrimLeft();
|
|
text.TrimRight();
|
|
|
|
m_list.AddHead(text);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GetDestPlusRelative
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
CString CQuickRecover::GetDestPlusRelative(
|
|
const CString &DestPath, const CString &RelativePath)
|
|
{
|
|
//
|
|
// combine destination and relative paths. but if the
|
|
//
|
|
|
|
CString Result = DestPath;
|
|
|
|
if (RelativePath.GetLength() > 1) {
|
|
|
|
int dIndex = DestPath.ReverseFind(L'\\');
|
|
if (dIndex != -1) {
|
|
|
|
int rIndex = RelativePath.Find(L'\\', 1);
|
|
if (rIndex == -1)
|
|
rIndex = RelativePath.GetLength();
|
|
|
|
CString LastPart = DestPath.Mid(dIndex);
|
|
CString FirstPart = RelativePath.Left(rIndex);
|
|
|
|
if (FirstPart.CompareNoCase(LastPart) == 0) {
|
|
|
|
Result = DestPath.Left(dIndex);
|
|
}
|
|
}
|
|
|
|
Result += RelativePath;
|
|
|
|
SHCreateDirectory(m_pParentWnd->m_hWnd, Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverToAnyFolder
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverToAnyFolder(const CString &RelativePath)
|
|
{
|
|
BOOL ok = FALSE;
|
|
|
|
//
|
|
// invoke Browse For Folder dialog box
|
|
//
|
|
|
|
WCHAR path[MAX_PATH + 32];
|
|
|
|
CMyMsg title(MSG_3723);
|
|
|
|
BROWSEINFO bi;
|
|
memzero(&bi, sizeof(BROWSEINFO));
|
|
bi.hwndOwner = m_pParentWnd->m_hWnd;
|
|
bi.pszDisplayName = path;
|
|
bi.lpszTitle = title;
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
|
bi.lpfn = BrowseCallback;
|
|
bi.lParam = (LPARAM)this;
|
|
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
|
|
if (pidl) {
|
|
|
|
ok = SHGetPathFromIDList(pidl, path);
|
|
CoTaskMemFree(pidl);
|
|
|
|
//
|
|
// update list of stored folders
|
|
//
|
|
|
|
if (ok) {
|
|
|
|
CUserSettings &ini = CUserSettings::GetInstance();
|
|
|
|
if (m_check) {
|
|
|
|
CString value = path;
|
|
while (! m_list.IsEmpty()) {
|
|
CString add = m_list.RemoveHead();
|
|
if (add.CompareNoCase(path) != 0)
|
|
value += L"\n" + add;
|
|
}
|
|
ini.SetText(_RecoverTarget, value);
|
|
}
|
|
|
|
ini.SetBool(_SaveRecoverTargets, m_check);
|
|
|
|
ok = RecoverFile(GetDestPlusRelative(path, RelativePath));
|
|
}
|
|
|
|
if (ok)
|
|
m_DstPath = path;
|
|
}
|
|
|
|
if (! ok)
|
|
m_DstPath = CString();
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// BrowseCallback
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
int CALLBACK CQuickRecover::BrowseCallback(
|
|
HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
|
|
{
|
|
if (msg == BFFM_INITIALIZED) {
|
|
CQuickRecover *pThis = (CQuickRecover *)lpData;
|
|
pThis->SubclassWindow(hwnd);
|
|
pThis->OnInitDialogAnyFolder();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnInitDialogAnyFolder
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnInitDialogAnyFolder()
|
|
{
|
|
//
|
|
// add box name in title bar
|
|
//
|
|
|
|
CString caption;
|
|
GetWindowText(caption);
|
|
caption += L" - " + m_BoxName;
|
|
SetWindowText(caption);
|
|
|
|
//
|
|
// remove context help button from dialog caption
|
|
//
|
|
|
|
ModifyStyle(DS_CONTEXTHELP, 0);
|
|
ModifyStyleEx(WS_EX_CONTEXTHELP, 0);
|
|
|
|
//
|
|
// find the folder tree and make dialog larger
|
|
//
|
|
|
|
//m_hwndTree = ::FindWindowEx(m_hWnd, NULL, L"SHBrowseForFolder ShellNameSpace Control", NULL);
|
|
m_hwndTree = ::FindWindowEx(m_hWnd, NULL, L"SysTreeView32", NULL);
|
|
if (! m_hwndTree)
|
|
return;
|
|
|
|
//
|
|
// add static text below the folder tree
|
|
//
|
|
|
|
CRect rc, rc2;
|
|
|
|
::GetWindowRect(m_hwndTree, &rc);
|
|
ScreenToClient(&rc);
|
|
::GetWindowRect(GetDlgItem(IDOK)->m_hWnd, &rc2);
|
|
ScreenToClient(&rc2);
|
|
rc.top = rc2.bottom + 10;
|
|
rc.bottom = rc.top + 25;
|
|
|
|
m_static.Create(CMyMsg(MSG_3724), SS_SIMPLE | WS_CHILD | WS_VISIBLE,
|
|
rc, this, IDC_STATIC);
|
|
m_static.SetFont(GetFont());
|
|
|
|
//
|
|
// add listbox below the static text
|
|
//
|
|
|
|
rc.top += 30;
|
|
rc.bottom = rc.top + 140;
|
|
|
|
m_listbox.Create(WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VISIBLE |
|
|
WS_HSCROLL | WS_VSCROLL | LBS_NOTIFY,
|
|
rc, this, ID_RECOVER_FOLDERS);
|
|
m_listbox.ModifyStyleEx(0, WS_EX_CLIENTEDGE);
|
|
m_listbox.SetFont(GetFont());
|
|
|
|
m_listbox.SetItemHeight(0, m_listbox.GetItemHeight(0) * 3 / 2);
|
|
|
|
InitFolderList(false, -1);
|
|
|
|
//
|
|
// add checkbox below the listbox
|
|
//
|
|
|
|
m_listbox.GetWindowRect(&rc);
|
|
ScreenToClient(&rc);
|
|
rc.top = rc.bottom + 10;
|
|
rc.bottom = rc.top + 30;
|
|
|
|
m_checkbox.Create(CMyMsg(MSG_3725),
|
|
BS_CHECKBOX | WS_TABSTOP | WS_CHILD | WS_VISIBLE,
|
|
rc, this, ID_RECOVER_DISABLE);
|
|
m_checkbox.SetFont(GetFont());
|
|
|
|
if (m_check)
|
|
m_checkbox.SetCheck(BST_CHECKED);
|
|
|
|
//
|
|
// resize dialog vertically
|
|
//
|
|
|
|
GetWindowRect(&rc2);
|
|
ScreenToClient(&rc2);
|
|
rc2.bottom = rc.bottom + 10;
|
|
ClientToScreen(&rc2);
|
|
MoveWindow(rc2, TRUE);
|
|
|
|
//
|
|
// enable list interaction
|
|
//
|
|
|
|
m_ready = TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// AutoRecover
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::AutoRecover()
|
|
{
|
|
SetDialogTemplate(L"AUTORECOVER_DIALOG");
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// AddAutoRecoverItem
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::AddAutoRecoverItem(const CString &SrcPath)
|
|
{
|
|
CBox &box = CBoxes::GetInstance().GetBox(m_BoxName);
|
|
CBoxFile &boxfile = box.GetBoxFile();
|
|
CString CopyPath = boxfile.GetCopyPathForTruePath(SrcPath);
|
|
|
|
POSITION pos = m_items.GetHeadPosition();
|
|
while (pos) {
|
|
const CString &OldCopyPath = m_items.GetNext(pos);
|
|
if (OldCopyPath == CopyPath)
|
|
return;
|
|
}
|
|
|
|
m_items.AddTail(CopyPath);
|
|
|
|
GetDlgItem(ID_RECOVER_SELECT_ALL)->ShowWindow(
|
|
(m_items.GetCount() > 1) ? SW_SHOW : SW_HIDE);
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
CString TruePath = SrcPath;
|
|
boxfile.TranslateNtToDosPath(TruePath);
|
|
|
|
CString text = TruePath;
|
|
int index = 0;
|
|
while (text.GetLength() - index > 65) {
|
|
int index2 = text.Find(L'\\', index);
|
|
if (index2 == -1)
|
|
break;
|
|
index = index2 + 1;
|
|
}
|
|
if (index)
|
|
text = CString(L"...\\") + text.Mid(index);
|
|
|
|
CListBox *items = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
items->AddString(text);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// MoveButtonIntoList
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::MoveButtonIntoList(
|
|
CButton *pButton, CListBox *pListBox, HBITMAP hBitmap)
|
|
{
|
|
pButton->ModifyStyle(0, BS_BITMAP | BS_CENTER);
|
|
pButton->SetBitmap(hBitmap);
|
|
|
|
RECT rc;
|
|
pListBox->GetWindowRect(&rc);
|
|
ScreenToClient(&rc);
|
|
rc.top = rc.bottom - 25;
|
|
|
|
if (! CMyApp::m_LayoutRTL) {
|
|
rc.right -= GetSystemMetrics(SM_CXHTHUMB) + 5;
|
|
rc.left = rc.right - 25;
|
|
} else {
|
|
rc.left += GetSystemMetrics(SM_CXHTHUMB) + 5;
|
|
rc.right = rc.left + 25;
|
|
pButton->ModifyStyleEx(WS_EX_LAYOUTRTL, 0);
|
|
}
|
|
|
|
pButton->SetWindowPos(&wndTop,
|
|
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
|
|
SWP_SHOWWINDOW);
|
|
pListBox->ModifyStyle(0, WS_CLIPSIBLINGS);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnInitDialog
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::OnInitDialog()
|
|
{
|
|
//
|
|
// init bitmap resources
|
|
//
|
|
|
|
static HBITMAP checkmark_bitmap = NULL;
|
|
static HBITMAP questionmark_bitmap = NULL;
|
|
static HBITMAP cycle_bitmap = NULL;
|
|
if (! checkmark_bitmap)
|
|
checkmark_bitmap = MyGdi_CreateFromResource(L"BLUE_CHECKMARK");
|
|
if (! questionmark_bitmap)
|
|
questionmark_bitmap = MyGdi_CreateFromResource(L"BLUE_QUESTIONMARK");
|
|
if (! cycle_bitmap)
|
|
cycle_bitmap = MyGdi_CreateFromResource(L"BLUE_CYCLE");
|
|
|
|
//
|
|
// we're not SHBrowseForFolder
|
|
//
|
|
|
|
m_hwndTree = NULL;
|
|
|
|
AddMinimizeButton();
|
|
|
|
//
|
|
// branch to Recovery Log if necessary
|
|
//
|
|
|
|
if (m_BoxName.IsEmpty())
|
|
return OnInitDialogRecoveryLog();
|
|
|
|
//
|
|
// set dialog texts and adjust dialog position
|
|
//
|
|
|
|
SetWindowText(CMyMsg(MSG_3715));
|
|
|
|
GetDlgItem(ID_DELETE_EXPLAIN_1)->SetWindowText(CMyMsg(MSG_3716));
|
|
GetDlgItem(ID_DELETE_EXPLAIN_2)->SetWindowText(CMyMsg(MSG_3717));
|
|
|
|
GetDlgItem(IDOK)->SetWindowText(CMyMsg(MSG_3718));
|
|
GetDlgItem(IDCANCEL)->SetWindowText(CMyMsg(MSG_3004));
|
|
|
|
GetDlgItem(ID_RECOVER_DISABLE)->SetWindowText(CMyMsg(MSG_3719));
|
|
|
|
SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
//
|
|
// add box name in title bar
|
|
//
|
|
|
|
CString caption;
|
|
GetWindowText(caption);
|
|
caption += L" - " + m_BoxName;
|
|
SetWindowText(caption);
|
|
|
|
//
|
|
// populate items and show the Select All button
|
|
//
|
|
|
|
MakeLTR(ID_RECOVER_ITEMS);
|
|
|
|
CListBox *pListBox = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
CButton *pButton = (CButton *)GetDlgItem(ID_RECOVER_SELECT_ALL);
|
|
|
|
MoveButtonIntoList(pButton, pListBox, checkmark_bitmap);
|
|
|
|
AddAutoRecoverItem(m_SrcPath);
|
|
pListBox->SetSel(0, TRUE);
|
|
|
|
if (! SelectAllButton.m_hWnd) {
|
|
CString tip = CMyMsg(MSG_3360);
|
|
tip.Remove(L'&');
|
|
SelectAllButton.Init(pButton->m_hWnd, tip);
|
|
}
|
|
|
|
//
|
|
// populate folder list
|
|
//
|
|
|
|
MakeLTR(ID_RECOVER_FOLDERS);
|
|
|
|
HWND hwnd = GetDlgItem(ID_RECOVER_FOLDERS)->m_hWnd;
|
|
m_listbox.Attach(hwnd);
|
|
|
|
m_listbox.SetItemHeight(0, m_listbox.GetItemHeight(0) * 3 / 2);
|
|
|
|
InitFolderList(true, 0);
|
|
|
|
//
|
|
// prepare the folder list tip button and the recover tool tip
|
|
//
|
|
|
|
pListBox = (CListBox *)GetDlgItem(ID_RECOVER_FOLDERS);
|
|
pButton = (CButton *)GetDlgItem(ID_RECOVER_RIGHT_CLICK);
|
|
|
|
MoveButtonIntoList(pButton, pListBox, questionmark_bitmap);
|
|
if (! RightClickButton.m_hWnd)
|
|
RightClickButton.Init(pButton->m_hWnd, CMyMsg(MSG_3734));
|
|
|
|
if (m_list.GetCount() <= 2)
|
|
pButton->ShowWindow(SW_HIDE);
|
|
|
|
//
|
|
// prepare the cycle button for the recover button
|
|
//
|
|
|
|
pButton = (CButton *)GetDlgItem(ID_RECOVER_CYCLE);
|
|
pButton->SetBitmap(cycle_bitmap);
|
|
pButton->SetWindowPos(NULL, 0, 0, 25, 25, SWP_NOMOVE | SWP_SHOWWINDOW);
|
|
|
|
if (! CycleRecoverButton.m_hWnd)
|
|
CycleRecoverButton.Init(pButton->m_hWnd, CMyMsg(MSG_3736));
|
|
|
|
//
|
|
// make sure the checkbox is reset
|
|
//
|
|
|
|
m_check = FALSE;
|
|
|
|
//
|
|
// enable list interaction
|
|
//
|
|
|
|
m_ready = TRUE;
|
|
|
|
//
|
|
// flash window
|
|
//
|
|
|
|
FlashTitle();
|
|
|
|
GetDlgItem(IDOK)->SetFocus();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnOK
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnOK()
|
|
{
|
|
//
|
|
// if this is OnOK for the customized SHBrowseForFolder, do nothing
|
|
//
|
|
|
|
if (m_hwndTree) {
|
|
CWnd::Default();
|
|
return;
|
|
}
|
|
|
|
if (m_log) {
|
|
OnOKRecoveryLog();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// get destination folder
|
|
//
|
|
|
|
BOOL ReorderFolders = FALSE;
|
|
|
|
CListBox *list = (CListBox *)GetDlgItem(ID_RECOVER_FOLDERS);
|
|
int index = list->GetCurSel();
|
|
if (index == LB_ERR)
|
|
return;
|
|
BOOL sameFolder = FALSE;
|
|
CString destFolder;
|
|
if (index == 0)
|
|
sameFolder = TRUE;
|
|
else if (index != 1) {
|
|
|
|
destFolder = m_list.GetAt(m_list.FindIndex(index));
|
|
|
|
//
|
|
// if selected from folder history, move folder to top
|
|
//
|
|
|
|
if (! destFolder.IsEmpty()) {
|
|
|
|
CUserSettings &ini = CUserSettings::GetInstance();
|
|
|
|
POSITION pos = m_list.GetHeadPosition();
|
|
m_list.GetNext(pos); // Recover to Same Folder
|
|
m_list.GetNext(pos); // Recover to Any Folder
|
|
|
|
CString value = destFolder;
|
|
while (pos) {
|
|
const CString &add = m_list.GetNext(pos);
|
|
if (add.CompareNoCase(destFolder) != 0)
|
|
value += L"\n" + add;
|
|
}
|
|
|
|
ini.SetText(_RecoverTarget, value);
|
|
|
|
ReorderFolders = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// recover selected items
|
|
//
|
|
|
|
BOOL AnySelected = FALSE;
|
|
|
|
list = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
while (1) {
|
|
|
|
int size = list->GetCount();
|
|
|
|
for (index = 0; index < size; ++index) {
|
|
if (list->GetSel(index) <= 0)
|
|
continue;
|
|
AnySelected = TRUE;
|
|
POSITION pos = m_items.FindIndex(index);
|
|
if (! pos)
|
|
continue;
|
|
m_SrcPath = m_items.GetAt(pos);
|
|
|
|
BOOL ok;
|
|
|
|
if (sameFolder) {
|
|
|
|
ok = RecoverToSameFolder();
|
|
|
|
} else {
|
|
|
|
if (destFolder.IsEmpty()) {
|
|
|
|
CQuickRecover *qr2 = new CQuickRecover(
|
|
this, m_BoxName, m_SrcPath, QR_ANY);
|
|
destFolder = qr2->m_DstPath;
|
|
m_replace = qr2->m_replace;
|
|
delete qr2;
|
|
|
|
if (destFolder.IsEmpty())
|
|
return;
|
|
|
|
ReorderFolders = TRUE;
|
|
}
|
|
|
|
if (ReorderFolders) {
|
|
|
|
InitFolderList(true, 1);
|
|
GetDlgItem(ID_RECOVER_RIGHT_CLICK)->ShowWindow(
|
|
(m_list.GetCount() > 2) ? SW_SHOW : SW_HIDE);
|
|
|
|
m_check = FALSE;
|
|
|
|
ReorderFolders = FALSE;
|
|
}
|
|
|
|
ok = RecoverFile(destFolder);
|
|
}
|
|
|
|
if (ok) {
|
|
|
|
m_items.RemoveAt(pos);
|
|
GetDlgItem(ID_RECOVER_SELECT_ALL)->ShowWindow(
|
|
(m_items.GetCount() > 1) ? SW_SHOW : SW_HIDE);
|
|
list->DeleteString(index);
|
|
|
|
} else
|
|
list->SetSel(index, FALSE);
|
|
break;
|
|
}
|
|
|
|
if (index == size)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
|
|
if (! AnySelected)
|
|
CMyApp::MsgBox(this, MSG_3728, MB_OK);
|
|
|
|
if (list->GetCount() == 0)
|
|
EndDialog(0);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverToSameFolder
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverToSameFolder()
|
|
{
|
|
CBox &box = CBoxes::GetInstance().GetBox(m_BoxName);
|
|
CBoxFile &boxfile = box.GetBoxFile();
|
|
|
|
CString CopyPath = m_SrcPath;
|
|
CString TruePath = boxfile.GetTruePathForCopyPath(CopyPath);
|
|
|
|
bool JustCreateDir = false;
|
|
int index = TruePath.ReverseFind(L'\\');
|
|
if (index != -1) {
|
|
if (TruePath.Mid(index + 1) == L"\\*?|") // see RecoverFolder
|
|
JustCreateDir = true;
|
|
TruePath = TruePath.Mid(0, index);
|
|
}
|
|
|
|
CString TruePathDos = TruePath;
|
|
boxfile.TranslateNtToDosPath(TruePathDos);
|
|
if (TruePathDos.GetLength() > 3)
|
|
SHCreateDirectory(m_pParentWnd->m_hWnd, TruePathDos);
|
|
|
|
if (JustCreateDir)
|
|
return TRUE;
|
|
|
|
return RecoverFile(TruePath, TRUE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverFile
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverFile(const CString &DestPath, BOOL SameFolder)
|
|
{
|
|
//
|
|
// prepare double-NULL-terminated versions of the
|
|
// source and target paths
|
|
//
|
|
|
|
ULONG src_len = wcslen(m_SrcPath);
|
|
WCHAR *src = malloc_WCHAR((src_len + 8) * sizeof(WCHAR));
|
|
wmemcpy(src, m_SrcPath, src_len);
|
|
wmemzero(src + src_len, 4);
|
|
SbieDll_TranslateNtToDosPath(src);
|
|
wmemzero(src + wcslen(src), 4);
|
|
|
|
ULONG dst_len = wcslen(DestPath);
|
|
WCHAR *dst = malloc_WCHAR((dst_len + 8) * sizeof(WCHAR));
|
|
wmemcpy(dst, DestPath, dst_len);
|
|
wmemzero(dst + dst_len, 4);
|
|
SbieDll_TranslateNtToDosPath(dst);
|
|
wmemzero(dst + wcslen(dst), 4);
|
|
|
|
//
|
|
// if destination path is too long, abort
|
|
// if source path is too long, rename to a shorter folder
|
|
//
|
|
|
|
BOOL ok = FALSE;
|
|
|
|
WCHAR *ptr = wcsrchr(src, L'\\');
|
|
if (ptr) {
|
|
|
|
if (wcslen(dst) + wcslen(ptr) >= 250) {
|
|
|
|
CWnd *pWnd = m_hWnd ? this : m_pParentWnd;
|
|
CMyApp::MsgBox(pWnd, CMyMsg(MSG_3733), MB_OK);
|
|
|
|
} else {
|
|
|
|
m_DstPath = DestPath;
|
|
|
|
if (wcslen(src) < 250)
|
|
ok = RecoverFile2(src, dst, SameFolder);
|
|
else
|
|
ok = RecoverFile3(src, dst, SameFolder);
|
|
}
|
|
}
|
|
|
|
if (! ok)
|
|
m_DstPath = CString();
|
|
|
|
free(dst);
|
|
free(src);
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverFile2
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverFile2(WCHAR *src, WCHAR *dst, BOOL SameFolder)
|
|
{
|
|
//
|
|
// handle missing files and directories
|
|
//
|
|
|
|
ULONG attrs = GetFileAttributes(src);
|
|
|
|
if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
BOOL ok;
|
|
|
|
if (attrs == INVALID_FILE_ATTRIBUTES) {
|
|
|
|
ULONG LastError = GetLastError();
|
|
ok = (LastError == 0 ||
|
|
LastError == ERROR_FILE_NOT_FOUND ||
|
|
LastError == ERROR_PATH_NOT_FOUND);
|
|
|
|
} else {
|
|
|
|
ok = RecoverFolder(SameFolder);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
//
|
|
// recover the file by moving it out of the sandbox
|
|
//
|
|
|
|
CWnd *pWnd = m_hWnd ? this : m_pParentWnd;
|
|
|
|
SHFILEOPSTRUCT op;
|
|
memzero(&op, sizeof(SHFILEOPSTRUCT));
|
|
|
|
op.hwnd = pWnd->m_hWnd;
|
|
op.wFunc = FO_MOVE;
|
|
op.fFlags = FOF_NOCONFIRMMKDIR | FOF_SILENT
|
|
| FOF_NOCOPYSECURITYATTRIBS;
|
|
if (m_replace)
|
|
op.fFlags |= FOF_NOCONFIRMATION;
|
|
op.pFrom = src;
|
|
op.pTo = dst;
|
|
|
|
// The default operation is to Move the file -> Check if we have Delete access
|
|
// If not, we'll switch to a Copy operation. This allows Office or Adobe files
|
|
// to be recovered while they are still in use.
|
|
HANDLE hDeleteTest = CreateFile(src, DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (hDeleteTest == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (GetLastError() == ERROR_SHARING_VIOLATION)
|
|
{
|
|
op.wFunc = FO_COPY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hDeleteTest);
|
|
hDeleteTest = NULL;
|
|
}
|
|
|
|
|
|
if (! ReplaceButtonText)
|
|
ReplaceButtonText = _wcsdup(CMyMsg(MSG_3735));
|
|
|
|
BOOL YesToAll;
|
|
int rc = Common_SHFileOperation(&op, &YesToAll, ReplaceButtonText);
|
|
if (YesToAll) {
|
|
m_replace = TRUE;
|
|
op.fFlags |= FOF_NOCONFIRMATION;
|
|
rc = Common_SHFileOperation(&op, &YesToAll, ReplaceButtonText);
|
|
}
|
|
|
|
//
|
|
// complain (on error) or add to log (on success)
|
|
//
|
|
|
|
if (GetFileAttributes(dst) == INVALID_FILE_ATTRIBUTES) {
|
|
rc = 1;
|
|
op.fAnyOperationsAborted = FALSE;
|
|
}
|
|
if ((rc != 0) && (! op.fAnyOperationsAborted))
|
|
RecoverFileX(src);
|
|
|
|
if ((rc == 0) && (! op.fAnyOperationsAborted)) {
|
|
|
|
const WCHAR *backslash = wcsrchr(src, L'\\');
|
|
if (backslash) {
|
|
CString item = CString(dst) + CString(backslash);
|
|
if (GetFileAttributes(item) != INVALID_FILE_ATTRIBUTES) {
|
|
|
|
m_past_files.AddTail(item);
|
|
|
|
if (m_recover_mode) {
|
|
const WCHAR *path = (m_recover_mode == 1) ? dst : item;
|
|
ShellExecute(
|
|
m_hWnd, NULL, path, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (rc == 0 ? TRUE : FALSE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverFile3
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverFile3(WCHAR *src, WCHAR *dst, BOOL SameFolder)
|
|
{
|
|
BOOL complain = TRUE;
|
|
BOOL ok;
|
|
|
|
CBox &box = CBoxes::GetInstance().GetBox(m_BoxName);
|
|
CBoxFile &boxfile = box.GetBoxFile();
|
|
|
|
//
|
|
// the source path is too long, rename it to something shorter.
|
|
// first, create a temporary directory
|
|
//
|
|
|
|
++m_TempFolderCounter;
|
|
CString StringCounter;
|
|
StringCounter.Format(L"\\temp-%04X", m_TempFolderCounter % 0x10000);
|
|
|
|
CString TempFolder = boxfile.GetPathDos() + StringCounter;
|
|
|
|
int SrcIndex = m_SrcPath.ReverseFind(L'\\');
|
|
if (SrcIndex == -1)
|
|
return FALSE;
|
|
CString NewSrcPath = TempFolder + m_SrcPath.Mid(SrcIndex);
|
|
if (NewSrcPath.GetLength() >= 250) {
|
|
RecoverFileX(src);
|
|
return FALSE;
|
|
}
|
|
|
|
ok = CreateDirectory(TempFolder, NULL);
|
|
if ((! ok) && GetLastError() == ERROR_ALREADY_EXISTS)
|
|
ok = TRUE;
|
|
|
|
if (ok) {
|
|
|
|
//
|
|
// move the source file into the temporary directory
|
|
//
|
|
|
|
ok = MoveFile(_LongPathPrefix + src, NewSrcPath);
|
|
if (ok) {
|
|
|
|
ULONG src2_len = NewSrcPath.GetLength();
|
|
WCHAR *src2 = malloc_WCHAR((src2_len + 4) * sizeof(WCHAR));
|
|
wmemcpy(src2, NewSrcPath, src2_len);
|
|
wmemzero(src2 + src2_len, 4);
|
|
|
|
CString SaveSrcPath(m_SrcPath);
|
|
m_SrcPath = boxfile.GetPathDos()
|
|
+ StringCounter
|
|
+ SaveSrcPath.Mid(SrcIndex);
|
|
|
|
complain = FALSE;
|
|
ok = RecoverFile2(src2, dst, SameFolder);
|
|
|
|
m_SrcPath = SaveSrcPath;
|
|
|
|
if (! ok) {
|
|
|
|
//
|
|
// if recovery failed, move the file back
|
|
//
|
|
|
|
MoveFile(NewSrcPath, _LongPathPrefix + src);
|
|
}
|
|
|
|
free(src2);
|
|
}
|
|
|
|
//
|
|
// remove the temporary directory
|
|
//
|
|
|
|
RemoveDirectory(TempFolder);
|
|
}
|
|
|
|
if ((! ok) && complain)
|
|
RecoverFileX(src);
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverFileX
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
NOINLINE void CQuickRecover::RecoverFileX(WCHAR *src)
|
|
{
|
|
CWnd *pWnd = m_hWnd ? this : m_pParentWnd;
|
|
|
|
CString msg = CMyMsg(MSG_3729);
|
|
msg += L"\n\n";
|
|
msg += src;
|
|
CMyApp::MsgBox(pWnd, msg, MB_OK);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoverFolder
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::RecoverFolder(BOOL SameFolder)
|
|
{
|
|
if (! SameFolder) {
|
|
|
|
int SrcIndex = m_SrcPath.ReverseFind(L'\\');
|
|
int DstIndex = m_DstPath.ReverseFind(L'\\');
|
|
if (SrcIndex != -1 && DstIndex != -1) {
|
|
|
|
CString SrcName = m_SrcPath.Mid(SrcIndex);
|
|
CString DstName = m_DstPath.Mid(DstIndex);
|
|
|
|
if (SrcName.CompareNoCase(DstName) != 0) {
|
|
|
|
m_DstPath += SrcName;
|
|
SHCreateDirectory(m_pParentWnd->m_hWnd, m_DstPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
CString SaveSrcPath(m_SrcPath);
|
|
CString SaveDstPath(m_DstPath);
|
|
|
|
CString SearchString;
|
|
if (m_SrcPath.GetLength() >= 250)
|
|
SearchString = _LongPathPrefix;
|
|
SearchString += SaveSrcPath + L"\\*";
|
|
|
|
bool FoundAtLeastOneFile = false;
|
|
|
|
WIN32_FIND_DATA data;
|
|
HANDLE handle = FindFirstFile(SearchString, &data);
|
|
while (handle != INVALID_HANDLE_VALUE) {
|
|
|
|
CString FileName(data.cFileName);
|
|
if (FileName != L"." && FileName != L".." &&
|
|
(data.ftCreationTime.dwHighDateTime != 0x01B01234 ||
|
|
data.ftCreationTime.dwLowDateTime != 0xDEAD44A0)) {
|
|
|
|
m_SrcPath += L"\\" + FileName;
|
|
|
|
BOOL ok;
|
|
if (SameFolder) {
|
|
|
|
FoundAtLeastOneFile = true;
|
|
|
|
ok = RecoverToSameFolder();
|
|
|
|
} else if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
m_DstPath += L"\\" + FileName;
|
|
|
|
SHCreateDirectory(m_pParentWnd->m_hWnd, m_DstPath);
|
|
|
|
ok = RecoverFolder(FALSE);
|
|
|
|
m_DstPath = SaveDstPath;
|
|
|
|
} else {
|
|
|
|
ok = RecoverFile(m_DstPath);
|
|
|
|
}
|
|
|
|
m_SrcPath = SaveSrcPath;
|
|
|
|
if (! ok) {
|
|
FindClose(handle);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (! FindNextFile(handle, &data)) {
|
|
FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
if (SameFolder && (! FoundAtLeastOneFile)) {
|
|
// make sure the folder itself is created even when it
|
|
// doesn't contain any files or sub-folders
|
|
m_SrcPath += L"\\*?|";
|
|
RecoverToSameFolder();
|
|
m_SrcPath = SaveSrcPath;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoveryLog
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::RecoveryLog()
|
|
{
|
|
AutoRecover(); // just for SetDialogTemplate
|
|
|
|
DoModal();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RecoveryLog
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
BOOL CQuickRecover::OnInitDialogRecoveryLog()
|
|
{
|
|
//
|
|
// set dialog texts and adjust dialog position
|
|
//
|
|
|
|
SetWindowText(CMyMsg(MSG_3986));
|
|
|
|
GetDlgItem(ID_DELETE_EXPLAIN_1)->SetWindowText(CMyMsg(MSG_3987));
|
|
GetDlgItem(ID_DELETE_EXPLAIN_2)->ShowWindow(SW_HIDE);
|
|
|
|
GetDlgItem(ID_RECOVER_DISABLE)->ShowWindow(SW_HIDE);
|
|
|
|
//
|
|
// stretch items list on top of folders list
|
|
//
|
|
|
|
CListBox *pListBox1 = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
CListBox *pListBox2 = (CListBox *)GetDlgItem(ID_RECOVER_FOLDERS);
|
|
|
|
RECT rc1, rc2, rc3;
|
|
pListBox1->GetWindowRect(&rc1);
|
|
pListBox2->GetWindowRect(&rc2);
|
|
rc1.bottom = rc2.bottom;
|
|
ScreenToClient(&rc1);
|
|
|
|
pListBox2->ShowWindow(SW_HIDE);
|
|
pListBox1->SetWindowPos(NULL,
|
|
rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, 0);
|
|
|
|
pListBox1->SetItemHeight(0, pListBox1->GetItemHeight(0) * 3 / 2);
|
|
|
|
pListBox1->ModifyStyle(LBS_EXTENDEDSEL, 0);
|
|
|
|
//
|
|
// reposition the CLOSE button
|
|
//
|
|
|
|
CButton *pButton1 = (CButton *)GetDlgItem(IDOK);
|
|
CButton *pButton2 = (CButton *)GetDlgItem(IDCANCEL);
|
|
CButton *pButton3 = (CButton *)GetDlgItem(ID_RECOVER_REMOVE);
|
|
|
|
pButton1->GetWindowRect(&rc1);
|
|
pButton2->GetWindowRect(&rc2);
|
|
rc2.top = rc1.bottom + 5;
|
|
rc2.bottom = rc2.top + (rc1.bottom - rc1.top);
|
|
rc1.right = rc2.right;
|
|
rc1.top -= 5;
|
|
rc1.bottom -= 5;
|
|
ScreenToClient(&rc1);
|
|
ScreenToClient(&rc2);
|
|
rc3.left = rc1.left;
|
|
rc3.top = rc2.top;
|
|
rc3.right = rc2.left - 15;
|
|
rc3.bottom = rc2.bottom;
|
|
|
|
pButton1->SetWindowPos(NULL,
|
|
rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, 0);
|
|
pButton2->SetWindowPos(NULL,
|
|
rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top, 0);
|
|
pButton3->SetWindowPos(NULL,
|
|
rc3.left, rc3.top, rc3.right - rc3.left, rc3.bottom - rc3.top,
|
|
SWP_SHOWWINDOW);
|
|
|
|
pButton1->SetWindowText(CMyMsg(MSG_3981));
|
|
pButton2->SetWindowText(CMyMsg(MSG_3004));
|
|
pButton3->SetWindowText(CMyMsg(MSG_3983));
|
|
|
|
//
|
|
// populate list of recently recovered files
|
|
//
|
|
|
|
POSITION pos = m_past_files.GetHeadPosition();
|
|
while (pos) {
|
|
CString &item = m_past_files.GetNext(pos);
|
|
pListBox1->InsertString(0, item);
|
|
}
|
|
|
|
m_log_count = (ULONG)(ULONG_PTR)m_past_files.GetCount();
|
|
if (! m_log_count) {
|
|
pButton1->EnableWindow(FALSE);
|
|
pButton3->EnableWindow(FALSE);
|
|
} else
|
|
pListBox1->SetCurSel(0);
|
|
|
|
//
|
|
// set recovery log mode of operation
|
|
//
|
|
|
|
m_log = TRUE;
|
|
m_ready = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnOKRecoveryLog
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnOKRecoveryLog()
|
|
{
|
|
CListBox *list = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
int index = list->GetCurSel();
|
|
if (index == LB_ERR)
|
|
return;
|
|
|
|
CString path = m_past_files.GetAt(m_past_files.FindIndex(index));
|
|
index = path.ReverseFind(L'\\');
|
|
if (index != -1) {
|
|
path = path.Mid(0, index);
|
|
ShellExecute(m_hWnd, NULL, path, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnActivateRecoveryLog
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnActivate(UINT nState, CWnd *pWndOther, BOOL bMinimized)
|
|
{
|
|
if (m_log && nState != WA_INACTIVE &&
|
|
m_log_count != (ULONG)(ULONG_PTR)m_past_files.GetCount()) {
|
|
|
|
CListBox *pListBox1 = (CListBox *)GetDlgItem(ID_RECOVER_ITEMS);
|
|
|
|
POSITION pos = m_past_files.FindIndex(m_log_count);
|
|
while (pos) {
|
|
CString &item = m_past_files.GetNext(pos);
|
|
pListBox1->InsertString(0, item);
|
|
}
|
|
|
|
m_log_count = (ULONG)(ULONG_PTR)m_past_files.GetCount();
|
|
if (m_log_count) {
|
|
GetDlgItem(IDOK)->EnableWindow(TRUE);
|
|
GetDlgItem(ID_RECOVER_REMOVE)->EnableWindow(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// OnRemoveFolders
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void CQuickRecover::OnRemoveFolders()
|
|
{
|
|
m_past_files.RemoveAll();
|
|
m_log_count = 0;
|
|
((CListBox *)GetDlgItem(ID_RECOVER_ITEMS))->ResetContent();
|
|
GetDlgItem(IDOK)->EnableWindow(FALSE);
|
|
GetDlgItem(ID_RECOVER_REMOVE)->EnableWindow(FALSE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Split Button Stuff
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
#define BS_DEFSPLITBUTTON 0x0000000DL
|
|
#define BCN_DROPDOWN (BCN_FIRST + 0x0002)
|
|
#define BCM_SETSPLITINFO (BCM_FIRST + 0x0007)
|
|
// SPLIT BUTTON INFO mask flags
|
|
#define BCSIF_GLYPH 0x0001
|
|
#define BCSIF_IMAGE 0x0002
|
|
#define BCSIF_STYLE 0x0004
|
|
#define BCSIF_SIZE 0x0008
|
|
// SPLIT BUTTON STYLE flags
|
|
#define BCSS_NOSPLIT 0x0001
|
|
#define BCSS_STRETCH 0x0002
|
|
#define BCSS_ALIGNLEFT 0x0004
|
|
#define BCSS_IMAGE 0x0008
|
|
|
|
|
|
ON_NOTIFY(BCN_DROPDOWN, IDOK, OnDropDownRecover)
|
|
|
|
|
|
void CQuickRecover::OnDropDownRecover(NMHDR *pNMHDR, LRESULT *pResult)
|
|
{
|
|
if (! CMyApp::m_WindowsVista)
|
|
return;
|
|
|
|
typedef struct tagNMBCDROPDOWN {
|
|
NMHDR hdr;
|
|
RECT rcButton;
|
|
} NMBCDROPDOWN;
|
|
NMBCDROPDOWN *pDropDown = (NMBCDROPDOWN *)pNMHDR;
|
|
|
|
POINT pt;
|
|
pt.x = pDropDown->rcButton.left;
|
|
pt.y = pDropDown->rcButton.bottom;
|
|
::ClientToScreen(pDropDown->hdr.hwndFrom, &pt);
|
|
|
|
CMenu menu;
|
|
menu.CreatePopupMenu();
|
|
menu.AppendMenu(MF_STRING, 1, CMyMsg(MSG_3718));
|
|
menu.AppendMenu(MF_STRING, 2, CMyMsg(MSG_3736));
|
|
menu.AppendMenu(MF_STRING, 3, CMyMsg(MSG_3737));
|
|
ULONG menucmd = menu.TrackPopupMenu(
|
|
TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN,
|
|
pt.x, pt.y, this);
|
|
|
|
while (menucmd >= 1 && menucmd <= 3 && m_recover_mode != menucmd)
|
|
OnCycleRecover();
|
|
}
|
|
|
|
|
|
//
|
|
// prepare the cycle button for the recover button
|
|
//
|
|
|
|
if (CMyApp::m_WindowsVista) {
|
|
|
|
pButton = (CButton *)GetDlgItem(IDOK);
|
|
pButton->ModifyStyle(0, BS_DEFSPLITBUTTON);
|
|
|
|
CImageList imglist;
|
|
imglist.Create(25, 25, ILC_COLORDDB | ILC_MASK, 8, 8);
|
|
imglist.SetBkColor(CLR_NONE);
|
|
imglist.Add(CBitmap::FromHandle(cycle_bitmap), RGB(0,0,0));
|
|
|
|
struct {
|
|
UINT mask;
|
|
HIMAGELIST himlGlyph;
|
|
UINT uSplitStyle;
|
|
SIZE size;
|
|
} SplitInfo;
|
|
memzero(&SplitInfo, sizeof(SplitInfo));
|
|
SplitInfo.mask = BCSIF_IMAGE | BCSIF_STYLE;
|
|
SplitInfo.himlGlyph = imglist.Detach();
|
|
SplitInfo.uSplitStyle = BCSS_STRETCH | BCSS_IMAGE;
|
|
pButton->SendMessage(BCM_SETSPLITINFO, 0, (LPARAM)&SplitInfo);
|
|
}
|
|
|
|
pButton = (CButton *)GetDlgItem(ID_RECOVER_CYCLE);
|
|
pButton->SetBitmap(cycle_bitmap);
|
|
pButton->SetWindowPos(NULL, 0, 0, 25, 25, SWP_NOMOVE | SWP_SHOWWINDOW);
|
|
|
|
if (! CycleRecoverButton.m_hWnd)
|
|
CycleRecoverButton.Init(pButton->m_hWnd, CMyMsg(MSG_3736));
|
|
|
|
|
|
#endif
|