Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1171 lines
27 KiB

/****************************** Module Header ******************************\
* Module Name: rcmd.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Remote shell NT client main module
*
* History:
* 05-20-92 Davidc Created.
* 05-01-94 DaveTh Modified for remote command service (single cmd mode)
\***************************************************************************/
// #define UNICODE // BUGBUG - Unicode support not complete
#include <nt.h>
#include <ntrtl.h>
#include <windef.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#include <conio.h>
#include <rcmd.h>
#define PIPE_NAME TEXT("%hs\\pipe\\rcmdsvc")
#define BUFFER_SIZE 1000
#define MAX_SERVER_NAME_LENGTH 15
//
// Globals
//
HANDLE PipeHandle = NULL; // These are used by Ctrl-C handler
BOOLEAN SessionConnected = FALSE;
BOOLEAN MultiServerMode = FALSE;
HANDLE ReadThreadHandle;
HANDLE WriteThreadHandle;
BOOLEAN RcDbgPrintEnable = FALSE; // If TRUE, enables DbgPrint
LPTSTR ServerName = NULL; // Name of remote server, for messages
//
// Private prototypes
//
DWORD
ReadThreadProc(
LPVOID Parameter
);
DWORD
WriteThreadProc(
LPVOID Parameter
);
BOOL
CtrlHandler(
DWORD CtrlType
);
int RcPrintf (
const char *format,
...
);
int RcDbgPrint (
const char *format,
...
);
void Usage(
void
);
long ParseCommandLine(
LPTSTR lpszServer,
COMMAND_HEADER *chCommandHeader,
LPTSTR *aszArgv,
int iArgc
);
void
Usage(
void
)
/*++
Routine Description:
Prints a usage message and exits the program
Arguments:
None
Return Value:
void
--*/
{
RcPrintf("\nUsage: rcmd [server_name [command] ]\n\n");
RcPrintf("Prompts for server_name if not supplied. Session is\n");
RcPrintf("interactive and is terminated by ctrl-Break or Exit of\n");
RcPrintf("remote shell. Program is terminated by ctrl-Break or\n");
RcPrintf("ctrl-C when no session is in progress.\n\n");
RcPrintf("If no command supplied, session is interactive and is\n");
RcPrintf("terminated by ctrl-Break or Exit of remote cmd shell\n\n");
RcPrintf("If command is supplied, remote shell executes single\n");
RcPrintf("command on specified server and exits.\n\n");
RcPrintf("Note : Command line server_name requires leading '\\\\'s\n");
exit(0);
}
LONG ParseCommandLine(
LPTSTR lpszServer,
COMMAND_HEADER *chCommandHeader,
LPTSTR *aszArgv,
int iArgc
)
/*++
Routine Description:
Parses command line of the form:
rcmd [server_name [[command] | ["command"]]
Arguments:
lpszServer - on exit gets the name of the server from the command line
chCommandHeader - information to pass to rcmdsvc on exit
aszArgv - array of zero terminated strings (passed in from command line)
iArgc - number of strings in argv (passed in from command line)
Return Value:
LONG
--*/
{
LPTSTR buf = NULL;
LONG nChars = 0;
int i;
//
// get the first argument (either the server name or a [-/][?hH])
//
if (iArgc > 1)
{
//
// convert argument to lower case
//
CharLowerBuff(aszArgv[1], lstrlen(aszArgv[1]));
//
// check for switch (only ?Hh are valid)
//
if ((*aszArgv[1] == TEXT('-')) ||
(*aszArgv[1] == TEXT('/'))) {
//
// check the switch
//
if ( (aszArgv[1][1] == TEXT('h')) ||
(aszArgv[1][1] == TEXT('?')) ) {
Usage();
}
else {
RcPrintf(TEXT("Unknown switch %s\n"), aszArgv[1]);
Usage();
}
}
else if ( (*aszArgv[1] == TEXT('\\')) && (aszArgv[1][1] == TEXT('\\'))) {
//
// first argument is a server name
//
lstrcpy(lpszServer, aszArgv[1]);
}
else {
//
// usage error
//
Usage();
}
}
else {
//
// user failed to enter a server name
// default to local machine
//
lstrcpy(lpszServer, "\\\\.");
}
//
// If user entered anything beyond the server name, save it for passing to
// to rcmdsvc.
//
// init
chCommandHeader->CommandFixedHeader.CommandLength = 0;
buf = chCommandHeader->Command;
buf[0] = TEXT('\0');
for (i = 2; i < iArgc; i++) {
//
// append each argument to saved command line
//
if (NULL != strchr(aszArgv[i], ' '))
{
nChars = wsprintf(buf, "\"%s\" ", aszArgv[i]);
}
else
{
nChars = wsprintf(buf, "%s ", aszArgv[i]);
}
buf += nChars;
chCommandHeader->CommandFixedHeader.CommandLength += nChars;
}
//
// in case we went too far, truncate the string
//
chCommandHeader->Command[MAX_CMD_LENGTH] = TEXT('\0');
return (long)iArgc;
}
/***************************************************************************\
* FUNCTION: Main
*
* PURPOSE: Main entry point.
*
* RETURNS: 0 on success, 1 on failure
*
* HISTORY:
*
* 07-10-92 Davidc Created.
*
\***************************************************************************/
int
__cdecl main(
int argc,
char **argv
)
{
SECURITY_ATTRIBUTES SecurityAttributes;
HANDLE StdInputHandle;
HANDLE StdOutputHandle;
HANDLE StdErrorHandle;
CHAR PipeName[MAX_PATH];
//WCHAR PipeName[MAX_PATH];
DWORD ThreadId;
HANDLE HandleArray[2];
COMMAND_HEADER CommandHeader;
RESPONSE_HEADER ResponseHeader;
DWORD BytesWritten, BytesRead;
DWORD Result;
CHAR ServerNameBuffer[MAX_SERVER_NAME_LENGTH+3]; // +3 for gets counts, null
CHAR FullServerNameBuffer[MAX_SERVER_NAME_LENGTH+3]; // +3 for "\\", null
LONG nArgs = 0;
BOOLEAN bBadServerName = TRUE;
//
// Install a handler for Ctrl-C
//
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) &CtrlHandler, TRUE)) {
RcPrintf("Error:1 - Internal error = %d\n", GetLastError());
return(1);
}
//
// Command line parsing
//
nArgs = ParseCommandLine(FullServerNameBuffer, &CommandHeader, argv, argc);
ServerName = FullServerNameBuffer;
if (nArgs == 1) {
MultiServerMode = TRUE;
ServerNameBuffer[0] = MAX_SERVER_NAME_LENGTH;
FullServerNameBuffer[0] = '\\';
FullServerNameBuffer[1] = '\\';
}
//
// Loop for MultServerMode case (will return appropriately if not)
//
while (TRUE) {
//
// If MultiServerMode, prompt for server name until it's right (enough)
//
while (MultiServerMode) {
//
// BUGBUG - call netapi to validate server name
//
RcPrintf("\nEnter Server Name : ");
FullServerNameBuffer[2] = '\0'; // re-terminate "\\" string
ServerNameBuffer[0] = MAX_SERVER_NAME_LENGTH;
ServerName = strcat(FullServerNameBuffer, _cgets(ServerNameBuffer));
if (strlen(ServerName) < 3) {
RcPrintf("\nError - Invalid Server Name\n");
} else {
break; // valid name, go on
}
}
//
// Construct server pipe name
//
wsprintf(PipeName, PIPE_NAME, ServerName);
//
// Store away our normal i/o handles
//
if (((StdInputHandle = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) ||
((StdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) ||
((StdErrorHandle = GetStdHandle(STD_ERROR_HANDLE)) == INVALID_HANDLE_VALUE)) {
RcPrintf("Error:2 - Internal error = %d\n", GetLastError());
return(1); // catastrophic error - exit
}
//
// Open the named pipe - need security flags to pass all privileges, not
// just effective during impersonation
//
SecurityAttributes.nLength = sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor = NULL; // Use default SD
SecurityAttributes.bInheritHandle = FALSE;
PipeHandle = CreateFile(PipeName, // pipe to server
GENERIC_READ | GENERIC_WRITE, // read/write
0, // No sharing
&SecurityAttributes, // default Security Descriptor
OPEN_EXISTING, // open existing pipe if it exists
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
SECURITY_SQOS_PRESENT |
SECURITY_IMPERSONATION | SECURITY_CONTEXT_TRACKING,
NULL // Template file
);
if (PipeHandle == INVALID_HANDLE_VALUE ) {
Result = GetLastError();
RcDbgPrint("Failed to open named pipe, error = %d\n", Result);
switch (Result) {
case ERROR_FILE_NOT_FOUND:
RcPrintf("Error - Failed to connect to <%s>, system not found or service not active\n", ServerName);
break;
case ERROR_PIPE_BUSY:
RcPrintf("Error - Failed to connect to <%s>, remote command server busy\n", ServerName);
break;
default:
RcPrintf("Error - Failed to connect to <%s>, Error = %d\n", ServerName, GetLastError());
}
goto ServerError;
}
//
// Send command header - if single command mode, send command for
// excecute and return. else 0 length indicates no command present
// Specify BASIC level support desired.
//
CommandHeader.CommandFixedHeader.Signature = RCMD_SIGNATURE;
CommandHeader.CommandFixedHeader.RequestedLevel =
RC_LEVEL_REQUEST | RC_LEVEL_BASIC;
if (!WriteFile(
PipeHandle,
&CommandHeader,
sizeof(CommandHeader.CommandFixedHeader) +
CommandHeader.CommandFixedHeader.CommandLength,
&BytesWritten,
NULL )) {
RcPrintf("Error - Failed to send to remote command server, Error = %ld\n", GetLastError());
goto ServerError;
}
//
// Get response header. Will specify reported level or any error.
//
if ((!ReadFile(
PipeHandle,
&ResponseHeader,
sizeof(ResponseHeader),
&BytesRead,
NULL)) || (BytesRead != sizeof(ResponseHeader))) {
RcPrintf("Error - Remote command server failed to respond, Error = %ld\n", GetLastError());
goto ServerError;
}
if (ResponseHeader.Signature != RCMD_SIGNATURE) {
RcPrintf("Error - Incompatible remote command server\n");
goto ServerError;
}
//
// Check for returned errors or supported level
//
if (!(ResponseHeader.SupportedLevel ==
(RC_LEVEL_RESPONSE | RC_LEVEL_BASIC))) {
if (ResponseHeader.SupportedLevel & RC_ERROR_RESPONSE) {
//
// Error returned
//
switch (ResponseHeader.SupportedLevel & ~RC_ERROR_RESPONSE) {
case ERROR_ACCESS_DENIED:
RcPrintf("Error - You have insufficient access on the remote system\n");
break;
default:
RcPrintf("Error - Failed to establish remote session, Error = %d\n",
(ResponseHeader.SupportedLevel & ~RC_ERROR_RESPONSE));
break;
} //switch
goto ServerError;
} else if (ResponseHeader.SupportedLevel & RC_LEVEL_RESPONSE) {
//
// Supported level returned - but not a valid value (not BASIC)
//
RcPrintf("Error - Invalid support level returned\n");
goto ServerError;
} else {
//
// Neither error nor supported level returned
//
RcPrintf("Error - Invalid response from remote server\n");
goto ServerError;
}
}
//
// All is well - Session is connected
//
SessionConnected = TRUE;
if (CommandHeader.CommandFixedHeader.CommandLength == 0) {
RcPrintf("Connected to %s\n\n", ServerName);
} else {
RcPrintf("Executing on %s: %s\n\n", ServerName, CommandHeader.Command);
}
//
// Exec 2 threads - 1 copies data from stdin to pipe, the other
// copies data from the pipe to stdout.
//
ReadThreadHandle = CreateThread(
NULL, // Default security
0, // Default Stack size
(LPTHREAD_START_ROUTINE) ReadThreadProc,
(PVOID)PipeHandle,
0,
&ThreadId);
if (ReadThreadHandle == NULL) {
RcPrintf("Error:3 - Internal error = %ld\n", GetLastError());
return(1); // catastrophic error - exit
}
//
// Create the write thread
//
WriteThreadHandle = CreateThread(
NULL, // Default security
0, // Default Stack size
(LPTHREAD_START_ROUTINE) WriteThreadProc,
(PVOID)PipeHandle,
0,
&ThreadId);
if (WriteThreadHandle == NULL) {
RcPrintf("Error:4 - Internal error = %ld\n", GetLastError());
TerminateThread(ReadThreadHandle, 0);
CloseHandle(ReadThreadHandle);
return(1); // catastrophic error, exit
}
//
// Wait for either thread to finish
//
HandleArray[0] = ReadThreadHandle;
HandleArray[1] = WriteThreadHandle;
Result = WaitForMultipleObjects(
2,
HandleArray,
FALSE, // Wait for either to finish
0xffffffff
); // Wait forever
//
// Finished - terminate other thread and close pipe handle
//
if (Result == (WAIT_OBJECT_0 + 0)) { // Read thread finished - terminate write
TerminateThread(WriteThreadHandle, 0);
}
if (Result == (WAIT_OBJECT_0 + 1)) { // Write thread finished - terminate read
TerminateThread(ReadThreadHandle, 0);
}
RcDbgPrint("Read or write thread terminated\n");
//
// Close our pipe handle
//
CloseHandle(PipeHandle);
PipeHandle = NULL;
//
// Re-enable normal ctrl-C processing
//
SessionConnected = FALSE;
//
// Normal completion - return if not MultServerMode
//
if (!MultiServerMode) {
//
// return - process exit will terminate threads and close thread handles
//
return(1);
}
ServerError:
if (PipeHandle != NULL) {
CloseHandle(PipeHandle);
}
if (!MultiServerMode) {
//
// return false on error - process exit terminates threads/closes handles
//
return(0);
}
//
// Multi-service mode exits occurs with ctrl-C/break only
//
}
}
/***************************************************************************\
* FUNCTION: ReadPipe
*
* PURPOSE: Implements an overlapped read such that read and write operations
* to the same pipe handle don't deadlock.
*
* RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
*
* HISTORY:
*
* 05-27-92 Davidc Created.
*
\***************************************************************************/
BOOL
ReadPipe(
HANDLE PipeHandle,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead
)
{
DWORD Result;
OVERLAPPED Overlapped;
HANDLE EventHandle;
DWORD Error;
//
// Create an event for the overlapped operation
//
EventHandle = CreateEvent(
NULL, // no security
TRUE, // Manual reset
FALSE, // Initial state
NULL // Name
);
if (EventHandle == NULL) {
RcDbgPrint("ReadPipe: CreateEvent failed, error = %d\n", GetLastError());
return(FALSE);
}
Overlapped.hEvent = EventHandle;
Overlapped.Internal = 0;
Overlapped.InternalHigh = 0;
Overlapped.Offset = 0;
Overlapped.OffsetHigh = 0;
Result = ReadFile(
PipeHandle,
lpBuffer,
nNumberOfBytesToRead,
lpNumberOfBytesRead,
&Overlapped
);
if (Result) {
//
// Success without waiting - it's too easy !
//
CloseHandle(EventHandle);
} else {
//
// Read failed, if it's overlapped io, go wait for it
// If failure due to server, print appropriate message.
//
Error = GetLastError();
switch (Error) {
case ERROR_IO_PENDING:
break;
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BROKEN_PIPE:
RcPrintf("\nRemote server %s disconnected\n", ServerName);
CloseHandle(EventHandle);
return(FALSE);
default:
RcPrintf("Error:5 - Internal error = %d\n", Error);
RcDbgPrint("ReadPipe: ReadFile failed, error = %d\n", Error);
CloseHandle(EventHandle);
return(FALSE);
}
//
// Wait for the I/O to complete
//
Result = WaitForSingleObject(EventHandle, (DWORD)-1);
if (Result != 0) {
RcDbgPrint("ReadPipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
CloseHandle(EventHandle);
return(FALSE);
}
//
// Go get the I/O result
//
Result = GetOverlappedResult( PipeHandle,
&Overlapped,
lpNumberOfBytesRead,
FALSE
);
//
// We're finished with the event handle
//
CloseHandle(EventHandle);
//
// Check result of GetOverlappedResult
//
if (!Result) {
Error = GetLastError();
switch (Error) {
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BROKEN_PIPE:
RcPrintf("\nRemote server %s disconnected\n", ServerName);
return(FALSE);
default:
RcPrintf("Error:9 - Internal error = %d\n", Error);
RcDbgPrint("ReadPipe: GetOverLappedRsult failed, error = %d\n", Error);
return(FALSE);
}
}
}
return(TRUE);
}
/***************************************************************************\
* FUNCTION: WritePipe
*
* PURPOSE: Implements an overlapped write such that read and write operations
* to the same pipe handle don't deadlock.
*
* RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
*
* HISTORY:
*
* 05-27-92 Davidc Created.
*
\***************************************************************************/
BOOL
WritePipe(
HANDLE PipeHandle,
CONST VOID *lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten
)
{
DWORD Result;
OVERLAPPED Overlapped;
HANDLE EventHandle;
DWORD Error;
//
// Create an event for the overlapped operation
//
EventHandle = CreateEvent(
NULL, // no security
TRUE, // Manual reset
FALSE, // Initial state
NULL // Name
);
if (EventHandle == NULL) {
RcDbgPrint("WritePipe: CreateEvent failed, error = %d\n", GetLastError());
return(FALSE);
}
Overlapped.hEvent = EventHandle;
Overlapped.Internal = 0;
Overlapped.InternalHigh = 0;
Overlapped.Offset = 0;
Overlapped.OffsetHigh = 0;
Result = WriteFile(
PipeHandle,
lpBuffer,
nNumberOfBytesToWrite,
lpNumberOfBytesWritten,
&Overlapped
);
if (Result) {
//
// Success without waiting - it's too easy !
//
CloseHandle(EventHandle);
} else {
//
// Write failed, if it's overlapped io, go wait for it
// If failure due to server, print appropriate message.
//
Error = GetLastError();
switch (Error) {
case ERROR_IO_PENDING:
break;
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BROKEN_PIPE:
RcPrintf("\nRemote server %s disconnected\n", ServerName);
CloseHandle(EventHandle);
return(FALSE);
default:
RcPrintf("Error:6 - Internal error = %d\n", Error);
RcDbgPrint("WritePipe: WriteFile failed, error = %d\n", Error);
CloseHandle(EventHandle);
return(FALSE);
}
//
// Wait for the I/O to complete
//
Result = WaitForSingleObject(EventHandle, (DWORD)-1);
if (Result != 0) {
RcDbgPrint("WritePipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
CloseHandle(EventHandle);
return(FALSE);
}
//
// Go get the I/O result
//
Result = GetOverlappedResult( PipeHandle,
&Overlapped,
lpNumberOfBytesWritten,
FALSE
);
//
// We're finished with the event handle
//
CloseHandle(EventHandle);
//
// Check result of GetOverlappedResult
//
if (!Result) {
Error = GetLastError();
switch (Error) {
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BROKEN_PIPE:
RcPrintf("\nRemote server %s disconnected\n", ServerName);
return(FALSE);
default:
RcPrintf("Error:10 - Internal error = %d\n", Error);
RcDbgPrint("WritePipe: GetOverLappedRsult failed, error = %d\n", Error);
return(FALSE);
}
}
}
return(TRUE);
}
/***************************************************************************\
* FUNCTION: ReadThreadProc
*
* PURPOSE: The read thread procedure. Reads from pipe and writes to STD_OUT
*
* RETURNS: Nothing
*
* HISTORY:
*
* 05-21-92 Davidc Created.
*
\***************************************************************************/
DWORD
ReadThreadProc(
LPVOID Parameter
)
{
HANDLE PipeHandle = Parameter;
BYTE Buffer[BUFFER_SIZE];
DWORD BytesRead;
DWORD BytesWritten;
while (ReadPipe(PipeHandle, Buffer, sizeof(Buffer), &BytesRead)) {
if (!WriteFile(
GetStdHandle(STD_OUTPUT_HANDLE),
Buffer,
BytesRead,
&BytesWritten,
NULL
)) {
RcPrintf("Error:7 - Internal error = %d\n", GetLastError());
RcDbgPrint("ReadThreadProc exitting, WriteFile error = %d\n",
GetLastError());
ExitThread((DWORD)0);
assert(FALSE); // Should never get here
break;
}
}
//
// ReadPipe issues more error information to user, debugger
// falls through here on read error
//
RcDbgPrint("WriteThreadProc exitting, ReadPipe failed\n");
ExitThread((DWORD)0);
return(0);
}
/***************************************************************************\
* FUNCTION: WriteThreadProc
*
* PURPOSE: The write thread procedure. Reads from STD_INPUT and writes to pipe
*
* RETURNS: Nothing
*
* HISTORY:
*
* 05-21-92 Davidc Created.
*
\***************************************************************************/
DWORD
WriteThreadProc(
LPVOID Parameter
)
{
HANDLE PipeHandle = Parameter;
BYTE Buffer[BUFFER_SIZE];
DWORD BytesRead;
DWORD BytesWritten;
DWORD Result;
while (ReadFile(
GetStdHandle(STD_INPUT_HANDLE),
Buffer,
sizeof(Buffer),
&BytesRead,
NULL
)) {
if ((DWORD)Buffer[0] == 0x0A0D0A0D) {
RcPrintf("\nDouble crlf sent\n");
}
if (!WritePipe(
PipeHandle,
Buffer,
BytesRead,
&BytesWritten
)) {
//
// WritePipe issues more error information to user, debugger
//
RcDbgPrint("WriteThreadProc exitted due to WritePipe\n");
ExitThread((DWORD)0);
break;
}
}
//
// Falls out if read fails
//
RcDbgPrint("WriteThreadProc, ReadFile error = %d\n", GetLastError());
RcPrintf("Error:8 - Internal error = %d\n", GetLastError());
ExitThread((DWORD)0);
return(0);
}
/***************************************************************************\
* FUNCTION: CtrlHandler
*
* PURPOSE: Handles console event notifications.
*
* RETURNS: TRUE if the event has been handled, otherwise FALSE.
*
* HISTORY:
*
* 05-21-92 Davidc Created.
*
\***************************************************************************/
BOOL
CtrlHandler(
DWORD CtrlType
)
{
//
// We'll handle Ctrl-C, Ctl-Break events if session is connected
//
if (SessionConnected) {
if (CtrlType == CTRL_C_EVENT) {
//
// Session established - pass ctl-C to remote server
//
if (PipeHandle != NULL) {
//
// Send a Ctrl-C to the server, don't care if it fails
//
CHAR CtrlC = '\003';
DWORD BytesWritten;
WriteFile(PipeHandle,
&CtrlC,
sizeof(CtrlC),
&BytesWritten,
NULL
);
return(TRUE); // we handled it
}
return(FALSE); // no pipe - not handled (when in doubt, bail out)
} else if (CtrlType == CTRL_BREAK_EVENT) {
if (MultiServerMode) {
//
// If ctl-Break in session w/MultiServerMode, break session
// BUGBUG - eliminate terminate thread
//
TerminateThread(ReadThreadHandle, 0);
CloseHandle(ReadThreadHandle);
TerminateThread(WriteThreadHandle, 0);
CloseHandle(WriteThreadHandle);
return(TRUE); // we handled it
} else {
//
// Not MultiServer mode - handle normally
//
return(FALSE);
}
} else {
return(FALSE); // not ctl-c or break - we didn't handle it
}
}
//
// Not connected - we didn't handle it
//
return(FALSE);
}
/***************************************************************************\
* FUNCTION: RcPrintf
*
* PURPOSE: Printf that uses low-level io.
*
* HISTORY:
*
* 07-15-92 Davidc Created.
*
\***************************************************************************/
int RcPrintf (
const char *format,
...
)
{
CHAR Buffer[MAX_PATH];
va_list argpointer;
int Result;
DWORD BytesWritten;
va_start(argpointer, format);
Result = vsprintf(Buffer, format, argpointer);
if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), Buffer, Result, &BytesWritten, NULL)) {
RcDbgPrint("RcPrintf : Write file to stdout failed, error = %d\n", GetLastError());
Result = 0;
}
va_end(argpointer);
return(Result);
}
/***************************************************************************\
* FUNCTION: RcDbgPrint
*
* PURPOSE: DbgPrint enabled at runtime by setting RcDbgPrintEnable
*
* HISTORY:
*
* 05-22-92 DaveTh Created.
*
\***************************************************************************/
int RcDbgPrint (
const char *format,
...
)
{
CHAR Buffer[MAX_PATH];
va_list argpointer;
int iRetval = 0;
if (RcDbgPrintEnable) {
va_start(argpointer, format);
iRetval = vsprintf(Buffer, format, argpointer);
assert (iRetval >= 0);
va_end(argpointer);
OutputDebugString(Buffer);
}
return(0);
}