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

// 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;
}