/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    ELTEST.C

Abstract:

    Test Routines for the EventLog.

THINGS I WANT THIS TO DO...
    AddReg <ServerName> <logname> <EntryName> <EventMessageFile>
        <CategoryMessageFile> <CategoryCount> <ParameterMessageFile>
        <TypesSupported>   - Creates A Registry Entry.

        eltest addreg application mytest mf= eltest.dll cat=

    CreateMessageFile <??? Is this possible ???>

    WriteEvent <ServerName> <EventSource> <Type> <Category> <EventId> <UserSid?>
        <NumStrings> <Strings> <RawData>

    ReadLog <Server> <LogFile> <ReadFlags> <RecordOffset> <bufSize>
        If LogFile isn't one of the popular ones, then it could be a backup
        logfile.

    GetNumEvents <Server> <LogFile>

    GetOldest <Server> <LogFile>

    Clear <Server> <LogFile>

    Backup <Server> <LogFile> <BackupFile>


    LOOPTESTS....
    I should be able to run this test like mprtest such that it doesn't leave
    the test process until told.  This way we can register an event source,
    then if we call WriteEvent without a specified EventSource, it will use
    the stored source.  Calling RegisterEventSource twice without calling
    DeRegisterSource would be an error.  (Or better yet, I could keep a table
    of sources and handles).

    RegisterEventSource <EventSource>
    DeRegisterSource <EventSource>




PROTOTYPES FOR FUNCTION....

BOOL
CloseEventLog (
    HANDLE hEventLog
    )
BOOL
DeregisterEventSource (
    HANDLE hEventLog
    )

BOOL
NotifyChangeEventLog(
    HANDLE  hEventLog,
    HANDLE  hEvent
    )
BOOL
GetNumberOfEventLogRecords (
    HANDLE hEventLog,
    PDWORD NumberOfRecords
    )
BOOL
GetOldestEventLogRecord (
    HANDLE hEventLog,
    PDWORD OldestRecord
    )
BOOL
ClearEventLogW (
    HANDLE hEventLog,
    LPCWSTR BackupFileName
    )
BOOL
BackupEventLogW (
    HANDLE hEventLog,
    LPCWSTR BackupFileName
    )
HANDLE
OpenEventLogW (
    LPCWSTR  UNCServerName,
    LPCWSTR  ModuleName
    )
HANDLE
RegisterEventSourceW (
    LPCWSTR  UNCServerName,
    LPCWSTR  ModuleName
    )
HANDLE
OpenBackupEventLogW (
    LPCWSTR  UNCServerName,
    LPCWSTR  FileName
    )
BOOL
ReadEventLogW (
    HANDLE      hEventLog,
    DWORD       dwReadFlags,
    DWORD       dwRecordOffset,
    LPVOID      lpBuffer,
    DWORD       nNumberOfBytesToRead,
    DWORD       *pnBytesRead,
    DWORD       *pnMinNumberOfBytesNeeded
    )
BOOL
ReportEventW (
    HANDLE      hEventLog,
    WORD        wType,
    WORD        wCategory       OPTIONAL,
    DWORD       dwEventID,
    PSID        lpUserSid       OPTIONAL,
    WORD        wNumStrings,
    DWORD       dwDataSize,
    LPCWSTR     *lpStrings      OPTIONAL,
    LPVOID      lpRawData       OPTIONAL
    )




Author:

    Dan Lafferty    (danl)  09-March-1994

Environment:

    User Mode - Win32

Revision History:

    09-Mar-1994     danl
        created

--*/

//
// INCLUDES
//
#define UNICODE 1
#include <nt.h>         // DbgPrint prototype
#include <ntrtl.h>      // DbgPrint prototype
#include <nturtl.h>     // needed for winbase.h


#include <stdlib.h>     // atoi
#include <stdio.h>      // printf
#include <conio.h>      // getch
#include <string.h>     // strcmp
#include <windows.h>    // win32 typedefs
#include <tstr.h>       // Unicode
#include <debugfmt.h>   // FORMAT_LPTSTR

//------------------
// DEFINES
//------------------
#define APPLICATION_LOG     "Application"
#define SYSTEM_LOG          "System"
#define SECURITY_LOG        "Security"

#define REG_APPLICATION_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"
#define REG_SYSTEM_KEY      "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\"
#define REG_SECURITY_KEY    "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Security\\"

#define EVENT_SOURCE_NAME       "tevent"
#define MSG_DLL                 "%SystemRoot%\\System32\\tevent.dll"

#define VALUE_EVENT_MF          TEXT("EventMessageFile")
#define VALUE_CATEGORY_MF       TEXT("CategoryMessageFile")
#define VALUE_PARAMETER_MF      TEXT("ParameterMessageFile")
#define VALUE_TYPES_SUPPORTED   TEXT("TypesSupported")
#define VALUE_CATEGORY_COUNT    TEXT("CategoryCount")

#define TYPES_SUPPORTED        (EVENTLOG_ERROR_TYPE     |   \
                                EVENTLOG_WARNING_TYPE   |   \
                                EVENTLOG_INFORMATION_TYPE)
