繁体   English   中英

在C中重定向ftp管道

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM