簡體   English   中英

無法從掛起進程的單獨線程中讀取管道

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

我正在嘗試使用處於掛起狀態的CreateProcess創建進程並從它的stdout讀取。 對於基礎我采用了MSDN代碼。 創建進程后,我將在進程上設置作業限制(尚未實現),然后我開始在STDOUT管道的單獨線程中讀取。 在線程啟動之前,我恢復暫停過程。 結果我從ReadFile調用中得不到任何東西,它只是停止並等待數據到達,即使進程完成。 這是代碼

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

如果我調用ResumeThread(piProcInfo.hThread); 就在CreateProcess函數之后 - 它運行良好。 但是我還是需要在單獨的函數中保持創建,然后調用ResumeThread之后的幾個函數。 所以,我想做什么來使程序在單獨的線程中獲得暫停進程的輸出。

始終檢查返回值。

你試圖在已經關閉的句柄上調用ResumeThread 如果你檢查了返回值,你會發現這個功能沒有成功,這會告訴你問題是什么。

CreateChildProcess刪除CloseHandle(piProcInfo.hThread) ,對ResumeThread將起作用。

您可能還應該在創建子進程后關閉g_hChildStd_OUT_Wrg_hChildStd_IN_Rd ,以便您可以判斷子進程何時退出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM