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.
773 lines
19 KiB
773 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Abstract:
|
|
|
|
@doc
|
|
@module vssadmin.cpp | Implementation of the Volume Snapshots demo
|
|
@end
|
|
|
|
Author:
|
|
|
|
Adi Oltean [aoltean] 09/17/1999
|
|
|
|
TBD:
|
|
|
|
Add comments.
|
|
|
|
Revision History:
|
|
|
|
Name Date Comments
|
|
aoltean 09/17/1999 Created
|
|
|
|
--*/
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
|
|
// The rest of includes are specified here
|
|
#include "vssadmin.h"
|
|
#include <locale.h>
|
|
#include <winnlsp.h> // in public\internal\base\inc
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Standard foo for file name aliasing. This code block must be after
|
|
// all includes of VSS header files.
|
|
//
|
|
#ifdef VSS_FILE_ALIAS
|
|
#undef VSS_FILE_ALIAS
|
|
#endif
|
|
#define VSS_FILE_ALIAS "ADMVADMC"
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Implementation
|
|
|
|
|
|
|
|
CVssAdminCLI::CVssAdminCLI(
|
|
IN HINSTANCE hInstance
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Standard constructor. Initializes internal members
|
|
|
|
--*/
|
|
|
|
{
|
|
BS_ASSERT(hInstance != NULL);
|
|
m_hInstance = hInstance;
|
|
|
|
m_eCommandType = VSS_CMD_UNKNOWN;
|
|
m_eListType = VSS_LIST_UNKNOWN;
|
|
m_eFilterObjectType = VSS_OBJECT_UNKNOWN;
|
|
m_eListedObjectType = VSS_OBJECT_UNKNOWN;
|
|
m_FilterSnapshotSetId = GUID_NULL;
|
|
m_FilterSnapshotId = GUID_NULL;
|
|
m_pwszCmdLine = NULL;
|
|
m_nReturnValue = VSS_CMDRET_ERROR;
|
|
m_hConsoleOutput = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
CVssAdminCLI::~CVssAdminCLI()
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Standard destructor. Calls Finalize and eventually frees the
|
|
memory allocated by internal members.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Release the cached resource strings
|
|
for( int nIndex = 0; nIndex < m_mapCachedResourceStrings.GetSize(); nIndex++) {
|
|
LPCWSTR& pwszResString = m_mapCachedResourceStrings.GetValueAt(nIndex);
|
|
::VssFreeString(pwszResString);
|
|
}
|
|
|
|
// Release the cached provider names
|
|
for( int nIndex = 0; nIndex < m_mapCachedProviderNames.GetSize(); nIndex++) {
|
|
LPCWSTR& pwszProvName = m_mapCachedProviderNames.GetValueAt(nIndex);
|
|
::VssFreeString(pwszProvName);
|
|
}
|
|
|
|
// Release the cached command line
|
|
::VssFreeString(m_pwszCmdLine);
|
|
|
|
// Uninitialize the COM library
|
|
Finalize();
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Implementation
|
|
|
|
|
|
|
|
LPCWSTR CVssAdminCLI::LoadString(
|
|
IN CVssFunctionTracer& ft,
|
|
IN UINT uStringId
|
|
)
|
|
{
|
|
LPCWSTR wszReturnedString = m_mapCachedResourceStrings.Lookup(uStringId);
|
|
if (wszReturnedString)
|
|
return wszReturnedString;
|
|
|
|
// Load the string from resources.
|
|
WCHAR wszBuffer[nStringBufferSize];
|
|
INT nReturnedCharacters = ::LoadStringW(
|
|
GetInstance(),
|
|
uStringId,
|
|
wszBuffer,
|
|
nStringBufferSize - 1
|
|
);
|
|
if (nReturnedCharacters == 0)
|
|
ft.Throw( VSSDBG_COORD, E_UNEXPECTED,
|
|
L"Error on loading the string %u. 0x%08lx",
|
|
uStringId, ::GetLastError() );
|
|
|
|
// Duplicate the new string
|
|
LPWSTR wszNewString = NULL;
|
|
::VssSafeDuplicateStr( ft, wszNewString, wszBuffer );
|
|
wszReturnedString = wszNewString;
|
|
|
|
// Save the string in the cache
|
|
if ( !m_mapCachedResourceStrings.Add( uStringId, wszReturnedString ) ) {
|
|
::VssFreeString( wszReturnedString );
|
|
ft.Throw( VSSDBG_COORD, E_OUTOFMEMORY, L"Memory allocation error");
|
|
}
|
|
|
|
return wszReturnedString;
|
|
}
|
|
|
|
|
|
LPCWSTR CVssAdminCLI::GetNextCmdlineToken(
|
|
IN CVssFunctionTracer& ft,
|
|
IN bool bFirstToken /* = false */
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function returns the tokens in the command line.
|
|
|
|
The function will skip any separators (space and tab).
|
|
|
|
If bFirstCall == true then it will return the first token.
|
|
Otherwise subsequent calls will return subsequent tokens.
|
|
|
|
If the last token is NULL then there are no more tokens in the command line.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ::wcstok( bFirstToken? m_pwszCmdLine: NULL, wszVssFmtSpaces );
|
|
UNREFERENCED_PARAMETER(ft);
|
|
}
|
|
|
|
|
|
bool CVssAdminCLI::Match(
|
|
IN CVssFunctionTracer& ft,
|
|
IN LPCWSTR wszString,
|
|
IN LPCWSTR wszPatternString
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function returns true iif the given string matches the
|
|
pattern string. The comparison is case insensitive.
|
|
|
|
--*/
|
|
|
|
{
|
|
// If the string is NULL then the Match failed.
|
|
if (wszString == NULL) return false;
|
|
|
|
// Check for string equality (case insensitive)
|
|
return (::_wcsicmp( wszString, wszPatternString ) == 0);
|
|
UNREFERENCED_PARAMETER(ft);
|
|
}
|
|
|
|
|
|
bool CVssAdminCLI::ScanGuid(
|
|
IN CVssFunctionTracer& /* ft */,
|
|
IN LPCWSTR wszString,
|
|
IN VSS_ID& Guid
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function returns true iif the given string matches a guid.
|
|
The guid is returned in the proper variable.
|
|
The formatting is case insensitive.
|
|
|
|
--*/
|
|
|
|
{
|
|
return SUCCEEDED(::CLSIDFromString(W2OLE(const_cast<WCHAR*>(wszString)), &Guid));
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::Output(
|
|
IN CVssFunctionTracer& ft,
|
|
IN UINT uFormatStringId,
|
|
...
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function returns true iif the given string matches the
|
|
pattern strig from resources. The comparison is case insensitive.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR wszOutputBuffer[nStringBufferSize];
|
|
|
|
// Load the format string
|
|
LPCWSTR wszFormat = LoadString( ft, uFormatStringId );
|
|
|
|
// Format the final string
|
|
va_list marker;
|
|
va_start( marker, uFormatStringId );
|
|
_vsnwprintf( wszOutputBuffer, nStringBufferSize - 1, wszFormat, marker );
|
|
va_end( marker );
|
|
|
|
// Print the final string to the output
|
|
OutputOnConsole( wszOutputBuffer );
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::Output(
|
|
IN CVssFunctionTracer& ft,
|
|
IN LPCWSTR wszFormat,
|
|
...
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function returns true iif the given string matches the
|
|
pattern strig from resources. The comparison is case insensitive.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR wszOutputBuffer[nStringBufferSize];
|
|
|
|
// Format the final string
|
|
va_list marker;
|
|
va_start( marker, wszFormat );
|
|
_vsnwprintf( wszOutputBuffer, nStringBufferSize - 1, wszFormat, marker );
|
|
va_end( marker );
|
|
|
|
// Print the final string to the output
|
|
OutputOnConsole( wszOutputBuffer );
|
|
|
|
UNREFERENCED_PARAMETER(ft);
|
|
}
|
|
|
|
void CVssAdminCLI::OutputOnConsole(
|
|
IN LPCWSTR wszStr
|
|
)
|
|
{
|
|
DWORD dwCharsOutput;
|
|
DWORD fdwMode;
|
|
static BOOL bFirstTime = TRUE;
|
|
static BOOL bIsTrueConsoleOutput;
|
|
|
|
if ( m_hConsoleOutput == INVALID_HANDLE_VALUE )
|
|
{
|
|
throw E_UNEXPECTED;
|
|
}
|
|
|
|
if ( bFirstTime )
|
|
{
|
|
//
|
|
// Stash away the results in static vars. bIsTrueConsoleOutput is TRUE when the
|
|
// standard output handle is pointing to a console character device.
|
|
//
|
|
bIsTrueConsoleOutput = ( ::GetFileType( m_hConsoleOutput ) & FILE_TYPE_CHAR ) &&
|
|
::GetConsoleMode( m_hConsoleOutput, &fdwMode );
|
|
bFirstTime = FALSE;
|
|
}
|
|
|
|
if ( bIsTrueConsoleOutput )
|
|
{
|
|
//
|
|
// Output to the console
|
|
//
|
|
if ( !::WriteConsoleW( m_hConsoleOutput,
|
|
( PVOID )wszStr,
|
|
( DWORD )::wcslen( wszStr ),
|
|
&dwCharsOutput,
|
|
NULL ) )
|
|
{
|
|
throw HRESULT_FROM_WIN32( ::GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Output being redirected. WriteConsoleW doesn't work for redirected output. Convert
|
|
// UNICODE to the current output CP multibyte charset.
|
|
//
|
|
|
|
// ---------------- To be removed later - Start -----------------
|
|
//
|
|
// Translate \n to \r\n since the string might be directed to a disk file.
|
|
// Remove this code if the .rc file can be updated to include
|
|
// \r\n. This was needed since we are in UI lockdown.
|
|
//
|
|
LPWSTR pwszConversion;
|
|
|
|
// Allocate a string twice the size of the original
|
|
pwszConversion = ( LPWSTR )::malloc( ( ( ::wcslen( wszStr ) * 2 ) + 1 ) * sizeof( WCHAR ) );
|
|
if ( pwszConversion == NULL )
|
|
{
|
|
throw E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Copy the string to the new string and place a \r in front of any \n. Also
|
|
// handle the case if \r\n is already in the string.
|
|
DWORD dwIdx = 0;
|
|
|
|
while ( wszStr[0] != L'\0' )
|
|
{
|
|
if ( wszStr[0] == L'\r' && wszStr[1] == L'\n' )
|
|
{
|
|
pwszConversion[dwIdx++] = L'\r';
|
|
pwszConversion[dwIdx++] = L'\n';
|
|
wszStr += 2;
|
|
}
|
|
else if ( wszStr[0] == L'\n' )
|
|
{
|
|
pwszConversion[dwIdx++] = L'\r';
|
|
pwszConversion[dwIdx++] = L'\n';
|
|
wszStr += 1;
|
|
}
|
|
else
|
|
{
|
|
pwszConversion[dwIdx++] = wszStr[0];
|
|
wszStr += 1;
|
|
}
|
|
}
|
|
pwszConversion[dwIdx] = L'\0';
|
|
|
|
// ---------------- To be removed later - End -----------------
|
|
|
|
|
|
LPSTR pszMultibyteBuffer;
|
|
DWORD dwByteCount;
|
|
|
|
//
|
|
// Get size of temp buffer needed for the conversion.
|
|
//
|
|
dwByteCount = ::WideCharToMultiByte(
|
|
::GetConsoleOutputCP(),
|
|
0,
|
|
pwszConversion,
|
|
-1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( dwByteCount == 0 )
|
|
{
|
|
::free( pwszConversion );
|
|
throw HRESULT_FROM_WIN32( ::GetLastError() );
|
|
}
|
|
|
|
pszMultibyteBuffer = ( LPSTR )::malloc( dwByteCount );
|
|
if ( pszMultibyteBuffer == NULL )
|
|
{
|
|
::free( pwszConversion );
|
|
throw E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Now convert it.
|
|
//
|
|
dwByteCount = ::WideCharToMultiByte(
|
|
::GetConsoleOutputCP(),
|
|
0,
|
|
pwszConversion,
|
|
-1,
|
|
pszMultibyteBuffer,
|
|
dwByteCount,
|
|
NULL,
|
|
NULL
|
|
);
|
|
::free( pwszConversion );
|
|
if ( dwByteCount == 0 )
|
|
{
|
|
::free( pszMultibyteBuffer );
|
|
throw HRESULT_FROM_WIN32( ::GetLastError() );
|
|
}
|
|
|
|
// Finally output it.
|
|
if ( !::WriteFile(
|
|
m_hConsoleOutput,
|
|
pszMultibyteBuffer,
|
|
dwByteCount - 1, // Get rid of the trailing NULL char
|
|
&dwCharsOutput,
|
|
NULL ) )
|
|
{
|
|
throw HRESULT_FROM_WIN32( ::GetLastError() );
|
|
}
|
|
|
|
::free( pszMultibyteBuffer );
|
|
}
|
|
}
|
|
|
|
|
|
LPCWSTR CVssAdminCLI::GetProviderName(
|
|
IN CVssFunctionTracer& ft,
|
|
IN VSS_ID& ProviderId
|
|
) throw(HRESULT)
|
|
{
|
|
LPCWSTR wszReturnedString = m_mapCachedProviderNames.Lookup(ProviderId);
|
|
if (wszReturnedString)
|
|
return wszReturnedString;
|
|
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.LogVssStartupAttempt();
|
|
ft.hr = pICoord.CoCreateInstance( CLSID_VSSCoordinator );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
CComPtr<IVssEnumObject> pIEnumProvider;
|
|
ft.hr = pICoord->Query( GUID_NULL,
|
|
VSS_OBJECT_NONE,
|
|
VSS_OBJECT_PROVIDER,
|
|
&pIEnumProvider );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Query failed with hr = 0x%08lx", ft.hr);
|
|
|
|
VSS_OBJECT_PROP Prop;
|
|
VSS_PROVIDER_PROP& Prov = Prop.Obj.Prov;
|
|
|
|
// Go through the list of providers to find the one we are interested in.
|
|
ULONG ulFetched;
|
|
while( 1 )
|
|
{
|
|
ft.hr = pIEnumProvider->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Next failed with hr = 0x%08lx", ft.hr);
|
|
|
|
if (ft.hr == S_FALSE) {
|
|
// End of enumeration.
|
|
// Provider not registered? Where did this snapshot come from?
|
|
// It might be still possible if a snapshot provider was deleted
|
|
// before querying the snapshot provider but after the snapshot attributes
|
|
// were queried.
|
|
BS_ASSERT(ulFetched == 0);
|
|
return LoadString( ft, IDS_UNKNOWN_PROVIDER );
|
|
}
|
|
|
|
if (Prov.m_ProviderId == ProviderId)
|
|
break;
|
|
}
|
|
|
|
// Duplicate the new string
|
|
LPWSTR wszNewString = NULL;
|
|
BS_ASSERT(Prov.m_pwszProviderName);
|
|
::VssSafeDuplicateStr( ft, wszNewString, Prov.m_pwszProviderName );
|
|
wszReturnedString = wszNewString;
|
|
|
|
// Save the string in the cache
|
|
if (!m_mapCachedProviderNames.Add( ProviderId, wszReturnedString )) {
|
|
::VssFreeString( wszReturnedString );
|
|
ft.Throw( VSSDBG_COORD, E_OUTOFMEMORY, L"Memory allocation error");
|
|
}
|
|
|
|
return wszReturnedString;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Implementation
|
|
|
|
|
|
void CVssAdminCLI::Initialize(
|
|
IN CVssFunctionTracer& ft
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Initializes the COM library. Called explicitely after instantiating the CVssAdminCLI object.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Use the OEM code page ...
|
|
::setlocale(LC_ALL, ".OCP");
|
|
|
|
// Use the console UI language
|
|
::SetThreadUILanguage( 0 );
|
|
|
|
//
|
|
// Use only the Console routines to output messages. To do so, need to open standard
|
|
// output.
|
|
//
|
|
m_hConsoleOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (m_hConsoleOutput == INVALID_HANDLE_VALUE)
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, HRESULT_FROM_WIN32( ::GetLastError() ),
|
|
L"Initialize - Error from GetStdHandle(), rc: %d",
|
|
::GetLastError() );
|
|
}
|
|
|
|
// Initialize COM library
|
|
ft.hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Failure in initializing the COM library 0x%08lx", ft.hr);
|
|
|
|
|
|
// Initialize COM security
|
|
ft.hr = CoInitializeSecurity(
|
|
NULL, // IN PSECURITY_DESCRIPTOR pSecDesc,
|
|
-1, // IN LONG cAuthSvc,
|
|
NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
|
|
NULL, // IN void *pReserved1,
|
|
RPC_C_AUTHN_LEVEL_CONNECT, // IN DWORD dwAuthnLevel,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, // IN DWORD dwImpLevel,
|
|
NULL, // IN void *pAuthList,
|
|
EOAC_NONE, // IN DWORD dwCapabilities,
|
|
NULL // IN void *pReserved3
|
|
);
|
|
|
|
if (ft.HrFailed()) {
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L" Error: CoInitializeSecurity() returned 0x%08lx", ft.hr );
|
|
}
|
|
|
|
// Print the header
|
|
Output( ft, IDS_HEADER );
|
|
|
|
// Initialize the command line
|
|
::VssSafeDuplicateStr( ft, m_pwszCmdLine, ::GetCommandLineW() );
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::ParseCmdLine(
|
|
IN CVssFunctionTracer& ft
|
|
) throw(HRESULT)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Parses the command line.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Skip the executable name
|
|
GetNextCmdlineToken( ft, true );
|
|
|
|
// Get the first token after the executable name
|
|
LPCWSTR pwszArg1 = GetNextCmdlineToken( ft );
|
|
|
|
// Check if this is a list process
|
|
if ( Match( ft, pwszArg1, wszVssOptList)) {
|
|
|
|
m_eCommandType = VSS_CMD_LIST;
|
|
|
|
// Get the next token after "list"
|
|
LPCWSTR pwszArg2 = GetNextCmdlineToken( ft );
|
|
|
|
// Check if this is a list snapshots process
|
|
if ( Match( ft, pwszArg2, wszVssOptSnapshots )) {
|
|
|
|
m_eListType = VSS_LIST_SNAPSHOTS;
|
|
|
|
// Get the next token after "snapshots"
|
|
LPCWSTR pwszArg3 = GetNextCmdlineToken( ft );
|
|
|
|
if ( pwszArg3 == NULL ) {
|
|
m_FilterSnapshotSetId = GUID_NULL;
|
|
m_eFilterObjectType = VSS_OBJECT_NONE;
|
|
return;
|
|
}
|
|
|
|
// Check if this is a snapshot set filter
|
|
if ( ::_wcsnicmp( pwszArg3, wszVssOptSet, ::wcslen( wszVssOptSet ) ) == 0 ) {
|
|
|
|
// Get the next token after "snapshots"
|
|
LPCWSTR pwszArg4 = pwszArg3 + ::wcslen( wszVssOptSet );
|
|
|
|
// Get the snapshot set Id
|
|
if ( (pwszArg4[0] != '\0' ) && ScanGuid( ft, pwszArg4, m_FilterSnapshotSetId ) && (GetNextCmdlineToken(ft) == NULL) ) {
|
|
|
|
m_eFilterObjectType = VSS_OBJECT_SNAPSHOT_SET;
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Check if this is a list writers process
|
|
if ( Match( ft, pwszArg2, wszVssOptWriters) && (GetNextCmdlineToken(ft) == NULL)) {
|
|
m_eListType = VSS_LIST_WRITERS;
|
|
m_FilterSnapshotSetId = GUID_NULL;
|
|
m_eFilterObjectType = VSS_OBJECT_NONE;
|
|
return;
|
|
}
|
|
|
|
// Check if this is a list providers process
|
|
if ( Match( ft, pwszArg2, wszVssOptProviders)&& (GetNextCmdlineToken(ft) == NULL)) {
|
|
m_eListType = VSS_LIST_PROVIDERS;
|
|
m_FilterSnapshotSetId = GUID_NULL;
|
|
m_eFilterObjectType = VSS_OBJECT_NONE;
|
|
return;
|
|
}
|
|
}
|
|
else if (pwszArg1 == NULL)
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
|
|
m_eCommandType = VSS_CMD_USAGE;
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::DoProcessing(
|
|
IN CVssFunctionTracer& ft
|
|
) throw(HRESULT)
|
|
{
|
|
switch( m_eCommandType)
|
|
{
|
|
case VSS_CMD_USAGE:
|
|
PrintUsage(ft);
|
|
break;
|
|
|
|
case VSS_CMD_LIST:
|
|
switch (m_eListType)
|
|
{
|
|
case VSS_LIST_SNAPSHOTS:
|
|
ListSnapshots(ft);
|
|
break;
|
|
|
|
case VSS_LIST_WRITERS:
|
|
ListWriters(ft);
|
|
break;
|
|
|
|
case VSS_LIST_PROVIDERS:
|
|
ListProviders(ft);
|
|
break;
|
|
|
|
default:
|
|
ft.Throw( VSSDBG_COORD, E_UNEXPECTED,
|
|
L"Invalid list type: %d %d",
|
|
m_eListType, m_eCommandType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ft.Throw( VSSDBG_COORD, E_UNEXPECTED,
|
|
L"Invalid command type: %d", m_eCommandType);
|
|
}
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::Finalize()
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Uninitialize the COM library. Called in CVssAdminCLI destructor.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Uninitialize COM library
|
|
CoUninitialize();
|
|
}
|
|
|
|
|
|
HRESULT CVssAdminCLI::Main(
|
|
IN HINSTANCE hInstance
|
|
)
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
CVssAdminCLI::Main
|
|
|
|
Description:
|
|
|
|
Static function used as the main entry point in the VSS CLI
|
|
|
|
--*/
|
|
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::Main" );
|
|
INT nReturnValue = VSS_CMDRET_ERROR;
|
|
|
|
try
|
|
{
|
|
CVssAdminCLI program(hInstance);
|
|
|
|
try
|
|
{
|
|
// Initialize the program. This calls CoInitialize()
|
|
program.Initialize(ft);
|
|
|
|
// Parse the command line
|
|
program.ParseCmdLine(ft);
|
|
|
|
// Do the work...
|
|
program.DoProcessing(ft);
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
// Prints the error, if any
|
|
if (ft.HrFailed())
|
|
program.Output( ft, IDS_ERROR, ft.hr );
|
|
|
|
nReturnValue = program.GetReturnValue();
|
|
|
|
// The destructor automatically calls CoUninitialize()
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
return nReturnValue;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// WinMain
|
|
|
|
|
|
|
|
extern "C" int WINAPI _tWinMain(
|
|
IN HINSTANCE hInstance,
|
|
IN HINSTANCE /*hPrevInstance*/,
|
|
IN LPTSTR /*lpCmdLine*/,
|
|
IN int /*nShowCmd*/)
|
|
{
|
|
return CVssAdminCLI::Main(hInstance);
|
|
}
|