Redirecting CMD.exe output and input in c through

2019-09-19 14:23发布

Im trying to print the output and input of cmd commands recieved to stdout just like a normal cmd.exe would do. I could use the function _popen but when i start a program like Python or Powershell whith it, it doesnt work. So i Need the Output of the child process and be able to send commands to the child process.

there is a simmilar question here

So i modified the code from this link to look like 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);
}

the main loop looks like this:

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

everything else (from the code) stayed the same.

Now my Problem is, i want to enter multiple commands to the same process, but there is a CloseHandle fucntion in WriteToPipe, after the handle is closed i cant enter more commands.

How to get a valid HANDLE to write more than 1 command to the process ?

标签: c windows cmd pipe
2条回答
淡お忘
2楼-- · 2019-09-19 14:40
int WriteToPipe(char* command){
    DWORD dwRead, dwWritten;
    BOOL bSuccess = FALSE;

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

   return bSuccess ;
}

close the handle in main() function since g_hChildStd_IN_Wr is global. also, return bSuccess; notify you if write to pipe has succeeded

查看更多
家丑人穷心不美
3楼-- · 2019-09-19 14:43

put ReadFromPipe() in a separate Thread; my code here is a garbage but it is working code, it is for test purpose only.

#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 ;

}
查看更多
登录 后发表回答