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
1254 lines
39 KiB
// Utils.cpp : helper functions
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "utils.h"
|
|
#include <lm.h>
|
|
|
|
#include <clusapi.h>
|
|
#include <msclus.h>
|
|
#include <vs_clus.hxx> // vss\server\inc
|
|
|
|
ULONGLONG g_llKB = 1024;
|
|
ULONGLONG g_llMB = 1024 * 1024;
|
|
|
|
HRESULT
|
|
AddLVColumns(
|
|
IN const HWND hwndListBox,
|
|
IN const INT iStartingResourceID,
|
|
IN const UINT uiColumns
|
|
)
|
|
{
|
|
//
|
|
// calculate the listview column width
|
|
//
|
|
RECT rect;
|
|
ZeroMemory(&rect, sizeof(rect));
|
|
::GetWindowRect(hwndListBox, &rect);
|
|
int nControlWidth = rect.right - rect.left;
|
|
int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
|
|
int nBorderWidth = GetSystemMetrics(SM_CXBORDER);
|
|
int nControlNetWidth = nControlWidth - 4 * nBorderWidth;
|
|
int nWidth = nControlNetWidth / uiColumns;
|
|
|
|
LVCOLUMN lvColumn;
|
|
ZeroMemory(&lvColumn, sizeof(lvColumn));
|
|
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
|
|
|
|
lvColumn.fmt = LVCFMT_LEFT;
|
|
lvColumn.cx = nWidth;
|
|
|
|
for (UINT i = 0; i < uiColumns; i++)
|
|
{
|
|
CString strColumnText;
|
|
strColumnText.LoadString(iStartingResourceID + i);
|
|
|
|
lvColumn.pszText = (LPTSTR)(LPCTSTR)strColumnText;
|
|
lvColumn.iSubItem = i;
|
|
|
|
ListView_InsertColumn(hwndListBox, i, &lvColumn);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LPARAM GetListViewItemData(
|
|
IN HWND hwndList,
|
|
IN int index
|
|
)
|
|
{
|
|
if (-1 == index)
|
|
return NULL;
|
|
|
|
LVITEM lvItem;
|
|
ZeroMemory(&lvItem, sizeof(lvItem));
|
|
|
|
lvItem.mask = LVIF_PARAM;
|
|
lvItem.iItem = index;
|
|
if (ListView_GetItem(hwndList, &lvItem))
|
|
return lvItem.lParam;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int MyCompareStringN(
|
|
IN LPCTSTR lpString1,
|
|
IN LPCTSTR lpString2,
|
|
IN UINT cchCount,
|
|
IN DWORD dwCmpFlags
|
|
)
|
|
{
|
|
UINT nLen1 = (lpString1 ? lstrlen(lpString1) : 0);
|
|
UINT nLen2 = (lpString2 ? lstrlen(lpString2) : 0);
|
|
int nRet = CompareString(
|
|
LOCALE_USER_DEFAULT,
|
|
dwCmpFlags,
|
|
lpString1,
|
|
min(cchCount, nLen1),
|
|
lpString2,
|
|
min(cchCount, nLen2)
|
|
);
|
|
|
|
return (nRet - CSTR_EQUAL);
|
|
}
|
|
|
|
int mylstrncmpi(
|
|
IN LPCTSTR lpString1,
|
|
IN LPCTSTR lpString2,
|
|
IN UINT cchCount
|
|
)
|
|
{
|
|
return MyCompareStringN(lpString1, lpString2, cchCount, NORM_IGNORECASE);
|
|
}
|
|
|
|
HRESULT GetArgV(
|
|
IN LPCTSTR i_pszParameters,
|
|
OUT UINT *o_pargc,
|
|
OUT void ***o_pargv
|
|
)
|
|
{
|
|
if (!o_pargc || !o_pargv)
|
|
return E_INVALIDARG;
|
|
|
|
*o_pargc = 0;
|
|
*o_pargv = NULL;
|
|
|
|
TCHAR *p = (TCHAR *)i_pszParameters;
|
|
while (*p && _istspace(*p)) // skip leading spaces
|
|
p++;
|
|
if (!*p)
|
|
return S_FALSE; // i_pszParameters contains no parameters
|
|
|
|
UINT nChars = lstrlen(p) + 1;
|
|
BYTE *pbData = (BYTE *)calloc((nChars / 2) * sizeof(PTSTR *) + nChars * sizeof(TCHAR), sizeof(BYTE));
|
|
if (!pbData)
|
|
return E_OUTOFMEMORY;
|
|
|
|
PTSTR *pargv = (PTSTR *)pbData;
|
|
PTSTR t = (PTSTR)(pbData + (nChars / 2) * sizeof(PTSTR *));
|
|
_tcscpy(t, p);
|
|
|
|
UINT argc = 0;
|
|
do {
|
|
*pargv++ = t;
|
|
argc++;
|
|
|
|
while (*t && !_istspace(*t)) // move to the end of the token
|
|
t++;
|
|
if (!*t)
|
|
break;
|
|
|
|
*t++ = _T('\0'); // end the token with '\0'
|
|
|
|
while (*t && _istspace(*t)) // skip leading spaces of the next token
|
|
t++;
|
|
|
|
} while (*t);
|
|
|
|
*o_pargv = (void **)pbData;
|
|
*o_pargc = argc;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#define TIMEWARP_CMD_APPNAME _T("vssadmin")
|
|
#define TIMEWARP_CMD_APPEXENAME _T("vssadmin.exe")
|
|
#define TIMEWARP_TASK_ACTION_MAJOR _T("Create")
|
|
#define TIMEWARP_TASK_ACTION_MINOR _T("Shadow")
|
|
#define TIMEWARP_TASK_VOLUME _T("/For=")
|
|
#define TIMEWARP_TASK_PARAMETERS _T("Create Shadow /AutoRetry=5 /For=")
|
|
|
|
BOOL IsTimewarpTask(
|
|
IN LPCTSTR i_pszAppName,
|
|
IN LPCTSTR i_pszParameters,
|
|
IN LPCTSTR i_pszVolume
|
|
)
|
|
{
|
|
if (!i_pszAppName || !*i_pszAppName ||
|
|
!i_pszParameters || !*i_pszParameters ||
|
|
!i_pszVolume || !*i_pszVolume)
|
|
return FALSE;
|
|
|
|
//
|
|
// check the application name
|
|
//
|
|
TCHAR *p = (PTSTR)(i_pszAppName + lstrlen(i_pszAppName) - 1);
|
|
while (p > i_pszAppName && *p != _T('\\'))
|
|
p--;
|
|
|
|
if (*p == _T('\\'))
|
|
p++;
|
|
|
|
if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, p, -1, TIMEWARP_CMD_APPEXENAME, -1) &&
|
|
CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, p, -1, TIMEWARP_CMD_APPNAME, -1))
|
|
return FALSE; // application name doesn't match
|
|
|
|
//
|
|
// check the parameters
|
|
//
|
|
BOOL bVolume = FALSE;
|
|
|
|
UINT argc = 0;
|
|
void **argv = NULL;
|
|
if (SUCCEEDED(GetArgV(i_pszParameters, &argc, &argv)))
|
|
{
|
|
if (argc >= 4 &&
|
|
CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, (PTSTR)(argv[0]), -1, TIMEWARP_TASK_ACTION_MAJOR, -1) &&
|
|
CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, (PTSTR)(argv[1]), -1, TIMEWARP_TASK_ACTION_MINOR, -1))
|
|
{
|
|
UINT nVolume = lstrlen(TIMEWARP_TASK_VOLUME);
|
|
for (UINT i = 2; i < argc; i++)
|
|
{
|
|
if (!bVolume &&
|
|
!mylstrncmpi((PTSTR)(argv[i]), TIMEWARP_TASK_VOLUME, nVolume) &&
|
|
!lstrcmpi((PTSTR)(argv[i]) + nVolume, i_pszVolume))
|
|
{
|
|
bVolume = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (argv)
|
|
free(argv);
|
|
}
|
|
|
|
return bVolume;
|
|
}
|
|
|
|
#define NUM_OF_TASKS 5
|
|
|
|
//
|
|
// Find the first enabled Timewarp task, skip all disabled tasks.
|
|
//
|
|
HRESULT FindScheduledTimewarpTask(
|
|
IN ITaskScheduler* i_piTS,
|
|
IN LPCTSTR i_pszVolumeName,
|
|
OUT ITask** o_ppiTask,
|
|
OUT PTSTR* o_ppszTaskName /* = NULL */
|
|
)
|
|
{
|
|
if (!i_piTS ||
|
|
!i_pszVolumeName || !*i_pszVolumeName ||
|
|
!o_ppiTask)
|
|
return E_INVALIDARG;
|
|
|
|
*o_ppiTask = NULL;
|
|
if (o_ppszTaskName)
|
|
*o_ppszTaskName = NULL;
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Call ITaskScheduler::Enum to get an enumeration object.
|
|
/////////////////////////////////////////////////////////////////
|
|
CComPtr<IEnumWorkItems> spiEnum;
|
|
HRESULT hr = i_piTS->Enum(&spiEnum);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Call IEnumWorkItems::Next to retrieve tasks. Note that
|
|
// this example tries to retrieve five tasks for each call.
|
|
/////////////////////////////////////////////////////////////////
|
|
BOOL bTimewarpTask = FALSE;
|
|
BOOL bEnabled = FALSE;
|
|
SYSTEMTIME stNextRun = {0};
|
|
LPTSTR *ppszNames = NULL;
|
|
DWORD dwFetchedTasks = 0;
|
|
while (!bTimewarpTask && SUCCEEDED(spiEnum->Next(NUM_OF_TASKS, &ppszNames, &dwFetchedTasks)) && (dwFetchedTasks != 0))
|
|
{
|
|
///////////////////////////////////////////////////////////////
|
|
// Process each task.
|
|
//////////////////////////////////////////////////////////////
|
|
while (!bTimewarpTask && dwFetchedTasks)
|
|
{
|
|
LPTSTR pszTaskName = ppszNames[--dwFetchedTasks];
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Call ITaskScheduler::Activate to get the Task object.
|
|
///////////////////////////////////////////////////////////////////
|
|
CComPtr<ITask> spiTask;
|
|
hr = i_piTS->Activate(pszTaskName,
|
|
IID_ITask,
|
|
(IUnknown**) &spiTask);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszApplicationName = NULL;
|
|
hr = spiTask->GetApplicationName(&pszApplicationName);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszParameters = NULL;
|
|
hr = spiTask->GetParameters(&pszParameters);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (IsTimewarpTask(pszApplicationName, pszParameters, i_pszVolumeName))
|
|
{
|
|
bEnabled = FALSE;
|
|
GetScheduledTimewarpTaskStatus(spiTask, &bEnabled, &stNextRun);
|
|
|
|
if (bEnabled)
|
|
bTimewarpTask = TRUE;
|
|
}
|
|
CoTaskMemFree(pszParameters);
|
|
}
|
|
|
|
CoTaskMemFree(pszApplicationName);
|
|
}
|
|
|
|
if (bTimewarpTask)
|
|
{
|
|
if (o_ppszTaskName)
|
|
{
|
|
// omit the ending .job
|
|
int nLen = lstrlen(pszTaskName);
|
|
BOOL bEndingFound = (nLen > 4 && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pszTaskName + nLen - 4, -1, _T(".job"), -1));
|
|
if (bEndingFound)
|
|
*(pszTaskName + nLen - 4) = _T('\0');
|
|
|
|
*o_ppszTaskName = _tcsdup(pszTaskName);
|
|
if (bEndingFound)
|
|
*(pszTaskName + nLen - 4) = _T('.');
|
|
|
|
if (!*o_ppszTaskName)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*o_ppiTask = (ITask *)spiTask;
|
|
spiTask.Detach();
|
|
}
|
|
}
|
|
}
|
|
|
|
CoTaskMemFree(ppszNames[dwFetchedTasks]);
|
|
}
|
|
CoTaskMemFree(ppszNames);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
return (bTimewarpTask ? S_OK : S_FALSE);
|
|
}
|
|
|
|
HRESULT GetScheduledTimewarpTaskStatus(
|
|
IN ITask* i_piTask,
|
|
OUT BOOL* o_pbEnabled,
|
|
OUT SYSTEMTIME* o_pstNextRunTime
|
|
)
|
|
{
|
|
if (!i_piTask ||
|
|
!o_pbEnabled || !o_pstNextRunTime)
|
|
return E_INVALIDARG;
|
|
|
|
*o_pbEnabled = FALSE;
|
|
ZeroMemory(o_pstNextRunTime, sizeof(SYSTEMTIME));
|
|
|
|
HRESULT hrStatus = S_OK;
|
|
HRESULT hr = i_piTask->GetStatus(&hrStatus);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
switch (hrStatus)
|
|
{
|
|
case SCHED_S_TASK_HAS_NOT_RUN:
|
|
case SCHED_S_TASK_READY:
|
|
case SCHED_S_TASK_RUNNING:
|
|
{
|
|
hr = i_piTask->GetNextRunTime(o_pstNextRunTime);
|
|
if (S_OK == hr)
|
|
*o_pbEnabled = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CreateDefaultEnableSchedule(
|
|
IN ITaskScheduler* i_piTS,
|
|
IN LPCTSTR i_pszComputer,
|
|
IN LPCTSTR i_pszVolumeDisplayName,
|
|
IN LPCTSTR i_pszVolumeName,
|
|
OUT ITask** o_ppiTask,
|
|
OUT PTSTR* o_ppszTaskName /* = NULL */
|
|
)
|
|
{
|
|
if (!i_piTS ||
|
|
!i_pszVolumeDisplayName || !*i_pszVolumeDisplayName ||
|
|
!i_pszVolumeName || !*i_pszVolumeName ||
|
|
!o_ppiTask)
|
|
return E_INVALIDARG;
|
|
|
|
*o_ppiTask = NULL;
|
|
if (o_ppszTaskName)
|
|
*o_ppszTaskName = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
//
|
|
// i_pszVolumeName is in the form of \\?\Volume{xxx.....xxx}\
|
|
// The task name will be ShadowCopy concatenating with Volume{xxx.....xxx}
|
|
//
|
|
TCHAR szTaskName[MAX_PATH] = _T("ShadowCopy");
|
|
_tcscat(szTaskName, i_pszVolumeName + 4); // skip the beginning "\\?\"
|
|
TCHAR *p = szTaskName + lstrlen(szTaskName) - 1;
|
|
if (*p == _T('\\'))
|
|
*p = _T('\0'); // remove the ending whack
|
|
|
|
if (o_ppszTaskName)
|
|
{
|
|
*o_ppszTaskName = _tcsdup(szTaskName);
|
|
if (!*o_ppszTaskName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// delete any task that has the same name
|
|
//
|
|
(void)i_piTS->Delete(szTaskName);
|
|
|
|
TCHAR szSystem32Directory[MAX_PATH];
|
|
DWORD dwSize = sizeof(szSystem32Directory) / sizeof(TCHAR);
|
|
hr = GetSystem32Directory(i_pszComputer, szSystem32Directory, &dwSize);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
TCHAR szApplicationName[MAX_PATH * 2];
|
|
lstrcpyn(szApplicationName, szSystem32Directory, MAX_PATH);
|
|
_tcscat(szApplicationName, _T("\\vssadmin.exe"));
|
|
|
|
TCHAR szParameters[MAX_PATH] = TIMEWARP_TASK_PARAMETERS;
|
|
_tcscat(szParameters, i_pszVolumeName);
|
|
|
|
SYSTEMTIME st = {0};
|
|
GetSystemTime(&st);
|
|
|
|
WORD wStartHours[] = {7, 12};
|
|
TASK_TRIGGER Triggers[2];
|
|
for (DWORD i = 0; i < sizeof(wStartHours)/sizeof(wStartHours[0]); i++)
|
|
{
|
|
//////////////////////////////////////////////////////
|
|
// Define TASK_TRIGGER structure. Note that wBeginDay,
|
|
// wBeginMonth, and wBeginYear must be set to a valid
|
|
// day, month, and year respectively.
|
|
//////////////////////////////////////////////////////
|
|
ZeroMemory(Triggers + i, sizeof(TASK_TRIGGER));
|
|
Triggers[i].wBeginDay =st.wDay;
|
|
Triggers[i].wBeginMonth =st.wMonth;
|
|
Triggers[i].wBeginYear =st.wYear;
|
|
Triggers[i].cbTriggerSize = sizeof(TASK_TRIGGER);
|
|
Triggers[i].wStartHour = wStartHours[i];
|
|
Triggers[i].TriggerType = TASK_TIME_TRIGGER_WEEKLY;
|
|
Triggers[i].Type.Weekly.WeeksInterval = 1;
|
|
Triggers[i].Type.Weekly.rgfDaysOfTheWeek = TASK_MONDAY | TASK_TUESDAY | TASK_WEDNESDAY | TASK_THURSDAY | TASK_FRIDAY;
|
|
}
|
|
|
|
try
|
|
{
|
|
CVssClusterAPI cluster;
|
|
|
|
bool bRet = cluster.Initialize(i_pszComputer);
|
|
if (!bRet || !cluster.IsVolumeBelongingToPhysicalDiskResource(i_pszVolumeName))
|
|
{
|
|
CComPtr<ITask> spiTask;
|
|
hr = i_piTS->NewWorkItem(szTaskName, // Name of task
|
|
CLSID_CTask, // Class identifier
|
|
IID_ITask, // Interface identifier
|
|
(IUnknown**)&spiTask); // Address of task interface
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
hr = spiTask->SetWorkingDirectory(szSystem32Directory);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
hr = spiTask->SetApplicationName(szApplicationName);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
hr = spiTask->SetParameters(szParameters);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
// run as local system account
|
|
hr = spiTask->SetAccountInformation(_T(""), NULL);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
for (i = 0; i < sizeof(wStartHours)/sizeof(wStartHours[0]); i++)
|
|
{
|
|
///////////////////////////////////////////////////////////////////
|
|
// Call ITask::CreateTrigger to create new trigger.
|
|
///////////////////////////////////////////////////////////////////
|
|
CComPtr<ITaskTrigger> spiTaskTrigger;
|
|
WORD piNewTrigger;
|
|
hr = spiTask->CreateTrigger(&piNewTrigger, &spiTaskTrigger);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Call ITaskTrigger::SetTrigger to set trigger criteria.
|
|
///////////////////////////////////////////////////////////////////
|
|
hr = spiTaskTrigger->SetTrigger(Triggers + i);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Call IPersistFile::Save to save trigger to disk.
|
|
///////////////////////////////////////////////////////////////////
|
|
CComPtr<IPersistFile> spiPersistFile;
|
|
hr = spiTask->QueryInterface(IID_IPersistFile, (void **)&spiPersistFile);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
hr = spiPersistFile->Save(NULL, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*o_ppiTask = (ITask *)spiTask;
|
|
spiTask.Detach();
|
|
}
|
|
} else // cluster
|
|
{
|
|
bRet = cluster.CreateTaskSchedulerResource(
|
|
szTaskName,
|
|
szApplicationName,
|
|
szParameters,
|
|
2,
|
|
Triggers,
|
|
i_pszVolumeName
|
|
);
|
|
if (bRet)
|
|
{
|
|
hr = FindScheduledTimewarpTask(i_piTS, i_pszVolumeName, o_ppiTask);
|
|
if (S_FALSE == hr)
|
|
hr = E_FAIL; // we failed to find a valid enabled task, something is wrong
|
|
} else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
} catch (HRESULT hrClus)
|
|
{
|
|
hr = hrClus;
|
|
}
|
|
} while(0);
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (o_ppszTaskName && *o_ppszTaskName)
|
|
{
|
|
free(*o_ppszTaskName);
|
|
*o_ppszTaskName = NULL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DeleteOneScheduledTimewarpTasks(
|
|
IN ITaskScheduler* i_piTS,
|
|
IN LPCTSTR i_pszComputer,
|
|
IN LPCTSTR i_pszTaskName
|
|
)
|
|
{
|
|
if (!i_piTS || !i_pszTaskName || !*i_pszTaskName)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
try
|
|
{
|
|
CVssClusterAPI cluster;
|
|
bool bRet = cluster.Initialize(i_pszComputer);
|
|
if (bRet)
|
|
{
|
|
// omit the ending .job
|
|
PTSTR pszTaskName = (PTSTR)i_pszTaskName;
|
|
int nLen = lstrlen(pszTaskName);
|
|
BOOL bEndingFound = (nLen > 4 && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pszTaskName + nLen - 4, -1, _T(".job"), -1));
|
|
if (bEndingFound)
|
|
*(pszTaskName + nLen - 4) = _T('\0');
|
|
|
|
bRet = cluster.DeleteTaskSchedulerResource(pszTaskName);
|
|
|
|
if (bEndingFound)
|
|
*(pszTaskName + nLen - 4) = _T('.');
|
|
|
|
if (!bRet)
|
|
{
|
|
hr = i_piTS->Delete(i_pszTaskName);
|
|
}
|
|
} else
|
|
{
|
|
hr = i_piTS->Delete(i_pszTaskName);
|
|
}
|
|
} catch (HRESULT hrIgnore)
|
|
{
|
|
hr = i_piTS->Delete(i_pszTaskName);;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DeleteAllScheduledTimewarpTasks(
|
|
IN ITaskScheduler* i_piTS,
|
|
IN LPCTSTR i_pszComputer,
|
|
IN LPCTSTR i_pszVolumeName,
|
|
IN BOOL i_bDeleteDisabledOnesOnly
|
|
)
|
|
{
|
|
if (!i_piTS ||
|
|
!i_pszVolumeName || !*i_pszVolumeName)
|
|
return E_INVALIDARG;
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Call ITaskScheduler::Enum to get an enumeration object.
|
|
/////////////////////////////////////////////////////////////////
|
|
CComPtr<IEnumWorkItems> spiEnum;
|
|
HRESULT hr = i_piTS->Enum(&spiEnum);
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Call IEnumWorkItems::Next to retrieve tasks. Note that
|
|
// this example tries to retrieve five tasks for each call.
|
|
/////////////////////////////////////////////////////////////////
|
|
BOOL bEnabled = FALSE;
|
|
SYSTEMTIME stNextRun = {0};
|
|
LPTSTR *ppszNames = NULL;
|
|
DWORD dwFetchedTasks = 0;
|
|
while (SUCCEEDED(hr) && SUCCEEDED(spiEnum->Next(NUM_OF_TASKS, &ppszNames, &dwFetchedTasks)) && (dwFetchedTasks != 0))
|
|
{
|
|
///////////////////////////////////////////////////////////////
|
|
// Process each task.
|
|
//////////////////////////////////////////////////////////////
|
|
while (SUCCEEDED(hr) && dwFetchedTasks)
|
|
{
|
|
LPTSTR pszTaskName = ppszNames[--dwFetchedTasks];
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Call ITaskScheduler::Activate to get the Task object.
|
|
///////////////////////////////////////////////////////////////////
|
|
CComPtr<ITask> spiTask;
|
|
hr = i_piTS->Activate(pszTaskName,
|
|
IID_ITask,
|
|
(IUnknown**) &spiTask);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszApplicationName = NULL;
|
|
hr = spiTask->GetApplicationName(&pszApplicationName);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszParameters = NULL;
|
|
hr = spiTask->GetParameters(&pszParameters);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (IsTimewarpTask(pszApplicationName, pszParameters, i_pszVolumeName))
|
|
{
|
|
if (i_bDeleteDisabledOnesOnly)
|
|
{
|
|
bEnabled = FALSE;
|
|
GetScheduledTimewarpTaskStatus(spiTask, &bEnabled, &stNextRun);
|
|
if (!bEnabled)
|
|
hr = DeleteOneScheduledTimewarpTasks(i_piTS, i_pszComputer, pszTaskName);
|
|
//hr = i_piTS->Delete(pszTaskName);
|
|
} else
|
|
{
|
|
hr = DeleteOneScheduledTimewarpTasks(i_piTS, i_pszComputer, pszTaskName);
|
|
//hr = i_piTS->Delete(pszTaskName);
|
|
}
|
|
}
|
|
|
|
CoTaskMemFree(pszParameters);
|
|
}
|
|
|
|
CoTaskMemFree(pszApplicationName);
|
|
}
|
|
}
|
|
|
|
CoTaskMemFree(ppszNames[dwFetchedTasks]);
|
|
}
|
|
CoTaskMemFree(ppszNames);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT VssTimeToSystemTime(
|
|
IN VSS_TIMESTAMP* i_pVssTime,
|
|
OUT SYSTEMTIME* o_pSystemTime
|
|
)
|
|
{
|
|
if (!o_pSystemTime)
|
|
return E_INVALIDARG;
|
|
|
|
SYSTEMTIME stLocal = {0};
|
|
FILETIME ftLocal = {0};
|
|
|
|
if (!i_pVssTime)
|
|
{
|
|
SYSTEMTIME sysTime = {0};
|
|
FILETIME fileTime = {0};
|
|
|
|
// Get current time
|
|
::GetSystemTime(&sysTime);
|
|
|
|
// Convert system time to file time
|
|
::SystemTimeToFileTime(&sysTime, &fileTime);
|
|
|
|
// Compensate for local TZ
|
|
::FileTimeToLocalFileTime(&fileTime, &ftLocal);
|
|
} else
|
|
{
|
|
// Compensate for local TZ
|
|
::FileTimeToLocalFileTime((FILETIME *)i_pVssTime, &ftLocal);
|
|
}
|
|
|
|
// Finally convert it to system time
|
|
::FileTimeToSystemTime(&ftLocal, o_pSystemTime);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT SystemTimeToString(
|
|
IN SYSTEMTIME* i_pSystemTime,
|
|
OUT PTSTR o_pszText,
|
|
IN OUT DWORD* io_pdwSize
|
|
)
|
|
{
|
|
if (!i_pSystemTime || !o_pszText || !io_pdwSize)
|
|
return E_INVALIDARG;
|
|
|
|
// Convert to a date string
|
|
TCHAR pszDate[64];
|
|
::GetDateFormat(GetThreadLocale( ),
|
|
DATE_SHORTDATE,
|
|
i_pSystemTime,
|
|
NULL,
|
|
pszDate,
|
|
sizeof(pszDate) / sizeof(TCHAR));
|
|
|
|
// Convert to a time string
|
|
TCHAR pszTime[64];
|
|
::GetTimeFormat(GetThreadLocale( ),
|
|
TIME_NOSECONDS,
|
|
i_pSystemTime,
|
|
NULL,
|
|
pszTime,
|
|
sizeof( pszTime ) / sizeof(TCHAR));
|
|
|
|
CString strMsg;
|
|
strMsg.Format(IDS_DATE_TIME, pszDate, pszTime);
|
|
DWORD dwRequiredSize = strMsg.GetLength() + 1;
|
|
if (*io_pdwSize < dwRequiredSize)
|
|
{
|
|
*io_pdwSize = dwRequiredSize;
|
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
*io_pdwSize = dwRequiredSize;
|
|
_tcscpy(o_pszText, strMsg);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DiskSpaceToString(
|
|
IN ULONGLONG i_llDiskSpace,
|
|
OUT PTSTR o_pszText,
|
|
IN OUT DWORD* io_pdwSize
|
|
)
|
|
{
|
|
if (!o_pszText || !io_pdwSize)
|
|
return E_INVALIDARG;
|
|
|
|
CString strMsg;
|
|
if (i_llDiskSpace < g_llKB)
|
|
strMsg.Format(IDS_SPACE_LABEL_B, i_llDiskSpace);
|
|
else if (i_llDiskSpace < g_llMB)
|
|
strMsg.Format(IDS_SPACE_LABEL_KB, i_llDiskSpace / g_llKB);
|
|
else
|
|
strMsg.Format(IDS_SPACE_LABEL_MB, i_llDiskSpace / g_llMB);
|
|
|
|
DWORD dwRequiredSize = strMsg.GetLength() + 1;
|
|
if (*io_pdwSize < dwRequiredSize)
|
|
{
|
|
*io_pdwSize = dwRequiredSize;
|
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
*io_pdwSize = dwRequiredSize;
|
|
_tcscpy(o_pszText, strMsg);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT GetVolumeSpace(
|
|
IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
|
|
IN LPCTSTR i_pszVolumeDisplayName,
|
|
OUT ULONGLONG* o_pllVolumeTotalSpace, // = NULL
|
|
OUT ULONGLONG* o_pllVolumeFreeSpace // = NULL
|
|
)
|
|
{
|
|
if (!piDiffSnapMgmt ||
|
|
!i_pszVolumeDisplayName || !*i_pszVolumeDisplayName ||
|
|
!o_pllVolumeTotalSpace && !o_pllVolumeFreeSpace)
|
|
return E_INVALIDARG;
|
|
|
|
CComPtr<IVssEnumMgmtObject> spiEnum;
|
|
HRESULT hr = piDiffSnapMgmt->QueryVolumesSupportedForDiffAreas((PTSTR)i_pszVolumeDisplayName, &spiEnum);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
BOOL bFound = FALSE;
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_DIFF_VOLUME_PROP *pDiffVolProp = &(Prop.Obj.DiffVol);
|
|
ULONG ulFetched = 0;
|
|
while (!bFound && SUCCEEDED(spiEnum->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
|
|
{
|
|
if (VSS_MGMT_OBJECT_DIFF_VOLUME != Prop.Type)
|
|
return E_FAIL;
|
|
|
|
if (!lstrcmpi(i_pszVolumeDisplayName, pDiffVolProp->m_pwszVolumeDisplayName))
|
|
{
|
|
bFound = TRUE;
|
|
if (o_pllVolumeTotalSpace)
|
|
*o_pllVolumeTotalSpace = pDiffVolProp->m_llVolumeTotalSpace;
|
|
|
|
if (o_pllVolumeFreeSpace)
|
|
*o_pllVolumeFreeSpace = pDiffVolProp->m_llVolumeFreeSpace;
|
|
}
|
|
|
|
CoTaskMemFree(pDiffVolProp->m_pwszVolumeName);
|
|
CoTaskMemFree(pDiffVolProp->m_pwszVolumeDisplayName);
|
|
}
|
|
|
|
return (bFound ? S_OK : S_FALSE);
|
|
}
|
|
|
|
HRESULT GetDiffAreaInfo(
|
|
IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
|
|
IN VSSUI_VOLUME_LIST* pVolumeList,
|
|
IN LPCTSTR pszVolumeName,
|
|
OUT VSSUI_DIFFAREA* pDiffArea
|
|
)
|
|
{
|
|
if (!piDiffSnapMgmt ||
|
|
!pVolumeList ||
|
|
!pszVolumeName || !*pszVolumeName ||
|
|
!pDiffArea)
|
|
return E_INVALIDARG;
|
|
|
|
ZeroMemory(pDiffArea, sizeof(VSSUI_DIFFAREA));
|
|
|
|
CComPtr<IVssEnumMgmtObject> spiEnumMgmtDiffArea;
|
|
HRESULT hr = piDiffSnapMgmt->QueryDiffAreasForVolume(
|
|
(PTSTR)pszVolumeName,
|
|
&spiEnumMgmtDiffArea);
|
|
if (S_OK == hr)
|
|
{
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_DIFF_AREA_PROP *pDiffAreaProp = &(Prop.Obj.DiffArea);
|
|
ULONG ulDiffFetched = 0;
|
|
hr = spiEnumMgmtDiffArea->Next(1, &Prop, &ulDiffFetched);
|
|
if (SUCCEEDED(hr) && ulDiffFetched > 0)
|
|
{
|
|
if (VSS_MGMT_OBJECT_DIFF_AREA != Prop.Type || 1 != ulDiffFetched)
|
|
return E_FAIL;
|
|
|
|
PTSTR pszVolumeDisplayName = GetDisplayName(pVolumeList, pDiffAreaProp->m_pwszVolumeName);
|
|
PTSTR pszDiffVolumeDisplayName = GetDisplayName(pVolumeList, pDiffAreaProp->m_pwszDiffAreaVolumeName);
|
|
if (pszVolumeDisplayName && pszDiffVolumeDisplayName)
|
|
{
|
|
lstrcpyn(pDiffArea->pszVolumeDisplayName, pszVolumeDisplayName, MAX_PATH);
|
|
lstrcpyn(pDiffArea->pszDiffVolumeDisplayName, pszDiffVolumeDisplayName, MAX_PATH);
|
|
pDiffArea->llMaximumDiffSpace = pDiffAreaProp->m_llMaximumDiffSpace;
|
|
pDiffArea->llUsedDiffSpace = pDiffAreaProp->m_llAllocatedDiffSpace;
|
|
} else
|
|
{
|
|
hr = S_FALSE; // indicate something inconsistent happened (e.g., DiffVol formated to be FAT), we disgard the result
|
|
}
|
|
|
|
CoTaskMemFree(pDiffAreaProp->m_pwszVolumeName);
|
|
CoTaskMemFree(pDiffAreaProp->m_pwszDiffAreaVolumeName);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
PTSTR GetDisplayName(VSSUI_VOLUME_LIST *pVolumeList, LPCTSTR pszVolumeName)
|
|
{
|
|
if (!pVolumeList || !pszVolumeName || !*pszVolumeName)
|
|
return NULL;
|
|
|
|
for (VSSUI_VOLUME_LIST::iterator i = pVolumeList->begin(); i != pVolumeList->end(); i++)
|
|
{
|
|
if (!lstrcmpi(pszVolumeName, (*i)->pszVolumeName))
|
|
return (*i)->pszDisplayName;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PTSTR GetVolumeName(VSSUI_VOLUME_LIST *pVolumeList, LPCTSTR pszDisplayName)
|
|
{
|
|
if (!pVolumeList || !pszDisplayName || !*pszDisplayName)
|
|
return NULL;
|
|
|
|
for (VSSUI_VOLUME_LIST::iterator i = pVolumeList->begin(); i != pVolumeList->end(); i++)
|
|
{
|
|
if (!lstrcmpi(pszDisplayName, (*i)->pszDisplayName))
|
|
return (*i)->pszVolumeName;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void FreeVolumeList(VSSUI_VOLUME_LIST *pList)
|
|
{
|
|
if (!pList || pList->empty())
|
|
return;
|
|
|
|
for (VSSUI_VOLUME_LIST::iterator i = pList->begin(); i != pList->end(); i++)
|
|
free(*i);
|
|
|
|
pList->clear();
|
|
}
|
|
|
|
void FreeSnapshotList(VSSUI_SNAPSHOT_LIST *pList)
|
|
{
|
|
if (!pList || pList->empty())
|
|
return;
|
|
|
|
for (VSSUI_SNAPSHOT_LIST::iterator i = pList->begin(); i != pList->end(); i++)
|
|
free(*i);
|
|
|
|
pList->clear();
|
|
}
|
|
|
|
void FreeDiffAreaList(VSSUI_DIFFAREA_LIST *pList)
|
|
{
|
|
if (!pList || pList->empty())
|
|
return;
|
|
|
|
for (VSSUI_DIFFAREA_LIST::iterator i = pList->begin(); i != pList->end(); i++)
|
|
free(*i);
|
|
|
|
pList->clear();
|
|
}
|
|
|
|
HRESULT GetSystem32Directory(
|
|
IN LPCTSTR i_pszComputer,
|
|
OUT PTSTR o_pszSystem32Directory,
|
|
IN OUT DWORD* o_pdwSize
|
|
)
|
|
{
|
|
if (!o_pszSystem32Directory)
|
|
return E_INVALIDARG;
|
|
|
|
SHARE_INFO_2 *pInfo = NULL;
|
|
DWORD dwRet = NetShareGetInfo((PTSTR)i_pszComputer, _T("ADMIN$"), 2, (LPBYTE *)&pInfo);
|
|
if (NERR_Success == dwRet)
|
|
{
|
|
DWORD dwRequiredLength = lstrlen(pInfo->shi2_path) + lstrlen(_T("\\system32")) + 1;
|
|
if (*o_pdwSize < dwRequiredLength)
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
else
|
|
{
|
|
_tcscpy(o_pszSystem32Directory, pInfo->shi2_path);
|
|
|
|
TCHAR *p = o_pszSystem32Directory + lstrlen(pInfo->shi2_path) - 1;
|
|
if (_T('\\') != *p)
|
|
p++;
|
|
_tcscpy(p, _T("\\system32"));
|
|
}
|
|
|
|
*o_pdwSize = dwRequiredLength;
|
|
}
|
|
|
|
if (pInfo)
|
|
NetApiBufferFree(pInfo);
|
|
|
|
return HRESULT_FROM_WIN32(dwRet);
|
|
}
|
|
|
|
HRESULT GetErrorMessageFromModule(
|
|
IN DWORD dwError,
|
|
IN LPCTSTR lpszDll,
|
|
OUT LPTSTR *ppBuffer
|
|
)
|
|
{
|
|
if (0 == dwError || !lpszDll || !*lpszDll || !ppBuffer)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
HINSTANCE hMsgLib = LoadLibrary(lpszDll);
|
|
if (!hMsgLib)
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
else
|
|
{
|
|
DWORD dwRet = ::FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
|
|
hMsgLib, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)ppBuffer, 0, NULL);
|
|
|
|
if (0 == dwRet)
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
FreeLibrary(hMsgLib);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetErrorMessage(
|
|
IN DWORD i_dwError,
|
|
OUT CString& cstrErrorMsg
|
|
)
|
|
{
|
|
if (0 == i_dwError)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
LPTSTR lpBuffer = NULL;
|
|
|
|
DWORD dwRet = ::FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, i_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&lpBuffer, 0, NULL);
|
|
if (0 == dwRet)
|
|
{
|
|
// if no message is found, GetLastError will return ERROR_MR_MID_NOT_FOUND
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr ||
|
|
0x80070000 == (i_dwError & 0xffff0000) ||
|
|
0 == (i_dwError & 0xffff0000) )
|
|
{
|
|
hr = GetErrorMessageFromModule((i_dwError & 0x0000ffff), _T("netmsg.dll"), &lpBuffer);
|
|
}
|
|
|
|
// could be a VSS error, try myself - vssui.dll
|
|
if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr)
|
|
{
|
|
hr = GetErrorMessageFromModule(i_dwError, _T("vssui.dll"), &lpBuffer);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
cstrErrorMsg = lpBuffer;
|
|
LocalFree(lpBuffer);
|
|
}
|
|
else
|
|
{
|
|
// we failed to retrieve the error message from system/netmsg.dll/sfmmsg.dll,
|
|
// report the error code directly to user
|
|
hr = S_OK;
|
|
cstrErrorMsg.Format(_T("0x%x"), i_dwError);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// GetMsgHelper()
|
|
//
|
|
// This function will retrieve the error msg if dwErr is specified,
|
|
// load resource string if specified, and format the string with
|
|
// the error msg and other optional arguments.
|
|
//
|
|
//
|
|
HRESULT GetMsgHelper(
|
|
OUT CString& strMsg,// OUT: the message
|
|
DWORD dwErr, // IN: Error code from GetLastError()
|
|
UINT wIdString, // IN: String ID
|
|
va_list* parglist // IN: OPTIONAL arguments
|
|
)
|
|
{
|
|
if (!dwErr && !wIdString)
|
|
return E_INVALIDARG;
|
|
|
|
//
|
|
// retrieve error msg
|
|
//
|
|
CString strErrorMessage;
|
|
if (dwErr != 0)
|
|
GetErrorMessage(dwErr, strErrorMessage);
|
|
|
|
//
|
|
// load string resource, and format it with the error msg and
|
|
// other optional arguments
|
|
//
|
|
if (wIdString == 0)
|
|
{
|
|
strMsg = strErrorMessage;
|
|
} else
|
|
{
|
|
CString strFormat;
|
|
strFormat.LoadString(wIdString);
|
|
|
|
CString strFormatedMsg;
|
|
strFormatedMsg.FormatV(strFormat, *parglist);
|
|
|
|
if (dwErr == 0)
|
|
strMsg = strFormatedMsg;
|
|
else
|
|
strMsg.FormatMessage((((HRESULT)dwErr < 0) ? IDS_ERROR_HR : IDS_ERROR),
|
|
strFormatedMsg,
|
|
dwErr,
|
|
strErrorMessage);
|
|
}
|
|
|
|
return S_OK;
|
|
} // GetMsgHelper()
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// GetMsg()
|
|
//
|
|
// This function will call GetMsgHelp to retrieve the error msg
|
|
// if dwErr is specified, load resource string if specified, and
|
|
// format the string with the error msg and other optional arguments.
|
|
//
|
|
//
|
|
void GetMsg(
|
|
OUT CString& strMsg,// OUT: the message
|
|
DWORD dwErr, // IN: Error code from GetLastError()
|
|
UINT wIdString, // IN: String resource Id
|
|
...) // IN: Optional arguments
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, wIdString);
|
|
|
|
HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
|
|
if (FAILED(hr))
|
|
strMsg.Format(_T("0x%x"), hr);
|
|
|
|
va_end(arglist);
|
|
|
|
} // GetMsg()
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// DoErrMsgBox()
|
|
//
|
|
// Display a message box for the error code. This function will
|
|
// load the error message from the system resource and append
|
|
// the optional string (if any)
|
|
//
|
|
// EXAMPLE
|
|
// DoErrMsgBox(GetActiveWindow(), MB_OK, GetLastError(), IDS_s_FILE_READ_ERROR, L"foo.txt");
|
|
//
|
|
INT DoErrMsgBox(
|
|
HWND hwndParent, // IN: Parent of the dialog box
|
|
UINT uType, // IN: style of message box
|
|
DWORD dwErr, // IN: Error code from GetLastError()
|
|
UINT wIdString, // IN: String resource Id
|
|
...) // IN: Optional arguments
|
|
{
|
|
//
|
|
// get string and the error msg
|
|
//
|
|
va_list arglist;
|
|
va_start(arglist, wIdString);
|
|
|
|
CString strMsg;
|
|
HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
|
|
if (FAILED(hr))
|
|
strMsg.Format(_T("0x%x"), hr);
|
|
|
|
va_end(arglist);
|
|
|
|
//
|
|
// Load the caption
|
|
//
|
|
CString strCaption;
|
|
strCaption.LoadString(IDS_PROJNAME);
|
|
|
|
//
|
|
// Display the message.
|
|
//
|
|
return ::MessageBox(hwndParent, strMsg, strCaption, uType);
|
|
|
|
}
|
|
|
|
BOOL IsPostW2KServer(LPCTSTR pszComputer)
|
|
{
|
|
BOOL bPostW2KServer = FALSE;
|
|
SERVER_INFO_102* pServerInfo = NULL;
|
|
DWORD dwRet = NetServerGetInfo((LPTSTR)pszComputer, 102, (LPBYTE*)&pServerInfo);
|
|
if (NERR_Success == dwRet)
|
|
{
|
|
bPostW2KServer = (pServerInfo->sv102_type & SV_TYPE_NT) && // NT/W2K/XP or after
|
|
(pServerInfo->sv102_version_major & MAJOR_VERSION_MASK) >= 5 &&
|
|
pServerInfo->sv102_version_minor > 0 && // XP or after
|
|
((pServerInfo->sv102_type & SV_TYPE_DOMAIN_CTRL) ||
|
|
(pServerInfo->sv102_type & SV_TYPE_DOMAIN_BAKCTRL) ||
|
|
(pServerInfo->sv102_type & SV_TYPE_SERVER_NT)); // server
|
|
|
|
NetApiBufferFree(pServerInfo);
|
|
}
|
|
|
|
return bPostW2KServer;
|
|
}
|
|
|
|
HRESULT GetVolumesSupportedForDiffArea(
|
|
IN IVssDifferentialSoftwareSnapshotMgmt* piDiffSnapMgmt,
|
|
IN LPCTSTR pszVolumeDisplayName,
|
|
IN OUT VSSUI_VOLUME_LIST* pVolumeList
|
|
)
|
|
{
|
|
if (!piDiffSnapMgmt || !pszVolumeDisplayName || !*pszVolumeDisplayName)
|
|
return E_INVALIDARG;
|
|
|
|
if (!pVolumeList || (!pVolumeList->empty()))
|
|
// Expect an empty list...
|
|
return E_INVALIDARG;
|
|
|
|
CComPtr<IVssEnumMgmtObject> spiEnumMgmt;
|
|
HRESULT hr = piDiffSnapMgmt->QueryVolumesSupportedForDiffAreas((PTSTR)pszVolumeDisplayName, &spiEnumMgmt);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_DIFF_VOLUME_PROP *pDiffVolProp = &(Prop.Obj.DiffVol);
|
|
ULONG ulFetched = 0;
|
|
while (SUCCEEDED(hr = spiEnumMgmt->Next(1, &Prop, &ulFetched)) && ulFetched > 0)
|
|
{
|
|
if (VSS_MGMT_OBJECT_DIFF_VOLUME != Prop.Type)
|
|
return E_FAIL;
|
|
|
|
VSSUI_VOLUME *pVolInfo = (VSSUI_VOLUME *)calloc(1, sizeof(VSSUI_VOLUME));
|
|
if (pVolInfo)
|
|
{
|
|
lstrcpyn(pVolInfo->pszVolumeName, pDiffVolProp->m_pwszVolumeName, MAX_PATH);
|
|
lstrcpyn(pVolInfo->pszDisplayName, pDiffVolProp->m_pwszVolumeDisplayName, MAX_PATH);
|
|
pVolumeList->push_back(pVolInfo);
|
|
} else
|
|
{
|
|
FreeVolumeList(pVolumeList);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
CoTaskMemFree(pDiffVolProp->m_pwszVolumeName);
|
|
CoTaskMemFree(pDiffVolProp->m_pwszVolumeDisplayName);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
if (hr == S_FALSE)
|
|
// End of loop detected
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|