重定向输入和输出
2010-05-17 17:42
197 查看
本文介绍如何重定向输入和输出的子进程从标准输入句柄接收输入,或将输出发送到标准输出句柄。Win32 API 使应用程序可以生成与重定向标准的句柄的子控制台进程。此功能允许父进程发送和接收的输入和输出的子进程。
注意某些基于的控制台应用程序并为其输入/输出 (IO) 操作不使用标准的句柄。Win32 API 不支持这些进程的重定向。
通过 STARTUPINFO 结构 CreateProcess() API 使您能够重定向标准的句柄的子基于控制台进程。如果 dwFlags 成员被设置为 ST...
通过 STARTUPINFO 结构 CreateProcess() API 使您能够重定向标准的句柄的子基于控制台进程。如果 dwFlags 成员被设置为 STARTF_USESTDHANDLES,然后以下 STARTUPINFO 成员指定的子基于控制台进程标准控点:
HANDLE hStdInput - Standard input handle of the child process.
HANDLE hStdOutput - Standard output handle of the child process.
HANDLE hStdError - Standard error handle of the child process.
可以以任意一个管道句柄,文件的句柄来设置这些图柄或任何控点上,可以执行同步读取和写入通过 ReadFile() 和 WriteFile() API。控点必须是可继承,并且 CreateProcess() API 必须指定的可继承句柄的子进程继承通过 bInheritHandles 参数中指定为 TRUE。如果父进程只希望重定向一个或两个标准的句柄,指定为特定的句柄的 GetStdHandle() 会导致子创建标准的句柄,因为它通常不重定向。例如对于如果父进程只需要重定向标准输出和错误的子进程,然后 hStdInput 成员 STARTUPINFO 结构的填充,如下所示:
hStdInput = GetStdHandle(STD_INPUT_HANDLE);
重定向时,注意 子进程的此类 C 运行时函数用作 printf () 和 fprintf() 可以不良行为。C 运行时函数维护单独的 IO 缓冲区。重定向时, 可能不在每个 IO 调用后立即刷新这些缓冲区。如此一来从 getch() 调用 printf () 调用或输入的重定向管道输出不立即刷新,延迟,有时无限延迟发生。如果在子进程会 IO 缓冲区刷新到 C 运行时 IO 函数每次调用后,被避免此问题。只有子进程可以刷新其 C 运行时 IO 缓冲区。一个进程可以通过调用 fflush() 函数刷新其 C 运行时 IO 缓冲区。
注意重定向特定的子进程的标准控点时,windows 95 和 Windows 98 将需要额外的步骤。
下面的示例将重定向标准输入、 输出和 CreateProcess 调用中指定的子进程的错误。本示例将重定向提供的控制台进程 (Child.c)。
示例代码
#include<windows.h>
#pragma comment(lib, "User32.lib")
void DisplayError(char *pszAPI);
void ReadAndHandleOutput(HANDLE hPipeRead);
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL; // Handle to parents std input.
BOOL bRunThread = TRUE;
void main ()
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child output pipe.
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle");
// Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
// Close inheritable copies of the handles you do not want to be inherited.
if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
// Get std input handle so you can close it and force the ReadFile to
// fail when you want the input thread to exit.
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle");
PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);
// Close pipe handles (do not continue to modify the parent).
// You need to make sure that no handles to the write end of the
// output pipe are maintained in this process or else the pipe will
// not close when the child process exits and the ReadFile will hang.
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete
// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// PrepAndLaunchRedirectedChild
// Sets up STARTUPINFO structure, and launches redirected child.
///////////////////////////////////////////////////////////////////////
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
// Use this if you want to hide the child:
// si.wShowWindow = SW_HIDE;
// Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
// use the wShowWindow flags.
// Launch the process that you want to redirect (in this case,
// Child.exe). Make sure Child.exe is in the same directory as
// redirect.c launch redirect from a command line to prevent location
// confusion.
if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
DisplayError("CreateProcess");
// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess;
// Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// ReadAndHandleOutput
// Monitors handle for input. Exits when child exits or pipe breaks.
///////////////////////////////////////////////////////////////////////
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
}
// Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}
///////////////////////////////////////////////////////////////////////
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
///////////////////////////////////////////////////////////////////////
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
// Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole");
read_buff[nBytesRead] = '/0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
}
return 1;
}
///////////////////////////////////////////////////////////////////////
// DisplayError
// Displays the error number and corresponding message.
///////////////////////////////////////////////////////////////////////
void DisplayError(char *pszAPI)
{
LPVOID lpvMessageBuffer;
CHAR szPrintBuffer[512];
DWORD nCharsWritten;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
wsprintf(szPrintBuffer,
"ERROR: API = %s./n error code = %d./n message = %s./n",
pszAPI, GetLastError(), (char *)lpvMessageBuffer);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
lstrlen(szPrintBuffer),&nCharsWritten,NULL);
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
//////////////////////////////////////////////////////////////////////
// child.c
// Echoes all input to stdout. This will be redirected by the redirect
// sample. Compile and build child.c as a Win32 Console application and
// put it in the same directory as the redirect sample.
//
#include<windows.h>
#include<stdio.h>
#include<string.h>
void main ()
{
FILE* fp;
CHAR szInput[1024];
// Open the console. By doing this, you can send output directly to
// the console that will not be redirected.
fp = fopen("CON", "w");
if (!fp) {
printf("Error opening child console - perhaps there is none./n");
fflush(NULL);
}
else
{
// Write a message direct to the console (will not be redirected).
fprintf(fp,"This data is being printed directly to the/n");
fprintf(fp,"console and will not be redirected./n/n");
fprintf(fp,"Since the standard input and output have been/n");
fprintf(fp,"redirected data sent to and from those handles/n");
fprintf(fp,"will be redirected./n/n");
fprintf(fp,"To send data to the std input of this process./n");
fprintf(fp,"Click on the console window of the parent process/n");
fprintf(fp,"(redirect), and enter data from it's console/n/n");
fprintf(fp,"To exit this process send the string 'exit' to/n");
fprintf(fp,"it's standard input/n");
fflush(fp);
}
ZeroMemory(szInput,1024);
while (TRUE)
{
gets(szInput);
printf("Child echoing [%s]/n",szInput);
fflush(NULL); // Must flush output buffers or else redirection
// will be problematic.
if (!_stricmp(szInput,"Exit") )
break;
ZeroMemory(szInput,strlen(szInput) );
}
}
注意某些基于的控制台应用程序并为其输入/输出 (IO) 操作不使用标准的句柄。Win32 API 不支持这些进程的重定向。
通过 STARTUPINFO 结构 CreateProcess() API 使您能够重定向标准的句柄的子基于控制台进程。如果 dwFlags 成员被设置为 ST...
通过 STARTUPINFO 结构 CreateProcess() API 使您能够重定向标准的句柄的子基于控制台进程。如果 dwFlags 成员被设置为 STARTF_USESTDHANDLES,然后以下 STARTUPINFO 成员指定的子基于控制台进程标准控点:
HANDLE hStdInput - Standard input handle of the child process.
HANDLE hStdOutput - Standard output handle of the child process.
HANDLE hStdError - Standard error handle of the child process.
可以以任意一个管道句柄,文件的句柄来设置这些图柄或任何控点上,可以执行同步读取和写入通过 ReadFile() 和 WriteFile() API。控点必须是可继承,并且 CreateProcess() API 必须指定的可继承句柄的子进程继承通过 bInheritHandles 参数中指定为 TRUE。如果父进程只希望重定向一个或两个标准的句柄,指定为特定的句柄的 GetStdHandle() 会导致子创建标准的句柄,因为它通常不重定向。例如对于如果父进程只需要重定向标准输出和错误的子进程,然后 hStdInput 成员 STARTUPINFO 结构的填充,如下所示:
hStdInput = GetStdHandle(STD_INPUT_HANDLE);
重定向时,注意 子进程的此类 C 运行时函数用作 printf () 和 fprintf() 可以不良行为。C 运行时函数维护单独的 IO 缓冲区。重定向时, 可能不在每个 IO 调用后立即刷新这些缓冲区。如此一来从 getch() 调用 printf () 调用或输入的重定向管道输出不立即刷新,延迟,有时无限延迟发生。如果在子进程会 IO 缓冲区刷新到 C 运行时 IO 函数每次调用后,被避免此问题。只有子进程可以刷新其 C 运行时 IO 缓冲区。一个进程可以通过调用 fflush() 函数刷新其 C 运行时 IO 缓冲区。
注意重定向特定的子进程的标准控点时,windows 95 和 Windows 98 将需要额外的步骤。
下面的示例将重定向标准输入、 输出和 CreateProcess 调用中指定的子进程的错误。本示例将重定向提供的控制台进程 (Child.c)。
示例代码
#include<windows.h>
#pragma comment(lib, "User32.lib")
void DisplayError(char *pszAPI);
void ReadAndHandleOutput(HANDLE hPipeRead);
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL; // Handle to parents std input.
BOOL bRunThread = TRUE;
void main ()
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child output pipe.
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle");
// Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
// Close inheritable copies of the handles you do not want to be inherited.
if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
// Get std input handle so you can close it and force the ReadFile to
// fail when you want the input thread to exit.
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle");
PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);
// Close pipe handles (do not continue to modify the parent).
// You need to make sure that no handles to the write end of the
// output pipe are maintained in this process or else the pipe will
// not close when the child process exits and the ReadFile will hang.
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete
// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// PrepAndLaunchRedirectedChild
// Sets up STARTUPINFO structure, and launches redirected child.
///////////////////////////////////////////////////////////////////////
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
// Use this if you want to hide the child:
// si.wShowWindow = SW_HIDE;
// Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
// use the wShowWindow flags.
// Launch the process that you want to redirect (in this case,
// Child.exe). Make sure Child.exe is in the same directory as
// redirect.c launch redirect from a command line to prevent location
// confusion.
if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
DisplayError("CreateProcess");
// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess;
// Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// ReadAndHandleOutput
// Monitors handle for input. Exits when child exits or pipe breaks.
///////////////////////////////////////////////////////////////////////
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
}
// Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}
///////////////////////////////////////////////////////////////////////
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
///////////////////////////////////////////////////////////////////////
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
// Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole");
read_buff[nBytesRead] = '/0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
}
return 1;
}
///////////////////////////////////////////////////////////////////////
// DisplayError
// Displays the error number and corresponding message.
///////////////////////////////////////////////////////////////////////
void DisplayError(char *pszAPI)
{
LPVOID lpvMessageBuffer;
CHAR szPrintBuffer[512];
DWORD nCharsWritten;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
wsprintf(szPrintBuffer,
"ERROR: API = %s./n error code = %d./n message = %s./n",
pszAPI, GetLastError(), (char *)lpvMessageBuffer);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
lstrlen(szPrintBuffer),&nCharsWritten,NULL);
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
//////////////////////////////////////////////////////////////////////
// child.c
// Echoes all input to stdout. This will be redirected by the redirect
// sample. Compile and build child.c as a Win32 Console application and
// put it in the same directory as the redirect sample.
//
#include<windows.h>
#include<stdio.h>
#include<string.h>
void main ()
{
FILE* fp;
CHAR szInput[1024];
// Open the console. By doing this, you can send output directly to
// the console that will not be redirected.
fp = fopen("CON", "w");
if (!fp) {
printf("Error opening child console - perhaps there is none./n");
fflush(NULL);
}
else
{
// Write a message direct to the console (will not be redirected).
fprintf(fp,"This data is being printed directly to the/n");
fprintf(fp,"console and will not be redirected./n/n");
fprintf(fp,"Since the standard input and output have been/n");
fprintf(fp,"redirected data sent to and from those handles/n");
fprintf(fp,"will be redirected./n/n");
fprintf(fp,"To send data to the std input of this process./n");
fprintf(fp,"Click on the console window of the parent process/n");
fprintf(fp,"(redirect), and enter data from it's console/n/n");
fprintf(fp,"To exit this process send the string 'exit' to/n");
fprintf(fp,"it's standard input/n");
fflush(fp);
}
ZeroMemory(szInput,1024);
while (TRUE)
{
gets(szInput);
printf("Child echoing [%s]/n",szInput);
fflush(NULL); // Must flush output buffers or else redirection
// will be problematic.
if (!_stricmp(szInput,"Exit") )
break;
ZeroMemory(szInput,strlen(szInput) );
}
}
相关文章推荐
- shell 输入 输出重定向
- Linux教程-标准输入/输出和重定向1. 标准输入与输出
- 进程输入、输出、错误流的重定向 .
- Shell 输入/输出重定向
- shell脚本之重定向、标准输入、输出、错误输出的使用
- OJ 调试技巧:VS2010 中 通过设置编译参数定义宏,无需修改源文件重定向标准输入输出
- Shell 输入/输出重定向
- C/C++输入/输出重定向
- 装载 linux shell数据输出到文件 输入与输出重定向 详细分析
- 输入/输出重定向
- Java重定向标准输入/输出
- linux 输入--输出--重定向 stdin/stdout/stderr
- Shell—输入/输出重定向
- Linux基础(6)标准输入输出与重定向
- 如何判断标准输入或输出是否经过了重定向,即是否在命令行上使用了“”?
- linux 重定向输出/输入
- 【Linux 系统编程】shell 输入/输出重定向
- 标准输入、输出和错误和文件重定向
- Linux下的输入/输出重定向
- linux 输入重定向和输出重定向