Resolvi escrever um programa para gerenciar o cmd.exe sem atrair a atenção dos auxiliares.

Eu preciso: iniciar o processo, obter a saída.
Em seguida, faça a entrada e leia a saída. e assim por diante o tempo todo.

Trabalhar com Pipe é como ficção científica.

Usando CreateProcess eu inicio cmd.exe com os parâmetros "cmd /c dir".

procedure StartExe(s: string); //Стартуем! В дорогу нам пора
var
  WaitThreadId: Cardinal;
  StartupInfo: TStartupInfo;
  SecurityAttributes: TSecurityAttributes;
  ProcessInformation: TProcessInformation;
begin
  Form1.Memo2.Lines.Add('Process started.');
  ZeroMemory(@SecurityAttributes, SizeOf(SecurityAttributes));
  SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
  SecurityAttributes.lpSecurityDescriptor := nil;
  SecurityAttributes.bInheritHandle := True;
  CreatePipe(hPipeInputRead, hPipeInputWrite, @SecurityAttributes, 0);
  //SetHandleInformation(hPipeInputRead, HANDLE_FLAG_INHERIT, 0);
  CreatePipe(hPipeOutputRead, hPipeOutputWrite, @SecurityAttributes,
0);
  //SetHandleInformation(hPipeOutputRead, HANDLE_FLAG_INHERIT, 0);
  ZeroMemory(@StartupInfo, SizeOf(TStartupInfo));
  ZeroMemory(@ProcessInformation, SizeOf(TProcessInformation));
  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.hStdInput := hPipeInputRead;
  StartupInfo.hStdOutput := hPipeOutputWrite;
  StartupInfo.hStdError := hPipeOutputWrite;
  if CreateProcess(nil, PChar(s), nil, nil, True, CREATE_NEW_CONSOLE,
nil, nil, StartupInfo, ProcessInformation) then
  begin
    hProcess := ProcessInformation.hProcess;
    hThread := CreateThread(nil, 0, @ReadThreadProc, nil, 0,
ThreadId);
  end;
end;

Após iniciar o processo na função anterior na linha 30, crio um thread ReadThreadProc usando
CreateThread

procedure ReadThreadProc;
var
  BytesCount: Cardinal;
  buf: array [0..4096] of Char;
begin
  Terminated := false;
  while not Terminated do
  begin
    if hPipeOutputRead <> INVALID_HANDLE_VALUE then
    begin
      ZeroMemory(@buf, SizeOf(buf));
      if ReadFile(hPipeOutputRead, buf, Length(buf), BytesCount, nil)
then
      begin
        if BytesCount <> 0 then
        begin
          //Вроде ошибка не здесь
          OemToAnsiBuff(buf, buf, BytesCount);
          Form1.Memo2.Text := Form1.Memo2.Text + Copy(buf, 1,
BytesCount);
        end;
      end;
    end;
  end;
end;

Aqui estou lendo dados de PipeOutputRead e enviando-os para Memo.
<hr>
De tempos em tempos eu escrevo dados em hPipeInputWrite:

procedure InputText(s: string);
var
  BytesCount: Cardinal;
  buf: array [0..4096] of Char;
begin
//Проверяем размер вводимой строки:
  if Length(s) < 4090 then
  begin
    ZeroMemory(@buf, SizeOf(buf));
    StrPCopy(buf, s + #13#10); //
    WriteFile(hPipeInputWrite, buf, Length(s) + 2, BytesCount, nil);
  end;
end;

Às vezes eu encerro à força o thread/processo cmd.exe

procedure StopThread(); //Эта часть кода с глюками и часто вылетает
begin
  Terminated := true;

  if ThreadId <> INVALID_HANDLE_VALUE then
  begin
    WaitForSingleObject(ThreadId, INFINITE);
  end;
  if hThread <> INVALID_HANDLE_VALUE then CloseHandle(hThread);
  if hProcess <> INVALID_HANDLE_VALUE then
  begin
    TerminateProcess(hProcess, 255);
    WaitForSingleObject(hProcess, INFINITE);
    if hProcess <> INVALID_HANDLE_VALUE then CloseHandle(hProcess);
  end;
  if hPipeInputWrite <> INVALID_HANDLE_VALUE then CloseHandle
(hPipeInputWrite);
  if hPipeInputRead <> INVALID_HANDLE_VALUE then CloseHandle
(hPipeInputRead);
  if hPipeOutputWrite <> INVALID_HANDLE_VALUE then CloseHandle
(hPipeOutputWrite);
  if hPipeOutputRead <> INVALID_HANDLE_VALUE then CloseHandle
(hPipeOutputRead);
end;

O problema é que ao executar este código ocorrem erros constantemente:
Violação de acesso, Exceção externa C0000008, etc.

Trabalhar com Pipe é como ficção científica.
Às vezes funciona, às vezes não. O que estou fazendo de errado?

Eu li o artigo da Microsoft com. não trouxe clareza
https://learn.microsoft.com/ru-ru/w...h … and-output