1191 lines
35 KiB
C
1191 lines
35 KiB
C
// *********************************************************************************
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Module Name:
|
|
//
|
|
// EventCreate.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This modules implements creation of event in the user specified log / application
|
|
//
|
|
// Syntax:
|
|
// ------
|
|
// EventCreate [-s server [-u username [-p password]]]
|
|
// [-log name] [-source name] -id eventid -description description -type eventtype
|
|
//
|
|
// Author:
|
|
//
|
|
// Sunil G.V.N. Murali (murali.sunil@wipro.com) 24-Sep-2000
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Sunil G.V.N. Murali (murali.sunil@wipro.com) 24-Sep-2000 : Created It.
|
|
//
|
|
// *********************************************************************************
|
|
|
|
#include "pch.h"
|
|
#include "EvcrtMsg.h"
|
|
#include "EventCreate.h"
|
|
|
|
//
|
|
// local type definitions
|
|
//
|
|
typedef TCHAR __OPTION_VALUE[ 256 ];
|
|
|
|
//
|
|
// constants / defines / enumerators
|
|
//
|
|
#define FULL_SUCCESS 0
|
|
#define PARTIALLY_SUCCESS 128
|
|
#define COMPLETELY_FAILED 255
|
|
|
|
#define MAX_KEY_LENGTH 256
|
|
#define EVENT_LOG_NAMES_LOCATION _T( "SYSTEM\\CurrentControlSet\\Services\\EventLog" )
|
|
|
|
// constants
|
|
const TCHAR g_szDefaultLog[] = _T( "Application" );
|
|
const TCHAR g_szDefaultSource[] = _T( "EventCreate" );
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
VOID Usage();
|
|
BOOL AddEventSource( HKEY hLogsKey, LPCTSTR pszSource );
|
|
BOOL CheckExistence( LPCTSTR szServer,
|
|
LPCTSTR szLog, LPCTSTR szSource, PBOOL pbCustom );
|
|
BOOL CreateLogEvent( LPCTSTR szServer,
|
|
LPCTSTR szLog, LPCTSTR szSource,
|
|
WORD wType, DWORD dwEventID, LPCTSTR szDescription );
|
|
BOOL ProcessOptions( LONG argc,
|
|
LPCTSTR argv[],
|
|
PBOOL pbShowUsage,
|
|
PTARRAY parrServer, LPTSTR ppszUserName, LPTSTR ppszPassword,
|
|
LPTSTR ppszLogName, LPTSTR ppszLogSource, LPTSTR ppszLogType,
|
|
PDWORD pdwEventID, LPTSTR ppszDescription, PBOOL pbNeedPwd );
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This the entry point to this utility.
|
|
//
|
|
// Arguments:
|
|
// [ in ] argc : argument(s) count specified at the command prompt
|
|
// [ in ] argv : argument(s) specified at the command prompt
|
|
//
|
|
// Return Value:
|
|
// The below are actually not return values but are the exit values
|
|
// returned to the OS by this application
|
|
// 0 : utility successfully created the events
|
|
// 255 : utility completely failed in creating events
|
|
// 128 : utility has partially successfull in creating events
|
|
// ***************************************************************************
|
|
DWORD _cdecl _tmain( LONG argc, LPCTSTR argv[] )
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
WORD wEventType = 0;
|
|
BOOL bResult = FALSE;
|
|
LPCTSTR pszServer = NULL;
|
|
BOOL bNeedPassword = FALSE;
|
|
BOOL bCloseConnection = FALSE;
|
|
DWORD dwServers = 0, dwSuccess = 0;
|
|
__STRING_512 szBuffer = NULL_STRING;
|
|
|
|
// variables to hold the command line inputs
|
|
BOOL bUsage = FALSE; // usage
|
|
DWORD dwEventID = 0; // event id
|
|
TARRAY arrServers = NULL; // holds the list of server names
|
|
__OPTION_VALUE szLogName = NULL_STRING; // log file name
|
|
__OPTION_VALUE szSource = NULL_STRING; // source name
|
|
__OPTION_VALUE szType = NULL_STRING; // event type
|
|
__OPTION_VALUE szUserName = NULL_STRING; // user name
|
|
__OPTION_VALUE szPassword = NULL_STRING; // password
|
|
__OPTION_VALUE szDescription = NULL_STRING; // description of the event
|
|
|
|
// create a dynamic array
|
|
arrServers = CreateDynamicArray();
|
|
if ( arrServers == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
ShowLastError( stderr );
|
|
EXIT_PROCESS( 1 );
|
|
}
|
|
|
|
// process the command-line options
|
|
bResult = ProcessOptions( argc, argv, &bUsage,
|
|
&arrServers, szUserName, szPassword, szLogName,
|
|
szSource, szType, &dwEventID, szDescription, &bNeedPassword );
|
|
|
|
// check the result of the parsing
|
|
if ( bResult == FALSE )
|
|
{
|
|
// invalid syntax
|
|
DISPLAY_MESSAGE2( stderr, szBuffer, _T( "%s %s" ), TAG_ERROR, GetReason() );
|
|
|
|
// release memory
|
|
DestroyDynamicArray( &arrServers );
|
|
|
|
// exit from program
|
|
EXIT_PROCESS( 1 );
|
|
}
|
|
|
|
// check whether usage has to be displayed or not
|
|
if ( bUsage == TRUE )
|
|
{
|
|
// show the usage of the utility
|
|
Usage();
|
|
|
|
// release memory
|
|
DestroyDynamicArray( &arrServers );
|
|
|
|
// finally exit from the program
|
|
EXIT_PROCESS( 0 );
|
|
}
|
|
|
|
// determine the actual event type
|
|
if ( StringCompare( szType, LOGTYPE_ERROR, TRUE, 0 ) == 0 )
|
|
wEventType = EVENTLOG_ERROR_TYPE;
|
|
else if ( StringCompare( szType, LOGTYPE_WARNING, TRUE, 0 ) == 0 )
|
|
wEventType = EVENTLOG_WARNING_TYPE;
|
|
else if ( StringCompare( szType, LOGTYPE_INFORMATION, TRUE, 0 ) == 0 )
|
|
wEventType = EVENTLOG_INFORMATION_TYPE;
|
|
|
|
// ******
|
|
// actual creation of events in respective log files will start from here
|
|
|
|
// get the no. of servers specified
|
|
dwServers = DynArrayGetCount( arrServers );
|
|
|
|
// now traverse thru the list of servers, and do the needed operations
|
|
dwSuccess = 0;
|
|
for( dw = 0; dw < dwServers; dw++ )
|
|
{
|
|
// get the system name
|
|
pszServer = DynArrayItemAsString( arrServers, dw );
|
|
if ( pszServer == NULL )
|
|
continue;
|
|
|
|
// try establishing connection to the required terminal
|
|
bCloseConnection = TRUE;
|
|
bResult = EstablishConnection(
|
|
pszServer, szUserName, SIZE_OF_ARRAY( szUserName ),
|
|
szPassword, SIZE_OF_ARRAY( szPassword ), bNeedPassword );
|
|
bNeedPassword = FALSE; // from next time onwards, we shouldn't prompt for passwd
|
|
if ( bResult == FALSE )
|
|
{
|
|
//
|
|
// failed in establishing n/w connection
|
|
SHOW_RESULT_MESSAGE( NULL, TAG_ERROR, GetReason() );
|
|
|
|
// try with next server
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// though the connection is successfull, some conflict might have occured
|
|
switch( GetLastError() )
|
|
{
|
|
case I_NO_CLOSE_CONNECTION:
|
|
bCloseConnection = FALSE;
|
|
break;
|
|
|
|
case E_LOCAL_CREDENTIALS:
|
|
case ERROR_SESSION_CREDENTIAL_CONFLICT:
|
|
{
|
|
bCloseConnection = FALSE;
|
|
SHOW_RESULT_MESSAGE( NULL, TAG_WARNING, GetReason() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// report the log message
|
|
bResult = CreateLogEvent( pszServer, szLogName,
|
|
szSource, wEventType, dwEventID, szDescription );
|
|
if ( bResult == TRUE )
|
|
{
|
|
// display the message depending on the mode of conncetivity
|
|
if ( lstrlen( szSource ) != 0 )
|
|
{
|
|
DISPLAY_MESSAGE( stdout, _T( "\n" ) );
|
|
DISPLAY_MESSAGE2(stdout, szBuffer, EVENTCREATE_SUCCESS, szType, szSource);
|
|
}
|
|
else
|
|
{
|
|
DISPLAY_MESSAGE( stdout, _T( "\n" ) );
|
|
DISPLAY_MESSAGE2(stdout, szBuffer, EVENTCREATE_SUCCESS, szType, szLogName);
|
|
}
|
|
|
|
// update the success count
|
|
dwSuccess++;
|
|
}
|
|
else
|
|
{
|
|
// display the message depending on the mode of conncetivity
|
|
// SHOW_RESULT_MESSAGE( pszServer, TAG_ERROR, GetReason() );
|
|
// ( we are temporarily displaying only the error message )
|
|
SHOW_RESULT_MESSAGE( NULL, TAG_ERROR, GetReason() );
|
|
}
|
|
|
|
// close the connection that was established by the utility
|
|
if ( bCloseConnection == TRUE )
|
|
CloseConnection( pszServer );
|
|
}
|
|
|
|
// destroy the dynamic array
|
|
DestroyDynamicArray( &arrServers );
|
|
|
|
// depending the success count, determine whether the exit value
|
|
// FULL SUCCESS / PARTIAL SUCCESS / COMPLETELY FAILED
|
|
return (dwSuccess == dwServers) ? FULL_SUCCESS :
|
|
((dwSuccess == 0) ? COMPLETELY_FAILED : PARTIALLY_SUCCESS);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function connects to the specified server's event log (or) source
|
|
// and appropriately creates the needed event in it.
|
|
//
|
|
// Arguments:
|
|
// [ in ] szServer : server name on which event has to be created.
|
|
// null string has to be passed in order to create
|
|
// event on a local system.
|
|
// [ in ] szLog : Log name in which event has to be created.
|
|
// [ in ] szSource : Source name in which event has to be created.
|
|
// if log name is also specified, log name will be
|
|
// given priority and value in this variable is ignored.
|
|
// [ in ] wType : specifies type of the event that has to be created
|
|
// [ in ] dwEventID : event id for the event is being created
|
|
// [ in ] szDescription : description to the event
|
|
//
|
|
// Return Value:
|
|
// TRUE : if the event creation is successful
|
|
// FALSE : if failed in creating the event
|
|
// ***************************************************************************
|
|
BOOL CreateLogEvent( LPCTSTR szServer, LPCTSTR szLog, LPCTSTR szSource,
|
|
WORD wType, DWORD dwEventID, LPCTSTR szDescription )
|
|
{
|
|
// local variables
|
|
BOOL bReturn = 0; // return value
|
|
BOOL bCustom = FALSE;
|
|
DWORD dwSeverity = 0;
|
|
HANDLE hEventLog = NULL; // points to the event log
|
|
LPCTSTR lpszDescriptions[ 1 ] = { NULL }; // building descriptions
|
|
__MAX_SIZE_STRING szBuffer = NULL_STRING;
|
|
|
|
//
|
|
// start the process
|
|
|
|
// check whether the log / source exists in the registry or not
|
|
bCustom = FALSE;
|
|
if ( CheckExistence( szServer, szLog, szSource, &bCustom ) == FALSE )
|
|
return FALSE; // return failure
|
|
|
|
// check whether the source is custom create or pre-existing source
|
|
if ( bCustom == FALSE )
|
|
{
|
|
// we wont create events in a non-custom source
|
|
SetReason( ERROR_NONCUSTOM_SOURCE );
|
|
return FALSE;
|
|
}
|
|
|
|
// open the appropriate event log using the specified 'source' or 'log file'
|
|
// and check the result of the operation
|
|
// Note: At one time, we will make use of log name (or) source but not both
|
|
if ( lstrlen( szSource ) != 0 )
|
|
hEventLog = RegisterEventSource( szServer, szSource ); // open log using source name
|
|
else
|
|
hEventLog = OpenEventLog( szServer, szLog ); // open log
|
|
|
|
// check the log open/register result
|
|
if ( hEventLog == NULL )
|
|
{
|
|
// opening/registering is failed
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// determine the severity code
|
|
dwSeverity = 0;
|
|
if ( wType == EVENTLOG_ERROR_TYPE )
|
|
dwSeverity = 3;
|
|
else if ( wType == EVENTLOG_WARNING_TYPE )
|
|
dwSeverity = 2;
|
|
else if ( wType == EVENTLOG_INFORMATION_TYPE )
|
|
dwSeverity = 1;
|
|
|
|
// report event
|
|
lpszDescriptions[ 0 ] = szDescription;
|
|
if ( bCustom == TRUE )
|
|
{
|
|
// validate the range of the event id specified
|
|
if ( dwEventID >= MSG_EVENTID_START && dwEventID <= MSG_EVENTID_END )
|
|
{
|
|
// valid event id
|
|
bReturn = ReportEvent( hEventLog, wType, 0, dwEventID, NULL, 1, 0, lpszDescriptions, NULL);
|
|
|
|
// check the result
|
|
if ( bReturn == FALSE )
|
|
SaveLastError(); // save the error info
|
|
}
|
|
else
|
|
{
|
|
// format the error message
|
|
bReturn = FALSE;
|
|
_stprintf( szBuffer, ERROR_ID_OUTOFRANGE, MSG_EVENTID_START, MSG_EVENTID_END - 1 );
|
|
SetReason( szBuffer );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we are stopping from creating the events in a non-custom source
|
|
// ********************************************************************
|
|
// bReturn = ReportEvent( hEventLog, wType, 0,
|
|
// (((unsigned long)(dwSeverity)<<30) | ((unsigned long)(dwEventID))), NULL, 1, 0, lpszDescriptions, NULL);
|
|
|
|
// check the result
|
|
// if ( bReturn == FALSE )
|
|
// SaveLastError(); // save the error info
|
|
}
|
|
|
|
// close the event source
|
|
if ( lstrlen( szSource ) != 0 )
|
|
DeregisterEventSource( hEventLog );
|
|
else
|
|
CloseEventLog( hEventLog );
|
|
|
|
// return the result
|
|
return bReturn;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function checks wether the log name or source name specified
|
|
// actually exists in the registry
|
|
//
|
|
// Arguments:
|
|
// [ in ] szServer - server name
|
|
// [ in ] szLog - log name
|
|
// [ in ] szSource - source name
|
|
//
|
|
// Return Value:
|
|
// TRUE : If log / source exists in the registry
|
|
// FALSE : if failed find the match
|
|
// ***************************************************************************
|
|
BOOL CheckExistence( LPCTSTR szServer, LPCTSTR szLog, LPCTSTR szSource, PBOOL pbCustom )
|
|
{
|
|
// local variables
|
|
DWORD dwSize = 0;
|
|
DWORD dwLogsIndex = 0;
|
|
DWORD dwDisposition = 0;
|
|
DWORD dwSourcesIndex = 0;
|
|
LONG lResult = 0L;
|
|
HKEY hKey = NULL;
|
|
HKEY hLogsKey = NULL;
|
|
HKEY hSourcesKey = NULL;
|
|
BOOL bFoundMatch = FALSE;
|
|
BOOL bDuplicating = FALSE;
|
|
FILETIME ftLastWriteTime; // variable that will hold the last write info
|
|
BOOL bErrorOccurred = FALSE;
|
|
BOOL bLog = FALSE, bLogMatched = FALSE;
|
|
BOOL bSource = FALSE, bSourceMatched = FALSE;
|
|
__MAX_SIZE_STRING szBuffer = NULL_STRING;
|
|
TCHAR szRLog[ MAX_KEY_LENGTH ] = NULL_STRING;
|
|
TCHAR szRSource[ MAX_KEY_LENGTH ] = NULL_STRING;
|
|
|
|
// prepare the server name into UNC format
|
|
lstrcpy( szBuffer, szServer );
|
|
if ( lstrlen( szServer ) != 0 && IsUNCFormat( szServer ) == FALSE )
|
|
{
|
|
// format the server name in UNC format
|
|
FORMAT_STRING( szBuffer, _T( "\\\\%s" ), szServer );
|
|
}
|
|
|
|
// Connect to the registry
|
|
lResult = RegConnectRegistry( szBuffer, HKEY_LOCAL_MACHINE, &hKey );
|
|
if ( lResult != ERROR_SUCCESS)
|
|
{
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// open the "EventLogs" registry key for enumerating its sub-keys (which are log names)
|
|
lResult = RegOpenKeyEx( hKey, EVENT_LOG_NAMES_LOCATION, 0, KEY_READ, &hLogsKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
switch( lResult )
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
SetLastError( ERROR_REGISTRY_CORRUPT );
|
|
break;
|
|
|
|
default:
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
break;
|
|
}
|
|
|
|
// close the key and return
|
|
SaveLastError();
|
|
RegCloseKey( hKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// start enumerating the logs present
|
|
dwLogsIndex = 0; // initialize the logs index
|
|
bFoundMatch = FALSE; // assume neither log (or) source doesn't match
|
|
bErrorOccurred = FALSE; // assume error is not occured
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
bLogMatched = FALSE;
|
|
bSourceMatched = FALSE;
|
|
bDuplicating = FALSE;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Logic:-
|
|
// 1. determine whether user has supplied the log name or not
|
|
// 2. determine whether user has supplied the source name or not
|
|
// 3. Start enumerating all the logs present in the system
|
|
// 4. check whether log is supplied or not, if yes, check whether
|
|
// the current log matches with user supplied one.
|
|
// 5. check whether source is supplied or not, if yes, enumerate the
|
|
// sources available under the current log
|
|
|
|
// determine whether searching has to be done of LOG (or) SOURCE
|
|
bLog = ( szLog != NULL && lstrlen( szLog ) != 0 ) ? TRUE : FALSE; // #1
|
|
bSource = ( szSource != NULL && lstrlen( szSource ) != 0 ) ? TRUE : FALSE; // #2
|
|
|
|
// initiate the enumeration of log present in the system -- #3
|
|
ZeroMemory( szRLog, MAX_KEY_LENGTH * sizeof( TCHAR ) ); // init to 0's - safe check
|
|
lResult = RegEnumKeyEx( hLogsKey, 0, szRLog, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
|
|
// traverse thru the sub-keys until there are no more items -- #3
|
|
do
|
|
{
|
|
// check the result
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// if log name is passed, compare the current key value
|
|
// compare the log name with the current key -- #4
|
|
if ( bLog == TRUE && StringCompare( szLog, szRLog, TRUE, 0 ) == 0 )
|
|
bLogMatched = TRUE;
|
|
|
|
// if source name is passed ... -- #5
|
|
if ( bSource == TRUE && bSourceMatched == FALSE )
|
|
{
|
|
// open the current log name to enumerate the sources under this log
|
|
lResult = RegOpenKeyEx( hLogsKey, szRLog, 0, KEY_READ, &hSourcesKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// start enumerating the sources present
|
|
dwSourcesIndex = 0; // initialize the sources index
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
ZeroMemory( szRSource, MAX_KEY_LENGTH * sizeof( TCHAR ) );
|
|
lResult = RegEnumKeyEx( hSourcesKey, 0,
|
|
szRSource, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
|
|
// traverse thru the sub-keys until there are no more items
|
|
do
|
|
{
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// check whether this key matches with the required source or not
|
|
if ( StringCompare( szSource, szRSource, TRUE, 0 ) == 0 )
|
|
{
|
|
// source matched
|
|
bSourceMatched = TRUE;
|
|
break; // break from the loop
|
|
}
|
|
|
|
// update the sources index and fetch the next source key
|
|
dwSourcesIndex += 1;
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
ZeroMemory( szRSource, MAX_KEY_LENGTH * sizeof( TCHAR ) );
|
|
lResult = RegEnumKeyEx( hSourcesKey, dwSourcesIndex, szRSource, &dwSize, NULL,
|
|
NULL, NULL, &ftLastWriteTime );
|
|
} while( lResult != ERROR_NO_MORE_ITEMS );
|
|
|
|
// close the sources registry key
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL; // clear the key value
|
|
|
|
// check how the loop ended
|
|
// 1. Source might have found
|
|
// Action:- we found required key .. exit from the main loop
|
|
// 2. Error might have occured
|
|
// Action:- ignore the error and continue fetching other log's sources
|
|
// 3. End of sources reached in this log
|
|
// Action:- check if log name is supplied or not.
|
|
// if log specified, then source if not found, break
|
|
// for cases 2 & 3, clear the contents of lResult for smooth processing
|
|
|
|
// Case #2 & #3
|
|
lResult = 0; // we are not much bothered abt the errors
|
|
bErrorOccurred = FALSE; // occured while traversing thru the source under logs
|
|
|
|
// Case #1
|
|
if ( bSourceMatched == TRUE )
|
|
{
|
|
// check whether log is specified or not
|
|
// if log is specified, it should have matched .. otherwise
|
|
// error ... because duplicate source should not be created
|
|
if ( bLog == FALSE || ( bLog && bLogMatched && lstrcmpi( szLog, szRLog ) == 0 ) )
|
|
{
|
|
// no problem ...
|
|
bFoundMatch = TRUE;
|
|
|
|
//
|
|
// determine whether this is custom created source or not
|
|
|
|
// mark this as custom source
|
|
if ( pbCustom != NULL )
|
|
*pbCustom = FALSE;
|
|
|
|
// open the source registry key
|
|
_stprintf( szBuffer, _T( "%s\\%s\\%s" ), EVENT_LOG_NAMES_LOCATION, szRLog, szRSource );
|
|
lResult = RegOpenKeyEx( hKey, szBuffer, 0, KEY_QUERY_VALUE, &hSourcesKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// now query for the value
|
|
lResult = RegQueryValueEx( hSourcesKey, _T( "CustomSource" ), NULL, NULL, NULL, NULL );
|
|
if ( lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
RegCloseKey( hSourcesKey );
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// close the souces key
|
|
RegCloseKey( hSourcesKey );
|
|
|
|
// mark this as custom source
|
|
if ( pbCustom != NULL && lResult == ERROR_SUCCESS )
|
|
*pbCustom = TRUE;
|
|
|
|
// break from the loop
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// this should not be the case .. sources should not be duplicated
|
|
FORMAT_STRING( szBuffer, ERROR_SOURCE_DUPLICATING, szRLog );
|
|
SetReason( szBuffer );
|
|
bDuplicating = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if ( bLogMatched == TRUE && bSource == FALSE )
|
|
{
|
|
// mark this as a custom event source
|
|
if ( pbCustom != NULL )
|
|
*pbCustom = TRUE;
|
|
|
|
// ...
|
|
bFoundMatch = TRUE;
|
|
break;
|
|
}
|
|
else if ( bLogMatched == TRUE && bDuplicating == TRUE )
|
|
{
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// update the sources index and fetch the next log key
|
|
dwLogsIndex += 1;
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
ZeroMemory( szRLog, MAX_KEY_LENGTH * sizeof( TCHAR ) );
|
|
lResult = RegEnumKeyEx( hLogsKey, dwLogsIndex, szRLog, &dwSize, NULL,
|
|
NULL, NULL, &ftLastWriteTime );
|
|
} while( lResult != ERROR_NO_MORE_ITEMS );
|
|
|
|
// close the logs registry key
|
|
RegCloseKey( hLogsKey );
|
|
hLogsKey = NULL;
|
|
|
|
// check whether any error has occured or not in doing above tasks
|
|
if ( bErrorOccurred )
|
|
{
|
|
// close the still opened registry keys
|
|
RegCloseKey( hKey );
|
|
|
|
// return failure
|
|
return FALSE;
|
|
}
|
|
|
|
// now check whether location for creating the event is found or not
|
|
// if not, check for the possibilities to create the source at appropriate location
|
|
// NOTE:-
|
|
// we won't create the logs. also to create the source, user needs to specify
|
|
// the log name in which this source needs to be created.
|
|
if ( bFoundMatch == FALSE )
|
|
{
|
|
if ( bLog == TRUE && bLogMatched == FALSE )
|
|
{
|
|
// log itself was not found ... error message
|
|
FORMAT_STRING( szBuffer, ERROR_LOG_NOTEXISTS, szLog );
|
|
SetReason( szBuffer );
|
|
}
|
|
else if ( bLog && bSource && bLogMatched && bSourceMatched == FALSE )
|
|
{
|
|
//
|
|
// log name and source both were supplied but only log was found
|
|
// so create the source in it
|
|
|
|
// open the "EventLogs\{logname}" registry key for creating new source
|
|
FORMAT_STRING2( szBuffer, _T( "%s\\%s" ), EVENT_LOG_NAMES_LOCATION, szLog );
|
|
lResult = RegOpenKeyEx( hKey, szBuffer, 0, KEY_WRITE, &hLogsKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
switch( lResult )
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
SetLastError( ERROR_REGISTRY_CORRUPT );
|
|
break;
|
|
|
|
default:
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
break;
|
|
}
|
|
|
|
// close the key and return
|
|
SaveLastError();
|
|
RegCloseKey( hKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// now create the subkey with the source name given
|
|
if ( AddEventSource( hLogsKey, szSource ) == FALSE )
|
|
{
|
|
RegCloseKey( hKey );
|
|
RegCloseKey( hLogsKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// creation of new source is successfull
|
|
bFoundMatch = TRUE;
|
|
RegCloseKey( hSourcesKey );
|
|
RegCloseKey( hLogsKey );
|
|
|
|
// mark this as a custom event source
|
|
if ( pbCustom != NULL )
|
|
*pbCustom = TRUE;
|
|
}
|
|
else if ( bLog == FALSE && bSource == TRUE && bSourceMatched == FALSE )
|
|
{
|
|
// else we need both log name and source in order to create the source
|
|
SetReason( ERROR_NEED_LOG_ALSO );
|
|
}
|
|
}
|
|
|
|
// close the currently open registry keys
|
|
RegCloseKey( hKey );
|
|
|
|
// return the result
|
|
return bFoundMatch;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function adds a new source to under the specifie log
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
// TRUE : on success
|
|
// FALSE : on failure
|
|
// ***************************************************************************
|
|
BOOL AddEventSource( HKEY hLogsKey, LPCTSTR pszSource )
|
|
{
|
|
// local variables
|
|
HKEY hSourcesKey;
|
|
LONG lResult = 0;
|
|
DWORD dwData = 0;
|
|
DWORD dwLength = 0;
|
|
DWORD dwDisposition = 0;
|
|
LPTSTR pszBuffer = NULL;
|
|
|
|
// validate the inputs
|
|
if ( hLogsKey == NULL || pszSource == NULL )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// create the custom source
|
|
lResult = RegCreateKeyEx( hLogsKey, pszSource, 0, _T( "" ),
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSourcesKey, &dwDisposition );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// set the name of the message file.
|
|
dwLength = lstrlen( _T( "%SystemRoot%\\System32\\EventCreate.exe" ) );
|
|
pszBuffer = calloc( dwLength + 1, sizeof( TCHAR ) );
|
|
if ( pszBuffer == NULL )
|
|
{
|
|
// set the error
|
|
SetLastError( E_OUTOFMEMORY );
|
|
SaveLastError();
|
|
|
|
// close the created registry key
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// copy the required value into buffer
|
|
lstrcpy( pszBuffer, _T( "%SystemRoot%\\System32\\EventCreate.exe" ) );
|
|
|
|
// add the name to the EventMessageFile subkey.
|
|
lResult = RegSetValueEx( hSourcesKey,
|
|
_T( "EventMessageFile" ), 0, REG_EXPAND_SZ, (LPBYTE) pszBuffer, (dwLength + 1) * sizeof( TCHAR ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
if ( pszBuffer != NULL )
|
|
{
|
|
free( pszBuffer );
|
|
pszBuffer = NULL;
|
|
}
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// set the supported event types in the TypesSupported subkey.
|
|
dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
|
|
lResult = RegSetValueEx( hSourcesKey, _T( "TypesSupported" ), 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
if ( pszBuffer != NULL )
|
|
{
|
|
free( pszBuffer );
|
|
pszBuffer = NULL;
|
|
}
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// mark this source as custom created source
|
|
dwData = 1;
|
|
lResult = RegSetValueEx( hSourcesKey, _T( "CustomSource" ), 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
if ( pszBuffer != NULL )
|
|
{
|
|
free( pszBuffer );
|
|
pszBuffer = NULL;
|
|
}
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// close the key
|
|
RegCloseKey( hSourcesKey );
|
|
|
|
// free the allocated memory
|
|
if ( pszBuffer != NULL )
|
|
{
|
|
free( pszBuffer );
|
|
pszBuffer = NULL;
|
|
}
|
|
|
|
// return success
|
|
return TRUE;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function parses the options specified at the command prompt
|
|
//
|
|
// Arguments:
|
|
// [ in ] argc : count of elements in argv
|
|
// [ in ] argv : command-line parameterd specified by the user
|
|
// [ out ] pbShowUsage : sets to TRUE if -? exists in 'argv'
|
|
// [ out ] parrServers : value(s) specified with -s ( server ) option in 'argv'
|
|
// [ out ] pszUserName : value of -u ( username ) option in 'argv'
|
|
// [ out ] pszPassword : value of -p ( password ) option in 'argv'
|
|
// [ out ] pszLogName : value of -log ( log name ) option in 'argv'
|
|
// [ out ] pszLogSource : value of -source ( source name ) option in 'argv'
|
|
// [ out ] pszLogType : value of -type ( log type ) option in 'argv'
|
|
// [ out ] pdwEventID : value of -id ( event id ) option in 'argv'
|
|
// [ out ] pszDescription : value of -description ( description ) option in 'argv'
|
|
// [ out ] pbNeedPwd : sets to TRUE if -s exists without -p in 'argv'
|
|
//
|
|
// Return Value:
|
|
// TRUE : the parsing is successful
|
|
// FALSE : errors occured in parsing
|
|
// ***************************************************************************
|
|
BOOL ProcessOptions( LONG argc,
|
|
LPCTSTR argv[],
|
|
PBOOL pbShowUsage,
|
|
PTARRAY parrServers, LPTSTR pszUserName, LPTSTR pszPassword,
|
|
LPTSTR pszLogName, LPTSTR pszLogSource, LPTSTR pszLogType,
|
|
PDWORD pdwEventID, LPTSTR pszDescription, PBOOL pbNeedPwd )
|
|
{
|
|
// local variables
|
|
LPTSTR pszDup = NULL;
|
|
LPCTSTR pszServer = NULL;
|
|
PTCMDPARSER pcmdOption = NULL;
|
|
TCMDPARSER cmdOptions[ MAX_OPTIONS ];
|
|
|
|
//
|
|
// prepare the command options
|
|
ZeroMemory( cmdOptions, sizeof( TCMDPARSER ) * MAX_OPTIONS );
|
|
|
|
// init the password with "*"
|
|
if ( pszPassword != NULL )
|
|
{
|
|
lstrcpy( pszPassword, _T( "*" ) );
|
|
}
|
|
|
|
// -?
|
|
pcmdOption = &cmdOptions[ OI_HELP ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_USAGE;
|
|
pcmdOption->pValue = pbShowUsage;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_HELP );
|
|
|
|
// -s
|
|
pcmdOption = &cmdOptions[ OI_SERVER ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags =
|
|
CP_TYPE_TEXT | CP_VALUE_NODUPLICATES | CP_MODE_ARRAY | CP_VALUE_MANDATORY;
|
|
pcmdOption->pValue = parrServers;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_SERVER );
|
|
|
|
// -u
|
|
pcmdOption = &cmdOptions[ OI_USERNAME ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
|
|
pcmdOption->pValue = pszUserName;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_USERNAME );
|
|
|
|
// -p
|
|
pcmdOption = &cmdOptions[ OI_PASSWORD ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_OPTIONAL;
|
|
pcmdOption->pValue = pszPassword;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_PASSWORD );
|
|
|
|
// -log
|
|
pcmdOption = &cmdOptions[ OI_LOG ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
|
|
pcmdOption->pValue = pszLogName;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_LOG );
|
|
|
|
// -type
|
|
pcmdOption = &cmdOptions[ OI_TYPE ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY | CP_MODE_VALUES | CP_MANDATORY;
|
|
pcmdOption->pValue = pszLogType;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, OVALUES_TYPE );
|
|
lstrcpy( pcmdOption->szOption, OPTION_TYPE );
|
|
|
|
// -source
|
|
pcmdOption = &cmdOptions[ OI_SOURCE ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
|
|
pcmdOption->pValue = pszLogSource;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_SOURCE );
|
|
|
|
// -id
|
|
pcmdOption = &cmdOptions[ OI_ID ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_UNUMERIC | CP_VALUE_MANDATORY | CP_MANDATORY;
|
|
pcmdOption->pValue = pdwEventID;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_ID );
|
|
|
|
// -description
|
|
pcmdOption = &cmdOptions[ OI_DESCRIPTION ];
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwActuals = 0;
|
|
pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY | CP_MANDATORY;
|
|
pcmdOption->pValue = pszDescription;
|
|
pcmdOption->pFunction = NULL;
|
|
pcmdOption->pFunctionData = NULL;
|
|
lstrcpy( pcmdOption->szValues, NULL_STRING );
|
|
lstrcpy( pcmdOption->szOption, OPTION_DESCRIPTION );
|
|
|
|
//
|
|
// do the parsing
|
|
if ( DoParseParam( argc, argv, MAX_OPTIONS, cmdOptions ) == FALSE )
|
|
return FALSE; // invalid syntax
|
|
|
|
//
|
|
// now, check the mutually exclusive options
|
|
|
|
// check the usage option
|
|
if ( *pbShowUsage == TRUE )
|
|
{
|
|
if ( argc > 2 )
|
|
{
|
|
// no other options are accepted along with -? option
|
|
SetLastError( MK_E_SYNTAX );
|
|
SetReason( ERROR_INVALID_USAGE_REQUEST );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// no need of furthur checking of the values
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// empty system is not valid
|
|
if ( cmdOptions[ OI_SERVER ].dwActuals != 0 )
|
|
{
|
|
// get the server name
|
|
pszServer = DynArrayItemAsString( *parrServers, 0 );
|
|
if ( pszServer != NULL )
|
|
{
|
|
// get the duplicate of this server name
|
|
// we need to trim the value and then check
|
|
pszDup = _tcsdup( pszServer );
|
|
if ( pszDup == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// trim the string value
|
|
TrimString( pszDup, TRIM_ALL );
|
|
|
|
// check the length now
|
|
if ( lstrlen( pszDup ) == 0 )
|
|
{
|
|
// release the memory and return error
|
|
free( pszDup );
|
|
pszDup = NULL;
|
|
SetLastError( MK_E_SYNTAX );
|
|
SetReason( ERROR_SYSTEM_EMPTY );
|
|
return FALSE;
|
|
}
|
|
|
|
// release memory
|
|
free( pszDup );
|
|
pszDup = NULL;
|
|
}
|
|
}
|
|
|
|
// "-u" should not be specified without "-s"
|
|
if ( cmdOptions[ OI_SERVER ].dwActuals == 0 &&
|
|
cmdOptions[ OI_USERNAME ].dwActuals != 0 )
|
|
{
|
|
// invalid syntax
|
|
SetReason( ERROR_USERNAME_BUT_NOMACHINE );
|
|
return FALSE; // indicate failure
|
|
}
|
|
|
|
// empty user is not valid
|
|
TrimString( pszUserName, TRIM_ALL ); // trim the string
|
|
if ( cmdOptions[ OI_USERNAME ].dwActuals != 0 && lstrlen( pszUserName ) == 0 )
|
|
{
|
|
// invalid syntax
|
|
SetReason( ERROR_USERNAME_EMPTY );
|
|
return FALSE;
|
|
}
|
|
|
|
// "-p" should not be specified without "-u"
|
|
if ( cmdOptions[ OI_USERNAME ].dwActuals == 0 &&
|
|
cmdOptions[ OI_PASSWORD ].dwActuals != 0 )
|
|
{
|
|
// invalid syntax
|
|
SetReason( ERROR_PASSWORD_BUT_NOUSERNAME );
|
|
return FALSE; // indicate failure
|
|
}
|
|
|
|
// check whether caller should accept the password or not
|
|
// if -s ( server ) or -u ( username ) is specified
|
|
// but no "-p", then utility should accept password
|
|
// provided if establish connection is failed without the credentials information
|
|
if ( cmdOptions[ OI_PASSWORD ].dwActuals != 0 &&
|
|
pszPassword != NULL && lstrcmp( pszPassword, _T( "*" ) ) == 0 )
|
|
{
|
|
// user wants the utility to prompt for the password before trying to connect
|
|
*pbNeedPwd = TRUE;
|
|
}
|
|
else if ( cmdOptions[ OI_PASSWORD ].dwActuals == 0 &&
|
|
( cmdOptions[ OI_SERVER ].dwActuals != 0 || cmdOptions[ OI_USERNAME ].dwActuals != 0 ) )
|
|
{
|
|
// -s, -u is specified without password ...
|
|
// utility needs to try to connect first and if it fails then prompt for the password
|
|
*pbNeedPwd = TRUE;
|
|
if ( pszPassword != NULL )
|
|
{
|
|
lstrcpy( pszPassword, _T( "" ) );
|
|
}
|
|
}
|
|
|
|
// event id should be greater than 0 ( zero ) and less than 65536
|
|
if ( *pdwEventID <= 0 || *pdwEventID >= 65536 )
|
|
{
|
|
// invalid numeric value
|
|
SetReason( ERROR_INVALID_EVENT_ID );
|
|
return FALSE;
|
|
}
|
|
|
|
// description should not be empty
|
|
TrimString( pszDescription, TRIM_ALL ); // trim the string
|
|
if ( lstrlen( pszDescription ) == 0 )
|
|
{
|
|
// description is null
|
|
SetReason( ERROR_DESCRIPTION_IS_EMPTY );
|
|
return FALSE;
|
|
}
|
|
|
|
// either -source (or) -log must be specified ( both can also be specified )
|
|
if ( cmdOptions[ OI_SOURCE ].dwActuals == 0 && cmdOptions[ OI_LOG ].dwActuals == 0 )
|
|
{
|
|
// if log name and application were not specified, we will set to defaults
|
|
lstrcpy( pszLogName, g_szDefaultLog );
|
|
lstrcpy( pszLogSource, g_szDefaultSource );
|
|
}
|
|
|
|
// -source option value should not be empty ( if specified )
|
|
TrimString( pszLogSource, TRIM_ALL ); // trim the string
|
|
if ( cmdOptions[ OI_SOURCE ].dwActuals != 0 && lstrlen( pszLogSource ) == 0 )
|
|
{
|
|
// description is null
|
|
SetReason( ERROR_LOGSOURCE_IS_EMPTY );
|
|
return FALSE;
|
|
}
|
|
|
|
// -log option value should not be empty ( if specified )
|
|
TrimString( pszLogName, TRIM_ALL ); // trim the string
|
|
if ( cmdOptions[ OI_LOG ].dwActuals != 0 && lstrlen( pszLogName ) == 0 )
|
|
{
|
|
// description is null
|
|
SetReason( ERROR_LOGSOURCE_IS_EMPTY );
|
|
return FALSE;
|
|
}
|
|
|
|
// check whether atleast one -s is specified or not ... if not, add 'null string' to
|
|
// the servers array so that default it will work for local system
|
|
if ( cmdOptions[ OI_SERVER ].dwActuals == 0 )
|
|
DynArrayAppendString( *parrServers, NULL_STRING, 0 );
|
|
|
|
// command-line parsing is successfull
|
|
return TRUE;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function fetches usage information from resource file and shows it
|
|
//
|
|
// Arguments:
|
|
// None
|
|
//
|
|
// Return Value:
|
|
// None
|
|
// ***************************************************************************
|
|
VOID Usage()
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
|
|
// start displaying the usage
|
|
for( dw = ID_USAGE_START; dw <= ID_USAGE_END; dw++ )
|
|
ShowMessage( stdout, GetResString( dw ) );
|
|
}
|