Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1425 lines
45 KiB

  1. // CVSSProp.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "utils.h"
  5. #include "VSSProp.h"
  6. #include "RemDlg.h"
  7. #include "Settings.h"
  8. #include "Hosting.h"
  9. #include "uihelp.h"
  10. #include "msgcomm.h" // vss error msg
  11. #include <vss.h> // _VSS_SNAPSHOT_CONTEXT
  12. #include <vsmgmt.h>
  13. #include <vsswprv.h> // VSS_SWPRV_ProviderId
  14. #include <vswriter.h>// VssFreeSnapshotProperties
  15. #include <vsbackup.h> // VssFreeSnapshotProperties
  16. #include <htmlhelp.h>
  17. #include <clusapi.h> // GetNodeClusterState
  18. #include <lm.h>
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CVSSProp property page
  26. IMPLEMENT_DYNCREATE(CVSSProp, CPropertyPage)
  27. CVSSProp::CVSSProp() : CPropertyPage(CVSSProp::IDD)
  28. {
  29. //{{AFX_DATA_INIT(CVSSProp)
  30. //}}AFX_DATA_INIT
  31. m_strComputer = _T("");
  32. m_strSelectedVolume = _T("");
  33. m_strDisabled.LoadString(IDS_DISABLED);
  34. m_hImageList = NULL;
  35. m_nScrollbarWidth = 16;
  36. m_nSnapshotListColumnWidth = 0;
  37. m_nSnapshotListCountPerPage = 0;
  38. }
  39. CVSSProp::CVSSProp(LPCTSTR pszComputer, LPCTSTR pszVolume) : CPropertyPage(CVSSProp::IDD)
  40. {
  41. #ifdef DEBUG
  42. OutputDebugString(_T("CVSSProp::CVSSPRop\n"));
  43. #endif
  44. if (!pszComputer)
  45. m_strComputer = _T("");
  46. else
  47. m_strComputer = pszComputer + (TWO_WHACKS(pszComputer) ? 2 : 0);
  48. m_strSelectedVolume = (pszVolume ? pszVolume : _T(""));
  49. m_strDisabled.LoadString(IDS_DISABLED);
  50. m_hImageList = NULL;
  51. m_nScrollbarWidth = 16;
  52. m_nSnapshotListColumnWidth = 0;
  53. m_nSnapshotListCountPerPage = 0;
  54. }
  55. CVSSProp::~CVSSProp()
  56. {
  57. #ifdef DEBUG
  58. OutputDebugString(_T("CVSSProp::~CVSSPRop\n"));
  59. #endif
  60. if(NULL != m_hImageList)
  61. {
  62. ImageList_Destroy(m_hImageList);
  63. m_hImageList = NULL;
  64. }
  65. }
  66. HRESULT CVSSProp::StoreShellExtPointer(IShellPropSheetExt* piShellExt)
  67. {
  68. if (!piShellExt)
  69. return E_INVALIDARG;
  70. // This assignment will call AddRef().
  71. // Release() will later be called by ~CVSSProp().
  72. m_spiShellExt = piShellExt;
  73. return S_OK;
  74. }
  75. void CVSSProp::DoDataExchange(CDataExchange* pDX)
  76. {
  77. CPropertyPage::DoDataExchange(pDX);
  78. //{{AFX_DATA_MAP(CVSSProp)
  79. DDX_Control(pDX, IDC_VOLUME_LIST, m_ctrlVolumeList);
  80. DDX_Control(pDX, IDC_ENABLE, m_ctrlEnable);
  81. DDX_Control(pDX, IDC_DISABLE, m_ctrlDisable);
  82. DDX_Control(pDX, IDC_SETTINGS, m_ctrlSettings);
  83. DDX_Control(pDX, IDC_SNAPSHOT_LIST, m_ctrlSnapshotList);
  84. DDX_Control(pDX, IDC_CREATE, m_ctrlCreate);
  85. DDX_Control(pDX, IDC_DELETE, m_ctrlDelete);
  86. //}}AFX_DATA_MAP
  87. }
  88. BEGIN_MESSAGE_MAP(CVSSProp, CPropertyPage)
  89. //{{AFX_MSG_MAP(CVSSProp)
  90. ON_BN_CLICKED(IDC_CREATE, OnCreateNow)
  91. ON_BN_CLICKED(IDC_DELETE, OnDeleteNow)
  92. ON_NOTIFY(LVN_ITEMCHANGED, IDC_SNAPSHOT_LIST, OnItemchangedSnapshotList)
  93. ON_NOTIFY(LVN_ITEMCHANGED, IDC_VOLUME_LIST, OnItemchangedVolumeList)
  94. ON_WM_CONTEXTMENU()
  95. ON_WM_HELPINFO()
  96. ON_BN_CLICKED(IDC_ENABLE, OnEnable)
  97. ON_BN_CLICKED(IDC_DISABLE, OnDisable)
  98. ON_BN_CLICKED(IDC_SETTINGS, OnSettings)
  99. ON_NOTIFY(NM_CLICK, IDC_EXPLANATION, OnHelpLink)
  100. ON_NOTIFY(NM_RETURN, IDC_EXPLANATION, OnHelpLink)
  101. ON_MESSAGE(WM_SETPAGEFOCUS, OnSetPageFocus)
  102. //}}AFX_MSG_MAP
  103. END_MESSAGE_MAP()
  104. /////////////////////////////////////////////////////////////////////////////
  105. // CVSSProp message handlers
  106. //
  107. // If we have successfully taken one snapshot of the specified volume, we will
  108. // return VSS_S_ASYNC_FINISHED.
  109. //
  110. HRESULT CVSSProp::TakeOneSnapshotNow(IN LPCTSTR pszVolumeName)
  111. {
  112. if (!pszVolumeName || !*pszVolumeName)
  113. return E_INVALIDARG;
  114. VSS_ID SnapshotSetId = GUID_NULL;
  115. HRESULT hr = m_spiCoord->StartSnapshotSet(&SnapshotSetId);
  116. if (SUCCEEDED(hr))
  117. {
  118. VSS_ID SnapshotId = GUID_NULL;
  119. hr = m_spiCoord->AddToSnapshotSet(
  120. (PTSTR)pszVolumeName,
  121. VSS_SWPRV_ProviderId,
  122. &SnapshotId);
  123. if (SUCCEEDED(hr))
  124. {
  125. CComPtr<IVssAsync> spiAsync;
  126. hr = m_spiCoord->DoSnapshotSet(NULL, &spiAsync);
  127. if (SUCCEEDED(hr))
  128. {
  129. hr = spiAsync->Wait();
  130. if (SUCCEEDED(hr))
  131. {
  132. HRESULT hrStatus = S_OK;
  133. hr = spiAsync->QueryStatus(&hrStatus, NULL);
  134. if (SUCCEEDED(hr))
  135. {
  136. return hrStatus;
  137. }
  138. }
  139. }
  140. }
  141. }
  142. return hr;
  143. }
  144. //
  145. // OnCreateNow works when only one volume is currently selected.
  146. //
  147. void CVSSProp::OnCreateNow()
  148. {
  149. CWaitCursor wait;
  150. if (m_strSelectedVolume.IsEmpty())
  151. return;
  152. PTSTR pszVolumeName = GetVolumeName(&m_VolumeList, m_strSelectedVolume);
  153. ASSERT(pszVolumeName);
  154. HRESULT hr = TakeOneSnapshotNow(pszVolumeName);
  155. if (VSS_S_ASYNC_FINISHED == (DWORD)hr)
  156. {
  157. UpdateSnapshotList();
  158. UpdateDiffArea();
  159. UpdateEnableDisableButtons();
  160. } else if (FAILED(hr))
  161. {
  162. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_TAKESNAPSHOT_ERROR, m_strSelectedVolume);
  163. }
  164. }
  165. //
  166. // OnDeleteNow works on multi-selected snapshots when only one volume is currently selected.
  167. //
  168. void CVSSProp::OnDeleteNow()
  169. {
  170. CWaitCursor wait;
  171. if (m_strSelectedVolume.IsEmpty())
  172. return;
  173. BOOL bAtLeastOneDeleted = FALSE;
  174. HRESULT hr = S_OK;
  175. int nIndex = -1;
  176. while (-1 != (nIndex = m_ctrlSnapshotList.GetNextItem(nIndex, LVNI_SELECTED)))
  177. {
  178. VSSUI_SNAPSHOT *pSnapshot = (VSSUI_SNAPSHOT *)GetListViewItemData(m_ctrlSnapshotList.m_hWnd, nIndex);
  179. ASSERT(pSnapshot);
  180. if (!pSnapshot)
  181. continue; // shouldn't happen, skip it just in case
  182. LONG lDeletedSnapshots = 0;
  183. VSS_ID ProblemSnapshotId = GUID_NULL;
  184. hr = m_spiCoord->DeleteSnapshots(pSnapshot->idSnapshot,
  185. VSS_OBJECT_SNAPSHOT,
  186. TRUE,
  187. &lDeletedSnapshots,
  188. &ProblemSnapshotId
  189. );
  190. if (SUCCEEDED(hr) || VSS_E_OBJECT_NOT_FOUND == hr)
  191. {
  192. hr = S_OK; // ignore if snapshot has already been deleted
  193. bAtLeastOneDeleted = TRUE;
  194. }
  195. if (FAILED(hr))
  196. break;
  197. }
  198. if (FAILED(hr))
  199. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETESNAPSHOTS_ERROR, m_strSelectedVolume);
  200. if (bAtLeastOneDeleted)
  201. {
  202. UpdateSnapshotList();
  203. if (0 == m_ctrlSnapshotList.GetSelectedCount())
  204. {
  205. ::SendMessage(m_hWnd, DM_SETDEFID, (WPARAM)IDC_CREATE, (LPARAM)0);
  206. m_ctrlCreate.SetFocus(); // DeleteNow button has been disabled, set focus to CreateNow button
  207. }
  208. UpdateDiffArea();
  209. UpdateEnableDisableButtons();
  210. }
  211. }
  212. #define HKCU_VSSUI_KEY _T("Software\\Microsoft\\VSSUI")
  213. #define REGVALUENAME_ENABLE _T("EnableReminderOff")
  214. #define REGVALUENAME_DISABLE _T("DisableReminderOff")
  215. void CVSSProp::OnEnable()
  216. {
  217. BOOL bShowReminder = TRUE;
  218. HKEY hKey = NULL;
  219. LONG lErr = RegCreateKeyEx(HKEY_CURRENT_USER,
  220. HKCU_VSSUI_KEY,
  221. 0, // reserved
  222. _T(""), // lpClass
  223. REG_OPTION_NON_VOLATILE,
  224. KEY_QUERY_VALUE | KEY_SET_VALUE,
  225. NULL, // lpSecurityAttributes
  226. &hKey,
  227. NULL // lpdwDisposition
  228. );
  229. if (ERROR_SUCCESS == lErr)
  230. {
  231. DWORD dwType = 0;
  232. DWORD dwData = 0;
  233. DWORD cbData = sizeof(DWORD);
  234. lErr = RegQueryValueEx(hKey, REGVALUENAME_ENABLE, 0, &dwType, (LPBYTE)&dwData, &cbData);
  235. if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != dwData)
  236. bShowReminder = FALSE;
  237. }
  238. int nRet = IDOK;
  239. if (bShowReminder)
  240. {
  241. CReminderDlgEx dlg(hKey, REGVALUENAME_ENABLE);
  242. nRet = dlg.DoModal();
  243. }
  244. if (hKey)
  245. RegCloseKey(hKey);
  246. if (IDOK == nRet)
  247. DoEnable();
  248. }
  249. HRESULT CVSSProp::DoEnable()
  250. {
  251. CWaitCursor wait;
  252. HRESULT hr = S_OK;
  253. LVITEM lvItem = {0};
  254. int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
  255. if (nSelectedCount > 0)
  256. {
  257. POSITION pos = m_ctrlVolumeList.GetFirstSelectedItemPosition();
  258. while (pos)
  259. {
  260. int nIndex = m_ctrlVolumeList.GetNextSelectedItem(pos);
  261. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(m_ctrlVolumeList.m_hWnd, nIndex);
  262. ASSERT(pVolume);
  263. if (!pVolume)
  264. continue; // shouldn't happen, skip it just in case
  265. // bug#495719 - prompt instructions when enabling vss on a small volume
  266. ULONGLONG llDiffVolumeTotalSpace = 0;
  267. ULONGLONG llDiffVolumeFreeSpace = 0;
  268. hr = GetVolumeSpace(
  269. m_spiDiffSnapMgmt,
  270. pVolume->pszDisplayName,
  271. &llDiffVolumeTotalSpace,
  272. &llDiffVolumeFreeSpace);
  273. if (SUCCEEDED(hr) && llDiffVolumeTotalSpace < MINIMUM_DIFF_LIMIT) // ignore the failure of GetVolumeSpace
  274. {
  275. VSSUI_DIFFAREA diffArea;
  276. hr = GetDiffAreaInfo(m_spiDiffSnapMgmt, &m_VolumeList, pVolume->pszVolumeName, &diffArea);
  277. if (S_OK != hr) // failed to retrieve diff area association, assume it doesn't have one
  278. {
  279. DoErrMsgBox(m_hWnd, MB_OK, 0, IDS_CANNOT_ENABLE_SMALL_VOLUME, pVolume->pszDisplayName);
  280. continue; // skip enabling this selection
  281. }
  282. }
  283. // bug#494209: take a snapshot first, if failed, no need to create the default schedule
  284. //
  285. // take one snapshot now, it will create default diff area association if none
  286. //
  287. hr = TakeOneSnapshotNow(pVolume->pszVolumeName);
  288. if (VSS_S_ASYNC_FINISHED == (DWORD)hr)
  289. {
  290. if (1 == nSelectedCount)
  291. UpdateSnapshotList();
  292. UpdateDiffArea(nIndex, pVolume->pszVolumeName);
  293. } else if (FAILED(hr))
  294. {
  295. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_TAKESNAPSHOT_ERROR, pVolume->pszDisplayName);
  296. break;
  297. }
  298. //
  299. // if none, create default schedule for that volume
  300. //
  301. CComPtr<ITask> spiTask;
  302. hr = FindScheduledTimewarpTask(
  303. (ITaskScheduler *)m_spiTS,
  304. pVolume->pszVolumeName,
  305. &spiTask);
  306. if (FAILED(hr))
  307. {
  308. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_FINDSCHEDULE_ERROR, pVolume->pszDisplayName);
  309. } else if (S_FALSE == hr) // task not found
  310. {
  311. (void)DeleteAllScheduledTimewarpTasks((ITaskScheduler *)m_spiTS,
  312. m_strComputer,
  313. pVolume->pszVolumeName,
  314. TRUE // i_bDeleteDisabledOnesOnly
  315. );
  316. hr = CreateDefaultEnableSchedule(
  317. (ITaskScheduler *)m_spiTS,
  318. m_strComputer,
  319. pVolume->pszDisplayName,
  320. pVolume->pszVolumeName,
  321. &spiTask);
  322. if (FAILED(hr))
  323. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_CREATESCHEDULE_ERROR, pVolume->pszDisplayName);
  324. }
  325. if (SUCCEEDED(hr))
  326. {
  327. UpdateSchedule((ITask *)spiTask, nIndex);
  328. // bug#494491: we need to update the Enable/Disable button when schedule changes.
  329. if (1 == nSelectedCount)
  330. {
  331. UpdateEnableDisableButtons();
  332. ::SendMessage(m_hWnd, DM_SETDEFID, (WPARAM)IDC_DISABLE, (LPARAM)0);
  333. m_ctrlDisable.SetFocus(); // Disable button will be enabled, set focus to it
  334. }
  335. } else
  336. break;
  337. }
  338. }
  339. return hr;
  340. }
  341. void CVSSProp::OnDisable()
  342. {
  343. BOOL bShowReminder = TRUE;
  344. HKEY hKey = NULL;
  345. LONG lErr = RegCreateKeyEx(HKEY_CURRENT_USER,
  346. HKCU_VSSUI_KEY,
  347. 0, // reserved
  348. _T(""), // lpClass
  349. REG_OPTION_NON_VOLATILE,
  350. KEY_QUERY_VALUE | KEY_SET_VALUE,
  351. NULL, // lpSecurityAttributes
  352. &hKey,
  353. NULL // lpdwDisposition
  354. );
  355. if (ERROR_SUCCESS == lErr)
  356. {
  357. DWORD dwType = 0;
  358. DWORD dwData = 0;
  359. DWORD cbData = sizeof(DWORD);
  360. lErr = RegQueryValueEx(hKey, REGVALUENAME_DISABLE, 0, &dwType, (LPBYTE)&dwData, &cbData);
  361. if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != dwData)
  362. bShowReminder = FALSE;
  363. }
  364. int nRet = IDOK;
  365. if (bShowReminder)
  366. {
  367. CReminderDlg dlg(hKey, REGVALUENAME_DISABLE);
  368. nRet = dlg.DoModal();
  369. }
  370. if (hKey)
  371. RegCloseKey(hKey);
  372. if (IDOK == nRet)
  373. DoDisable();
  374. }
  375. HRESULT CVSSProp::DoDisable()
  376. {
  377. CWaitCursor wait;
  378. HRESULT hr = S_OK;
  379. LVITEM lvItem = {0};
  380. int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
  381. if (nSelectedCount > 0)
  382. {
  383. POSITION pos = m_ctrlVolumeList.GetFirstSelectedItemPosition();
  384. while (pos)
  385. {
  386. int nIndex = m_ctrlVolumeList.GetNextSelectedItem(pos);
  387. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(m_ctrlVolumeList.m_hWnd, nIndex);
  388. ASSERT(pVolume);
  389. if (!pVolume)
  390. continue; // shouldn't happen, skip it just in case
  391. //
  392. // delete all snapshots on that volume
  393. //
  394. hr = DeleteAllSnapshotsOnVolume(pVolume->pszVolumeName);
  395. if (1 == nSelectedCount)
  396. UpdateSnapshotList();
  397. if (FAILED(hr))
  398. {
  399. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETESNAPSHOTS_ERROR, pVolume->pszDisplayName);
  400. break;
  401. }
  402. //
  403. // delete all scheduled tasks for that volume
  404. //
  405. hr = DeleteAllScheduledTimewarpTasks((ITaskScheduler *)m_spiTS,
  406. m_strComputer,
  407. pVolume->pszVolumeName,
  408. FALSE // i_bDeleteDisabledOnesOnly
  409. );
  410. if (SUCCEEDED(hr))
  411. UpdateSchedule(NULL, nIndex);
  412. else
  413. {
  414. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_FINDSCHEDULE_ERROR, pVolume->pszDisplayName);
  415. break;
  416. }
  417. //
  418. // remove diff area associate for that volume
  419. //
  420. VSSUI_DIFFAREA diffArea;
  421. hr = GetDiffAreaInfo(m_spiDiffSnapMgmt, &m_VolumeList, pVolume->pszVolumeName, &diffArea);
  422. if (S_OK == hr)
  423. {
  424. PTSTR pszDiffAreaVolumeName = GetVolumeName(&m_VolumeList, diffArea.pszDiffVolumeDisplayName);
  425. ASSERT(pszDiffAreaVolumeName);
  426. hr = m_spiDiffSnapMgmt->ChangeDiffAreaMaximumSize(
  427. pVolume->pszVolumeName,
  428. pszDiffAreaVolumeName,
  429. VSS_ASSOC_REMOVE);
  430. if (VSS_E_OBJECT_NOT_FOUND == hr)
  431. hr = S_OK; // ignore if diff assoc has already been deleted
  432. }
  433. if (SUCCEEDED(hr))
  434. {
  435. UpdateDiffArea(nIndex, pVolume->pszVolumeName);
  436. }
  437. else if (hr == VSS_E_VOLUME_IN_USE)
  438. {
  439. // Special error message (Bug 519124)
  440. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETEDIFFAREA_ERROR_IN_USE, pVolume->pszDisplayName);
  441. }
  442. else
  443. {
  444. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_DELETEDIFFAREA_ERROR, pVolume->pszDisplayName);
  445. }
  446. // bug#494491: we need to update the Enable/Disable button even when failure occurs.
  447. if (1 == nSelectedCount)
  448. {
  449. UpdateEnableDisableButtons();
  450. if (SUCCEEDED(hr))
  451. {
  452. ::SendMessage(m_hWnd, DM_SETDEFID, (WPARAM)IDC_ENABLE, (LPARAM)0);
  453. m_ctrlEnable.SetFocus(); // Enable button will be enabled, set focus to it
  454. }
  455. }
  456. if (FAILED(hr))
  457. break;
  458. }
  459. }
  460. return hr;
  461. }
  462. HRESULT CVSSProp::DeleteAllSnapshotsOnVolume(
  463. IN LPCTSTR pszVolumeName
  464. )
  465. {
  466. if (!pszVolumeName || !*pszVolumeName)
  467. return E_INVALIDARG;
  468. CComPtr<IVssEnumObject> spiEnumSnapshots;
  469. HRESULT hr = m_spiMgmt->QuerySnapshotsByVolume(
  470. (PTSTR)pszVolumeName,
  471. VSS_SWPRV_ProviderId,
  472. &spiEnumSnapshots
  473. );
  474. if (S_OK == hr)
  475. {
  476. VSS_OBJECT_PROP Prop;
  477. VSS_SNAPSHOT_PROP* pSnapProp = &(Prop.Obj.Snap);
  478. ULONG ulFetched = 0;
  479. while (SUCCEEDED(spiEnumSnapshots->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
  480. {
  481. if (VSS_OBJECT_SNAPSHOT != Prop.Type)
  482. return E_FAIL;
  483. if (pSnapProp->m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
  484. {
  485. LONG lDeletedSnapshots = 0;
  486. VSS_ID ProblemSnapshotId = GUID_NULL;
  487. hr = m_spiCoord->DeleteSnapshots(pSnapProp->m_SnapshotId,
  488. VSS_OBJECT_SNAPSHOT,
  489. TRUE,
  490. &lDeletedSnapshots,
  491. &ProblemSnapshotId
  492. );
  493. VssFreeSnapshotProperties(pSnapProp);
  494. if (VSS_E_OBJECT_NOT_FOUND == hr)
  495. hr = S_OK; // ignore if snapshot has already been deleted
  496. if (FAILED(hr))
  497. break;
  498. }
  499. }
  500. }
  501. return hr;
  502. }
  503. void CVSSProp::OnSettings()
  504. {
  505. CWaitCursor wait;
  506. CSettings dlg(m_strComputer, m_strSelectedVolume);
  507. HRESULT hr = dlg.Init(m_spiDiffSnapMgmt,
  508. m_spiTS,
  509. m_bCluster,
  510. &m_VolumeList,
  511. !m_SnapshotList.empty());
  512. if (FAILED(hr))
  513. {
  514. DoErrMsgBox(m_hWnd, MB_OK, hr, IDS_SETTINGS_ERROR, m_strSelectedVolume);
  515. return;
  516. }
  517. dlg.DoModal();
  518. UpdateDiffArea();
  519. UpdateSchedule();
  520. UpdateEnableDisableButtons();
  521. UpdateSnapshotList();
  522. }
  523. void CVSSProp::OnItemchangedSnapshotList(NMHDR* pNMHDR, LRESULT* pResult)
  524. {
  525. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  526. m_ctrlDelete.EnableWindow(0 < m_ctrlSnapshotList.GetSelectedCount());
  527. *pResult = 0;
  528. }
  529. void CVSSProp::OnItemchangedVolumeList(NMHDR* pNMHDR, LRESULT* pResult)
  530. {
  531. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  532. int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
  533. if (0 == nSelectedCount)
  534. {
  535. m_ctrlEnable.EnableWindow(FALSE);
  536. m_ctrlDisable.EnableWindow(FALSE);
  537. m_ctrlSettings.EnableWindow(FALSE);
  538. m_ctrlCreate.EnableWindow(FALSE);
  539. m_ctrlDelete.EnableWindow(FALSE);
  540. } else
  541. {
  542. m_ctrlSettings.EnableWindow(1 == nSelectedCount);
  543. m_ctrlCreate.EnableWindow(1 == nSelectedCount);
  544. UpdateEnableDisableButtons();
  545. }
  546. if (1 < nSelectedCount)
  547. {
  548. m_strSelectedVolume = _T("");
  549. } else
  550. {
  551. int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
  552. if (-1 != nIndex)
  553. {
  554. m_strSelectedVolume = m_ctrlVolumeList.GetItemText(nIndex, 0);
  555. } else
  556. {
  557. m_strSelectedVolume = _T("");
  558. }
  559. }
  560. CWaitCursor wait;
  561. UpdateSnapshotList();
  562. *pResult = 0;
  563. }
  564. void CVSSProp::OnContextMenu(CWnd* pWnd, CPoint point)
  565. {
  566. if (!pWnd)
  567. return;
  568. ::WinHelp(pWnd->GetSafeHwnd(),
  569. VSSUI_CTX_HELP_FILE,
  570. HELP_CONTEXTMENU,
  571. (DWORD_PTR)(PVOID)aMenuHelpIDsForVSSProp);
  572. }
  573. BOOL CVSSProp::OnHelpInfo(HELPINFO* pHelpInfo)
  574. {
  575. if (!pHelpInfo ||
  576. pHelpInfo->iContextType != HELPINFO_WINDOW ||
  577. pHelpInfo->iCtrlId < 0)
  578. return FALSE;
  579. ::WinHelp((HWND)pHelpInfo->hItemHandle,
  580. VSSUI_CTX_HELP_FILE,
  581. HELP_WM_HELP,
  582. (DWORD_PTR)(PVOID)aMenuHelpIDsForVSSProp);
  583. return TRUE;
  584. }
  585. BOOL CVSSProp::OnInitDialog()
  586. {
  587. CWaitCursor wait;
  588. CPropertyPage::OnInitDialog();
  589. m_bHideAllControls = FALSE;
  590. CString strMsg;
  591. HRESULT hr = S_OK;
  592. do {
  593. hr = InitInterfacePointers();
  594. if (FAILED(hr))
  595. {
  596. GetMsg(strMsg, hr, IDS_VSSPROP_INIT_ERROR);
  597. m_bHideAllControls = TRUE;
  598. break;
  599. }
  600. hr = GetVolumes(); // get a list of volumes that are suitable for taking snapshots
  601. if (FAILED(hr))
  602. {
  603. GetMsg(strMsg, hr, IDS_VSSPROP_GETVOLUMES_ERROR);
  604. m_bHideAllControls = TRUE;
  605. break;
  606. }
  607. if (m_VolumeList.empty())
  608. {
  609. GetMsg(strMsg, 0, IDS_VSSPROP_EMPTY_VOLUMELIST);
  610. m_bHideAllControls = TRUE;
  611. break;
  612. }
  613. if (!m_strSelectedVolume.IsEmpty())
  614. {
  615. BOOL bFound = FALSE;
  616. for (VSSUI_VOLUME_LIST::iterator i = m_VolumeList.begin(); i != m_VolumeList.end(); i++)
  617. {
  618. if (!m_strSelectedVolume.CompareNoCase((*i)->pszDisplayName))
  619. {
  620. bFound = TRUE;
  621. break;
  622. }
  623. }
  624. // in case of mounted drive without assigned drive letter, the SelectedVolume could be the GUID name
  625. if (!bFound)
  626. {
  627. for (VSSUI_VOLUME_LIST::iterator i = m_VolumeList.begin(); i != m_VolumeList.end(); i++)
  628. {
  629. if (!m_strSelectedVolume.CompareNoCase((*i)->pszVolumeName))
  630. {
  631. bFound = TRUE;
  632. m_strSelectedVolume = (*i)->pszDisplayName; // change the selected volume to hold the display name
  633. break;
  634. }
  635. }
  636. }
  637. if (!bFound)
  638. {
  639. GetMsg(strMsg, 0, IDS_VSSPROP_VOLUME_ILEGIBLE, m_strSelectedVolume);
  640. m_bHideAllControls = TRUE;
  641. break;
  642. }
  643. }
  644. } while (0);
  645. if (m_bHideAllControls)
  646. {
  647. GetDlgItem(IDC_VSSPROP_ERROR)->SetWindowText(strMsg);
  648. GetDlgItem(IDC_VSSPROP_ERROR)->EnableWindow(TRUE);
  649. for (int i = IDC_EXPLANATION; i < IDC_VSSPROP_ERROR; i++)
  650. {
  651. GetDlgItem(i)->EnableWindow(FALSE);
  652. GetDlgItem(i)->ShowWindow(SW_HIDE);
  653. }
  654. } else
  655. {
  656. GetDlgItem(IDC_VSSPROP_ERROR)->EnableWindow(FALSE);
  657. GetDlgItem(IDC_VSSPROP_ERROR)->ShowWindow(SW_HIDE);
  658. //
  659. // insert column header of the Volume listbox
  660. //
  661. HWND hwnd = m_ctrlVolumeList.m_hWnd;
  662. m_hImageList = ImageList_LoadBitmap(
  663. _Module.GetResourceInstance(),
  664. MAKEINTRESOURCE(IDB_VOLUME_16x16),
  665. 16,
  666. 8,
  667. CLR_DEFAULT);
  668. ListView_SetImageList(hwnd, m_hImageList, LVSIL_SMALL);
  669. AddLVColumns(
  670. hwnd,
  671. IDS_VOLUMELIST_COLUMN_VOLUME,
  672. IDS_VOLUMELIST_COLUMN_USED - IDS_VOLUMELIST_COLUMN_VOLUME + 1);
  673. ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
  674. //
  675. // insert column headers for the snapshot listbox
  676. //
  677. AddLVColumns(
  678. m_ctrlSnapshotList.m_hWnd,
  679. IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP,
  680. IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP - IDS_SNAPSHOTLIST_COLUMN_TIMESTAMP + 1);
  681. ListView_SetExtendedListViewStyle(m_ctrlSnapshotList.m_hWnd, LVS_EX_FULLROWSELECT);
  682. // remember the original column width, later we need to adjust the width
  683. // to eliminate the horizontal scroll bar
  684. m_nSnapshotListColumnWidth = ListView_GetColumnWidth(m_ctrlSnapshotList.m_hWnd, 0);
  685. // before we insert rows, we need to remember the initial volume such that
  686. // we can pass it to SelectVolume() later.
  687. CString cstrVolume = m_strSelectedVolume;
  688. InsertVolumeInfo(hwnd);
  689. InsertDiffAreaInfo(hwnd);
  690. InsertShareInfo(hwnd);
  691. InsertScheduleInfo(hwnd);
  692. SelectVolume(hwnd, cstrVolume);
  693. // Since we're using the medium property page size (227, 215) as other shell pages,
  694. // we need to adjust the column width a little bit to make the UI look prettier.
  695. // We adjust column width after InsertVolumeInfo call, where we might shrink the
  696. // Share column to eliminate the horizontal bar.
  697. int nAdjustment = 10; // we find this number by experiment
  698. int nCol = IDS_VOLUMELIST_COLUMN_VOLUME - IDS_VOLUMELIST_COLUMN_VOLUME;
  699. int nColumnWidth = ListView_GetColumnWidth(hwnd, nCol);
  700. if (nAdjustment < nColumnWidth)
  701. {
  702. // shrink the Volume column
  703. ListView_SetColumnWidth(hwnd, nCol, nColumnWidth - nAdjustment);
  704. // widen the Next Run Time column
  705. nCol = IDS_VOLUMELIST_COLUMN_NEXTRUNTIME - IDS_VOLUMELIST_COLUMN_VOLUME;
  706. nColumnWidth = ListView_GetColumnWidth(hwnd, nCol);
  707. ListView_SetColumnWidth(hwnd, nCol, nColumnWidth + nAdjustment);
  708. }
  709. UpdateEnableDisableButtons();
  710. UpdateSnapshotList();
  711. }
  712. return TRUE; // return TRUE unless you set the focus to a control
  713. // EXCEPTION: OCX Property Pages should return FALSE
  714. }
  715. void CVSSProp::_ResetInterfacePointers()
  716. {
  717. if ((IVssSnapshotMgmt *)m_spiMgmt)
  718. m_spiMgmt.Release();
  719. if ((IVssCoordinator *)m_spiCoord)
  720. m_spiCoord.Release();
  721. if ((IVssDifferentialSoftwareSnapshotMgmt *)m_spiDiffSnapMgmt)
  722. m_spiDiffSnapMgmt.Release();
  723. if ((ITaskScheduler *)m_spiTS)
  724. m_spiTS.Release();
  725. m_bCluster = FALSE;
  726. }
  727. HRESULT CVSSProp::InitInterfacePointers()
  728. {
  729. _ResetInterfacePointers();
  730. HRESULT hr = S_OK;
  731. if (m_strComputer.IsEmpty())
  732. {
  733. hr = CoCreateInstance(CLSID_VssSnapshotMgmt,
  734. NULL,
  735. CLSCTX_LOCAL_SERVER,
  736. IID_IVssSnapshotMgmt,
  737. (void **)&m_spiMgmt);
  738. if (SUCCEEDED(hr))
  739. hr = CoCreateInstance(CLSID_VSSCoordinator,
  740. NULL,
  741. CLSCTX_LOCAL_SERVER,
  742. IID_IVssCoordinator,
  743. (void **)&m_spiCoord);
  744. } else
  745. {
  746. COSERVERINFO serverInfo = {0};
  747. serverInfo.pwszName = (LPTSTR)(LPCTSTR)m_strComputer;
  748. IID iid = IID_IVssSnapshotMgmt;
  749. MULTI_QI MQI = {0};
  750. MQI.pIID = &iid;
  751. hr = CoCreateInstanceEx(CLSID_VssSnapshotMgmt,
  752. NULL,
  753. CLSCTX_REMOTE_SERVER,
  754. &serverInfo,
  755. 1,
  756. &MQI);
  757. if (SUCCEEDED(hr))
  758. {
  759. m_spiMgmt = (IVssSnapshotMgmt *)MQI.pItf;
  760. ZeroMemory(&MQI, sizeof(MQI));
  761. iid = IID_IVssCoordinator;
  762. MQI.pIID = &iid;
  763. hr = CoCreateInstanceEx(CLSID_VSSCoordinator,
  764. NULL,
  765. CLSCTX_REMOTE_SERVER,
  766. &serverInfo,
  767. 1,
  768. &MQI);
  769. if (SUCCEEDED(hr))
  770. m_spiCoord = (IVssCoordinator *)MQI.pItf;
  771. }
  772. }
  773. if (SUCCEEDED(hr))
  774. hr = m_spiCoord->SetContext(VSS_CTX_CLIENT_ACCESSIBLE);
  775. if (SUCCEEDED(hr))
  776. hr = m_spiMgmt->GetProviderMgmtInterface(
  777. VSS_SWPRV_ProviderId,
  778. IID_IVssDifferentialSoftwareSnapshotMgmt,
  779. (IUnknown**)&m_spiDiffSnapMgmt);
  780. if (SUCCEEDED(hr))
  781. hr = CoCreateInstance(CLSID_CTaskScheduler,
  782. NULL,
  783. CLSCTX_INPROC_SERVER,
  784. IID_ITaskScheduler,
  785. (void **)&m_spiTS);
  786. if (SUCCEEDED(hr))
  787. {
  788. // SetTargetComputer requires server name to start with whackwhack
  789. if (m_strComputer.IsEmpty())
  790. hr = m_spiTS->SetTargetComputer(NULL);
  791. else
  792. {
  793. CString strTargetComputer = _T("\\\\");
  794. strTargetComputer += m_strComputer;
  795. hr = m_spiTS->SetTargetComputer((LPCTSTR)strTargetComputer);
  796. }
  797. }
  798. if (SUCCEEDED(hr))
  799. {
  800. DWORD dwState = 0;
  801. if (ERROR_SUCCESS == GetNodeClusterState(m_strComputer, &dwState) && ClusterStateRunning == dwState)
  802. {
  803. m_bCluster = TRUE;
  804. }
  805. }
  806. if (FAILED(hr))
  807. _ResetInterfacePointers();
  808. return hr;
  809. }
  810. HRESULT CVSSProp::GetVolumes()
  811. {
  812. if (!m_spiMgmt)
  813. return E_INVALIDARG;
  814. FreeVolumeList(&m_VolumeList);
  815. CComPtr<IVssEnumMgmtObject> spiEnumMgmt;
  816. HRESULT hr = m_spiMgmt->QueryVolumesSupportedForSnapshots(
  817. VSS_SWPRV_ProviderId,
  818. VSS_CTX_CLIENT_ACCESSIBLE,
  819. &spiEnumMgmt);
  820. if (FAILED(hr))
  821. return hr;
  822. VSS_MGMT_OBJECT_PROP Prop;
  823. VSS_VOLUME_PROP *pVolProp = &(Prop.Obj.Vol);
  824. ULONG ulFetched = 0;
  825. while (SUCCEEDED(hr = spiEnumMgmt->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
  826. {
  827. if (VSS_MGMT_OBJECT_VOLUME != Prop.Type)
  828. return E_FAIL;
  829. VSSUI_VOLUME *pVolInfo = (VSSUI_VOLUME *)calloc(1, sizeof(VSSUI_VOLUME));
  830. if (pVolInfo)
  831. {
  832. lstrcpyn(pVolInfo->pszVolumeName, pVolProp->m_pwszVolumeName, MAX_PATH);
  833. lstrcpyn(pVolInfo->pszDisplayName, pVolProp->m_pwszVolumeDisplayName, MAX_PATH);
  834. m_VolumeList.push_back(pVolInfo);
  835. } else
  836. {
  837. FreeVolumeList(&m_VolumeList);
  838. hr = E_OUTOFMEMORY;
  839. }
  840. CoTaskMemFree(pVolProp->m_pwszVolumeName);
  841. CoTaskMemFree(pVolProp->m_pwszVolumeDisplayName);
  842. if (FAILED(hr))
  843. break;
  844. }
  845. if (hr == S_FALSE)
  846. // End of loop detected
  847. hr = S_OK;
  848. return hr;
  849. }
  850. HRESULT CVSSProp::InsertVolumeInfo(HWND hwnd)
  851. {
  852. ListView_DeleteAllItems(hwnd);
  853. for (VSSUI_VOLUME_LIST::iterator i = m_VolumeList.begin(); i != m_VolumeList.end(); i++)
  854. {
  855. LVITEM lvItem = {0};
  856. lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  857. lvItem.lParam = (LPARAM)(*i);
  858. lvItem.pszText = (*i)->pszDisplayName;
  859. lvItem.iSubItem = 0;
  860. lvItem.iImage = 1;
  861. ListView_InsertItem(hwnd, &lvItem);
  862. }
  863. if (m_VolumeList.size() > 0)
  864. {
  865. int nVolumeListCountPerPage = ListView_GetCountPerPage(hwnd);
  866. if (m_VolumeList.size() > nVolumeListCountPerPage)
  867. {
  868. // we shrink the "Shares" column to eliminate the honrizontal scroll bar
  869. int nCol = IDS_VOLUMELIST_COLUMN_NUMOFSHARES - IDS_VOLUMELIST_COLUMN_VOLUME;
  870. int nSharesColumnWidth = ListView_GetColumnWidth(hwnd, nCol);
  871. ListView_SetColumnWidth(hwnd, nCol, nSharesColumnWidth - m_nScrollbarWidth);
  872. }
  873. }
  874. return S_OK;
  875. }
  876. //
  877. // Update diff area column of the currently selected volume
  878. //
  879. HRESULT CVSSProp::UpdateDiffArea()
  880. {
  881. if (m_strSelectedVolume.IsEmpty())
  882. return E_INVALIDARG;
  883. int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
  884. ASSERT(-1 != nIndex);
  885. PTSTR pszVolumeName = GetVolumeName(&m_VolumeList, m_strSelectedVolume);
  886. ASSERT(pszVolumeName);
  887. return UpdateDiffArea(nIndex, pszVolumeName);
  888. }
  889. //
  890. // Update diff area column of the specified volume
  891. //
  892. HRESULT CVSSProp::UpdateDiffArea(int nIndex, LPCTSTR pszVolumeName)
  893. {
  894. CString strMsg = _T("");
  895. VSSUI_DIFFAREA diffArea;
  896. HRESULT hr = GetDiffAreaInfo(m_spiDiffSnapMgmt, &m_VolumeList, pszVolumeName, &diffArea);
  897. if (S_OK == hr)
  898. {
  899. //
  900. // "Used on DiffVolume"
  901. //
  902. TCHAR szUsed[MAX_PATH];
  903. DWORD dwSize = sizeof(szUsed)/sizeof(TCHAR);
  904. DiskSpaceToString(diffArea.llUsedDiffSpace, szUsed, &dwSize);
  905. strMsg.FormatMessage(IDS_USED_ON_VOLUME, szUsed, diffArea.pszDiffVolumeDisplayName);
  906. }
  907. LVITEM lvItem = {0};
  908. lvItem.iItem = nIndex;
  909. lvItem.mask = LVIF_TEXT;
  910. lvItem.pszText = (PTSTR)(LPCTSTR)strMsg;
  911. lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_USED - IDS_VOLUMELIST_COLUMN_VOLUME;
  912. m_ctrlVolumeList.SetItem(&lvItem);
  913. return hr;
  914. }
  915. HRESULT CVSSProp::InsertDiffAreaInfo(HWND hwnd)
  916. {
  917. if (m_VolumeList.empty())
  918. return S_OK;
  919. int nIndex = -1;
  920. while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
  921. {
  922. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
  923. ASSERT(pVolume);
  924. if (!pVolume)
  925. continue; // shouldn't happen, skip it just in case
  926. UpdateDiffArea(nIndex, pVolume->pszVolumeName);
  927. }
  928. return S_OK;
  929. }
  930. HRESULT CVSSProp::InsertShareInfo(HWND hwnd)
  931. {
  932. if (m_VolumeList.empty())
  933. return S_OK;
  934. SHARE_INFO_2 *pInfo = NULL;
  935. DWORD dwEntriesRead = 0;
  936. DWORD dwEntriesTotal = 0;
  937. DWORD dwRet = NetShareEnum((PTSTR)(LPCTSTR)m_strComputer,
  938. 2,
  939. (LPBYTE *)&pInfo,
  940. -1, //max
  941. &dwEntriesRead,
  942. &dwEntriesTotal,
  943. NULL // resume handle
  944. );
  945. if (NERR_Success != dwRet)
  946. return HRESULT_FROM_WIN32(dwRet);
  947. TCHAR szNumOfShares[256];
  948. int nIndex = -1;
  949. while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
  950. {
  951. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
  952. ASSERT(pVolume);
  953. if (!pVolume)
  954. continue; // shouldn't happen, skip it just in case
  955. UINT count = 0;
  956. for (DWORD i = 0; i < dwEntriesRead; i++)
  957. {
  958. if (pInfo[i].shi2_type == STYPE_DISKTREE)
  959. {
  960. if (!mylstrncmpi(pInfo[i].shi2_path, pVolume->pszDisplayName, lstrlen(pVolume->pszDisplayName)))
  961. count++;
  962. }
  963. }
  964. _stprintf(szNumOfShares, _T("%d"), count); // no need to localize the format
  965. LVITEM lvItem = {0};
  966. lvItem.iItem = nIndex;
  967. lvItem.mask = LVIF_TEXT;
  968. lvItem.pszText = szNumOfShares;
  969. lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_NUMOFSHARES - IDS_VOLUMELIST_COLUMN_VOLUME;
  970. ListView_SetItem(hwnd, &lvItem);
  971. }
  972. NetApiBufferFree(pInfo);
  973. return S_OK;
  974. }
  975. //
  976. // Update schedule column of the currently selected volume
  977. //
  978. HRESULT CVSSProp::UpdateSchedule()
  979. {
  980. if (m_strSelectedVolume.IsEmpty())
  981. return E_INVALIDARG;
  982. int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
  983. ASSERT(-1 != nIndex);
  984. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(m_ctrlVolumeList.m_hWnd, nIndex);
  985. ASSERT(pVolume);
  986. if (!pVolume)
  987. return E_FAIL;
  988. return UpdateSchedule(nIndex, pVolume->pszVolumeName);
  989. }
  990. //
  991. // Update schedule column of the specified volume
  992. //
  993. HRESULT CVSSProp::UpdateSchedule(int nIndex, LPCTSTR pszVolumeName)
  994. {
  995. if (!pszVolumeName || !*pszVolumeName)
  996. return E_INVALIDARG;
  997. CComPtr<ITask> spiTask;
  998. (void)FindScheduledTimewarpTask((ITaskScheduler *)m_spiTS, pszVolumeName, &spiTask);
  999. UpdateSchedule((ITask *)spiTask, nIndex);
  1000. return S_OK;
  1001. }
  1002. void CVSSProp::UpdateSchedule(ITask * i_piTask, int nIndex)
  1003. {
  1004. BOOL bEnabled = FALSE;
  1005. SYSTEMTIME stNextRun = {0};
  1006. if (i_piTask)
  1007. (void)GetScheduledTimewarpTaskStatus(i_piTask, &bEnabled, &stNextRun);
  1008. LVITEM lvItem = {0};
  1009. lvItem.iItem = nIndex;
  1010. lvItem.mask = LVIF_IMAGE;
  1011. lvItem.iImage = (bEnabled ? 0 : 1);
  1012. lvItem.iSubItem = 0;
  1013. m_ctrlVolumeList.SetItem(&lvItem);
  1014. TCHAR szNextRun[MAX_PATH] = _T("");
  1015. DWORD dwSize = sizeof(szNextRun)/sizeof(TCHAR);
  1016. if (bEnabled)
  1017. SystemTimeToString(&stNextRun, szNextRun, &dwSize);
  1018. else
  1019. lstrcpyn(szNextRun, m_strDisabled, MAX_PATH);
  1020. ZeroMemory(&lvItem, sizeof(LVITEM));
  1021. lvItem.iItem = nIndex;
  1022. lvItem.mask = LVIF_TEXT;
  1023. lvItem.pszText = szNextRun;
  1024. lvItem.iSubItem = IDS_VOLUMELIST_COLUMN_NEXTRUNTIME - IDS_VOLUMELIST_COLUMN_VOLUME;
  1025. m_ctrlVolumeList.SetItem(&lvItem);
  1026. }
  1027. HRESULT CVSSProp::InsertScheduleInfo(HWND hwnd)
  1028. {
  1029. if (m_VolumeList.empty())
  1030. return S_OK;
  1031. int nIndex = -1;
  1032. while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
  1033. {
  1034. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
  1035. ASSERT(pVolume);
  1036. if (!pVolume)
  1037. continue; // shouldn't happen, skip it just in case
  1038. UpdateSchedule(nIndex, pVolume->pszVolumeName);
  1039. }
  1040. return S_OK;
  1041. }
  1042. void CVSSProp::SelectVolume(HWND hwnd, LPCTSTR pszVolume)
  1043. {
  1044. if (m_VolumeList.empty())
  1045. return;
  1046. int nIndex = -1;
  1047. if (pszVolume && *pszVolume)
  1048. {
  1049. while (-1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL)))
  1050. {
  1051. VSSUI_VOLUME *pVolume = (VSSUI_VOLUME *)GetListViewItemData(hwnd, nIndex);
  1052. ASSERT(pVolume);
  1053. if (!pVolume)
  1054. continue; // shouldn't happen, skip it just in case
  1055. if (!lstrcmpi(pszVolume, pVolume->pszDisplayName))
  1056. break;
  1057. }
  1058. }
  1059. if (-1 == nIndex)
  1060. nIndex = 0;
  1061. ListView_SetItemState(hwnd, nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xffffffff);
  1062. ListView_EnsureVisible(hwnd, nIndex, FALSE);
  1063. }
  1064. HRESULT CVSSProp::GetSnapshots(LPCTSTR pszVolume)
  1065. {
  1066. if (!pszVolume || !*pszVolume)
  1067. return E_INVALIDARG;
  1068. FreeSnapshotList(&m_SnapshotList);
  1069. CComPtr<IVssEnumObject> spiEnumSnapshots;
  1070. HRESULT hr = m_spiMgmt->QuerySnapshotsByVolume((PTSTR)pszVolume, VSS_SWPRV_ProviderId, &spiEnumSnapshots);
  1071. if (S_OK == hr)
  1072. {
  1073. VSS_OBJECT_PROP Prop;
  1074. VSS_SNAPSHOT_PROP* pSnapProp = &(Prop.Obj.Snap);
  1075. ULONG ulFetched = 0;
  1076. while (SUCCEEDED(spiEnumSnapshots->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
  1077. {
  1078. if (VSS_OBJECT_SNAPSHOT != Prop.Type)
  1079. return E_FAIL;
  1080. if (pSnapProp->m_lSnapshotAttributes & VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE)
  1081. {
  1082. VSSUI_SNAPSHOT *pSnapInfo = (VSSUI_SNAPSHOT *)calloc(1, sizeof(VSSUI_SNAPSHOT));
  1083. if (pSnapInfo)
  1084. {
  1085. pSnapInfo->idSnapshot = pSnapProp->m_SnapshotId;
  1086. pSnapInfo->vssTimeStamp = pSnapProp->m_tsCreationTimestamp;
  1087. m_SnapshotList.push_back(pSnapInfo);
  1088. } else
  1089. {
  1090. FreeSnapshotList(&m_SnapshotList);
  1091. hr = E_OUTOFMEMORY;
  1092. }
  1093. VssFreeSnapshotProperties(pSnapProp);
  1094. if (FAILED(hr))
  1095. break;
  1096. }
  1097. }
  1098. }
  1099. return hr;
  1100. }
  1101. HRESULT CVSSProp::UpdateSnapshotList()
  1102. {
  1103. if (m_strSelectedVolume.IsEmpty())
  1104. {
  1105. m_ctrlSnapshotList.DeleteAllItems();
  1106. m_ctrlDelete.EnableWindow(FALSE);
  1107. return S_OK;
  1108. }
  1109. HRESULT hr = GetSnapshots(m_strSelectedVolume);
  1110. m_ctrlSnapshotList.DeleteAllItems();
  1111. m_ctrlDelete.EnableWindow(FALSE);
  1112. if (SUCCEEDED(hr))
  1113. {
  1114. TCHAR szTimeStamp[256];
  1115. DWORD dwSize = 0;
  1116. LVITEM lvItem = {0};
  1117. for (VSSUI_SNAPSHOT_LIST::iterator i = m_SnapshotList.begin(); i != m_SnapshotList.end(); i++)
  1118. {
  1119. SYSTEMTIME st = {0};
  1120. VssTimeToSystemTime(&((*i)->vssTimeStamp), &st);
  1121. dwSize = sizeof(szTimeStamp)/sizeof(TCHAR);
  1122. SystemTimeToString(&st, szTimeStamp, &dwSize);
  1123. ZeroMemory(&lvItem, sizeof(lvItem));
  1124. lvItem.mask = LVIF_TEXT | LVIF_PARAM;
  1125. lvItem.lParam = (LPARAM)(*i);
  1126. lvItem.pszText = szTimeStamp;
  1127. m_ctrlSnapshotList.InsertItem(&lvItem);
  1128. }
  1129. if (m_SnapshotList.size() > 0)
  1130. {
  1131. HWND hwnd = m_ctrlSnapshotList.m_hWnd;
  1132. if (!m_nSnapshotListCountPerPage)
  1133. m_nSnapshotListCountPerPage = ListView_GetCountPerPage(hwnd);
  1134. if (m_SnapshotList.size() > m_nSnapshotListCountPerPage)
  1135. ListView_SetColumnWidth(hwnd, 0, m_nSnapshotListColumnWidth - m_nScrollbarWidth);
  1136. else
  1137. ListView_SetColumnWidth(hwnd, 0, m_nSnapshotListColumnWidth);
  1138. }
  1139. }
  1140. return hr;
  1141. }
  1142. //
  1143. // If multi-selection: both "Enable" and "Disable" buttons are enabled.
  1144. // If single-selection:
  1145. // The "Enable" button is disabled whenever there is a schedule.
  1146. // The "Disable" button is disabled when no schedule and no diff association.
  1147. //
  1148. void CVSSProp::UpdateEnableDisableButtons()
  1149. {
  1150. int nSelectedCount = m_ctrlVolumeList.GetSelectedCount();
  1151. if (nSelectedCount == 0)
  1152. return;
  1153. if (nSelectedCount > 1)
  1154. {
  1155. m_ctrlEnable.EnableWindow(TRUE);
  1156. m_ctrlDisable.EnableWindow(TRUE);
  1157. return;
  1158. }
  1159. int nIndex = m_ctrlVolumeList.GetNextItem(-1, LVNI_SELECTED);
  1160. if (-1 == nIndex)
  1161. return; // shouldn't happen
  1162. CString strNextRunTime;
  1163. strNextRunTime = m_ctrlVolumeList.GetItemText(nIndex, IDS_VOLUMELIST_COLUMN_NEXTRUNTIME - IDS_VOLUMELIST_COLUMN_VOLUME);
  1164. if (strNextRunTime.CompareNoCase(m_strDisabled))
  1165. {
  1166. // schedule exists
  1167. m_ctrlEnable.EnableWindow(FALSE);
  1168. m_ctrlDisable.EnableWindow(TRUE);
  1169. return;
  1170. }
  1171. // no schedule
  1172. m_ctrlEnable.EnableWindow(TRUE);
  1173. CString strUsed;
  1174. strUsed = m_ctrlVolumeList.GetItemText(nIndex, IDS_VOLUMELIST_COLUMN_USED - IDS_VOLUMELIST_COLUMN_VOLUME);
  1175. m_ctrlDisable.EnableWindow(!strUsed.IsEmpty());
  1176. }
  1177. void CVSSProp::OnHelpLink(NMHDR* pNMHDR, LRESULT* pResult)
  1178. {
  1179. CWaitCursor wait;
  1180. ::HtmlHelp(0, _T("timewarp.chm"), HH_DISPLAY_TOPIC, (DWORD_PTR)(_T("deploy_timewarp_client.htm")));
  1181. *pResult = 0;
  1182. }
  1183. //
  1184. // Q148388 How to Change Default Control Focus on CPropertyPageEx
  1185. //
  1186. BOOL CVSSProp::OnSetActive()
  1187. {
  1188. BOOL fRet = CPropertyPage::OnSetActive();
  1189. if (!m_bHideAllControls)
  1190. {
  1191. PostMessage(WM_SETPAGEFOCUS, 0, 0L);
  1192. }
  1193. return fRet;
  1194. }
  1195. LRESULT CVSSProp::OnSetPageFocus(WPARAM wParam, LPARAM lParam)
  1196. {
  1197. GetDlgItem(IDC_VOLUME_LIST)->SetFocus();
  1198. return 0;
  1199. }