//----------------------
// GLOBALS
//----------------------
    LPTSTR  ApplLogRegName=TEXT(REG_APPLICATION_KEY);
    LPTSTR  SysLogRegName =TEXT(REG_SYSTEM_KEY);
    LPTSTR  SecLogRegName =TEXT(REG_SECURITY_KEY);
    LPTSTR  ApplLogName   = TEXT(APPLICATION_LOG);
    LPTSTR  SysLogName    = TEXT(SYSTEM_LOG);
    LPTSTR  SecLogName    = TEXT(SECURITY_LOG);

//----------------------
// FUNCTION PROTOTYPES
//----------------------

VOID
AddRegUsage(VOID);

DWORD
AddSourceToRegistry(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  LogName,
    IN  LPTSTR  EventSourceName,
    IN  LPTSTR  *argv,
    IN  DWORD   argc
    );

BOOL
ConvertToUnicode(
    OUT LPWSTR  *UnicodeOut,
    IN  LPSTR   AnsiIn
    );

DWORD
DelSourceInRegistry(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  LogName,
    IN  LPTSTR  EventSourceName
    );

VOID
DisplayStatus (
    IN  LPTSTR              ServiceName,
    IN  LPTSTR              DisplayName,
    IN  LPSERVICE_STATUS    ServiceStatus
    );

BOOL
MakeArgsUnicode (
    DWORD           argc,
    PCHAR           argv[]
    );

BOOL
ProcessArgs (
    LPTSTR      ServerName,
    DWORD       argc,
    LPTSTR      argv[]
    );

VOID
Usage(
    VOID);

VOID
ConfigUsage(VOID);

VOID
CreateUsage(VOID);

VOID
QueryUsage(VOID);

LONG
wtol(
    IN LPWSTR string
    );

VOID
UserInputLoop(
    LPTSTR  ServerName
    );
DWORD
ReadLogFile(
    LPTSTR  ServerName,
    LPTSTR  LogName,
    IN  LPTSTR  *argv,
    IN  DWORD   argc
    );
VOID
ReadLogUsage(VOID);

VOID
DisplayRecord(
    PEVENTLOGRECORD     pElRecord,
    BOOL                PrintTheHeader
    );

/****************************************************************************/
VOID _CRTAPI1
main (
    DWORD           argc,
    PCHAR           argvAnsi[]
    )

/*++

Routine Description:

    Allows manual testing of the EVENTLOG API.

        eltest



Arguments:



Return Value:



--*/
{
    UCHAR   i;
    DWORD   j;
    DWORD   argIndex;
    LPTSTR  pServerName=NULL;
    LPTSTR  *argv;

    if (argc <2) {
        Usage();
        return;
    }

    //
    // Make the arguments unicode if necessary.
    //
#ifdef UNICODE
    if (!MakeArgsUnicode(argc, argvAnsi)) {
        return;
    }
#endif

    argv = (LPTSTR *)argvAnsi;

    argIndex = 1;
    if (STRNCMP (argv[1], TEXT("\\\\"), 2) == 0) {
        pServerName = argv[1];
        argIndex = 2;               // skip over servername.
    }

    //
    // Check to see if we are to run in Loop Mode, or in single function
    // mode.  In Loop Mode, we go into a loop, and ask the user for
    // input until the user decides to quit.
    //
    // Process Arguments:
    //
    // INDEX   0       1            2              3
    //         EL <ServerName> <Function> <FunctionOptions...>
    //

    if (STRICMP (argv[argIndex], TEXT("Loop")) == 0) {
        UserInputLoop(pServerName);
    }
    else {
        ProcessArgs(pServerName, argc-argIndex, &(argv[argIndex]));
    }


#ifdef UNICODE
    //
    // Free up the unicode strings if there are any
    //
    for(j=0; j<argc; j++) {
        LocalFree(argv[j]);
    }
#endif

    return;
}

VOID
UserInputLoop(
    LPTSTR  ServerName
    )

/*++

Routine Description:

    This function sits in a loop, gathering input from the user, and
    processing that input until the user indicates that it should stop.
    The following user commands indicate that we should stop:
        done
        exit
        stop
        quit

Arguments:


Return Value:


--*/
{
    UCHAR   i;
    DWORD   j;
    LPTSTR  *argv;
    UCHAR   buffer[255];
    LPSTR   argvA[20];
    DWORD   argc=0;
    BOOL    KeepGoing;

    do {
        //------------------------------
        // Get input from the user
        //------------------------------
        buffer[0] = 90-2;

        printf("\nwaiting for instructions... \n");
        cgets(buffer);

        if (buffer[1] > 0) {
            //--------------------------------------
            // put the string in argv/argc format.
            //--------------------------------------
            buffer[1]+=2;       // make this an end offset
            argc=0;
            for (i=2,j=0; i<buffer[1]; i++,j++) {
                argc++;
                argvA[j] = &(buffer[i]);
                while ((buffer[i] != ' ') && (buffer[i] != '\0')) {
                    i++;
                }
                buffer[i] = '\0';
            }

            //------------------------------------------
            // Make the arguments unicode if necessary.
            //------------------------------------------
#ifdef UNICODE

            if (!MakeArgsUnicode(argc, argvA)) {
                return;
            }

#endif
            //-----------------------------------------------
            // If the first argument doesn't indicate that
            // we should stop, then process the arguments.
            //-----------------------------------------------
            argv = (LPTSTR *)argvA;

            if((STRICMP (argv[0], TEXT("done")) == 0) ||
               (STRICMP (argv[0], TEXT("stop")) == 0) ||
               (STRICMP (argv[0], TEXT("exit")) == 0) ||
               (STRICMP (argv[0], TEXT("quit")) == 0)) {
                KeepGoing  = FALSE;
            }
            else {
                KeepGoing = ProcessArgs(ServerName, argc, argv);
            }

#ifdef UNICODE
            //-----------------------------------------------
            // Free up the unicode strings if there are any
            //-----------------------------------------------
            for(j=0; j<argc; j++) {
                LocalFree(argv[j]);
            }
#endif
        }
    } while (KeepGoing);

    return;

}

