2012-04-21 2 views
0

createprocess 부모 및 자식에 대해 MSDN 예제를 실행하지만 올바르게 입력되지 않습니다. 자식 입력에 정보를 씁니다 (cmd에 인쇄하여 확인한 내용) , 그러나 이후 printf ("\ n-> 자식 프로세스의 내용 STDOUT : \ n \ n"); 이 응용 프로그램은 내가 아무것도받지하지만 대기 호출 된 cmd를create process 부모 자식, 자식으로부터의 정보 없음

ReadFromPipe(); 

를 호출 할 때 는 기다립니다. 나는 Ctrl + C를 눌러야 만 끝납니다. 그 이유는 무엇일까요?

#include "stdafx.h" 
#include <windows.h> 
#include <tchar.h> 
#include <stdio.h> 
#include <strsafe.h> 
#include <iostream> //only for cout 

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

void CreateChildProcess(void); 
void WriteToPipe(void); 
void ReadFromPipe(void); 
void ErrorExit(PTSTR); 

int _tmain(int argc, TCHAR *argv[]) 
{ 
    SECURITY_ATTRIBUTES saAttr; 

    printf("\n->Start of parent execution.\n"); 

// 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(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) 
     ErrorExit(TEXT("StdoutRd CreatePipe")); 

// Ensure the read handle to the pipe for STDOUT is not inherited. 

    if (! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) 
     ErrorExit(TEXT("Stdout SetHandleInformation")); 

// Create a pipe for the child process's STDIN. 

    if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
     ErrorExit(TEXT("Stdin CreatePipe")); 

// Ensure the write handle to the pipe for STDIN is not inherited. 

    if (! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) 
     ErrorExit(TEXT("Stdin SetHandleInformation")); 

// Create the child process. 

    CreateChildProcess(); 

// Get a handle to an input file for the parent. 
// This example assumes a plain text file and uses string output to verify data flow. 

    if (argc == 1) 
     ErrorExit(TEXT("Please specify an input file.\n")); 

    g_hInputFile = CreateFile(
     argv[1], 
     GENERIC_READ, 
     0, 
     NULL, 
     OPEN_EXISTING, 
     FILE_ATTRIBUTE_READONLY, 
     NULL); 

    if (g_hInputFile == INVALID_HANDLE_VALUE) 
     ErrorExit(TEXT("CreateFile")); 

// 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. 

    WriteToPipe(); 
    printf("\n->Contents of %s written to child STDIN pipe.\n", argv[1]); 

// Read from pipe that is the standard output for child process. 

    printf("\n->Contents of child process STDOUT:\n\n"); 
    ReadFromPipe(); 

    printf("\n->End of parent execution.\n"); 

// 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 CreateChildProcess() 
// Create a child process that uses the previously created pipes for STDIN and STDOUT. 
{ 
    TCHAR szCmdline[]=TEXT("C:\\Windows\\notepad.exe");//TEXT("C:\\Windows\\System32\\cmd.exe"); 
    PROCESS_INFORMATION piProcInfo; 
    STARTUPINFO siStartInfo; 
    BOOL bSuccess = FALSE; 
    std::cout<<"\nCreateChildProcess.\n"; 
// 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) 
     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, dwWritten; 
    CHAR chBuf[BUFSIZE]; 
    BOOL bSuccess = FALSE; 

    for (;;) 
    { 
     bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL); 
     if (! bSuccess || dwRead == 0) break; 

     bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL); 
     if (! bSuccess) break; 
    } 
    std::cout<<"\nchBuf: "<<chBuf<<std::endl; 
// Close the pipe handle so the child process stops reading. 

    if (! CloseHandle(g_hChildStd_IN_Wr)) 
     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, dwWritten; 
    CHAR chBuf[BUFSIZE]; 
    BOOL bSuccess = FALSE; 
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 

     bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, 4, &dwRead, NULL); 
     std::cout<<"\nchBuf: "<<chBuf<<std::endl; 

    /*for (int i=0;i<2;i++) //read twice 
    { 
     bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); 
     if(! bSuccess || dwRead == 0) break; 
     std::cout<<"\nchBuf: "<<chBuf<<std::endl; 

     bSuccess = WriteFile(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); 
} 

답변

1

GUI 응용 프로그램 인 notepad.exe를 시작하는 이유는 stdout에 기록하지 않기 때문입니다. 그래서 stdout은 열린 채로 앉아 아무 것도 쓰지 않아서 ReadFile 블록이 나타나서 뭔가를 기다리고 있습니다. 주석 처리 한 cmd.exe로 다시 전환하면 ReadFromPipe 호출에서 출력을 얻게됩니다.

또한 ReadFromPipe 함수는 대부분 정크 출력이 될 것입니다. 이를 테스트하기 위해 다음과 같이 변경했습니다 :

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; 
    CHAR chBuf[BUFSIZE]; 
    BOOL bSuccess = TRUE; 

    do 
    { 
     dwRead = 0; 
     bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE-1, &dwRead, NULL); 
     chBuf[dwRead] = '\0'; 
     std::cout<<"\nchBuf: "<<chBuf<<std::endl; 
    } while (bSuccess && dwRead > 0); 
} 
+0

예, 필자는 메모장 대신 cmd.exe를 사용하여 예상 한 결과를 반환합니다. 메모장의 출력을 파이프를 통해 cmd로 리디렉션하는 것이 불가능합니까? – 4pie0

+1

메모장과 같은 GUI 응용 프로그램은 stdout에 쓰거나 stdin에서 읽지 않으므로 입력 리디렉션과 함께 작동하는 것은 불가능합니다. 입력 리디렉션은 cmd.exe와 같은 콘솔 응용 프로그램에서만 작동합니다. – shf301

+0

하지만 자식의 출력에는 파일의 내용이 없습니다. 왜? ther은 cmd ("Microsoft .."및 프롬프트 라인)의 내용입니다. 파일에 열리고 자식이 읽는 파이프에 쓰는 문자열이 있습니다. – 4pie0