delphi CreatePipe / CreateProcess无效读取句柄

jtoj6r0c  于 2023-04-05  发布在  其他
关注(0)|答案(1)|浏览(262)

我尝试使用管道进行进程通信,但尝试从Read句柄读取时导致错误。
首先,这里有一些测试代码,看看管道是否工作,但它不工作:

procedure TestPipe;
const
  SecConst: TSecurityAttributes = (nLength: SizeOf(TSecurityAttributes); bInheritHandle: true);
var
  Security: TSecurityAttributes;
  PipeRead, PipeWrite: THandle;
  s: string;
begin
  Security:= SecConst;
  Win32Check(CreatePipe(PipeRead, PipeWrite, @Security, 0));
  Win32Check(SetStdHandle(STD_OUTPUT_HANDLE, PipeWrite));
  Win32Check(SetStdHandle(STD_INPUT_HANDLE, PipeRead));
  Writeln('555');
  Readln(s);  // <-- Hangs here!
  Assert(s = '555');
end;

程序挂起,而不是阅读我写入管道的字符串。
下面是我想稍微修改一下的实际代码:

procedure StartWorker;
const
  SecConst: TSecurityAttributes = (nLength: SizeOf(TSecurityAttributes); bInheritHandle: true);
var
  Security: TSecurityAttributes;
  PipeRead, PipeWrite: THandle;
  SI: TStartupInfo; PI: TProcessInformation;
  s: string;
begin
  Security:= SecConst;
  Win32Check(CreatePipe(PipeRead, PipeWrite, @Security, 0));
  Win32Check(SetStdHandle(STD_OUTPUT_HANDLE, PipeWrite));

  FillChar(SI, SizeOf(SI), 0);
  FillChar(PI, SizeOf(PI), 0);
  SI.cb:= SizeOf(SI);
  SI.dwFlags:= STARTF_FORCEOFFFEEDBACK or STARTF_USESTDHANDLES;
  SI.hStdInput:= PipeRead;
  SI.hStdOutput:= INVALID_HANDLE_VALUE;
  SI.hStdError:= INVALID_HANDLE_VALUE;
  s:= 'Worker.exe';
  UniqueString(s);
  Win32Check(CreateProcess(nil, PChar(s), nil, nil, false, 0, nil, nil, SI, PI));
  CloseHandle(PI.hThread);
  CloseHandle(PI.hProcess);
end;

在这种情况下,子进程获得了一个无效的StdIn句柄。子进程只是执行一个无限的“Readln”循环(并且应该对它读取的字符串执行某些操作)。第一次调用“Readln”失败,并出现“I/O error 6”(句柄无效)。

kiz8lqtg

kiz8lqtg1#

std::pair<int, std::string> LaunchExeFileAndWaitFull(std::string exe, std::string arg, std::string workdir)
{
    SECURITY_ATTRIBUTES     sa;
    HANDLE                  hRead, hWrite;
    char                    buf[8000] = { 0 };
    STARTUPINFOA            si;
    PROCESS_INFORMATION     pi;
    DWORD                   bytesRead;
    DWORD                   bytesWrite;
    RtlSecureZeroMemory(&si, sizeof(si));
    RtlSecureZeroMemory(&pi, sizeof(pi));
    RtlSecureZeroMemory(&sa, sizeof(sa));
    int br = 0;
    DWORD exitcode = 0;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = true;
    if (!CreatePipe(&hRead, &hWrite, &sa, 8000))
    {
        return std::make_pair(0, "启动进程失败");
    }

    si.cb = sizeof(si);



    si.hStdOutput = hWrite;
    si.hStdError = hWrite;
    si.hStdInput = hRead;
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    std::string cmdline = exe;
    if (!arg.empty())
    {
        cmdline += +" " + arg;
    }
    LPSTR pcmdline = _strdup(cmdline.c_str());
    LPCSTR lpCurrentDirectory = nullptr;
    if (!workdir.empty())
    {
        lpCurrentDirectory = workdir.c_str();
    }
    // Start the child process. 
    if (CreateProcessA(NULL,   // No module name (use command line)
        pcmdline,  // Command line
        NULL,
        NULL,
        TRUE,
        NULL,
        NULL,
        lpCurrentDirectory,
        &si,
        &pi)
        )
    {       

        while (1)
        {

            PeekNamedPipe(hRead, buf, 8000, &bytesRead, &bytesWrite, NULL);
            if (bytesRead != 0)
            {
                if (!ReadFile(hRead, buf + br, 8000, &bytesRead, NULL))
                    break;
                br += bytesRead;
            }
            else
            {
                if (::WaitForSingleObject(pi.hProcess, 1000) == WAIT_OBJECT_0) {

                    PeekNamedPipe(hRead, buf, 8000, &bytesRead, &bytesWrite, NULL);
                    if (bytesRead == 0)
                    {
                        break;
                    }

                }
            }
        }
        CloseHandle(hWrite);
        CloseHandle(hRead);
        ::GetExitCodeProcess(pi.hProcess, &exitcode);
        wpa_printf(MSG_DEBUG, "Run Pid:=>%d,ret:=>%d,cmd:=>%s\r\n", pi.dwProcessId, exitcode, pcmdline);
        free(pcmdline);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);

        std::string ret = "启动进程成功,返回值:" + std::to_string(exitcode) + ",命令行输出:";
        int retcode = 0;
        if (exitcode == 0)
        {
            retcode = 1;
        }
        ret.append(buf);
        return std::make_pair(retcode, ret);
    }
    else
    {
        exitcode = GetLastError();
        wpa_printf(MSG_DEBUG, "Run Pid :=> % d, ret :=> % d, cmd :=> % s\r\n", pi.dwProcessId, exitcode, pcmdline);
        free(pcmdline);
        std::string ret = "启动进程失败,错误码:" + std::to_string(exitcode);
        return std::make_pair(0, ret);
    }
    return std::make_pair(0, "启动进程失败");
}

相关问题