///////////////////////////////////////////////////////////////////////////////
//
//    (C) Copyright 1995 - 2005 OSR Open Systems Resources, Inc.
//    (C) Copyright 2000 MicroSoft, Inc.
//    All Rights Reserved
//
//    This sofware is supplied for instructional purposes only.
//
//    OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
//    for this software.  THIS SOFTWARE IS PROVIDED  "AS IS" WITHOUT WARRANTY
//    OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
//    THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
//    PURPOSE.  THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
//    WITH YOU.  OSR's entire liability and your exclusive remedy shall not
//    exceed the price paid for this material.  In no event shall OSR or its
//    suppliers be liable for any damages whatsoever (including, without
//    limitation, damages for loss of business profit, business interruption,
//    loss of business information, or any other pecuniary loss) arising out
//    of the use or inability to use this software, even if OSR has been
//    advised of the possibility of such damages.  Because some states/
//    jurisdictions do not allow the exclusion or limitation of liability for
//    consequential or incidental damages, the above limitation may not apply
//    to you.
//
//    OSR Open Systems Resources, Inc.
//    105 Route 101A Suite 19
//    Amherst, NH 03031  (603) 595-6500 FAX: (603) 595-6503
//    email bugs to: bugs@osr.com
//
//
//    MODULE:
//
//        Redirecttest.cpp -- Redirect Test Program
//
//    ABSTRACT:
//
//      Win32 console mode program to fire up requests to the
//      REDIRECT driver.
//
//    AUTHOR(S):
//
//        OSR Open Systems Resources, Inc.
// 
//    REVISION:   
//
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
#include <winioctl.h>
#include <redirect_ioctl.h>

//
// Simple test application for the REDIRECT project.
//

