1122 lines
34 KiB
C++
1122 lines
34 KiB
C++
// CVSSProp.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "utils.h"
|
|
#include "VSSProp.h"
|
|
#include "RemDlg.h"
|
|
#include "Settings.h"
|
|
#include "Hosting.h"
|
|
#include "uihelp.h"
|
|
|
|
#include <vss.h> // _VSS_SNAPSHOT_CONTEXT
|
|
#include <vsmgmt.h>
|
|
#include <vsswprv.h> // VSS_SWPRV_ProviderId
|
|
#include <vswriter.h>// VssFreeSnapshotProperties
|
|
#include <vsbackup.h> // VssFreeSnapshotProperties
|
|
|
|
#include <lm.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CVSSProp property page
|
|
|
|
IMPLEMENT_DYNCREATE(CVSSProp, CPropertyPage)
|
|
|
|
CVSSProp::CVSSProp() : CPropertyPage(CVSSProp::IDD)
|
|
{
|
|
//{{AFX_DATA_INIT(CVSSProp)
|
|
//}}AFX_DATA_INIT
|
|
m_strComputer = _T("");
|
|
m_strSelectedVolume = _T("");
|
|
}
|
|
|
|
CVSSProp::CVSSProp(LPCTSTR pszComputer, LPCTSTR pszVolume) : CPropertyPage(CVSSProp::IDD)
|
|
{
|
|
#ifdef DEBUG
|
|
OutputDebugString(_T("CVSSProp::CVSSPRop\n"));
|
|
#endif
|
|
if (!pszComputer)
|
|
m_strComputer = _T("");
|
|
else
|
|
m_strComputer = pszComputer + (TWO_WHACKS(pszComputer) ? 2 : 0);
|
|
|
|
m_strSelectedVolume = (pszVolume ? pszVolume : _T(""));
|
|
}
|
|
|
|
CVSSProp::~CVSSProp()
|
|
{
|
|
#ifdef DEBUG
|
|
OutputDebugString(_T("CVSSProp::~CVSSPRop\n"));
|
|
#endif
|
|
}
|
|
|
|
HRESULT CVSSProp::StoreShellExtPointer(IShellPropSheetExt* piShellExt)
|
|
{
|
|
if (!piShellExt)
|
|
return E_INVALIDARG;
|
|
|
|
// This assignment will call AddRef().
|
|
// Release() will later be called by ~CVSSProp().
|
|
m_spiShellExt = piShellExt;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CVSSProp::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CPropertyPage::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CVSSProp)
|
|
DDX_Control(pDX, IDC_VOLUME_LIST, m_ctrlVolumeList);
|
|
DDX_Control(pDX, IDC_ENABLE, m_ctrlEnable);
|
|
DDX_Control(pDX, IDC_DISABLE, m_ctrlDisable);
|
|
DDX_Control(pDX, IDC_SETTINGS, m_ctrlSettings);
|
|
DDX_Control(pDX, IDC_SNAPSHOT_LIST, m_ctrlSnapshotList);
|
|
DDX_Control(pDX, IDC_CREATE, m_ctrlCreate);
|
|
DDX_Control(pDX, IDC_DELETE, m_ctrlDelete);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CVSSProp, CPropertyPage)
|
|
//{{AFX_MSG_MAP(CVSSProp)
|
|
ON_BN_CLICKED(IDC_CREATE, OnCreateNow)
|
|
ON_BN_CLICKED(IDC_DELETE, OnDeleteNow)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_SNAPSHOT_LIST, OnItemchangedSnapshotList)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_VOLUME_LIST, OnItemchangedVolumeList)
|
|
ON_WM_HELPINFO()
|
|
ON_BN_CLICKED(IDC_ENABLE, OnEnable)
|
|
ON_BN_CLICKED(IDC_DISABLE, OnDisable)
|
|
ON_BN_CLICKED(IDC_SETTINGS, OnSettings)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CVSSProp message handlers
|
|
|
|
//
|
|
// If we have successfully taken one snapshot of the specified volume, we will
|
|
// return VSS_S_ASYNC_FINISHED.
|
|
//
|
|
HRESULT CVSSProp::TakeOneSnapshotNow(IN LPCTSTR pszVolumeName)
|
|
{
|
|
if (!pszVolumeName || !*pszVolumeName)
|
|
return E_INVALIDARG;
|
|
|
|
VSS_ID SnapshotSetId = GUID_NULL;
|
|
HRESULT hr = m_spiCoord->StartSnapshotSet(&SnapshotSetId);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VSS_ID SnapshotId = GUID_NULL;
|
|
hr = m_spiCoord->AddToSnapshotSet(
|
|
(PTSTR)pszVolumeName,
|
|
VSS_SWPRV_ProviderId,
|
|
&SnapshotId);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComPtr<IVssAsync> spiAsync;
|
|
hr = m_spiCoord->DoSnapshotSet(NULL, &spiAsync);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = spiAsync->Wait();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HRESULT hrStatus = S_OK;
|
|
hr = spiAsync->QueryStatus(&hrStatus, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
return hrStatus;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// OnCreateNow works when only one volume is currently selected.
|
|
//
|
|
void CVSSProp::OnCreateNow()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
if (m_strSelectedVolume.IsEmpty())
|
|
return;
|
|
|
|
PTSTR pszVolumeName = GetVolumeName(&m_VolumeList, m_strSelectedVolume);
|
|
ASSERT(pszVolumeName);
|
|
|
|
HRESULT hr = TakeOneSnapshotNow(pszVolumeName);
|
|
if (VSS_S_ASYNC_FINISHED == hr)
|
|
{
|
|
UpdateSnapshotList();
|
|
UpdateDiffArea();
|
|
} else if (FAILED(hr))
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_TAKESNAPSHOT_ERROR, m_strSelectedVolume);
|
|
}
|
|
}
|
|
|
|
//
|
|
// OnDeleteNow works on multi-selected snapshots when only one volume is currently selected.
|
|
//
|
|
void CVSSProp::OnDeleteNow()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
if (m_strSelectedVolume.IsEmpty())
|
|
return;
|
|
|
|
BOOL bAtLeastOneDeleted = FALSE;
|
|
HRESULT hr = S_OK;
|
|
|
|
int nIndex = -1;
|
|
while (-1 != (nIndex = m_ctrlSnapshotList.GetNextItem(nIndex, LVNI_SELECTED)))
|
|
{
|
|
VSSUI_SNAPSHOT *pSnapshot = (VSSUI_SNAPSHOT *)GetListViewItemData(m_ctrlSnapshotList.m_hWnd, nIndex);
|
|
ASSERT(pSnapshot);
|
|
|
|
LONG lDeletedSnapshots = 0;
|
|
VSS_ID ProblemSnapshotId = GUID_NULL;
|
|
hr = m_spiCoord->DeleteSnapshots(pSnapshot->idSnapshot,
|
|
VSS_OBJECT_SNAPSHOT,
|
|
TRUE,
|
|
&lDeletedSnapshots,
|
|
&ProblemSnapshotId
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
bAtLeastOneDeleted = TRUE;
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETESNAPSHOTS_ERROR, m_strSelectedVolume);
|
|
|
|
if (bAtLeastOneDeleted)
|
|
{
|
|
UpdateSnapshotList();
|
|
UpdateDiffArea();
|
|
}
|
|
}
|
|
|
|
#define HKCU_VSSUI_KEY _T("Software\\Microsoft\\VSSUI")
|
|
#define REGVALUENAME_ENABLE _T("EnableReminderOff")
|
|
#define REGVALUENAME_DISABLE _T("DisableReminderOff")
|
|
|
|
void CVSSProp::OnEnable()
|
|
{
|
|
BOOL bShowReminder = TRUE;
|
|
|
|
HKEY hKey = NULL;
|
|
LONG lErr = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
HKCU_VSSUI_KEY,
|
|
0, // reserved
|
|
_T(""), // lpClass
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
NULL, // lpSecurityAttributes
|
|
&hKey,
|
|
NULL // lpdwDisposition
|
|
);
|
|
if (ERROR_SUCCESS == lErr)
|
|
{
|
|
DWORD dwType = 0;
|
|
DWORD dwData = 0;
|
|
DWORD cbData = sizeof(DWORD);
|
|
|
|
lErr = RegQueryValueEx(hKey, REGVALUENAME_ENABLE, 0, &dwType, (LPBYTE)&dwData, &cbData);
|
|
|
|
if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != dwData)
|
|
bShowReminder = FALSE;
|
|
}
|
|
|
|
int nRet = IDOK;
|
|
if (bShowReminder)
|
|
{
|
|
CString strMsg;
|
|
strMsg.LoadString(IDS_ENABLE_REMINDER);
|
|
CReminderDlg dlg(strMsg, hKey, REGVALUENAME_ENABLE);
|
|
nRet = dlg.DoModal();
|
|
}
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (IDOK == nRet)
|
|
DoEnable();
|
|
}
|
|
|
|
HRESULT CVSSProp::DoEnable()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
HRESULT hr = S_OK;
|
|
LVITEM lvItem = {0};
|
|
int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
|
|
if (nSelectedCount > 0)
|
|
{
|
|
POSITION pos = m_ctrlVolumeList.GetFirstSelectedItemPosition();
|
|
while (pos)
|
|
{
|
|
int nIndex = m_ctrlVolumeList.GetNextSelectedItem(pos);
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(m_ctrlVolumeList.m_hWnd, nIndex);
|
|
ASSERT(pVolume);
|
|
|
|
//
|
|
// if none, create default schedule for that volume
|
|
//
|
|
CComPtr<ITask> spiTask;
|
|
hr = FindScheduledTimewarpTask(
|
|
(ITaskScheduler *)m_spiTS,
|
|
pVolume->pszDisplayName,
|
|
&spiTask);
|
|
if (FAILED(hr))
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_FINDSCHEDULE_ERROR, pVolume->pszDisplayName);
|
|
} else if (S_FALSE == hr) // task not found
|
|
{
|
|
(void)DeleteAllScheduledTimewarpTasks((ITaskScheduler *)m_spiTS,
|
|
pVolume->pszDisplayName,
|
|
TRUE // i_bDeleteDisabledOnesOnly
|
|
);
|
|
hr = CreateDefaultEnableSchedule(
|
|
(ITaskScheduler *)m_spiTS,
|
|
m_strComputer,
|
|
pVolume->pszDisplayName,
|
|
pVolume->pszVolumeName,
|
|
&spiTask);
|
|
if (FAILED(hr))
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_CREATESCHEDULE_ERROR, pVolume->pszDisplayName);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
UpdateSchedule((ITask *)spiTask, nIndex);
|
|
else
|
|
break;
|
|
|
|
//
|
|
// take one snapshot now, it will create default diff area association if none
|
|
//
|
|
hr = TakeOneSnapshotNow(pVolume->pszVolumeName);
|
|
if (VSS_S_ASYNC_FINISHED == hr)
|
|
{
|
|
if (1 == nSelectedCount)
|
|
UpdateSnapshotList();
|
|
|
|
UpdateDiffArea(nIndex, pVolume->pszVolumeName);
|
|
} else if (FAILED(hr))
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_TAKESNAPSHOT_ERROR, pVolume->pszDisplayName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CVSSProp::OnDisable()
|
|
{
|
|
BOOL bShowReminder = TRUE;
|
|
|
|
HKEY hKey = NULL;
|
|
LONG lErr = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
HKCU_VSSUI_KEY,
|
|
0, // reserved
|
|
_T(""), // lpClass
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
NULL, // lpSecurityAttributes
|
|
&hKey,
|
|
NULL // lpdwDisposition
|
|
);
|
|
if (ERROR_SUCCESS == lErr)
|
|
{
|
|
DWORD dwType = 0;
|
|
DWORD dwData = 0;
|
|
DWORD cbData = sizeof(DWORD);
|
|
|
|
lErr = RegQueryValueEx(hKey, REGVALUENAME_DISABLE, 0, &dwType, (LPBYTE)&dwData, &cbData);
|
|
|
|
if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != dwData)
|
|
bShowReminder = FALSE;
|
|
}
|
|
|
|
int nRet = IDOK;
|
|
if (bShowReminder)
|
|
{
|
|
CString strMsg;
|
|
strMsg.LoadString(IDS_DISABLE_REMINDER);
|
|
CReminderDlg dlg(strMsg, hKey, REGVALUENAME_DISABLE);
|
|
nRet = dlg.DoModal();
|
|
}
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (IDOK == nRet)
|
|
DoDisable();
|
|
}
|
|
|
|
HRESULT CVSSProp::DoDisable()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
HRESULT hr = S_OK;
|
|
LVITEM lvItem = {0};
|
|
int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
|
|
if (nSelectedCount > 0)
|
|
{
|
|
POSITION pos = m_ctrlVolumeList.GetFirstSelectedItemPosition();
|
|
while (pos)
|
|
{
|
|
int nIndex = m_ctrlVolumeList.GetNextSelectedItem(pos);
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(m_ctrlVolumeList.m_hWnd, nIndex);
|
|
ASSERT(pVolume);
|
|
|
|
//
|
|
// delete all snapshots on that volume
|
|
//
|
|
hr = DeleteAllSnapshotsOnVolume(pVolume->pszVolumeName);
|
|
UpdateSnapshotList();
|
|
if (FAILED(hr))
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETESNAPSHOTS_ERROR, pVolume->pszDisplayName);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// delete all scheduled tasks for that volume
|
|
//
|
|
hr = DeleteAllScheduledTimewarpTasks((ITaskScheduler *)m_spiTS,
|
|
pVolume->pszDisplayName,
|
|
FALSE // i_bDeleteDisabledOnesOnly
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
UpdateSchedule(NULL, nIndex);
|
|
else
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_FINDSCHEDULE_ERROR, pVolume->pszDisplayName);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// remove diff area associate for that volume
|
|
//
|
|
VSSUI_DIFFAREA diffArea;
|
|
hr = GetDiffAreaInfo(m_spiDiffSnapMgmt, &m_VolumeList, pVolume->pszVolumeName, &diffArea);
|
|
if (S_OK == hr)
|
|
{
|
|
PTSTR pszDiffAreaVolumeName = GetVolumeName(&m_VolumeList, diffArea.pszDiffVolumeDisplayName);
|
|
ASSERT(pszDiffAreaVolumeName);
|
|
hr = m_spiDiffSnapMgmt->ChangeDiffAreaMaximumSize(
|
|
pVolume->pszVolumeName,
|
|
pszDiffAreaVolumeName,
|
|
VSS_ASSOC_REMOVE);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
UpdateDiffArea(nIndex, pVolume->pszVolumeName);
|
|
else
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETEDIFFAREA_ERROR, pVolume->pszDisplayName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVSSProp::DeleteAllSnapshotsOnVolume(
|
|
IN LPCTSTR pszVolumeName
|
|
)
|
|
{
|
|
if (!pszVolumeName || !*pszVolumeName)
|
|
return E_INVALIDARG;
|
|
|
|
CComPtr<IVssEnumObject> spiEnumSnapshots;
|
|
HRESULT hr = m_spiMgmt->QuerySnapshotsByVolume(
|
|
(PTSTR)pszVolumeName,
|
|
VSS_SWPRV_ProviderId,
|
|
&spiEnumSnapshots
|
|
);
|
|
if (S_OK == hr)
|
|
{
|
|
VSS_OBJECT_PROP Prop;
|
|
VSS_SNAPSHOT_PROP* pSnapProp = &(Prop.Obj.Snap);
|
|
ULONG ulFetched = 0;
|
|
while (SUCCEEDED(spiEnumSnapshots->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
|
|
{
|
|
if (VSS_OBJECT_SNAPSHOT != Prop.Type)
|
|
return E_FAIL;
|
|
|
|
if (pSnapProp->m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
|
|
{
|
|
LONG lDeletedSnapshots = 0;
|
|
VSS_ID ProblemSnapshotId = GUID_NULL;
|
|
hr = m_spiCoord->DeleteSnapshots(pSnapProp->m_SnapshotId,
|
|
VSS_OBJECT_SNAPSHOT,
|
|
TRUE,
|
|
&lDeletedSnapshots,
|
|
&ProblemSnapshotId
|
|
);
|
|
VssFreeSnapshotProperties(pSnapProp);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CVSSProp::OnSettings()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
CSettings dlg(m_strComputer, m_strSelectedVolume);
|
|
HRESULT hr = dlg.Init(m_spiDiffSnapMgmt,
|
|
m_spiTS,
|
|
&m_VolumeList,
|
|
!m_SnapshotList.empty());
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_SETTINGS_ERROR, m_strSelectedVolume);
|
|
return;
|
|
}
|
|
|
|
if (IDOK == dlg.DoModal())
|
|
{
|
|
UpdateDiffArea();
|
|
UpdateSchedule();
|
|
}
|
|
}
|
|
|
|
void CVSSProp::OnItemchangedSnapshotList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
|
|
m_ctrlDelete.EnableWindow(0 < m_ctrlSnapshotList.GetSelectedCount());
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CVSSProp::OnItemchangedVolumeList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
|
|
BOOL bMultiSelected = (1 < m_ctrlVolumeList.GetSelectedCount());
|
|
m_ctrlSettings.EnableWindow(!bMultiSelected);
|
|
m_ctrlCreate.EnableWindow(!bMultiSelected);
|
|
|
|
if (bMultiSelected)
|
|
{
|
|
m_strSelectedVolume = _T("");
|
|
} else
|
|
{
|
|
int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
|
|
if (-1 != nIndex)
|
|
{
|
|
m_strSelectedVolume = m_ctrlVolumeList.GetItemText(nIndex, 0);
|
|
} else
|
|
{
|
|
m_strSelectedVolume = _T("");
|
|
}
|
|
}
|
|
|
|
CWaitCursor wait;
|
|
UpdateSnapshotList();
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
BOOL CVSSProp::OnHelpInfo(HELPINFO* pHelpInfo)
|
|
{
|
|
if (!pHelpInfo ||
|
|
pHelpInfo->iContextType != HELPINFO_WINDOW ||
|
|
pHelpInfo->iCtrlId < 0)
|
|
return FALSE;
|
|
|
|
::WinHelp((HWND)pHelpInfo->hItemHandle,
|
|
VSSUI_CTX_HELP_FILE,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(PVOID)aMenuHelpIDsForVSSProp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CVSSProp::OnInitDialog()
|
|
{
|
|
CWaitCursor wait;
|
|
|
|
CPropertyPage::OnInitDialog();
|
|
|
|
BOOL bHideAllControls = FALSE;
|
|
CString strMsg;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do {
|
|
hr = InitInterfacePointers();
|
|
if (FAILED(hr))
|
|
{
|
|
GetMsg(strMsg, hr, IDS_VSSPROP_INIT_ERROR);
|
|
bHideAllControls = TRUE;
|
|
break;
|
|
}
|
|
|
|
hr = GetVolumes(); // get a list of volumes that are suitable for taking snapshots
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
GetMsg(strMsg, hr, IDS_VSSPROP_GETVOLUMES_ERROR);
|
|
bHideAllControls = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (m_VolumeList.empty())
|
|
{
|
|
GetMsg(strMsg, 0, IDS_VSSPROP_EMPTY_VOLUMELIST);
|
|
bHideAllControls = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!m_strSelectedVolume.IsEmpty())
|
|
{
|
|
BOOL bFound = FALSE;
|
|
for (VSSUI_VOLUME_LIST::iterator i = m_VolumeList.begin(); i != m_VolumeList.end(); i++)
|
|
{
|
|
if (!m_strSelectedVolume.CompareNoCase((*i)->pszDisplayName))
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
GetMsg(strMsg, 0, IDS_VSSPROP_VOLUME_ILEGIBLE, m_strSelectedVolume);
|
|
bHideAllControls = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
if (bHideAllControls)
|
|
{
|
|
GetDlgItem(IDC_VSSPROP_ERROR)->SetWindowText(strMsg);
|
|
GetDlgItem(IDC_VSSPROP_ERROR)->EnableWindow(TRUE);
|
|
|
|
for (int i = IDC_EXPLANATION; i < IDC_VSSPROP_ERROR; i++)
|
|
{
|
|
GetDlgItem(i)->EnableWindow(FALSE);
|
|
GetDlgItem(i)->ShowWindow(SW_HIDE);
|
|
}
|
|
} else
|
|
{
|
|
GetDlgItem(IDC_VSSPROP_ERROR)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_VSSPROP_ERROR)->ShowWindow(SW_HIDE);
|
|
//
|
|
// insert column header of the Volume listbox
|
|
//
|
|
HWND hwnd = m_ctrlVolumeList.m_hWnd;
|
|
AddLVColumns(
|
|
hwnd,
|
|
IDS_VOLUMELIST_COLUMN_VOLUME,
|
|
IDS_VOLUMELIST_COLUMN_NEXTRUNTIME - IDS_VOLUMELIST_COLUMN_VOLUME + 1);
|
|
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
|
|
|
|
InsertVolumeInfo(hwnd);
|
|
InsertDiffAreaInfo(hwnd);
|
|
InsertShareInfo(hwnd);
|
|
InsertScheduleInfo(hwnd);
|
|
|
|
SelectVolume(hwnd);
|
|
|
|
//
|
|
// insert column headers for the snapshot listbox
|
|
//
|
|
hwnd = m_ctrlSnapshotList.m_hWnd;
|
|
AddLVColumns(
|
|
hwnd,
|
|
IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP,
|
|
IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP - IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP + 1);
|
|
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
|
|
|
|
UpdateSnapshotList();
|
|
}
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void CVSSProp::_ResetInterfacePointers()
|
|
{
|
|
if ((IVssSnapshotMgmt *)m_spiMgmt)
|
|
m_spiMgmt.Release();
|
|
|
|
if ((IVssCoordinator *)m_spiCoord)
|
|
m_spiCoord.Release();
|
|
|
|
if ((IVssDifferentialSoftwareSnapshotMgmt *)m_spiDiffSnapMgmt)
|
|
m_spiDiffSnapMgmt.Release();
|
|
|
|
if ((ITaskScheduler *)m_spiTS)
|
|
m_spiTS.Release();
|
|
}
|
|
|
|
HRESULT CVSSProp::InitInterfacePointers()
|
|
{
|
|
_ResetInterfacePointers();
|
|
|
|
HRESULT hr = S_OK;
|
|
if (m_strComputer.IsEmpty())
|
|
{
|
|
hr = CoCreateInstance(CLSID_VssSnapshotMgmt,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IVssSnapshotMgmt,
|
|
(void **)&m_spiMgmt);
|
|
if (SUCCEEDED(hr))
|
|
hr = CoCreateInstance(CLSID_VSSCoordinator,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IVssCoordinator,
|
|
(void **)&m_spiCoord);
|
|
|
|
} else
|
|
{
|
|
COSERVERINFO serverInfo = {0};
|
|
serverInfo.pwszName = (LPTSTR)(LPCTSTR)m_strComputer;
|
|
|
|
IID iid = IID_IVssSnapshotMgmt;
|
|
MULTI_QI MQI = {0};
|
|
MQI.pIID = &iid;
|
|
hr = CoCreateInstanceEx(CLSID_VssSnapshotMgmt,
|
|
NULL,
|
|
CLSCTX_REMOTE_SERVER,
|
|
&serverInfo,
|
|
1,
|
|
&MQI);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_spiMgmt = (IVssSnapshotMgmt *)MQI.pItf;
|
|
|
|
ZeroMemory(&MQI, sizeof(MQI));
|
|
iid = IID_IVssCoordinator;
|
|
MQI.pIID = &iid;
|
|
hr = CoCreateInstanceEx(CLSID_VSSCoordinator,
|
|
NULL,
|
|
CLSCTX_REMOTE_SERVER,
|
|
&serverInfo,
|
|
1,
|
|
&MQI);
|
|
if (SUCCEEDED(hr))
|
|
m_spiCoord = (IVssCoordinator *)MQI.pItf;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_spiCoord->SetContext(VSS_CTX_CLIENT_ACCESSIBLE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_spiMgmt->GetProviderMgmtInterface(
|
|
VSS_SWPRV_ProviderId,
|
|
IID_IVssDifferentialSoftwareSnapshotMgmt,
|
|
(IUnknown**)&m_spiDiffSnapMgmt);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = CoCreateInstance(CLSID_CTaskScheduler,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITaskScheduler,
|
|
(void **)&m_spiTS);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// SetTargetComputer requires server name to start with whackwhack
|
|
if (m_strComputer.IsEmpty())
|
|
hr = m_spiTS->SetTargetComputer(NULL);
|
|
else
|
|
{
|
|
CString strTargetComputer = _T("\\\\");
|
|
strTargetComputer += m_strComputer;
|
|
hr = m_spiTS->SetTargetComputer((LPCTSTR)strTargetComputer);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
_ResetInterfacePointers();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVSSProp::GetVolumes()
|
|
{
|
|
if (!m_spiMgmt)
|
|
return E_INVALIDARG;
|
|
|
|
FreeVolumeList(&m_VolumeList);
|
|
|
|
CComPtr<IVssEnumMgmtObject> spiEnumMgmt;
|
|
HRESULT hr = m_spiMgmt->QueryVolumesSupportedForSnapshots(
|
|
VSS_SWPRV_ProviderId,
|
|
VSS_CTX_CLIENT_ACCESSIBLE,
|
|
&spiEnumMgmt);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_VOLUME_PROP *pVolProp = &(Prop.Obj.Vol);
|
|
ULONG ulFetched = 0;
|
|
while (SUCCEEDED(hr = spiEnumMgmt->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
|
|
{
|
|
if (VSS_MGMT_OBJECT_VOLUME != Prop.Type)
|
|
return E_FAIL;
|
|
|
|
VSSUI_VOLUME *pVolInfo = (VSSUI_VOLUME *)calloc(1, sizeof(VSSUI_VOLUME));
|
|
if (pVolInfo)
|
|
{
|
|
_tcscpy(pVolInfo->pszVolumeName, pVolProp->m_pwszVolumeName);
|
|
_tcscpy(pVolInfo->pszDisplayName, pVolProp->m_pwszVolumeDisplayName);
|
|
m_VolumeList.push_back(pVolInfo);
|
|
} else
|
|
{
|
|
FreeVolumeList(&m_VolumeList);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
CoTaskMemFree(pVolProp->m_pwszVolumeName);
|
|
CoTaskMemFree(pVolProp->m_pwszVolumeDisplayName);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVSSProp::InsertVolumeInfo(HWND hwnd)
|
|
{
|
|
ListView_DeleteAllItems(hwnd);
|
|
|
|
for (VSSUI_VOLUME_LIST::iterator i = m_VolumeList.begin(); i != m_VolumeList.end(); i++)
|
|
{
|
|
LVITEM lvItem = {0};
|
|
lvItem.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvItem.lParam = (LPARAM)(*i);
|
|
lvItem.pszText = (*i)->pszDisplayName;
|
|
lvItem.iSubItem = 0;
|
|
ListView_InsertItem(hwnd, &lvItem);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Update diff area column of the currently selected volume
|
|
//
|
|
HRESULT CVSSProp::UpdateDiffArea()
|
|
{
|
|
if (m_strSelectedVolume.IsEmpty())
|
|
return E_INVALIDARG;
|
|
|
|
int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
|
|
ASSERT(-1 != nIndex);
|
|
|
|
PTSTR pszVolumeName = GetVolumeName(&m_VolumeList, m_strSelectedVolume);
|
|
ASSERT(pszVolumeName);
|
|
|
|
return UpdateDiffArea(nIndex, pszVolumeName);
|
|
}
|
|
|
|
//
|
|
// Update diff area column of the specified volume
|
|
//
|
|
HRESULT CVSSProp::UpdateDiffArea(int nIndex, LPCTSTR pszVolumeName)
|
|
{
|
|
CString strMsg = _T("");
|
|
VSSUI_DIFFAREA diffArea;
|
|
HRESULT hr = GetDiffAreaInfo(m_spiDiffSnapMgmt, &m_VolumeList, pszVolumeName, &diffArea);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// "Used on DiffVolume"
|
|
//
|
|
TCHAR szUsed[MAX_PATH];
|
|
DWORD dwSize = sizeof(szUsed)/sizeof(TCHAR);
|
|
DiskSpaceToString(diffArea.llUsedDiffSpace, szUsed, &dwSize);
|
|
|
|
strMsg.FormatMessage(IDS_USED_ON_VOLUME, szUsed, diffArea.pszDiffVolumeDisplayName);
|
|
}
|
|
|
|
LVITEM lvItem = {0};
|
|
lvItem.iItem = nIndex;
|
|
lvItem.mask = LVIF_TEXT;
|
|
lvItem.pszText = (PTSTR)(LPCTSTR)strMsg;
|
|
lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_USED - IDS_VOLUMELIST_COLUMN_VOLUME;
|
|
m_ctrlVolumeList.SetItem(&lvItem);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVSSProp::InsertDiffAreaInfo(HWND hwnd)
|
|
{
|
|
if (m_VolumeList.empty())
|
|
return S_OK;
|
|
|
|
int nIndex = -1;
|
|
while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
|
|
{
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
|
|
ASSERT(pVolume);
|
|
|
|
UpdateDiffArea(nIndex, pVolume->pszVolumeName);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CVSSProp::InsertShareInfo(HWND hwnd)
|
|
{
|
|
if (m_VolumeList.empty())
|
|
return S_OK;
|
|
|
|
SHARE_INFO_2 *pInfo = NULL;
|
|
DWORD dwEntriesRead = 0;
|
|
DWORD dwEntriesTotal = 0;
|
|
DWORD dwRet = NetShareEnum((PTSTR)(LPCTSTR)m_strComputer,
|
|
2,
|
|
(LPBYTE *)&pInfo,
|
|
-1, //max
|
|
&dwEntriesRead,
|
|
&dwEntriesTotal,
|
|
NULL // resume handle
|
|
);
|
|
|
|
if (NERR_Success != dwRet)
|
|
return HRESULT_FROM_WIN32(dwRet);
|
|
|
|
TCHAR szNumOfShares[256];
|
|
int nIndex = -1;
|
|
while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
|
|
{
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
|
|
ASSERT(pVolume);
|
|
UINT count = 0;
|
|
|
|
for (DWORD i = 0; i < dwEntriesRead; i++)
|
|
{
|
|
if (pInfo[i].shi2_type == STYPE_DISKTREE)
|
|
{
|
|
if (!mylstrncmpi(pInfo[i].shi2_path, pVolume->pszDisplayName, lstrlen(pVolume->pszDisplayName)))
|
|
count++;
|
|
}
|
|
}
|
|
|
|
_stprintf(szNumOfShares, _T("%d"), count); // no need to localize the format
|
|
LVITEM lvItem = {0};
|
|
lvItem.iItem = nIndex;
|
|
lvItem.mask = LVIF_TEXT;
|
|
lvItem.pszText = szNumOfShares;
|
|
lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_NUMOFSHARES - IDS_VOLUMELIST_COLUMN_VOLUME;
|
|
ListView_SetItem(hwnd, &lvItem);
|
|
}
|
|
|
|
NetApiBufferFree(pInfo);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Update schedule column of the currently selected volume
|
|
//
|
|
HRESULT CVSSProp::UpdateSchedule()
|
|
{
|
|
if (m_strSelectedVolume.IsEmpty())
|
|
return E_INVALIDARG;
|
|
|
|
int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
|
|
ASSERT(-1 != nIndex);
|
|
|
|
return UpdateSchedule(nIndex, m_strSelectedVolume);
|
|
}
|
|
|
|
//
|
|
// Update schedule column of the specified volume
|
|
//
|
|
HRESULT CVSSProp::UpdateSchedule(int nIndex, LPCTSTR pszVolumeDisplayName)
|
|
{
|
|
if (!pszVolumeDisplayName || !*pszVolumeDisplayName)
|
|
return E_INVALIDARG;
|
|
|
|
CComPtr<ITask> spiTask;
|
|
(void)FindScheduledTimewarpTask((ITaskScheduler *)m_spiTS, pszVolumeDisplayName, &spiTask);
|
|
|
|
UpdateSchedule((ITask *)spiTask, nIndex);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CVSSProp::UpdateSchedule(ITask * i_piTask, int nIndex)
|
|
{
|
|
BOOL bEnabled = FALSE;
|
|
SYSTEMTIME stNextRun = {0};
|
|
if (i_piTask)
|
|
(void)GetScheduledTimewarpTaskStatus(i_piTask, &bEnabled, &stNextRun);
|
|
|
|
LVITEM lvItem = {0};
|
|
lvItem.iItem = nIndex;
|
|
lvItem.mask = LVIF_TEXT;
|
|
lvItem.pszText = bEnabled ? _T("Enabled") : _T("Disabled");
|
|
lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_STATUS - IDS_VOLUMELIST_COLUMN_VOLUME;
|
|
m_ctrlVolumeList.SetItem(&lvItem);
|
|
|
|
TCHAR szNextRun[MAX_PATH] = _T("");
|
|
DWORD dwSize = sizeof(szNextRun)/sizeof(TCHAR);
|
|
|
|
if (bEnabled)
|
|
SystemTimeToString(&stNextRun, szNextRun, &dwSize);
|
|
|
|
lvItem.pszText = szNextRun;
|
|
lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_NEXTRUNTIME - IDS_VOLUMELIST_COLUMN_VOLUME;
|
|
m_ctrlVolumeList.SetItem(&lvItem);
|
|
}
|
|
|
|
HRESULT CVSSProp::InsertScheduleInfo(HWND hwnd)
|
|
{
|
|
if (m_VolumeList.empty())
|
|
return S_OK;
|
|
|
|
int nIndex = -1;
|
|
while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
|
|
{
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
|
|
ASSERT(pVolume);
|
|
|
|
UpdateSchedule(nIndex, pVolume->pszDisplayName);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CVSSProp::SelectVolume(HWND hwnd)
|
|
{
|
|
if (m_VolumeList.empty())
|
|
return;
|
|
|
|
int nIndex = -1;
|
|
if (!m_strSelectedVolume.IsEmpty())
|
|
{
|
|
while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
|
|
{
|
|
VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
|
|
ASSERT(pVolume);
|
|
if (!m_strSelectedVolume.CompareNoCase(pVolume->pszDisplayName))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (-1 == nIndex)
|
|
nIndex = 0;
|
|
|
|
ListView_SetItemState(hwnd, nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xffffffff);
|
|
}
|
|
|
|
HRESULT CVSSProp::GetSnapshots(LPCTSTR pszVolume)
|
|
{
|
|
if (!pszVolume || !*pszVolume)
|
|
return E_INVALIDARG;
|
|
|
|
FreeSnapshotList(&m_SnapshotList);
|
|
|
|
CComPtr<IVssEnumObject> spiEnumSnapshots;
|
|
HRESULT hr = m_spiMgmt->QuerySnapshotsByVolume((PTSTR)pszVolume, VSS_SWPRV_ProviderId, &spiEnumSnapshots);
|
|
if (S_OK == hr)
|
|
{
|
|
VSS_OBJECT_PROP Prop;
|
|
VSS_SNAPSHOT_PROP* pSnapProp = &(Prop.Obj.Snap);
|
|
ULONG ulFetched = 0;
|
|
while (SUCCEEDED(spiEnumSnapshots->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
|
|
{
|
|
if (VSS_OBJECT_SNAPSHOT != Prop.Type)
|
|
return E_FAIL;
|
|
|
|
if (pSnapProp->m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
|
|
{
|
|
VSSUI_SNAPSHOT *pSnapInfo = (VSSUI_SNAPSHOT *)calloc(1, sizeof(VSSUI_SNAPSHOT));
|
|
if (pSnapInfo)
|
|
{
|
|
pSnapInfo->idSnapshot = pSnapProp->m_SnapshotId;
|
|
pSnapInfo->vssTimeStamp = pSnapProp->m_tsCreationTimestamp;
|
|
m_SnapshotList.push_back(pSnapInfo);
|
|
} else
|
|
{
|
|
FreeSnapshotList(&m_SnapshotList);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
VssFreeSnapshotProperties(pSnapProp);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVSSProp::UpdateSnapshotList()
|
|
{
|
|
if (m_strSelectedVolume.IsEmpty())
|
|
{
|
|
m_ctrlSnapshotList.DeleteAllItems();
|
|
m_ctrlDelete.EnableWindow(FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT hr = GetSnapshots(m_strSelectedVolume);
|
|
|
|
m_ctrlSnapshotList.DeleteAllItems();
|
|
m_ctrlDelete.EnableWindow(FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szTimeStamp[256];
|
|
DWORD dwSize = 0;
|
|
LVITEM lvItem = {0};
|
|
|
|
for (VSSUI_SNAPSHOT_LIST::iterator i = m_SnapshotList.begin(); i != m_SnapshotList.end(); i++)
|
|
{
|
|
SYSTEMTIME st = {0};
|
|
VssTimeToSystemTime(&((*i)->vssTimeStamp), &st);
|
|
|
|
dwSize = sizeof(szTimeStamp)/sizeof(TCHAR);
|
|
SystemTimeToString(&st, szTimeStamp, &dwSize);
|
|
|
|
ZeroMemory(&lvItem, sizeof(lvItem));
|
|
lvItem.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvItem.lParam = (LPARAM)(*i);
|
|
lvItem.pszText = szTimeStamp;
|
|
m_ctrlSnapshotList.InsertItem(&lvItem);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|