Создание дочернего процесса с перенаправленным стандартным вводом / выводом в канал - PullRequest
1 голос
/ 30 мая 2020

Я пытаюсь создать дочерний процесс с перенаправленным stdin / stdout. Я создаю канал для перенаправления stdin и записи stdout в файл.

Вот что я пробовал

#include <Windows.h>
#include <iostream>

int main()
{
    STARTUPINFOA sInfo;
    PROCESS_INFORMATION pInfo;
    SECURITY_ATTRIBUTES sAttr;
    ZeroMemory(&sInfo, sizeof(sInfo));
    ZeroMemory(&pInfo, sizeof(pInfo));
    ZeroMemory(&sAttr, sizeof(sAttr));
    sInfo.cb = sizeof(sInfo);
    sAttr.bInheritHandle = true;
    HANDLE fileTest = CreateFileA("hello.txt", GENERIC_READ | GENERIC_WRITE, 0, &sAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE stdinPipe = CreateNamedPipeA("\\\\.\\pipe\\DokiDokiIn", PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, &sAttr);
    sInfo.hStdInput = stdinPipe;
    sInfo.hStdOutput = fileTest;
    sInfo.hStdError = fileTest;
    sInfo.dwFlags |= STARTF_USESTDHANDLES;
    char cmdLine[] = "cmd.exe";
    bool success = CreateProcessA("C:\\WINDOWS\\system32\\cmd.exe", NULL, &sAttr, NULL, NULL, NULL, NULL, NULL, &sInfo, &pInfo);
    if (!success) {
        std::cout << "CreateProcessA() failed with error " << GetLastError() << "\n";
    }
    std::cout << GetLastError() << "\n";
    return 0;
}

Кажется, это не работает, когда я указываю STARTF_USESTDHANDLES как dwFlags открытый процесс мгновенно закрывается (или не открывается вообще, не уверен). Это работает, когда я не указываю флаги, но ввод-вывод не перенаправляется. Кроме того, как и ожидалось, запись в него с использованием моего клиента канала не работает, он не может получить дескриптор этого канала. CreateFile всегда имеет значение true, и значения дескрипторов кажутся действительными, GetLastError () возвращает 0, но программа просто завершается, и нет всплывающего окна с дочерним процессом, и даже если он работал в фоновом режиме, я не могу писать в него.

1 Ответ

0 голосов
/ 01 июня 2020

На основе представленного вами кода обнаружены две проблемы:

  1. Установите bInheritHandles параметр CreateProcessA на TRUE вместо NULL, чтобы сделать каждый наследуемый дескриптор в вызывающем процессе наследуется новым процессом (здесь cmd.exe).
  2. cmd.exe показывает информацию о версии после запуска и завершает работу. Вы можете настроить командную строку для cmd.exe, чтобы он работал постоянно, если вы хотите предотвратить его выход.

Подсказка:

Позвоните GetLastError() сразу после сбоя функции, в противном случае код ошибки может быть установлен на zero другими функциями.

Ниже приведен пример работы для меня. Вы можете попробовать.

int main()
{
    STARTUPINFOA sInfo;
    PROCESS_INFORMATION pInfo;
    SECURITY_ATTRIBUTES sAttr;
    ZeroMemory(&sInfo, sizeof(sInfo));
    ZeroMemory(&pInfo, sizeof(pInfo));
    ZeroMemory(&sAttr, sizeof(sAttr));
    sInfo.cb = sizeof(sInfo);
    sAttr.bInheritHandle = true;
    HANDLE fileTest = CreateFileA("hello.txt", GENERIC_READ | GENERIC_WRITE, 0, &sAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE stdinPipe = CreateNamedPipeA("\\\\.\\pipe\\DokiDokiIn", PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, &sAttr);
    sInfo.hStdInput = stdinPipe;
    sInfo.hStdOutput = fileTest;
    sInfo.hStdError = fileTest;
    sInfo.dwFlags |= STARTF_USESTDHANDLES;

    char input[] = "ping www.google.com -t";
    char cmd[] = "cmd.exe";
    // initialize cmd
    char cmdline[MAX_PATH];
    sprintf_s(cmdline, sizeof(cmdline), "%s /c %s", cmd, input);
    bool success = CreateProcessA("C:\\WINDOWS\\system32\\cmd.exe", cmdline, &sAttr, NULL, TRUE, NULL, NULL, NULL, &sInfo, &pInfo);
    if (!success) {
        DWORD errCode = GetLastError();
        std::cout << "CreateProcessA() failed with error " << errCode << "\n";
    }

    return 0;
}
...