/****************************************************************************/
BOOL
ProcessArgs (
    LPTSTR      ServerName,
    DWORD       argc,
    LPTSTR      argv[]
    )

/*++

Routine Description:


Arguments:



Return Value:



--*/

{
    DWORD           status;
    DWORD           specialFlag = FALSE;
    DWORD           argIndex;       // index to unchecked portion of arglist.


    argIndex = 0;

    //
    // If we are adding a registry entry, the get a handle to it.
    // Otherwise, get a handle to the LogFile.
    //
    //-----------------------
    // AddSourceToRegistry
    //-----------------------
    if (STRICMP (argv[argIndex], TEXT("AddReg")) == 0 ) {

        //
        // Must have at least "AddReg logname EntryName"
        //
        if (argc < (argIndex + 3)) {
            AddRegUsage();
            goto CleanExit;
        }

        status = AddSourceToRegistry(
                    ServerName,
                    argv[argIndex+1],    // LogName
                    argv[argIndex+2],    // SourceName
                    &argv[argIndex+1],
                    argc-(argIndex+2)
                    );
    }
    //-----------------------
    // DeleteFromRegistry
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("DelReg")) == 0) {
        //
        // Must have at least "DelReg logname EntryName"
        //
        if (argc < (argIndex + 3)) {
            goto CleanExit;
        }

        status = DelSourceInRegistry(
                    ServerName,
                    argv[argIndex+1],    // LogName
                    argv[argIndex+2]     // SourceName
                    );

    }
    //-----------------------
    // WriteEvent
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("WriteEvent")) == 0) {
        printf("In WriteEvent\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // ReadLog
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("ReadLog")) == 0) {
        printf("In ReadLog\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
        //
        // Must have at least "ReadLog logname"
        //
        if (argc < (argIndex + 2)) {
            ReadLogUsage();
            goto CleanExit;
        }

        status = ReadLogFile(
                    ServerName,         // ServerName
                    argv[argIndex+1],   // LogName
                    &argv[argIndex+1],  // argv
                    argc-(argIndex+1)); // argc
    }
    //-----------------------
    // GetNumEvents
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("GetNumEvents")) == 0) {
        printf("in GetNumEvents\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // GetOldest
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("GetOldest")) == 0) {
        printf("in GetOldest\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // ClearLog
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("ClearLog")) == 0) {
        printf("in ClearLog\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // Backup
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("Backup")) == 0) {
        printf("in Backup\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // RegisterSource
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("RegisterSource")) == 0) {
        printf("in RegisterSource\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //-----------------------
    // DeRegisterSource
    //-----------------------
    else if (STRICMP (argv[argIndex], TEXT("DeRegisterSource")) == 0) {
        printf("in DeRegisterSource\n");
        if (ServerName != NULL) {
            printf("ServerName = "FORMAT_LPTSTR"\n",ServerName);
        }
    }
    //****************
    // Exit Program
    //****************
    else if (STRICMP (argv[0], TEXT("Exit")) == 0) {
        //
        // THIS SHOULD CLOSE HANDLES.
        //
        return(FALSE);
    }
    else {
        printf("Bad argument\n");
        Usage();
    }

CleanExit:


    return(TRUE);
}



BOOL
MakeArgsUnicode (
    DWORD           argc,
    PCHAR           argv[]
    )


/*++

Routine Description:


Arguments:


Return Value:


Note:


--*/
{
    DWORD   i;

    //
    // ScConvertToUnicode allocates storage for each string.
    // We will rely on process termination to free the memory.
    //
    for(i=0; i<argc; i++) {

        if(!ConvertToUnicode( (LPWSTR *)&(argv[i]), argv[i])) {
            printf("Couldn't convert argv[%d] to unicode\n",i);
            return(FALSE);
        }


    }
    return(TRUE);
}

BOOL
ConvertToUnicode(
    OUT LPWSTR  *UnicodeOut,
    IN  LPSTR   AnsiIn
    )

/*++

Routine Description:

    This function translates an AnsiString into a Unicode string.
    A new string buffer is created by this function.  If the call to
    this function is successful, the caller must take responsibility for
    the unicode string buffer that was allocated by this function.
    The allocated buffer should be free'd with a call to LocalFree.

    NOTE:  This function allocates memory for the Unicode String.

    BUGBUG:  This should be changed to return either
        ERROR_NOT_ENOUGH_MEMORY or ERROR_INVALID_PARAMETER

Arguments:

    AnsiIn - This is a pointer to an ansi string that is to be converted.

    UnicodeOut - This is a pointer to a location where the pointer to the
        unicode string is to be placed.

Return Value:

    TRUE - The conversion was successful.

    FALSE - The conversion was unsuccessful.  In this case a buffer for
        the unicode string was not allocated.

--*/
{

    NTSTATUS        ntStatus;
    DWORD           bufSize;
    UNICODE_STRING  unicodeString;
    ANSI_STRING     ansiString;

    //
    // Allocate a buffer for the unicode string.
    //

    bufSize = (strlen(AnsiIn)+1) * sizeof(WCHAR);

    *UnicodeOut = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT)bufSize);

    if (*UnicodeOut == NULL) {
        printf("ScConvertToUnicode:LocalAlloc Failure %ld\n",GetLastError());
        return(FALSE);
    }

    //
    // Initialize the string structures
    //
    RtlInitAnsiString( &ansiString, AnsiIn);

    unicodeString.Buffer = *UnicodeOut;
    unicodeString.MaximumLength = (USHORT)bufSize;
    unicodeString.Length = 0;

    //
    // Call the conversion function.
    //
    ntStatus = RtlAnsiStringToUnicodeString (
                &unicodeString,     // Destination
                &ansiString,        // Source
                (BOOLEAN)FALSE);    // Allocate the destination

    if (!NT_SUCCESS(ntStatus)) {

        printf("ScConvertToUnicode:RtlAnsiStringToUnicodeString Failure %lx\n",
        ntStatus);

        return(FALSE);
    }

    //
    // Fill in the pointer location with the unicode string buffer pointer.
    //
    *UnicodeOut = unicodeString.Buffer;

    return(TRUE);

}

