[英]redirect ftp pipe in C
我在Windows应用程序编程中使用NamedPipe将cmd.exe输入/输出缓冲区重定向到程序控制台。 一切正常,直到我输入“ ftp”之类的命令。 如果您在真正的cmd.exe控制台中键入此命令,则会在终端中接收到“ ftp>”,但我没有。这是我的代码:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
HANDLE hReadChildInput = NULL;
HANDLE hWriteChildInput = NULL;
HANDLE hReadChildOutput = NULL;
HANDLE hWriteChildOutput = NULL;
HANDLE hConsoleStd = NULL;
HANDLE hThread = NULL;
BOOL bRunThread = TRUE;
void ChildProcess(void);
void WriteToPipe(void*);
void ReadFromPipe(void);
void ErrorExit(PTSTR);
int _tmain(int argc, TCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if ( ! CreatePipe(&hReadChildOutput, &hWriteChildOutput, &saAttr, 0) )
ErrorExit(TEXT("StdoutRd CreatePipe"));
// Ensure the read handle to the pipe for STDOUT is not inherited.
if ( ! SetHandleInformation(hReadChildOutput, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdout SetHandleInformation"));
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&hReadChildInput, &hWriteChildInput, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
if ( ! SetHandleInformation(hWriteChildInput, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdin SetHandleInformation"));
// Get std input handle so you can close it and force the ReadFile to
// fail when you want the input thread to exit.
if ( (hConsoleStd = GetStdHandle(STD_INPUT_HANDLE)) ==
INVALID_HANDLE_VALUE )
ErrorExit(TEXT("GetStdHandle"));
// Write to the pipe that is the standard input for a child process.
// Data is written to the pipe's buffers, so it is not necessary to wait
// until the child process is running before writing data.
hThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)WriteToPipe,0,0,0);
// Create the child process.
ChildProcess();
// Read from pipe that is the standard output for child process.
ReadFromPipe();
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
ErrorExit(TEXT("WaitForSingleObject"));
// The remaining open handles are cleaned up when this process terminates.
// To avoid resource leaks in a larger application, close handles explicitly.
return 0;
}
void ChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
TCHAR szCmdline[]=TEXT("cmd.exe");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hWriteChildOutput;
siStartInfo.hStdOutput = hWriteChildOutput;
siStartInfo.hStdInput = hReadChildInput;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if ( ! bSuccess )
ErrorExit(TEXT("CreateProcess"));
else
{
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void WriteToPipe(void*)
// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data.
{
DWORD dwRead = 0, dwWritten = 0;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
for (;bRunThread;)
{
chBuf[dwRead] = '\0';
bSuccess = ReadConsole(hConsoleStd,chBuf,1,&dwRead,NULL);
if ( ! bSuccess || dwRead == 0 ) break;
chBuf[dwRead] = '\0';
bSuccess = WriteFile(hWriteChildInput, chBuf, dwRead, &dwWritten, NULL);
if ( ! bSuccess ) break;
}
// Close the pipe handle so the child process stops reading.
if ( ! CloseHandle(hWriteChildInput) )
ErrorExit(TEXT("StdInWr CloseHandle"));
}
void ReadFromPipe(void)
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
{
DWORD dwRead = 0, dwWritten = 0;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
chBuf[dwRead] = '\0';
bSuccess = ReadFile( hReadChildOutput, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) break;
chBuf[dwRead] = '\0';
bSuccess = WriteConsole(hParentStdOut,chBuf,dwRead,&dwWritten,NULL);
if (! bSuccess ) break;
}
}
void ErrorExit(PTSTR lpszFunction)
// Format a readable error message, display a message box,
// and exit from the application.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}
msdn中的此代码链接为: http : //msdn.microsoft.com/zh-cn/library/ms682499 (v=VS.85) .aspx ,我进行了一些更改以使其具有交互性。 谢谢
许多控制台程序(包括ftp)都会检查stdin是实际的控制台还是管道,并区分交互式和非交互式使用。 在非交互模式下运行时,ftp不会显示提示。
您无需编写大量代码即可进行测试。 创建一个名为input.txt
的文本文件,其中包含:
open ftp.example.com
quit
在命令提示符下运行:
ftp < input.txt > output.txt 2>&1
然后output.txt将包含ftp的正常和错误输出。 您会看到没有提示。
在您的情况下,ftp的行为没有帮助。 它认为它是非交互式运行的,因为stdin是管道,但是您实际上是在交互式运行。 我不知道可以说服它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.