【问题标题】:Redirecting CMD.exe output and input in c through pipes通过管道在c中重定向CMD.exe输出和输入
【发布时间】:2015-10-14 16:16:13
【问题描述】:

我正在尝试将收到的 cmd 命令的输出和输入打印到标准输出,就像普通的 cmd.exe 一样。 我可以使用函数_popen,但是当我使用它启动 Python 或 Powershell 之类的程序时,它不起作用。 所以我需要子进程的输出并能够向子进程发送命令。

有一个类似的问题here

所以我修改了this链接中的代码,如下所示:

void WriteToPipe(char* command){
    DWORD dwRead, dwWritten;
    BOOL bSuccess = FALSE;

    bSuccess = WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);

    // Close the pipe handle so the child process stops reading. 

    if (!CloseHandle(g_hChildStd_IN_Wr))
        ErrorExit(TEXT("StdInWr CloseHandle"));
}

void ReadFromPipe(void){
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
    bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
    //bSuccess = PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, BUFSIZE, &dwRead, &dwTotalAvailBytes, &dwBytesLeft);
}

主循环如下所示:

CreateChildProcess("C:\\Python27\\python.exe");
char input_buffer[100] = { 0 };
while (1){
    fgets(input_buffer, 99, stdin);
    WriteToPipe(input_buffer);
    ReadFromPipe();
}

其他一切(来自代码)保持不变。

现在我的问题是,我想在同一个进程中输入多个命令,但是 WriteToPipe 中有一个 CloseHandle 功能,句柄关闭后我无法输入更多命令。

如何获取有效的 HANDLE 以向进程写入多个命令?

【问题讨论】:

  • 在函数中:ReadFromPipe 局部变量 bSuccess 在每个子函数调用中设置,但从不使用。你的编译器应该告诉你这个问题。编译时,始终启用所有警告,然后修复警告。 (对于 gcc,至少使用:-Wall -Wextra -pedantic
  • 由于你使用的是windows函数,而不是使用函数CreateChildProcess(),使用windows的CreateProcess,那么你可以替换stdin、stdout和stderrhandels。你会得到更多的控制权。有很多关于那个的教程
  • @user3629249 我知道,但就像我说的前两个电话有效....
  • @milevyo uhhmmmm CreateChildProcess 在我的源代码中定义并实际调用 CreateProcess,是的,我定义了 hStdOutput 等,但是谢谢

标签: c windows cmd pipe


【解决方案1】:
int WriteToPipe(char* command){
    DWORD dwRead, dwWritten;
    BOOL bSuccess = FALSE;

    bSuccess = WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);

   return bSuccess ;
}

关闭 main() 函数中的句柄,因为 g_hChildStd_IN_Wr 是全局的。另外,return bSuccess; 会在写入管道成功时通知您

【讨论】:

  • 用ReadFromPipe同样的东西,在main函数中检查是否成功
【解决方案2】:

将 ReadFromPipe() 放在一个单独的线程中; 我这里的代码是垃圾,但它是工作代码,仅用于测试目的。

#include <windows.h> 
#include <tchar.h>
#include <stdio.h> 
#include <strsafe.h>

#define BUFSIZE 4096 

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;

int CreateChildProcess(TCHAR *szCmdline);

void PrintError(char *text,int err);
int InitPipes();


int WriteToPipe(char* command){
    DWORD dwRead, dwWritten;
    BOOL bSuccess = FALSE;
    SetLastError(0);
    WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);


    bSuccess=GetLastError();

    PrintError("WriteToPipe",bSuccess);
    return (bSuccess==0)||(bSuccess==ERROR_IO_PENDING);
}

int ReadFromPipe(void){
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    SetLastError(0);
    while(
        ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL)
        &&
        WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL)
        );

    bSuccess=GetLastError();
    PrintError("ReadFromPipe",bSuccess);


    return (bSuccess==0)||(bSuccess==ERROR_IO_PENDING);
}

HANDLE hThread;

int __stdcall ThreadProc(int arg){

    while(ReadFromPipe())
        ;

    return 0;
}

int main(){
    char input_buffer[100] = { 0 };
    if(!InitPipes()){
        printf("Failed to CreatePipes\n");
        return -1;
    }

    if(!CreateChildProcess("cmd.exe")){
        printf("Failed to create child process\n");
        return -2;
    }


    hThread=CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

    while (1){
        fgets(input_buffer, 99, stdin);
        if(!WriteToPipe(input_buffer)) break;
    }
    printf("Program terminated\n");
    return 0;
}





int CreateChildProcess(TCHAR *szCmdline){ 

   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 = g_hChildStd_OUT_Wr;
   siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
   siStartInfo.hStdInput = g_hChildStd_IN_Rd;
   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 ){
      // 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);
   }
    return bSuccess;
}



int InitPipes(){
   SECURITY_ATTRIBUTES saAttr; 

// Set the bInheritHandle flag so pipe handles are inherited. 

   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
   saAttr.bInheritHandle = TRUE; 
   saAttr.lpSecurityDescriptor = NULL; 



   if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) 
      return 0;

   if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
      return 0;

   if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
      return 0;

   if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
      return 0; 

    return 1;
}





void PrintError(char *text,int err){
     DWORD retSize;
     LPTSTR pTemp=NULL;

    if(!err) return;

     retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
                           FORMAT_MESSAGE_FROM_SYSTEM|
                           FORMAT_MESSAGE_ARGUMENT_ARRAY,
                           NULL,
                           err,
                           LANG_NEUTRAL,
                           (LPTSTR)&pTemp,
                           0,
                           NULL );


    if(pTemp) printf("%s: %s\n",text,pTemp);
     LocalFree((HLOCAL)pTemp);
    return ;

}

【讨论】:

  • Remark the udplicate output of the input,尝试修复它;
  • 测试结果如何?
  • WriteFile 不能返回 ERROR_IO_PENDING,除非它被异步使用。针对同步写入操作检查 ERROR_IO_PENDING 的返回值没有意义。
  • 好吧,我提到代码是垃圾:)。主要问题已经解决了。
  • 我没有提到它,因为这对我来说似乎很明显:Stackoverflow 并不完全是关于发布垃圾答案。您可能希望通过tour 了解stackoverflow 是什么。 (这也不是要对一个问题发布多个答案;出于某种原因,您的答案上有一个edit 链接。)
猜你喜欢
  • 2013-03-30
  • 1970-01-01
  • 2021-10-16
  • 2016-10-21
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多