/****************************************************************************/
VOID
DisplayStatus (
    IN  LPTSTR              ServiceName,
    IN  LPTSTR              DisplayName,
    IN  LPSERVICE_STATUS    ServiceStatus
    )

/*++

Routine Description:

    Displays the service name and  the service status.

    |
    |SERVICE_NAME: messenger
    |DISPLAY_NAME: messenger
    |        TYPE       : WIN32
    |        STATE      : ACTIVE,STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN
    |        EXIT_CODE  : 0xC002001
    |        CHECKPOINT : 0x00000001
    |        WAIT_HINT  : 0x00003f21
    |

Arguments:

    ServiceName - This is a pointer to a string containing the name of
        the service.

    DisplayName - This is a pointer to a string containing the display
        name for the service.

    ServiceStatus - This is a pointer to a SERVICE_STATUS structure from
        which information is to be displayed.

Return Value:

    none.

--*/
{

    printf("\nSERVICE_NAME: "FORMAT_LPTSTR"\n", ServiceName);
    if (DisplayName != NULL) {
        printf("DISPLAY_NAME: "FORMAT_LPTSTR"\n", DisplayName);
    }

    printf("        TYPE               : %lx  ", ServiceStatus->dwServiceType);

    switch(ServiceStatus->dwServiceType){
    case SERVICE_WIN32_OWN_PROCESS:
        printf("WIN32_OWN_PROCESS \n");
        break;
    case SERVICE_WIN32_SHARE_PROCESS:
        printf("WIN32_SHARE_PROCESS \n");
        break;
    case SERVICE_WIN32:
        printf("WIN32 \n");
        break;
    case SERVICE_ADAPTER:
        printf("ADAPTER \n");
        break;
    case SERVICE_KERNEL_DRIVER:
        printf("KERNEL_DRIVER \n");
        break;
    case SERVICE_FILE_SYSTEM_DRIVER:
        printf("FILE_SYSTEM_DRIVER \n");
        break;
    case SERVICE_DRIVER:
        printf("DRIVER \n");
        break;
    default:
        printf(" ERROR \n");
    }

    printf("        STATE              : %lx  ", ServiceStatus->dwCurrentState);

    switch(ServiceStatus->dwCurrentState){
        case SERVICE_STOPPED:
            printf("STOPPED ");
            break;
        case SERVICE_START_PENDING:
            printf("START_PENDING ");
            break;
        case SERVICE_STOP_PENDING:
            printf("STOP_PENDING ");
            break;
        case SERVICE_RUNNING:
            printf("RUNNING ");
            break;
        case SERVICE_CONTINUE_PENDING:
            printf("CONTINUE_PENDING ");
            break;
        case SERVICE_PAUSE_PENDING:
            printf("PAUSE_PENDING ");
            break;
        case SERVICE_PAUSED:
            printf("PAUSED ");
            break;
        default:
            printf(" ERROR ");
    }

    //
    // Print Controls Accepted Information
    //

    if (ServiceStatus->dwControlsAccepted & SERVICE_ACCEPT_STOP) {
        printf("\n                                (STOPPABLE,");
    }
    else {
        printf("\n                                (NOT_STOPPABLE,");
    }

    if (ServiceStatus->dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) {
        printf("PAUSABLE,");
    }
    else {
        printf("NOT_PAUSABLE,");
    }

    if (ServiceStatus->dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) {
        printf("ACCEPTS_SHUTDOWN)\n");
    }
    else {
        printf("IGNORES_SHUTDOWN)\n");
    }

    //
    // Print Exit Code
    //
    printf("        WIN32_EXIT_CODE    : %d\t(0x%lx)\n",
        ServiceStatus->dwWin32ExitCode,
        ServiceStatus->dwWin32ExitCode);
    printf("        SERVICE_EXIT_CODE  : %d\t(0x%lx)\n",
        ServiceStatus->dwServiceSpecificExitCode,
        ServiceStatus->dwServiceSpecificExitCode  );

    //
    // Print CheckPoint & WaitHint Information
    //

    printf("        CHECKPOINT         : 0x%lx\n", ServiceStatus->dwCheckPoint);
    printf("        WAIT_HINT          : 0x%lx\n", ServiceStatus->dwWaitHint  );

    return;
}

