使用重定向输入和输出的C ++进程间通信不适用于发布版本

时间:2015-09-23 10:43:12

标签: c++ ipc

我正在开发一个需要创建子进程并将其输入和输出重定向到父进程的项目。 我在MSDN(link)上关注此示例。目前它适用于调试版本,但不适用于发布版本。我无法弄明白为什么。请帮我 子进程的编码如下(非常类似于示例):

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string>
#include <Iepmapi.h>
#include <Wininet.h>
#include <vector>

#define BUFSIZE 4096 
using namespace std;

vector<wstring> subStringByString(wstring input, wstring delimiter)
{
    int pos = input.find(delimiter);
    vector<wstring> arr;
    while (pos != wstring::npos)
    {
        wstring token = input.substr(0, pos);
        arr.push_back(token);
        input = input.substr(pos + delimiter.size(), input.size());
        pos = input.find(delimiter);
    }
    arr.push_back(input);
    return arr;
}

int main(void)
{
    WCHAR chBuf[BUFSIZE];
    DWORD dwRead, dwWritten;
    HANDLE hStdin, hStdout;
    BOOL bSuccess;

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    hStdin = GetStdHandle(STD_INPUT_HANDLE);
    if (
        (hStdout == INVALID_HANDLE_VALUE) ||
        (hStdin == INVALID_HANDLE_VALUE)
        )
        ExitProcess(1);

    // Send something to this process's stdout using printf.
    printf("\n ** This is a message from the child process. ** \n");

    // This simple algorithm uses the existence of the pipes to control execution.
    // It relies on the pipe buffers to ensure that no data is lost.
    // Larger applications would use more advanced process control.
    int rc = 0;
    for (;;)
    {
        // Read from standard input and stop on error or no data.
        bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
        wstring input = wstring(chBuf);
        wstring delimiter = L"  ";
        vector<wstring> arr = subStringByString(input, delimiter);

        int rc = 0;

        if (!bSuccess || dwRead == 0) 
            break;
        if (IESetProtectedModeCookie(arr[0].c_str(), arr[1].c_str(), arr[2].c_str(), INTERNET_COOKIE_THIRD_PARTY) != S_OK)
        {
            DWORD error = GetLastError();
            rc = -27;
        }
        // Write to standard output and stop on error.
        if (rc == 0 )
            bSuccess = WriteFile(hStdout, L"0", dwRead, &dwWritten, NULL);
        else 
            bSuccess = WriteFile(hStdout, L"-27", dwRead, &dwWritten, NULL);
        if (!bSuccess)
            break;
    }

    return 0;
}

谢谢, 荣

父流程代码:

std::wstring invoke(const std::wstring input)
{
    if (!CreateChildProcess())
        return L"error";
    DWORD dwRead, dwWritten;
    WCHAR chBuf[BUFSIZE] ;
    const WCHAR* temp = input.c_str();
    wcscpy(chBuf, temp);
    BOOL bSuccess = FALSE;

    for (;;)
    {
        bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
        if (!bSuccess) break;
    }
    CloseHandle(g_hChildStd_IN_Wr);
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

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

        bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
        if (!bSuccess) break;
    }
    //TerminateProcess(_processId, 0);
    return std::wstring(&chBuf[0]);
}

bool CreateChildProcess(void)
{
    SECURITY_ATTRIBUTES saAttr;
    // 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 STDIN. 
    if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
        return false;
    if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
    {
        cleanUpHandle();
        return false;
    }
    // Create a pipe for the child process's STDOUT.
    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
    {
        cleanUpHandle();
        return false;
    }
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
    {
        cleanUpHandle();
        return false;
    }

    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
    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. 
    HANDLE hToken = NULL;
    HANDLE hNewToken = NULL;
    bSuccess = OpenProcessToken(GetCurrentProcess(),
        TOKEN_DUPLICATE |
        TOKEN_ADJUST_DEFAULT |
        TOKEN_QUERY |
        TOKEN_ASSIGN_PRIMARY,
        &hToken);

    if (!bSuccess) {
        return 0;
    }
    hNewToken = CreateLowLevelToken(hToken);
    wa_wstring deploymentPath;
    if (WAAPI_FAILED(ProcessUtils::getDeploymentPath(deploymentPath)))
    {
        return false;
    }
    wa_wstring path = deploymentPath + wa_wstring(PROCESS_PATH);

    LPTSTR szCmdline = wstring_to_LPTSTR(path);
    if (_processId != 0)
    {
        TerminateProcess(_processId, 0);
    }

    TCHAR szCmdline2[] = PROCESS_PATH;
    bSuccess = CreateProcessAsUser(hNewToken, NULL, szCmdline2, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo);

    DWORD error = GetLastError();
    if (!bSuccess)
    {
        cleanUpHandle();
        return false;
    }
    else {
        _processId = piProcInfo.dwProcessId;
        CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);
    }

    return true;
}

1 个答案:

答案 0 :(得分:0)

我发现了问题。 在“调试版本中, dwRead dwWritten 的值是垃圾值,但是,在relase版本中的值为0.这导致父挂起。 解决这个问题:

DWORD dwRead = -1, dwWritten = -1;