简体   繁体   English

无法从挂起进程的单独线程中读取管道

[英]Cannot read from pipe in separate thread from suspended process

I am trying to create process with CreateProcess in suspended state and the read from it's stdout. 我正在尝试使用处于挂起状态的CreateProcess创建进程并从它的stdout读取。 For base I took MSDN code. 对于基础我采用了MSDN代码。 After creating process I'm going to set Job restrictions(not implemented yet) on the process and then I'm starting reading in separate thread from STDOUT pipe. 创建进程后,我将在进程上设置作业限制(尚未实现),然后我开始在STDOUT管道的单独线程中读取。 Before thread is initiated I resume suspended process. 在线程启动之前,我恢复暂停过程。 In result I'm getting nothing from ReadFile call, it just stops and waits for data to arrive even when the process is finished. 结果我从ReadFile调用中得不到任何东西,它只是停止并等待数据到达,即使进程完成。 Here is the code 这是代码

#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_RdDup = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hSavedStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;

DWORD WINAPI CreateChildProcess(LPVOID param);
void WriteToPipe(void); 
DWORD WINAPI ReadFromPipe(LPVOID param);
void ErrorExit(PTSTR); 
    PROCESS_INFORMATION piProcInfo; 

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")); 

    STARTUPINFO siStartInfo;
    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;
    //CreateThread(&saAttr,0, CreateChildProcess, &siStartInfo, 0, NULL);
    CreateChildProcess(&siStartInfo);
    ResumeThread(piProcInfo.hThread);

    printf( "\n->Contents of child process STDOUT:\n\n", argv[1]);
    //ReadFromPipe(NULL); 
    HANDLE thread = CreateThread(&saAttr,0, ReadFromPipe, &siStartInfo, 0, NULL);
    WaitForSingleObject(thread, INFINITE);

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

DWORD WINAPI CreateChildProcess(LPVOID param)
    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
{ 
    TCHAR szCmdline[]=TEXT("C:\\GnuWin32\\bin\\ls.exe");

    STARTUPINFO *siStartInfo = (STARTUPINFO*)param;

    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.


    // Create the child process. 

    bSuccess = CreateProcess(NULL, 
        szCmdline,     // command line 
        NULL,          // process security attributes 
        NULL,          // primary thread security attributes 
        TRUE,          // handles are inherited 
        CREATE_SUSPENDED | CREATE_SEPARATE_WOW_VDM | CREATE_NO_WINDOW,             // creation flags 
        NULL,          // use parent's environment 
        NULL,          // use parent's current directory 
        siStartInfo,  // STARTUPINFO pointer 
        &piProcInfo);  // receives PROCESS_INFORMATION 
    //If resumethread is here - it works well

   // 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);
    }
    return 0;
}

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

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

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

DWORD WINAPI ReadFromPipe(LPVOID param) 

    // 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);

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

        bSuccess = WriteFile(hParentStdOut, chBuf, 
            dwRead, &dwWritten, NULL);
        if (! bSuccess ) break; 
    } 
    return 0;
} 

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);
}

And if I call ResumeThread(piProcInfo.hThread); 如果我调用ResumeThread(piProcInfo.hThread); just after CreateProcess function - It works well. 就在CreateProcess函数之后 - 它运行良好。 But I need to keep creation in separate function anyway and call ResumeThread few functions after. 但是我还是需要在单独的函数中保持创建,然后调用ResumeThread之后的几个函数。 So, I would like to what to do to make program get suspended process's output in separate thread. 所以,我想做什么来使程序在单独的线程中获得暂停进程的输出。

Always check return values. 始终检查返回值。

You're trying to call ResumeThread on a handle that's already been closed. 你试图在已经关闭的句柄上调用ResumeThread If you had checked the return value, you'd have noticed that this function wasn't succeeding, which would have told you what the problem was. 如果你检查了返回值,你会发现这个功能没有成功,这会告诉你问题是什么。

Remove CloseHandle(piProcInfo.hThread) from CreateChildProcess and the call to ResumeThread will work. CreateChildProcess删除CloseHandle(piProcInfo.hThread) ,对ResumeThread将起作用。

You should probably also be closing g_hChildStd_OUT_Wr and g_hChildStd_IN_Rd after creating the child process, so that you can tell when the child process exits. 您可能还应该在创建子进程后关闭g_hChildStd_OUT_Wrg_hChildStd_IN_Rd ,以便您可以判断子进程何时退出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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