VOID
Usage(
    VOID)
{
    printf("DESCRIPTION:\n");
    printf("\tEL is a command line program used for testing the eventlog \n");
    printf("USAGE:\n");
    printf("\tEL <ServerName> [Function] <FunctionOptions...> \n\n");
    printf("\tThe option <server> has the form \"\\\\ServerName\"\n");
    printf("\tFurther help on Functions can be obtained by typing: \"el [Function]\"\n");
    printf("\tFunctions:\n"
           "\t  AddReg-----------Creates a registry entry for an event source.\n"
           "\t  DelReg-----------Deletes a registry entry.\n"
           "\t  WriteEvent-------Writes an event.\n"
           "\t  ReadLog----------Reads from the logfile.\n"
           "\t  GetNumEvents-----Gets the number of events in the specified log.\n"
           "\t  GetOldest--------Gets the record number for the oldest record"
           "\t                   in the log\n"
           "\t  ClearLog---------Clears the specified Log.\n"
           "\t  Backup-----------Copies the specified log to a new file.\n"
           "\t  RegisterSource---Registers a name for the event source.\n"
           "\t                   The handle is stored internally.\n"
           "\t  DeRegisterSource-Closes handle opened with RegSource.\n"
           "\t  NotifyChange-----A thread is created which gets notified of EL changes.\n");

    printf("\n");
}

VOID
AddRegUsage(VOID)
{

    printf("\nAdds a subkey under one of the logfiles listed in the registry.\n");
    printf("SYNTAX: \n  eltest addreg <ServerName> logfile <SubKeyName> <option1> <option2>...\n");
    printf("ADDREG OPTIONS:\n");
    printf("NOTE: The option name includes the equal sign.\n");

    printf("    MsgFile=    Name of Event Message File\n"
           "    CatFile=    Name of Category Message File\n"
           "    ParamFile=  Name of Parameter Message File\n"
           "    CatCount=   Category Count\n"
           "    Type=       <error|warning|information|AuditSuccess|AuditFailure|All>\n");
    printf("EXAMPLE:\n   eltest addreg application myapp MsgFile= MyMsgs.dll"
           " Type= error Type= warning\n");

}

VOID
ConfigUsage(VOID)
{
    printf("Modifies a service entry in the registry and Service Database.\n");
    printf("SYNTAX: \nsc config <service> <option1> <option2>...\n");
    printf("CONFIG OPTIONS:\n");
    printf("NOTE: The option name includes the equal sign.\n"
        " type= <own|share|kernel|filesys|rec|adapt|error>\n"
        " start= <boot|system|auto|demand|disabled|error>\n"
        " error= <normal|severe|critical|error|ignore>\n"
        " binPath= <BinaryPathName>\n"
        " group= <LoadOrderGroup>\n"
        " tag= <yes|no>\n"
        " depend= <Dependencies(space seperated)>\n"
        " obj= <AccountName|ObjectName>\n"
        " DisplayName= <display name>\n"
        " password= <password> \n");
}
VOID
CreateUsage(VOID)
{
    printf("Creates a service entry in the registry and Service Database.\n");
    printf("SYNTAX: \nsc create <service> <option1> <option2>...\n");
    printf("CREATE OPTIONS:\n");
    printf("NOTE: The option name includes the equal sign.\n"
        " type= <own|share|kernel|filesys|rec|error>\n"
        " start= <boot|system|auto|demand|disabled|error>\n"
        " error= <normal|severe|critical|error|ignore>\n"
        " binPath= <BinaryPathName>\n"
        " group= <LoadOrderGroup>\n"
        " tag= <yes|no>\n"
        " depend= <Dependencies(space seperated)>\n"
        " obj= <AccountName|ObjectName>\n"
        " DisplayName= <display name>\n"
        " password= <password> \n");
}

