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