The Logger Code

As promised, here’s the C code source for the spy type application we used earlier. The application in Listing 8-2 on the next page is written in C because it seemed to want to work correctly only as a Win32 console application, not as a windowed Windows application. (So I couldn’t write it in Visual Basic—even Visual Basic 5!) You can find this file on the companion CD in the CHAP08 folder. A compiled executable made from this file is in CHAP08/Release.

Listing 8-2

The OUTARGS logger application /*********************************************************************

 Small C applet used to replace Visual Basic 5 compiler apps 
 so as to gather their output and manipulate their 
 command-line switches.
 
 See notes in main text for more details.

*********************************************************************/

#include < stdio.h   >
#include < string.h  >
#include < time.h    >
#include < windows.h >

int main
(
    int    argc     // Number of command-line arguments
   ,char * argv[]   // The arguments themselves
   ,char * env []   // Environment variables
)
{
    /* ***************************************************************
    ** General declares.
    */
    #define BUFF 2048                   // Change to const if you
                                        // prefer C++.

    auto FILE *      stream;            // File to write to

    auto struct tm * tt;                // Time stuff for time of
                                        // write
    auto time_t      t;                 // ----- “ “ -----

    auto char        carBuff[255];      // Used for holding output
                                        // filename

    auto char        carArgs[BUFF];     // Holds command line
                                        // arguments for display
    auto int         nLoop;             // Loop counter


    /* ***************************************************************
    ** Used by CreateProcess.
    */ 
static STARTUPINFO            sui = {sizeof(STARTUPINFO)};
    // Filled in by CreateProcess()
    auto   PROCESS_INFORMATION    pi;   
    auto   long                   l   = 0;


    /* ***************
    ** Code starts ...
    */ 

    // Change according to what real (renamed) application you
    // want to start.
    (void)strcat(&carArgs[0], “.\\C3 “);

    // Get the system time, and convert it to ASCII string.
    (void)time(&t);
    tt = localtime(&t);

    // Going to need to append to our EXE name, so write to 
    // temp buffer.
    (void)strcpy(&carBuff[0], argv[0]);

    // Now append .OUT - should contain ???.OUT after this, where ??? 
    // could be APP.EXE or just APP depending on how this program is 
    // run.
    (void)strcat(&carBuff[0], “.OUT”);

    // Write to EXEName.OUT file (append mode)...
    if(NULL != (stream = fopen(&carBuff[0], “a”)))
    {
        // Write out the time.
        (void)fprintf(stream, “********** Run @ %s\n", asctime(tt));

        // Output name of EXE file.
        (void)fprintf(stream, “* EXE file...\n\n”);
        (void)fprintf(stream, “\t%s\n", argv[0]);

        /* *****************************************************
        ** Output command line arguments 
        ** (exclude our EXE name argv[0]).
        */

        (void)fprintf(stream, “\n* Command Line Arguments...\n\n”);

        for(nLoop = 1; nLoop < argc; nLoop++)
        {
            (void)fprintf(stream,"%d\t%s\n", nLoop, argv[nLoop]);

            // Append to arguments buffer.
            (void)strcat(&carArgs[0]   , argv[nLoop]);
            (void)strcat(&carArgs[0]   , “ “);
        }

        /* *****************************
        ** Output environment variables.
        */

        (void)fprintf(stream, “\n* Environment Variables...\n\n”);

        for(nLoop = 0; NULL != env[nLoop]; nLoop++)
        {
            (void)fprintf(stream, “%d\t%s\n", nLoop, env[nLoop]);
        }

        /* ********************************************************
        ** Output name and arguments of other application to start.
        */

        (void)fprintf(stream, 
                “\n* ‘Real’ program and arguments...\n\n”);
        (void)fprintf(stream, “\t%s\n", &carArgs[0]);

        (void)fprintf(stream, “\n********** Run End\n\n\n”);

        // All done, so tidy up.
        (void)fclose(stream);
    }

    /* *********************************************************
    ** Execute the real (renamed) EXE as if it had been executed
    ** directly by Visual Basic
    */

    sui.dwFlags     = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW;
    sui.wShowWindow = SW_SHOWNORMAL;

    // Creating a process whose main thread will be realtime-class
    // privileged - we need this to execute without any yielding.
    if (TRUE == CreateProcess(
                              NULL
                             ,&carArgs[0]
                             ,NULL
                             ,NULL
                             ,TRUE
                             ,REALTIME_PRIORITY_CLASS
                             ,NULL
                             ,NULL
                             ,&sui
                             ,&pi
                             )
    )
    {
        // EXEcuted OK, so now wait for the process to complete.
        // Assume CreateProcess() worked OK.
        (void)WaitForSingleObject(pi.hProcess, INFINITE);

        // Get its exit code for returning to Visual Basic.
        (void)GetExitCodeThread(pi.hThread, (LPDWORD)&l);

        (void)CloseHandle(pi.hProcess);

        // Return exit code.
        return l;
    }

    return 0;
}