VOID
ReadLogUsage(VOID)
{

    printf("\nReads a logfile and dumps the contents.\n");
    printf("SYNTAX: \n  eltest readlog <ServerName> logfile <option1> <option2>...\n");
    printf("READLOG OPTIONS:\n");
    printf("NOTE: The option name includes the equal sign.\n");

    printf("    ReadFlag=  <fwd|back|seek|seq> (default = fwd) \n"
           "    RecordNum=  record number where read should start (default=0)\n"
           "    BufSize=    size of the buffer (default = 10000)\n");
    printf("EXAMPLE:\n   eltest addreg application myapp MsgFile= MyMsgs.dll"
           " Type= error Type= warning\n");
}

DWORD
AddSourceToRegistry(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  LogName,
    IN  LPTSTR  EventSourceName,
    IN  LPTSTR  *argv,
    IN  DWORD   argc
    )

/*++

Routine Description:

    This function writes to the registry all the information to register
    this application as an event source.

Arguments:


Return Value:


--*/
{
    TCHAR   tempName[MAX_PATH];
    HKEY    hKey;
    DWORD   dwStatus=NO_ERROR;
    HKEY    hRegistry=HKEY_LOCAL_MACHINE;

    LPTSTR  EventMessageFile=NULL;
    LPTSTR  CategoryMessageFile=NULL;
    LPTSTR  ParameterMessageFile=NULL;
    DWORD   dwTypes=0;
    DWORD   dwCategoryCount=0;
    DWORD   i;

    //
    // Look at the LogName, and generate the appropriate registry key
    // path for that log.
    //
    if (STRICMP(LogName, ApplLogName) == 0) {
        STRCPY(tempName, ApplLogRegName);
    }
    else if (STRICMP(LogName, SysLogName) == 0) {
        STRCPY(tempName, SysLogRegName);
    }
    else if (STRICMP(LogName, SecLogName) == 0) {
        STRCPY(tempName, SecLogRegName);
    }
    else {
        printf("AddSourceToRegistry: Invalid LogName\n");
        return(ERROR_INVALID_PARAMETER);
    }
    STRCAT(tempName, EventSourceName);


    //
    // Get Variable Arguments
    //
    for (i=0; i<argc ;i++ ) {
        if (STRICMP(argv[i], TEXT("EventMsgFile=")) == 0) {
            EventMessageFile = argv[i+1];
            i++;
        }
        if (STRICMP(argv[i], TEXT("CategoryMsgFile=")) == 0) {
            CategoryMessageFile = argv[i+1];
            i++;
        }
        if (STRICMP(argv[i], TEXT("ParameterMsgFile=")) == 0) {
            ParameterMessageFile = argv[i+1];
            i++;
        }
        if (STRICMP(argv[i], TEXT("Type=")) == 0) {
            //--------------------------------------------------------
            // We want to allow for several arguments of type= in the
            // same line.  These should cause the different arguments
            // to be or'd together.
            //--------------------------------------------------------
            if (STRICMP(argv[i+1],TEXT("error")) == 0) {
                dwTypes |= EVENTLOG_ERROR_TYPE;
            }
            if (STRICMP(argv[i+1],TEXT("warning")) == 0) {
                dwTypes |= EVENTLOG_WARNING_TYPE;
            }
            if (STRICMP(argv[i+1],TEXT("information")) == 0) {
                dwTypes |= EVENTLOG_INFORMATION_TYPE;
            }
            if (STRICMP(argv[i+1],TEXT("AuditSuccess")) == 0) {
                dwTypes |= EVENTLOG_AUDIT_SUCCESS;
            }
            if (STRICMP(argv[i+1],TEXT("AuditFailure")) == 0) {
                dwTypes |= EVENTLOG_AUDIT_FAILURE;
            }
            if (STRICMP(argv[i+1],TEXT("All")) == 0) {
                dwTypes |= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
                            EVENTLOG_INFORMATION_TYPE | EVENTLOG_AUDIT_SUCCESS |
                            EVENTLOG_AUDIT_FAILURE);
            }
            else {
                printf("Invalid Type\n");
                AddRegUsage();
                return(ERROR_INVALID_PARAMETER);
            }
            i++;
        }
        if (STRICMP(argv[i], TEXT("CategoryCount=")) == 0) {
            dwCategoryCount = ATOL(argv[i+1]);
            i++;
        }

    }

    //
    // Connect to the registry on the correct machine.
    //
    printf("Connect to Registry\n");
    dwStatus = RegConnectRegistry(ServerName, HKEY_LOCAL_MACHINE, &hRegistry);
    if (dwStatus != NO_ERROR) {
        printf("RegConnectRegistry Failed %d\n",GetLastError());
        return(dwStatus);
    }

    //
    // Create the new key for this source
    //
    printf("Create Key\n");
    dwStatus = RegCreateKey(hRegistry, tempName, &hKey);
    if (dwStatus != ERROR_SUCCESS) {
        printf("Couldn't create Source Key in registry %d\n",dwStatus);
        return(dwStatus);
    }
    if (EventMessageFile != NULL) {
        printf("Set EventMessageFile\n");
        dwStatus = RegSetValueEx(
                hKey,
                VALUE_EVENT_MF,
                0,
                REG_EXPAND_SZ,
                (LPBYTE)EventMessageFile,
                STRLEN(EventMessageFile) + sizeof(TCHAR));

        if (dwStatus != ERROR_SUCCESS) {
            printf("RegSetValue (messageFile) failed %d\n",GetLastError());
            goto CleanExit;
        }
    }
    //
    // Set the Category Message File
    //
    if (CategoryMessageFile != NULL) {
        printf("Set Category Message File\n");
        dwStatus = RegSetValueEx(
                hKey,
                VALUE_CATEGORY_MF,
                0,
                REG_EXPAND_SZ,
                (LPBYTE)CategoryMessageFile,
                STRLEN(CategoryMessageFile) + sizeof(TCHAR));

        if (dwStatus != ERROR_SUCCESS) {
            printf("RegSetValue (category mf) failed %d\n",GetLastError());
            goto CleanExit;
        }
    }

    //
    // Set the Parameter Message File
    //
    if (ParameterMessageFile != NULL) {
        printf("Set Parameter Message File\n");
        dwStatus = RegSetValueEx(
                hKey,
                VALUE_PARAMETER_MF,
                0,
                REG_EXPAND_SZ,
                (LPBYTE)ParameterMessageFile,
                STRLEN(ParameterMessageFile) + sizeof(TCHAR));

        if (dwStatus != ERROR_SUCCESS) {
            printf("RegSetValue (Parameter mf) failed %d\n",GetLastError());
            goto CleanExit;
        }
    }

    //
    // Set the Types Supported
    //
    if (dwTypes != 0) {
        printf("Set Types Supported\n");
        dwStatus = RegSetValueEx(
                hKey,
                VALUE_TYPES_SUPPORTED,
                0,
                REG_DWORD,
                (LPBYTE) &dwTypes,
                sizeof(DWORD));

        if (dwStatus != ERROR_SUCCESS) {
            printf("RegSetValue (TypesSupported) failed %d\n",GetLastError());
            goto CleanExit;
        }

    }

    //
    // Set the Category Count
    //
    if (dwCategoryCount != 0) {
        printf("Set CategoryCount\n");
        dwStatus = RegSetValueEx(
                hKey,
                VALUE_CATEGORY_COUNT,
                0,
                REG_DWORD,
                (LPBYTE) &dwCategoryCount,
                sizeof(DWORD));

        if (dwStatus != ERROR_SUCCESS) {
            printf("RegSetValue (CategoryCount) failed %d\n",GetLastError());
            goto CleanExit;
        }
    }
    dwStatus = NO_ERROR;