__cdecl main(ULONG argc, LPSTR *argv)
{
    HANDLE          DriverHandle;
    HANDLE          NewDriverHandle;
    DWORD           code;
    ULONG           index;
    UCHAR           WriteBuffer[4096];
    UCHAR           ReadBuffer[9096];
    OVERLAPPED      WriteOverlapped;
    OVERLAPPED      ReadOverlapped;
    HANDLE          WriteEvent;
    HANDLE          ReadEvent;
    DWORD           WaitResult;
    DWORD           BytesRead, BytesWritten;
    DWORD           Function;

    //
    // Build the overlapped structures, creating a couple of
    // events to use in the process
    //
    WriteOverlapped.Offset     = 0; 
    WriteOverlapped.OffsetHigh = 0; 
    WriteOverlapped.hEvent     = CreateEvent(NULL, TRUE, FALSE, NULL);

    ReadOverlapped.Offset     = 0; 
    ReadOverlapped.OffsetHigh = 0; 
    ReadOverlapped.hEvent     = CreateEvent(NULL, TRUE, FALSE, NULL);

    //
    // Init the write and read buffers with known data
    //
    memset(ReadBuffer, 0xAA, sizeof(ReadBuffer));

    memset(WriteBuffer, 0xEE, sizeof(WriteBuffer));

    //
    // Open the REDIRECT device
    //
    DriverHandle = CreateFile("\\\\.\\REDIRECT",  // Name of the NT "device" to open
                            GENERIC_READ|GENERIC_WRITE,  // Access rights requested
                            FILE_SHARE_READ|FILE_SHARE_WRITE, // Share access - NONE
                            0,                           // Security attributes - not used!
                            OPEN_EXISTING,               // Device must exist to open it.
                            FILE_FLAG_OVERLAPPED,        // Open for overlapped I/O
                            0);                          // extended attributes - not used!

    //
    // If this call fails, check to figure out what the error is and report it.
    //
    if (DriverHandle == INVALID_HANDLE_VALUE) {

        code = GetLastError();

        printf("CreateFile failed with error 0x%x\n", code);

        return(code);
    }

    //
    // Infinitely print out the list of choices, ask for input, process
    // the request
    //
    while(TRUE)  {

        printf ("\nREDIRECT TEST -- Functions:\n\n");
        printf ("\t1. Open a Different Device\n");
        printf ("\t2. Queue a READ\n");
        printf ("\t3. Issue a WRITE\n");
        printf ("\t4. Wait for READ\n");
        printf ("\t5. Wait for WRITE\n");
        printf ("\t6. Print READ buffer\n");
        printf ("\t7. Print WRITE buffer\n");
        printf ("\t8. Send REDIRECT IOCTL\n");
        printf ("\n\t0. Exit\n");
        printf ("\n\tSelection: ");
        scanf ("%x", &Function);

        switch(Function)  {

            case 1:
                //
                // Open the REDIRECT device again
                //
                NewDriverHandle = CreateFile("\\\\.\\REDIRECT",  // Name of the NT "device" to open
                                        GENERIC_READ|GENERIC_WRITE,  // Access rights requested
                                        FILE_SHARE_READ|FILE_SHARE_WRITE, // Share access - NONE
                                        0,                           // Security attributes - not used!
                                        OPEN_EXISTING,               // Device must exist to open it.
                                        FILE_FLAG_OVERLAPPED,        // Open for overlapped I/O
                                        0);                          // extended attributes - not used!

                if (DriverHandle == INVALID_HANDLE_VALUE) {

                    code = GetLastError();

                    printf("CreateFile failed with error 0x%x\n", code);

                } else {
                    CloseHandle(DriverHandle);
                    DriverHandle = NewDriverHandle;
                }
                break;

            case 2:
                //
                // Send a read
                //
                if ( !ReadFile(DriverHandle,
                                ReadBuffer,
                                sizeof(ReadBuffer),
                                &index,
                                &ReadOverlapped)) {

                    code = GetLastError();

                    if(code != ERROR_IO_PENDING)  {

                        printf("ReadFile failed with error 0x%x\n", code);

                        return(code);
                    }
                }
                break;

            case 3:
                //
                // Send a write
                //
                if (!WriteFile(DriverHandle,
                                WriteBuffer,
                                sizeof(WriteBuffer),
                                &index, 
                                &WriteOverlapped)) {

                    code = GetLastError();

                    if(code != ERROR_IO_PENDING)  {

                        printf("WriteFile failed with error 0x%x\n", code);

                        return(code);
                    }
                }
                break;

            case 4:

                //
                // Wait for Read to complete
                //
                if(!GetOverlappedResult(DriverHandle, &ReadOverlapped, &BytesRead, TRUE)) {

                    printf("GetOverlappedResult for READ failed?\n"); 

                }
                code = GetLastError();

                printf("Read result = %d., Bytes Read = %d.\n", code, BytesRead);

                break;

            case 5:
                //
                // Wait for WRITE to complete
                //
                if(!GetOverlappedResult(DriverHandle, &WriteOverlapped, &BytesWritten, TRUE))  {

                    printf("GetOverlappedResult for WRITE failed?\n"); 

                }

                code = GetLastError();

                printf("Write result = %d., Bytes Written = %d.\n", code, BytesWritten);

                break;

            case 6:
                //
                // Show read buffer
                //
                printf("Printing first 32 bytes of READ buffer\n");

                for(index = 0; index < 32; index++)  {

                    printf("0x%0x,",ReadBuffer[index]);
                }

                break;

            case 7:
                //
                // Show WRITE buffer
                //
                printf("Printing first 32 bytes of WRITE buffer\n");

                for(index = 0; index < 32; index++)  {

                    printf("0x%0x,",WriteBuffer[index]);
                }

                break;

            case 8:
                //
                // Test the IOCTL interface
                //
                if (!DeviceIoControl(DriverHandle,
                                    (DWORD)IOCTL_OSR_REDIRECT,
                                    0,      // Ptr to InBuffer
                                    0,      // Length of InBuffer
                                    0,      // Ptr to OutBuffer
                                    0,      // Length of OutBuffer
                                    &index, // BytesReturned
                                    0) )    // Ptr to Overlapped structure
                                    {

                    code = GetLastError();

                    printf("DeviceIoControl (reset) failed with error 0x%x\n", code);

                    return(code);
                }

                printf("DeviceIoControl worked OK. \n");

                break;

            case 0:

                //
                // zero is get out!
                //
                return(0);

        }
    }   
}
