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;
}