CleanExit:
    RegCloseKey(hKey);
    RegCloseKey(hRegistry);
    return(dwStatus);
}

DWORD
DelSourceInRegistry(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  LogName,
    IN  LPTSTR  EventSourceName
    )

/*++

Routine Description:

    This function writes to the registry all the information to register
    this application as an event source.

Arguments:


Return Value:


--*/
{
    LPTSTR  tempName;
    HKEY    hParentKey;
    BOOL    status=FALSE;
    DWORD   dwStatus;
    HKEY    hRegistry=HKEY_LOCAL_MACHINE;


    //
    // Look at the LogName, and generate the appropriate registry key
    // path for that log.
    //
    if (STRICMP(LogName, ApplLogName) == 0) {
        tempName = ApplLogRegName;
    }
    else if (STRICMP(LogName, SysLogName) == 0) {
        tempName = SysLogRegName;
    }
    else if (STRICMP(LogName, SecLogName) == 0) {
        tempName = SecLogRegName;
    }
    else {
        printf("AddSourceToRegistry: Invalid LogName\n");
        return(ERROR_INVALID_PARAMETER);
    }

    //
    // Connect to the registry on the correct machine.
    //
    dwStatus = RegConnectRegistry(ServerName, HKEY_LOCAL_MACHINE, &hRegistry);
    if (dwStatus != NO_ERROR) {
        printf("RegConnectRegistry Failed %d\n",GetLastError());
        return(status);
    }

    //
    // Open the Parent Key of the key we want to delete.
    //
    dwStatus = RegOpenKeyEx(
                hRegistry,
                tempName,
                0,
                KEY_ALL_ACCESS,
                &hParentKey);

    if (dwStatus != ERROR_SUCCESS) {
        printf("Couldn't open Parent of key to be deleted. %d\n",dwStatus);
        goto CleanExit;
    }
    //
    // Delete the subkey.
    //
    dwStatus = RegDeleteKey(hParentKey, EventSourceName);
    if (dwStatus != ERROR_SUCCESS) {
        printf("Couldn't delete "FORMAT_LPTSTR" key from registry %d\n",
            EventSourceName, dwStatus);
    }

    RegCloseKey(hParentKey);
CleanExit:
    RegCloseKey(hRegistry);
    return(status);
}

DWORD
ReadLogFile(
    LPTSTR  ServerName,
    LPTSTR  LogName,
    IN  LPTSTR  *argv,
    IN  DWORD   argc
    )

