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.

1254 lines
39 KiB

  1. // Utils.cpp : helper functions
  2. //
  3. #include "stdafx.h"
  4. #include "utils.h"
  5. #include <lm.h>
  6. #include <clusapi.h>
  7. #include <msclus.h>
  8. #include <vs_clus.hxx> // vss\server\inc
  9. ULONGLONG g_llKB = 1024;
  10. ULONGLONG g_llMB = 1024 * 1024;
  11. HRESULT
  12. AddLVColumns(
  13. IN const HWND hwndListBox,
  14. IN const INT iStartingResourceID,
  15. IN const UINT uiColumns
  16. )
  17. {
  18. //
  19. // calculate the listview column width
  20. //
  21. RECT rect;
  22. ZeroMemory(&rect, sizeof(rect));
  23. ::GetWindowRect(hwndListBox, &rect);
  24. int nControlWidth = rect.right - rect.left;
  25. int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
  26. int nBorderWidth = GetSystemMetrics(SM_CXBORDER);
  27. int nControlNetWidth = nControlWidth - 4 * nBorderWidth;
  28. int nWidth = nControlNetWidth / uiColumns;
  29. LVCOLUMN lvColumn;
  30. ZeroMemory(&lvColumn, sizeof(lvColumn));
  31. lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  32. lvColumn.fmt = LVCFMT_LEFT;
  33. lvColumn.cx = nWidth;
  34. for (UINT i = 0; i < uiColumns; i++)
  35. {
  36. CString strColumnText;
  37. strColumnText.LoadString(iStartingResourceID + i);
  38. lvColumn.pszText = (LPTSTR)(LPCTSTR)strColumnText;
  39. lvColumn.iSubItem = i;
  40. ListView_InsertColumn(hwndListBox, i, &lvColumn);
  41. }
  42. return S_OK;
  43. }
  44. LPARAM GetListViewItemData(
  45. IN HWND hwndList,
  46. IN int index
  47. )
  48. {
  49. if (-1 == index)
  50. return NULL;
  51. LVITEM lvItem;
  52. ZeroMemory(&lvItem, sizeof(lvItem));
  53. lvItem.mask = LVIF_PARAM;
  54. lvItem.iItem = index;
  55. if (ListView_GetItem(hwndList, &lvItem))
  56. return lvItem.lParam;
  57. return NULL;
  58. }
  59. int MyCompareStringN(
  60. IN LPCTSTR lpString1,
  61. IN LPCTSTR lpString2,
  62. IN UINT cchCount,
  63. IN DWORD dwCmpFlags
  64. )
  65. {
  66. UINT nLen1 = (lpString1 ? lstrlen(lpString1) : 0);
  67. UINT nLen2 = (lpString2 ? lstrlen(lpString2) : 0);
  68. int nRet = CompareString(
  69. LOCALE_USER_DEFAULT,
  70. dwCmpFlags,
  71. lpString1,
  72. min(cchCount, nLen1),
  73. lpString2,
  74. min(cchCount, nLen2)
  75. );
  76. return (nRet - CSTR_EQUAL);
  77. }
  78. int mylstrncmpi(
  79. IN LPCTSTR lpString1,
  80. IN LPCTSTR lpString2,
  81. IN UINT cchCount
  82. )
  83. {
  84. return MyCompareStringN(lpString1, lpString2, cchCount, NORM_IGNORECASE);
  85. }
  86. HRESULT GetArgV(
  87. IN LPCTSTR i_pszParameters,
  88. OUT UINT *o_pargc,
  89. OUT void ***o_pargv
  90. )
  91. {
  92. if (!o_pargc || !o_pargv)
  93. return E_INVALIDARG;
  94. *o_pargc = 0;
  95. *o_pargv = NULL;
  96. TCHAR *p = (TCHAR *)i_pszParameters;
  97. while (*p && _istspace(*p)) // skip leading spaces
  98. p++;
  99. if (!*p)
  100. return S_FALSE; // i_pszParameters contains no parameters
  101. UINT nChars = lstrlen(p) + 1;
  102. BYTE *pbData = (BYTE *)calloc((nChars / 2) * sizeof(PTSTR *) + nChars * sizeof(TCHAR), sizeof(BYTE));
  103. if (!pbData)
  104. return E_OUTOFMEMORY;
  105. PTSTR *pargv = (PTSTR *)pbData;
  106. PTSTR t = (PTSTR)(pbData + (nChars / 2) * sizeof(PTSTR *));
  107. _tcscpy(t, p);
  108. UINT argc = 0;
  109. do {
  110. *pargv++ = t;
  111. argc++;
  112. while (*t && !_istspace(*t)) // move to the end of the token
  113. t++;
  114. if (!*t)
  115. break;
  116. *t++ = _T('\0'); // end the token with '\0'
  117. while (*t && _istspace(*t)) // skip leading spaces of the next token
  118. t++;
  119. } while (*t);
  120. *o_pargv = (void **)pbData;
  121. *o_pargc = argc;
  122. return S_OK;
  123. }
  124. #define TIMEWARP_CMD_APPNAME _T("vssadmin")
  125. #define TIMEWARP_CMD_APPEXENAME _T("vssadmin.exe")
  126. #define TIMEWARP_TASK_ACTION_MAJOR _T("Create")
  127. #define TIMEWARP_TASK_ACTION_MINOR _T("Shadow")
  128. #define TIMEWARP_TASK_VOLUME _T("/For=")
  129. #define TIMEWARP_TASK_PARAMETERS _T("Create Shadow /AutoRetry=5 /For=")
  130. BOOL IsTimewarpTask(
  131. IN LPCTSTR i_pszAppName,
  132. IN LPCTSTR i_pszParameters,
  133. IN LPCTSTR i_pszVolume
  134. )
  135. {
  136. if (!i_pszAppName || !*i_pszAppName ||
  137. !i_pszParameters || !*i_pszParameters ||
  138. !i_pszVolume || !*i_pszVolume)
  139. return FALSE;
  140. //
  141. // check the application name
  142. //
  143. TCHAR *p = (PTSTR)(i_pszAppName + lstrlen(i_pszAppName) - 1);
  144. while (p > i_pszAppName && *p != _T('\\'))
  145. p--;
  146. if (*p == _T('\\'))
  147. p++;
  148. if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, p, -1, TIMEWARP_CMD_APPEXENAME, -1) &&
  149. CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, p, -1, TIMEWARP_CMD_APPNAME, -1))
  150. return FALSE; // application name doesn't match
  151. //
  152. // check the parameters
  153. //
  154. BOOL bVolume = FALSE;
  155. UINT argc = 0;
  156. void **argv = NULL;
  157. if (SUCCEEDED(GetArgV(i_pszParameters, &argc, &argv)))
  158. {
  159. if (argc >= 4 &&
  160. CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, (PTSTR)(argv[0]), -1, TIMEWARP_TASK_ACTION_MAJOR, -1) &&
  161. CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, (PTSTR)(argv[1]), -1, TIMEWARP_TASK_ACTION_MINOR, -1))
  162. {
  163. UINT nVolume = lstrlen(TIMEWARP_TASK_VOLUME);
  164. for (UINT i = 2; i < argc; i++)
  165. {
  166. if (!bVolume &&
  167. !mylstrncmpi((PTSTR)(argv[i]), TIMEWARP_TASK_VOLUME, nVolume) &&
  168. !lstrcmpi((PTSTR)(argv[i]) + nVolume, i_pszVolume))
  169. {
  170. bVolume = TRUE;
  171. break;
  172. }
  173. }
  174. }
  175. if (argv)
  176. free(argv);
  177. }
  178. return bVolume;
  179. }
  180. #define NUM_OF_TASKS 5
  181. //
  182. // Find the first enabled Timewarp task, skip all disabled tasks.
  183. //
  184. HRESULT FindScheduledTimewarpTask(
  185. IN ITaskScheduler* i_piTS,
  186. IN LPCTSTR i_pszVolumeName,
  187. OUT ITask** o_ppiTask,
  188. OUT PTSTR* o_ppszTaskName /* = NULL */
  189. )
  190. {
  191. if (!i_piTS ||
  192. !i_pszVolumeName || !*i_pszVolumeName ||
  193. !o_ppiTask)
  194. return E_INVALIDARG;
  195. *o_ppiTask = NULL;
  196. if (o_ppszTaskName)
  197. *o_ppszTaskName = NULL;
  198. /////////////////////////////////////////////////////////////////
  199. // Call ITaskScheduler::Enum to get an enumeration object.
  200. /////////////////////////////////////////////////////////////////
  201. CComPtr<IEnumWorkItems> spiEnum;
  202. HRESULT hr = i_piTS->Enum(&spiEnum);
  203. if (FAILED(hr))
  204. return hr;
  205. /////////////////////////////////////////////////////////////////
  206. // Call IEnumWorkItems::Next to retrieve tasks. Note that
  207. // this example tries to retrieve five tasks for each call.
  208. /////////////////////////////////////////////////////////////////
  209. BOOL bTimewarpTask = FALSE;
  210. BOOL bEnabled = FALSE;
  211. SYSTEMTIME stNextRun = {0};
  212. LPTSTR *ppszNames = NULL;
  213. DWORD dwFetchedTasks = 0;
  214. while (!bTimewarpTask && SUCCEEDED(spiEnum->Next(NUM_OF_TASKS, &ppszNames, &dwFetchedTasks)) && (dwFetchedTasks != 0))
  215. {
  216. ///////////////////////////////////////////////////////////////
  217. // Process each task.
  218. //////////////////////////////////////////////////////////////
  219. while (!bTimewarpTask && dwFetchedTasks)
  220. {
  221. LPTSTR pszTaskName = ppszNames[--dwFetchedTasks];
  222. ///////////////////////////////////////////////////////////////////
  223. // Call ITaskScheduler::Activate to get the Task object.
  224. ///////////////////////////////////////////////////////////////////
  225. CComPtr<ITask> spiTask;
  226. hr = i_piTS->Activate(pszTaskName,
  227. IID_ITask,
  228. (IUnknown**) &spiTask);
  229. if (SUCCEEDED(hr))
  230. {
  231. LPTSTR pszApplicationName = NULL;
  232. hr = spiTask->GetApplicationName(&pszApplicationName);
  233. if (SUCCEEDED(hr))
  234. {
  235. LPTSTR pszParameters = NULL;
  236. hr = spiTask->GetParameters(&pszParameters);
  237. if (SUCCEEDED(hr))
  238. {
  239. if (IsTimewarpTask(pszApplicationName, pszParameters, i_pszVolumeName))
  240. {
  241. bEnabled = FALSE;
  242. GetScheduledTimewarpTaskStatus(spiTask, &bEnabled, &stNextRun);
  243. if (bEnabled)
  244. bTimewarpTask = TRUE;
  245. }
  246. CoTaskMemFree(pszParameters);
  247. }
  248. CoTaskMemFree(pszApplicationName);
  249. }
  250. if (bTimewarpTask)
  251. {
  252. if (o_ppszTaskName)
  253. {
  254. // omit the ending .job
  255. int nLen = lstrlen(pszTaskName);
  256. BOOL bEndingFound = (nLen > 4 && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pszTaskName + nLen - 4, -1, _T(".job"), -1));
  257. if (bEndingFound)
  258. *(pszTaskName + nLen - 4) = _T('\0');
  259. *o_ppszTaskName = _tcsdup(pszTaskName);
  260. if (bEndingFound)
  261. *(pszTaskName + nLen - 4) = _T('.');
  262. if (!*o_ppszTaskName)
  263. hr = E_OUTOFMEMORY;
  264. }
  265. if (SUCCEEDED(hr))
  266. {
  267. *o_ppiTask = (ITask *)spiTask;
  268. spiTask.Detach();
  269. }
  270. }
  271. }
  272. CoTaskMemFree(ppszNames[dwFetchedTasks]);
  273. }
  274. CoTaskMemFree(ppszNames);
  275. }
  276. if (FAILED(hr))
  277. return hr;
  278. return (bTimewarpTask ? S_OK : S_FALSE);
  279. }
  280. HRESULT GetScheduledTimewarpTaskStatus(
  281. IN ITask* i_piTask,
  282. OUT BOOL* o_pbEnabled,
  283. OUT SYSTEMTIME* o_pstNextRunTime
  284. )
  285. {
  286. if (!i_piTask ||
  287. !o_pbEnabled || !o_pstNextRunTime)
  288. return E_INVALIDARG;
  289. *o_pbEnabled = FALSE;
  290. ZeroMemory(o_pstNextRunTime, sizeof(SYSTEMTIME));
  291. HRESULT hrStatus = S_OK;
  292. HRESULT hr = i_piTask->GetStatus(&hrStatus);
  293. if (SUCCEEDED(hr))
  294. {
  295. switch (hrStatus)
  296. {
  297. case SCHED_S_TASK_HAS_NOT_RUN:
  298. case SCHED_S_TASK_READY:
  299. case SCHED_S_TASK_RUNNING:
  300. {
  301. hr = i_piTask->GetNextRunTime(o_pstNextRunTime);
  302. if (S_OK == hr)
  303. *o_pbEnabled = TRUE;
  304. }
  305. break;
  306. default:
  307. break;
  308. }
  309. }
  310. return hr;
  311. }
  312. HRESULT CreateDefaultEnableSchedule(
  313. IN ITaskScheduler* i_piTS,
  314. IN LPCTSTR i_pszComputer,
  315. IN LPCTSTR i_pszVolumeDisplayName,
  316. IN LPCTSTR i_pszVolumeName,
  317. OUT ITask** o_ppiTask,
  318. OUT PTSTR* o_ppszTaskName /* = NULL */
  319. )
  320. {
  321. if (!i_piTS ||
  322. !i_pszVolumeDisplayName || !*i_pszVolumeDisplayName ||
  323. !i_pszVolumeName || !*i_pszVolumeName ||
  324. !o_ppiTask)
  325. return E_INVALIDARG;
  326. *o_ppiTask = NULL;
  327. if (o_ppszTaskName)
  328. *o_ppszTaskName = NULL;
  329. HRESULT hr = S_OK;
  330. do
  331. {
  332. //
  333. // i_pszVolumeName is in the form of \\?\Volume{xxx.....xxx}\
  334. // The task name will be ShadowCopy concatenating with Volume{xxx.....xxx}
  335. //
  336. TCHAR szTaskName[MAX_PATH] = _T("ShadowCopy");
  337. _tcscat(szTaskName, i_pszVolumeName + 4); // skip the beginning "\\?\"
  338. TCHAR *p = szTaskName + lstrlen(szTaskName) - 1;
  339. if (*p == _T('\\'))
  340. *p = _T('\0'); // remove the ending whack
  341. if (o_ppszTaskName)
  342. {
  343. *o_ppszTaskName = _tcsdup(szTaskName);
  344. if (!*o_ppszTaskName)
  345. {
  346. hr = E_OUTOFMEMORY;
  347. break;
  348. }
  349. }
  350. //
  351. // delete any task that has the same name
  352. //
  353. (void)i_piTS->Delete(szTaskName);
  354. TCHAR szSystem32Directory[MAX_PATH];
  355. DWORD dwSize = sizeof(szSystem32Directory) / sizeof(TCHAR);
  356. hr = GetSystem32Directory(i_pszComputer, szSystem32Directory, &dwSize);
  357. if (FAILED(hr))
  358. break;
  359. TCHAR szApplicationName[MAX_PATH * 2];
  360. lstrcpyn(szApplicationName, szSystem32Directory, MAX_PATH);
  361. _tcscat(szApplicationName, _T("\\vssadmin.exe"));
  362. TCHAR szParameters[MAX_PATH] = TIMEWARP_TASK_PARAMETERS;
  363. _tcscat(szParameters, i_pszVolumeName);
  364. SYSTEMTIME st = {0};
  365. GetSystemTime(&st);
  366. WORD wStartHours[] = {7, 12};
  367. TASK_TRIGGER Triggers[2];
  368. for (DWORD i = 0; i < sizeof(wStartHours)/sizeof(wStartHours[0]); i++)
  369. {
  370. //////////////////////////////////////////////////////
  371. // Define TASK_TRIGGER structure. Note that wBeginDay,
  372. // wBeginMonth, and wBeginYear must be set to a valid
  373. // day, month, and year respectively.
  374. //////////////////////////////////////////////////////
  375. ZeroMemory(Triggers + i, sizeof(TASK_TRIGGER));
  376. Triggers[i].wBeginDay =st.wDay;
  377. Triggers[i].wBeginMonth =st.wMonth;
  378. Triggers[i].wBeginYear =st.wYear;
  379. Triggers[i].cbTriggerSize = sizeof(TASK_TRIGGER);
  380. Triggers[i].wStartHour = wStartHours[i];
  381. Triggers[i].TriggerType = TASK_TIME_TRIGGER_WEEKLY;
  382. Triggers[i].Type.Weekly.WeeksInterval = 1;
  383. Triggers[i].Type.Weekly.rgfDaysOfTheWeek = TASK_MONDAY | TASK_TUESDAY | TASK_WEDNESDAY | TASK_THURSDAY | TASK_FRIDAY;
  384. }
  385. try
  386. {
  387. CVssClusterAPI cluster;
  388. bool bRet = cluster.Initialize(i_pszComputer);
  389. if (!bRet || !cluster.IsVolumeBelongingToPhysicalDiskResource(i_pszVolumeName))
  390. {
  391. CComPtr<ITask> spiTask;
  392. hr = i_piTS->NewWorkItem(szTaskName, // Name of task
  393. CLSID_CTask, // Class identifier
  394. IID_ITask, // Interface identifier
  395. (IUnknown**)&spiTask); // Address of task interface
  396. if (FAILED(hr))
  397. break;
  398. hr = spiTask->SetWorkingDirectory(szSystem32Directory);
  399. if (FAILED(hr))
  400. break;
  401. hr = spiTask->SetApplicationName(szApplicationName);
  402. if (FAILED(hr))
  403. break;
  404. hr = spiTask->SetParameters(szParameters);
  405. if (FAILED(hr))
  406. break;
  407. // run as local system account
  408. hr = spiTask->SetAccountInformation(_T(""), NULL);
  409. if (FAILED(hr))
  410. break;
  411. for (i = 0; i < sizeof(wStartHours)/sizeof(wStartHours[0]); i++)
  412. {
  413. ///////////////////////////////////////////////////////////////////
  414. // Call ITask::CreateTrigger to create new trigger.
  415. ///////////////////////////////////////////////////////////////////
  416. CComPtr<ITaskTrigger> spiTaskTrigger;
  417. WORD piNewTrigger;
  418. hr = spiTask->CreateTrigger(&piNewTrigger, &spiTaskTrigger);
  419. if (FAILED(hr))
  420. break;
  421. ///////////////////////////////////////////////////////////////////
  422. // Call ITaskTrigger::SetTrigger to set trigger criteria.
  423. ///////////////////////////////////////////////////////////////////
  424. hr = spiTaskTrigger->SetTrigger(Triggers + i);
  425. if (FAILED(hr))
  426. break;
  427. }
  428. if (FAILED(hr))
  429. break;
  430. ///////////////////////////////////////////////////////////////////
  431. // Call IPersistFile::Save to save trigger to disk.
  432. ///////////////////////////////////////////////////////////////////
  433. CComPtr<IPersistFile> spiPersistFile;
  434. hr = spiTask->QueryInterface(IID_IPersistFile, (void **)&spiPersistFile);
  435. if (FAILED(hr))
  436. break;
  437. hr = spiPersistFile->Save(NULL, TRUE);
  438. if (SUCCEEDED(hr))
  439. {
  440. *o_ppiTask = (ITask *)spiTask;
  441. spiTask.Detach();
  442. }
  443. } else // cluster
  444. {
  445. bRet = cluster.CreateTaskSchedulerResource(
  446. szTaskName,
  447. szApplicationName,
  448. szParameters,
  449. 2,
  450. Triggers,
  451. i_pszVolumeName
  452. );
  453. if (bRet)
  454. {
  455. hr = FindScheduledTimewarpTask(i_piTS, i_pszVolumeName, o_ppiTask);
  456. if (S_FALSE == hr)
  457. hr = E_FAIL; // we failed to find a valid enabled task, something is wrong
  458. } else
  459. {
  460. hr = E_FAIL;
  461. }
  462. }
  463. } catch (HRESULT hrClus)
  464. {
  465. hr = hrClus;
  466. }
  467. } while(0);
  468. if (FAILED(hr))
  469. {
  470. if (o_ppszTaskName && *o_ppszTaskName)
  471. {
  472. free(*o_ppszTaskName);
  473. *o_ppszTaskName = NULL;
  474. }
  475. }
  476. return hr;
  477. }
  478. HRESULT DeleteOneScheduledTimewarpTasks(
  479. IN ITaskScheduler* i_piTS,
  480. IN LPCTSTR i_pszComputer,
  481. IN LPCTSTR i_pszTaskName
  482. )
  483. {
  484. if (!i_piTS || !i_pszTaskName || !*i_pszTaskName)
  485. return E_INVALIDARG;
  486. HRESULT hr = S_OK;
  487. try
  488. {
  489. CVssClusterAPI cluster;
  490. bool bRet = cluster.Initialize(i_pszComputer);
  491. if (bRet)
  492. {
  493. // omit the ending .job
  494. PTSTR pszTaskName = (PTSTR)i_pszTaskName;
  495. int nLen = lstrlen(pszTaskName);
  496. BOOL bEndingFound = (nLen > 4 && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pszTaskName + nLen - 4, -1, _T(".job"), -1));
  497. if (bEndingFound)
  498. *(pszTaskName + nLen - 4) = _T('\0');
  499. bRet = cluster.DeleteTaskSchedulerResource(pszTaskName);
  500. if (bEndingFound)
  501. *(pszTaskName + nLen - 4) = _T('.');
  502. if (!bRet)
  503. {
  504. hr = i_piTS->Delete(i_pszTaskName);
  505. }
  506. } else
  507. {
  508. hr = i_piTS->Delete(i_pszTaskName);
  509. }
  510. } catch (HRESULT hrIgnore)
  511. {
  512. hr = i_piTS->Delete(i_pszTaskName);;
  513. }
  514. return hr;
  515. }
  516. HRESULT DeleteAllScheduledTimewarpTasks(
  517. IN ITaskScheduler* i_piTS,
  518. IN LPCTSTR i_pszComputer,
  519. IN LPCTSTR i_pszVolumeName,
  520. IN BOOL i_bDeleteDisabledOnesOnly
  521. )
  522. {
  523. if (!i_piTS ||
  524. !i_pszVolumeName || !*i_pszVolumeName)
  525. return E_INVALIDARG;
  526. /////////////////////////////////////////////////////////////////
  527. // Call ITaskScheduler::Enum to get an enumeration object.
  528. /////////////////////////////////////////////////////////////////
  529. CComPtr<IEnumWorkItems> spiEnum;
  530. HRESULT hr = i_piTS->Enum(&spiEnum);
  531. /////////////////////////////////////////////////////////////////
  532. // Call IEnumWorkItems::Next to retrieve tasks. Note that
  533. // this example tries to retrieve five tasks for each call.
  534. /////////////////////////////////////////////////////////////////
  535. BOOL bEnabled = FALSE;
  536. SYSTEMTIME stNextRun = {0};
  537. LPTSTR *ppszNames = NULL;
  538. DWORD dwFetchedTasks = 0;
  539. while (SUCCEEDED(hr) && SUCCEEDED(spiEnum->Next(NUM_OF_TASKS, &ppszNames, &dwFetchedTasks)) && (dwFetchedTasks != 0))
  540. {
  541. ///////////////////////////////////////////////////////////////
  542. // Process each task.
  543. //////////////////////////////////////////////////////////////
  544. while (SUCCEEDED(hr) && dwFetchedTasks)
  545. {
  546. LPTSTR pszTaskName = ppszNames[--dwFetchedTasks];
  547. ///////////////////////////////////////////////////////////////////
  548. // Call ITaskScheduler::Activate to get the Task object.
  549. ///////////////////////////////////////////////////////////////////
  550. CComPtr<ITask> spiTask;
  551. hr = i_piTS->Activate(pszTaskName,
  552. IID_ITask,
  553. (IUnknown**) &spiTask);
  554. if (SUCCEEDED(hr))
  555. {
  556. LPTSTR pszApplicationName = NULL;
  557. hr = spiTask->GetApplicationName(&pszApplicationName);
  558. if (SUCCEEDED(hr))
  559. {
  560. LPTSTR pszParameters = NULL;
  561. hr = spiTask->GetParameters(&pszParameters);
  562. if (SUCCEEDED(hr))
  563. {
  564. if (IsTimewarpTask(pszApplicationName, pszParameters, i_pszVolumeName))
  565. {
  566. if (i_bDeleteDisabledOnesOnly)
  567. {
  568. bEnabled = FALSE;
  569. GetScheduledTimewarpTaskStatus(spiTask, &bEnabled, &stNextRun);
  570. if (!bEnabled)
  571. hr = DeleteOneScheduledTimewarpTasks(i_piTS, i_pszComputer, pszTaskName);
  572. //hr = i_piTS->Delete(pszTaskName);
  573. } else
  574. {
  575. hr = DeleteOneScheduledTimewarpTasks(i_piTS, i_pszComputer, pszTaskName);
  576. //hr = i_piTS->Delete(pszTaskName);
  577. }
  578. }
  579. CoTaskMemFree(pszParameters);
  580. }
  581. CoTaskMemFree(pszApplicationName);
  582. }
  583. }
  584. CoTaskMemFree(ppszNames[dwFetchedTasks]);
  585. }
  586. CoTaskMemFree(ppszNames);
  587. }
  588. return hr;
  589. }
  590. HRESULT VssTimeToSystemTime(
  591. IN VSS_TIMESTAMP* i_pVssTime,
  592. OUT SYSTEMTIME* o_pSystemTime
  593. )
  594. {
  595. if (!o_pSystemTime)
  596. return E_INVALIDARG;
  597. SYSTEMTIME stLocal = {0};
  598. FILETIME ftLocal = {0};
  599. if (!i_pVssTime)
  600. {
  601. SYSTEMTIME sysTime = {0};
  602. FILETIME fileTime = {0};
  603. // Get current time
  604. ::GetSystemTime(&sysTime);
  605. // Convert system time to file time
  606. ::SystemTimeToFileTime(&sysTime, &fileTime);
  607. // Compensate for local TZ
  608. ::FileTimeToLocalFileTime(&fileTime, &ftLocal);
  609. } else
  610. {
  611. // Compensate for local TZ
  612. ::FileTimeToLocalFileTime((FILETIME *)i_pVssTime, &ftLocal);
  613. }
  614. // Finally convert it to system time
  615. ::FileTimeToSystemTime(&ftLocal, o_pSystemTime);
  616. return S_OK;
  617. }
  618. HRESULT SystemTimeToString(
  619. IN SYSTEMTIME* i_pSystemTime,
  620. OUT PTSTR o_pszText,
  621. IN OUT DWORD* io_pdwSize
  622. )
  623. {
  624. if (!i_pSystemTime || !o_pszText || !io_pdwSize)
  625. return E_INVALIDARG;
  626. // Convert to a date string
  627. TCHAR pszDate[64];
  628. ::GetDateFormat(GetThreadLocale( ),
  629. DATE_SHORTDATE,
  630. i_pSystemTime,
  631. NULL,
  632. pszDate,
  633. sizeof(pszDate) / sizeof(TCHAR));
  634. // Convert to a time string
  635. TCHAR pszTime[64];
  636. ::GetTimeFormat(GetThreadLocale( ),
  637. TIME_NOSECONDS,
  638. i_pSystemTime,
  639. NULL,
  640. pszTime,
  641. sizeof( pszTime ) / sizeof(TCHAR));
  642. CString strMsg;
  643. strMsg.Format(IDS_DATE_TIME, pszDate, pszTime);
  644. DWORD dwRequiredSize = strMsg.GetLength() + 1;
  645. if (*io_pdwSize < dwRequiredSize)
  646. {
  647. *io_pdwSize = dwRequiredSize;
  648. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  649. }
  650. *io_pdwSize = dwRequiredSize;
  651. _tcscpy(o_pszText, strMsg);
  652. return S_OK;
  653. }
  654. HRESULT DiskSpaceToString(
  655. IN ULONGLONG i_llDiskSpace,
  656. OUT PTSTR o_pszText,
  657. IN OUT DWORD* io_pdwSize
  658. )
  659. {
  660. if (!o_pszText || !io_pdwSize)
  661. return E_INVALIDARG;
  662. CString strMsg;
  663. if (i_llDiskSpace < g_llKB)
  664. strMsg.Format(IDS_SPACE_LABEL_B, i_llDiskSpace);
  665. else if (i_llDiskSpace < g_llMB)
  666. strMsg.Format(IDS_SPACE_LABEL_KB, i_llDiskSpace / g_llKB);
  667. else
  668. strMsg.Format(IDS_SPACE_LABEL_MB, i_llDiskSpace / g_llMB);
  669. DWORD dwRequiredSize = strMsg.GetLength() + 1;
  670. if (*io_pdwSize < dwRequiredSize)
  671. {
  672. *io_pdwSize = dwRequiredSize;
  673. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  674. }
  675. *io_pdwSize = dwRequiredSize;
  676. _tcscpy(o_pszText, strMsg);
  677. return S_OK;
  678. }
  679. HRESULT GetVolumeSpace(
  680. IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
  681. IN LPCTSTR i_pszVolumeDisplayName,
  682. OUT ULONGLONG* o_pllVolumeTotalSpace, // = NULL
  683. OUT ULONGLONG* o_pllVolumeFreeSpace // = NULL
  684. )
  685. {
  686. if (!piDiffSnapMgmt ||
  687. !i_pszVolumeDisplayName || !*i_pszVolumeDisplayName ||
  688. !o_pllVolumeTotalSpace && !o_pllVolumeFreeSpace)
  689. return E_INVALIDARG;
  690. CComPtr<IVssEnumMgmtObject> spiEnum;
  691. HRESULT hr = piDiffSnapMgmt->QueryVolumesSupportedForDiffAreas((PTSTR)i_pszVolumeDisplayName, &spiEnum);
  692. if (FAILED(hr))
  693. return hr;
  694. BOOL bFound = FALSE;
  695. VSS_MGMT_OBJECT_PROP Prop;
  696. VSS_DIFF_VOLUME_PROP *pDiffVolProp = &(Prop.Obj.DiffVol);
  697. ULONG ulFetched = 0;
  698. while (!bFound && SUCCEEDED(spiEnum->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
  699. {
  700. if (VSS_MGMT_OBJECT_DIFF_VOLUME != Prop.Type)
  701. return E_FAIL;
  702. if (!lstrcmpi(i_pszVolumeDisplayName, pDiffVolProp->m_pwszVolumeDisplayName))
  703. {
  704. bFound = TRUE;
  705. if (o_pllVolumeTotalSpace)
  706. *o_pllVolumeTotalSpace = pDiffVolProp->m_llVolumeTotalSpace;
  707. if (o_pllVolumeFreeSpace)
  708. *o_pllVolumeFreeSpace = pDiffVolProp->m_llVolumeFreeSpace;
  709. }
  710. CoTaskMemFree(pDiffVolProp->m_pwszVolumeName);
  711. CoTaskMemFree(pDiffVolProp->m_pwszVolumeDisplayName);
  712. }
  713. return (bFound ? S_OK : S_FALSE);
  714. }
  715. HRESULT GetDiffAreaInfo(
  716. IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
  717. IN VSSUI_VOLUME_LIST* pVolumeList,
  718. IN LPCTSTR pszVolumeName,
  719. OUT VSSUI_DIFFAREA* pDiffArea
  720. )
  721. {
  722. if (!piDiffSnapMgmt ||
  723. !pVolumeList ||
  724. !pszVolumeName || !*pszVolumeName ||
  725. !pDiffArea)
  726. return E_INVALIDARG;
  727. ZeroMemory(pDiffArea, sizeof(VSSUI_DIFFAREA));
  728. CComPtr<IVssEnumMgmtObject> spiEnumMgmtDiffArea;
  729. HRESULT hr = piDiffSnapMgmt->QueryDiffAreasForVolume(
  730. (PTSTR)pszVolumeName,
  731. &spiEnumMgmtDiffArea);
  732. if (S_OK == hr)
  733. {
  734. VSS_MGMT_OBJECT_PROP Prop;
  735. VSS_DIFF_AREA_PROP *pDiffAreaProp = &(Prop.Obj.DiffArea);
  736. ULONG ulDiffFetched = 0;
  737. hr = spiEnumMgmtDiffArea->Next(1, &Prop, &ulDiffFetched);
  738. if (SUCCEEDED(hr) && ulDiffFetched > 0)
  739. {
  740. if (VSS_MGMT_OBJECT_DIFF_AREA != Prop.Type || 1 != ulDiffFetched)
  741. return E_FAIL;
  742. PTSTR pszVolumeDisplayName = GetDisplayName(pVolumeList, pDiffAreaProp->m_pwszVolumeName);
  743. PTSTR pszDiffVolumeDisplayName = GetDisplayName(pVolumeList, pDiffAreaProp->m_pwszDiffAreaVolumeName);
  744. if (pszVolumeDisplayName && pszDiffVolumeDisplayName)
  745. {
  746. lstrcpyn(pDiffArea->pszVolumeDisplayName, pszVolumeDisplayName, MAX_PATH);
  747. lstrcpyn(pDiffArea->pszDiffVolumeDisplayName, pszDiffVolumeDisplayName, MAX_PATH);
  748. pDiffArea->llMaximumDiffSpace = pDiffAreaProp->m_llMaximumDiffSpace;
  749. pDiffArea->llUsedDiffSpace = pDiffAreaProp->m_llAllocatedDiffSpace;
  750. } else
  751. {
  752. hr = S_FALSE; // indicate something inconsistent happened (e.g., DiffVol formated to be FAT), we disgard the result
  753. }
  754. CoTaskMemFree(pDiffAreaProp->m_pwszVolumeName);
  755. CoTaskMemFree(pDiffAreaProp->m_pwszDiffAreaVolumeName);
  756. }
  757. }
  758. return hr;
  759. }
  760. PTSTR GetDisplayName(VSSUI_VOLUME_LIST *pVolumeList, LPCTSTR pszVolumeName)
  761. {
  762. if (!pVolumeList || !pszVolumeName || !*pszVolumeName)
  763. return NULL;
  764. for (VSSUI_VOLUME_LIST::iterator i = pVolumeList->begin(); i != pVolumeList->end(); i++)
  765. {
  766. if (!lstrcmpi(pszVolumeName, (*i)->pszVolumeName))
  767. return (*i)->pszDisplayName;
  768. }
  769. return NULL;
  770. }
  771. PTSTR GetVolumeName(VSSUI_VOLUME_LIST *pVolumeList, LPCTSTR pszDisplayName)
  772. {
  773. if (!pVolumeList || !pszDisplayName || !*pszDisplayName)
  774. return NULL;
  775. for (VSSUI_VOLUME_LIST::iterator i = pVolumeList->begin(); i != pVolumeList->end(); i++)
  776. {
  777. if (!lstrcmpi(pszDisplayName, (*i)->pszDisplayName))
  778. return (*i)->pszVolumeName;
  779. }
  780. return NULL;
  781. }
  782. void FreeVolumeList(VSSUI_VOLUME_LIST *pList)
  783. {
  784. if (!pList || pList->empty())
  785. return;
  786. for (VSSUI_VOLUME_LIST::iterator i = pList->begin(); i != pList->end(); i++)
  787. free(*i);
  788. pList->clear();
  789. }
  790. void FreeSnapshotList(VSSUI_SNAPSHOT_LIST *pList)
  791. {
  792. if (!pList || pList->empty())
  793. return;
  794. for (VSSUI_SNAPSHOT_LIST::iterator i = pList->begin(); i != pList->end(); i++)
  795. free(*i);
  796. pList->clear();
  797. }
  798. void FreeDiffAreaList(VSSUI_DIFFAREA_LIST *pList)
  799. {
  800. if (!pList || pList->empty())
  801. return;
  802. for (VSSUI_DIFFAREA_LIST::iterator i = pList->begin(); i != pList->end(); i++)
  803. free(*i);
  804. pList->clear();
  805. }
  806. HRESULT GetSystem32Directory(
  807. IN LPCTSTR i_pszComputer,
  808. OUT PTSTR o_pszSystem32Directory,
  809. IN OUT DWORD* o_pdwSize
  810. )
  811. {
  812. if (!o_pszSystem32Directory)
  813. return E_INVALIDARG;
  814. SHARE_INFO_2 *pInfo = NULL;
  815. DWORD dwRet = NetShareGetInfo((PTSTR)i_pszComputer, _T("ADMIN$"), 2, (LPBYTE *)&pInfo);
  816. if (NERR_Success == dwRet)
  817. {
  818. DWORD dwRequiredLength = lstrlen(pInfo->shi2_path) + lstrlen(_T("\\system32")) + 1;
  819. if (*o_pdwSize < dwRequiredLength)
  820. dwRet = ERROR_INSUFFICIENT_BUFFER;
  821. else
  822. {
  823. _tcscpy(o_pszSystem32Directory, pInfo->shi2_path);
  824. TCHAR *p = o_pszSystem32Directory + lstrlen(pInfo->shi2_path) - 1;
  825. if (_T('\\') != *p)
  826. p++;
  827. _tcscpy(p, _T("\\system32"));
  828. }
  829. *o_pdwSize = dwRequiredLength;
  830. }
  831. if (pInfo)
  832. NetApiBufferFree(pInfo);
  833. return HRESULT_FROM_WIN32(dwRet);
  834. }
  835. HRESULT GetErrorMessageFromModule(
  836. IN DWORD dwError,
  837. IN LPCTSTR lpszDll,
  838. OUT LPTSTR *ppBuffer
  839. )
  840. {
  841. if (0 == dwError || !lpszDll || !*lpszDll || !ppBuffer)
  842. return E_INVALIDARG;
  843. HRESULT hr = S_OK;
  844. HINSTANCE hMsgLib = LoadLibrary(lpszDll);
  845. if (!hMsgLib)
  846. hr = HRESULT_FROM_WIN32(GetLastError());
  847. else
  848. {
  849. DWORD dwRet = ::FormatMessage(
  850. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  851. hMsgLib, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  852. (LPTSTR)ppBuffer, 0, NULL);
  853. if (0 == dwRet)
  854. hr = HRESULT_FROM_WIN32(GetLastError());
  855. FreeLibrary(hMsgLib);
  856. }
  857. return hr;
  858. }
  859. HRESULT GetErrorMessage(
  860. IN DWORD i_dwError,
  861. OUT CString& cstrErrorMsg
  862. )
  863. {
  864. if (0 == i_dwError)
  865. return E_INVALIDARG;
  866. HRESULT hr = S_OK;
  867. LPTSTR lpBuffer = NULL;
  868. DWORD dwRet = ::FormatMessage(
  869. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  870. NULL, i_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  871. (LPTSTR)&lpBuffer, 0, NULL);
  872. if (0 == dwRet)
  873. {
  874. // if no message is found, GetLastError will return ERROR_MR_MID_NOT_FOUND
  875. hr = HRESULT_FROM_WIN32(GetLastError());
  876. if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr ||
  877. 0x80070000 == (i_dwError & 0xffff0000) ||
  878. 0 == (i_dwError & 0xffff0000) )
  879. {
  880. hr = GetErrorMessageFromModule((i_dwError & 0x0000ffff), _T("netmsg.dll"), &lpBuffer);
  881. }
  882. // could be a VSS error, try myself - vssui.dll
  883. if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr)
  884. {
  885. hr = GetErrorMessageFromModule(i_dwError, _T("vssui.dll"), &lpBuffer);
  886. }
  887. }
  888. if (SUCCEEDED(hr))
  889. {
  890. cstrErrorMsg = lpBuffer;
  891. LocalFree(lpBuffer);
  892. }
  893. else
  894. {
  895. // we failed to retrieve the error message from system/netmsg.dll/sfmmsg.dll,
  896. // report the error code directly to user
  897. hr = S_OK;
  898. cstrErrorMsg.Format(_T("0x%x"), i_dwError);
  899. }
  900. return S_OK;
  901. }
  902. /////////////////////////////////////////////////////////////////////
  903. // GetMsgHelper()
  904. //
  905. // This function will retrieve the error msg if dwErr is specified,
  906. // load resource string if specified, and format the string with
  907. // the error msg and other optional arguments.
  908. //
  909. //
  910. HRESULT GetMsgHelper(
  911. OUT CString& strMsg,// OUT: the message
  912. DWORD dwErr, // IN: Error code from GetLastError()
  913. UINT wIdString, // IN: String ID
  914. va_list* parglist // IN: OPTIONAL arguments
  915. )
  916. {
  917. if (!dwErr && !wIdString)
  918. return E_INVALIDARG;
  919. //
  920. // retrieve error msg
  921. //
  922. CString strErrorMessage;
  923. if (dwErr != 0)
  924. GetErrorMessage(dwErr, strErrorMessage);
  925. //
  926. // load string resource, and format it with the error msg and
  927. // other optional arguments
  928. //
  929. if (wIdString == 0)
  930. {
  931. strMsg = strErrorMessage;
  932. } else
  933. {
  934. CString strFormat;
  935. strFormat.LoadString(wIdString);
  936. CString strFormatedMsg;
  937. strFormatedMsg.FormatV(strFormat, *parglist);
  938. if (dwErr == 0)
  939. strMsg = strFormatedMsg;
  940. else
  941. strMsg.FormatMessage((((HRESULT)dwErr < 0) ? IDS_ERROR_HR : IDS_ERROR),
  942. strFormatedMsg,
  943. dwErr,
  944. strErrorMessage);
  945. }
  946. return S_OK;
  947. } // GetMsgHelper()
  948. /////////////////////////////////////////////////////////////////////
  949. // GetMsg()
  950. //
  951. // This function will call GetMsgHelp to retrieve the error msg
  952. // if dwErr is specified, load resource string if specified, and
  953. // format the string with the error msg and other optional arguments.
  954. //
  955. //
  956. void GetMsg(
  957. OUT CString& strMsg,// OUT: the message
  958. DWORD dwErr, // IN: Error code from GetLastError()
  959. UINT wIdString, // IN: String resource Id
  960. ...) // IN: Optional arguments
  961. {
  962. va_list arglist;
  963. va_start(arglist, wIdString);
  964. HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
  965. if (FAILED(hr))
  966. strMsg.Format(_T("0x%x"), hr);
  967. va_end(arglist);
  968. } // GetMsg()
  969. /////////////////////////////////////////////////////////////////////
  970. // DoErrMsgBox()
  971. //
  972. // Display a message box for the error code. This function will
  973. // load the error message from the system resource and append
  974. // the optional string (if any)
  975. //
  976. // EXAMPLE
  977. // DoErrMsgBox(GetActiveWindow(), MB_OK, GetLastError(), IDS_s_FILE_READ_ERROR, L"foo.txt");
  978. //
  979. INT DoErrMsgBox(
  980. HWND hwndParent, // IN: Parent of the dialog box
  981. UINT uType, // IN: style of message box
  982. DWORD dwErr, // IN: Error code from GetLastError()
  983. UINT wIdString, // IN: String resource Id
  984. ...) // IN: Optional arguments
  985. {
  986. //
  987. // get string and the error msg
  988. //
  989. va_list arglist;
  990. va_start(arglist, wIdString);
  991. CString strMsg;
  992. HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
  993. if (FAILED(hr))
  994. strMsg.Format(_T("0x%x"), hr);
  995. va_end(arglist);
  996. //
  997. // Load the caption
  998. //
  999. CString strCaption;
  1000. strCaption.LoadString(IDS_PROJNAME);
  1001. //
  1002. // Display the message.
  1003. //
  1004. return ::MessageBox(hwndParent, strMsg, strCaption, uType);
  1005. }
  1006. BOOL IsPostW2KServer(LPCTSTR pszComputer)
  1007. {
  1008. BOOL bPostW2KServer = FALSE;
  1009. SERVER_INFO_102* pServerInfo = NULL;
  1010. DWORD dwRet = NetServerGetInfo((LPTSTR)pszComputer, 102, (LPBYTE*)&pServerInfo);
  1011. if (NERR_Success == dwRet)
  1012. {
  1013. bPostW2KServer = (pServerInfo->sv102_type & SV_TYPE_NT) && // NT/W2K/XP or after
  1014. (pServerInfo->sv102_version_major & MAJOR_VERSION_MASK) >= 5 &&
  1015. pServerInfo->sv102_version_minor > 0 && // XP or after
  1016. ((pServerInfo->sv102_type & SV_TYPE_DOMAIN_CTRL) ||
  1017. (pServerInfo->sv102_type & SV_TYPE_DOMAIN_BAKCTRL) ||
  1018. (pServerInfo->sv102_type & SV_TYPE_SERVER_NT)); // server
  1019. NetApiBufferFree(pServerInfo);
  1020. }
  1021. return bPostW2KServer;
  1022. }
  1023. HRESULT GetVolumesSupportedForDiffArea(
  1024. IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
  1025. IN LPCTSTR pszVolumeDisplayName,
  1026. IN OUT VSSUI_VOLUME_LIST* pVolumeList
  1027. )
  1028. {
  1029. if (!piDiffSnapMgmt || !pszVolumeDisplayName || !*pszVolumeDisplayName)
  1030. return E_INVALIDARG;
  1031. if (!pVolumeList || (!pVolumeList->empty()))
  1032. // Expect an empty list...
  1033. return E_INVALIDARG;
  1034. CComPtr<IVssEnumMgmtObject> spiEnumMgmt;
  1035. HRESULT hr = piDiffSnapMgmt->QueryVolumesSupportedForDiffAreas((PTSTR)pszVolumeDisplayName, &spiEnumMgmt);
  1036. if (FAILED(hr))
  1037. return hr;
  1038. VSS_MGMT_OBJECT_PROP Prop;
  1039. VSS_DIFF_VOLUME_PROP *pDiffVolProp = &(Prop.Obj.DiffVol);
  1040. ULONG ulFetched = 0;
  1041. while (SUCCEEDED(hr = spiEnumMgmt->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
  1042. {
  1043. if (VSS_MGMT_OBJECT_DIFF_VOLUME != Prop.Type)
  1044. return E_FAIL;
  1045. VSSUI_VOLUME *pVolInfo = (VSSUI_VOLUME *)calloc(1, sizeof(VSSUI_VOLUME));
  1046. if (pVolInfo)
  1047. {
  1048. lstrcpyn(pVolInfo->pszVolumeName, pDiffVolProp->m_pwszVolumeName, MAX_PATH);
  1049. lstrcpyn(pVolInfo->pszDisplayName, pDiffVolProp->m_pwszVolumeDisplayName, MAX_PATH);
  1050. pVolumeList->push_back(pVolInfo);
  1051. } else
  1052. {
  1053. FreeVolumeList(pVolumeList);
  1054. hr = E_OUTOFMEMORY;
  1055. }
  1056. CoTaskMemFree(pDiffVolProp->m_pwszVolumeName);
  1057. CoTaskMemFree(pDiffVolProp->m_pwszVolumeDisplayName);
  1058. if (FAILED(hr))
  1059. break;
  1060. }
  1061. if (hr == S_FALSE)
  1062. // End of loop detected
  1063. hr = S_OK;
  1064. return hr;
  1065. }