/*++

Routine Description:


Arguments:


Return Value:


--*/
{
    DWORD   dwReadFlag = EVENTLOG_FORWARDS_READ;
    DWORD   dwRecordNum = 0;
    DWORD   BufSize = 10000;
    DWORD   numBytesRead;
    DWORD   numBytesReqd;
    LPVOID  pElBuffer = NULL;
    PEVENTLOGRECORD    pElRecord;
    BOOL    PrintTheHeader;
    DWORD   i;
    HANDLE  hEventLog=NULL;

    //
    // Get Variable Arguments
    //
    for (i=0; i<argc ;i++ ) {
        if (STRICMP(argv[i], TEXT("ReadFlag=")) == 0) {
            if (STRICMP(argv[i+1],TEXT("fwd")) == 0) {
                dwReadFlag |= EVENTLOG_FORWARDS_READ;
            }
            if (STRICMP(argv[i+1],TEXT("back")) == 0) {
                dwReadFlag |= EVENTLOG_BACKWARDS_READ;
            }
            if (STRICMP(argv[i+1],TEXT("seek")) == 0) {
                dwReadFlag |= EVENTLOG_SEEK_READ;
            }
            if (STRICMP(argv[i+1],TEXT("seq")) == 0) {
                dwReadFlag |= EVENTLOG_SEQUENTIAL_READ;
            }
            i++;
        }
        if (STRICMP(argv[i], TEXT("RecordNum=")) == 0) {
            dwRecordNum = ATOL(argv[i+1]);
            i++;
        }
        if (STRICMP(argv[i], TEXT("BufSize=")) == 0) {
            BufSize = ATOL(argv[i+1]);
            i++;
        }
        hEventLog = OpenEventLog(ServerName,LogName);
        if (hEventLog == NULL) {
            printf("OpenEventLog failed %d\n",GetLastError());
            return(0);
        }
        pElBuffer = LocalAlloc(LPTR, BufSize);
        if (pElBuffer == NULL) {
            printf("ReadLogFile: LocalAlloc Failed %d\n",GetLastError());
            goto CleanExit;
        }

        //---------------------------------------------------------
        // Read and Display the contents of the eventlog
        //---------------------------------------------------------
        PrintTheHeader = TRUE;
TryAgain:
        while(ReadEventLog(
                hEventLog,
                dwReadFlag,
                dwRecordNum,
                pElBuffer,
                BufSize,
                &numBytesRead,
                &numBytesReqd)) {

            pElRecord = (PEVENTLOGRECORD) pElBuffer;
            while ((PBYTE) pElRecord < (PBYTE) pElBuffer + numBytesRead) {
                //
                // Print the record to the display
                //
                DisplayRecord(pElRecord,PrintTheHeader);
                PrintTheHeader = FALSE;
                //
                // Move to the next event in the buffer
                //
                pElRecord = (PEVENTLOGRECORD)((PBYTE) pElRecord +
                    pElRecord->Length);
            }
        }
        switch(GetLastError()) {
        case ERROR_INSUFFICIENT_BUFFER:
            //
            // Increase the size of the buffer and try again
            //
            if (numBytesReqd > BufSize) {
                LocalFree(pElBuffer);
                BufSize = numBytesReqd;
                pElBuffer = LocalAlloc(LPTR, BufSize);
                if (!pElBuffer) {
                    printf("ReadLogFile: LocalAlloc Failed %d\n",GetLastError());
                }
                goto TryAgain;
            }
            else {
                printf("ReadLogFile #1: THIS SHOULD NEVER HAPPEN\n");
            }
            break;
        case ERROR_EVENTLOG_FILE_CHANGED:
            //
            // The current read position for this handle has been overwritten.
            // Reopen the file and print a message to the effect that some
            // records may have been missed.
            //
            printf("ReadLogFile: Current Read position has been overwritten\n");

            hEventLog = OpenEventLog(ServerName,LogName);
            if (hEventLog == NULL) {
                printf("OpenEventLog failed %d\n",GetLastError());
                goto CleanExit;
            }
            goto TryAgain;
        case ERROR_HANDLE_EOF:
            printf("EOF\n");
            break;
        default:
            printf("UnknownError: %d\n",GetLastError());
            break;
        }
    }
CleanExit:
    if (pElBuffer != NULL) {
        LocalFree(pElBuffer);
    }
    if (hEventLog != NULL) {
        CloseEventLog(hEventLog);
    }
    return(0);
}

VOID
DisplayRecord(
    PEVENTLOGRECORD     pElRecord,
    BOOL                PrintTheHeader
    )

/*++

Routine Description:


Arguments:


Return Value:


--*/
{
    if (PrintTheHeader) {
        printf("RecNum/tTimeGen/tWriteTime/tEventID/tType/tNumStr/tCat/n");
    }
    printf("%d/t%d/t%d/t%d/t%d/t%d/t%d\n",
        pElRecord->RecordNumber,
        pElRecord->TimeGenerated,
        pElRecord->TimeWritten,
        pElRecord->EventID,
        pElRecord->EventType,
        pElRecord->NumStrings,
        pElRecord->EventCategory);
}

LONG
wtol(
    IN LPWSTR string
    )
{
    LONG value = 0;

    while((*string != L'\0')  &&
            (*string >= L'0') &&
            ( *string <= L'9')) {
        value = value * 10 + (*string - L'0');
        string++;
    }

    return(value);
}

