ИМХО Для заметной части вариантов использования консоли вполне хватит "виртуальной консоли".
(А в ней особых проблем с кириллицей быть недолжно . "Memo и в африке Memo" )
Код: Выделить всё
// Выполнить команду в виртуальной консоли
Procedure RunDosInMemo(CmdLine: String; AMemo: TMemo);
Const
ReadBuffer = 1023;
Var
Security: TSecurityAttributes;
OutReadPipe, OutWritePipe: tHandle; // труба для output'a консольной проги.
InReadPipe, InWritePipe: tHandle; // труба для input'a консольной проги.
ErrReadPipe, ErrWritePipe: tHandle; // труба для error's консольной проги.
// InReadPipe, ErrReadPipe и объявлены для полноты картины,но не создаются
//и не используются.
start: TStartUpInfo;
Buffer: Pchar;
BytesRead: DWord;
Apprunning: DWord;
avail : dword;
notread:dword;
I,CL:Longint;
CS:String;
Int:TIniFile;
// stop:boolean;
Begin
//flPBar:=F_M3U8toMP4.ProgressBar1;
//flPBar.Position:=0;
//flPBar.Min:=0;
fsDuration:='';
fsProgress:='';
fsVideo:='';
vsSpeed:='';
Process_stop := false;
With Security Do Begin // инициализация структуры
nlength := SizeOf(TSecurityAttributes);
binherithandle := true;
lpsecuritydescriptor := Nil;
End;
Createpipe(InReadPipe, InWritePipe, @Security, 0);
Createpipe(ErrReadPipe, ErrWritePipe, @Security, 0);
If Createpipe(OutReadPipe, OutWritePipe, @Security, 0) Then Begin
// создали трубу для выхлопа бэкграунд-приложения
Buffer := AllocMem(ReadBuffer + 1);
// создали буфер для чтения
FillChar(Start, Sizeof(Start), #0);
// заполнили содержимое стартовой структуры #0
start.cb := SizeOf(start);
start.hStdOutput := OutWritePipe;
start.hStdError := OutWritePipe;
start.hStdInput := InReadPipe;
(*************************************************************
такой себе опширненьний комментарий...
Оказывается, мать их так, если сделать перенаправление
вывода в трубы, но не читать его, то если он(вывод)
будет достаточно длинный и сможет переполнить буфер,
который изначально отводится под трубу, то пишущий поток
остановится и будет ждать пока не освободится место в
буфере трубы. Как только оно освободилось, он сможет
продолжать работу и писать дальше.
start.hStdOutput := OutWritePipe;
start.hStdError := OutWritePipe;
почему собственно такой странный код: два потока
перенаправлены в одну трубу?
Потому что некоторые замечательные проги типа 7zip свой
вывод направляют не в StdOut, а почему то в StdErr...
и если для этих двух потоков назначить две разных трубы,
а читать только одну, то произойдет то, что описано выше.
РРРРРРРРРРРРРРРРРРРРРРРРР!!!!!!!!! сопли, слюни, ярость и
буйное помешательство на почве программирования под винду.
Может стоит сделать две трубы и читать каждую в отдельное
мемо???
**************************************************************)
start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
// окно прячем
If CreateProcess(Nil, PChar(CmdLine), @Security, @Security, true, NORMAL_PRIORITY_CLASS,
Nil, Nil, start, ProcessInfo) Then Begin
// создали процесс
Repeat
Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 100);
PeekNamedPipe(OutReadPipe, @Buffer[0], ReadBuffer, @BytesRead, @avail, @notread);
// PeekNamedPipe копирует из буфера трубы и оставляет его в первоначальном состоянии
// в то время как ReadFile читая из трубы - опустошает ее.
// PeekNamedPipe можно использовать для того чтобы узнать сколько данных есть в трубе
// и если в PeekNamedPipe передать 2 и 3 параметры пустыми, то она просто скажет
// сколько данных есть в трубе
if avail > 0 then begin
ReadFile(OutReadPipe, Buffer[0], BytesRead, BytesRead, Nil); // *******
// ReadFile при чтении из трубы опустошает ее(трубы) буфер.
end
else begin
if Apprunning <> 258 then
Process_stop := true;
end;
// читаем через читающий конец трубы из вывода консоли
Buffer[BytesRead] := #0;
// последний символ #0 - конец буфера
OemToAnsi(Buffer, Buffer);
// перевели из кодировки DOS в кодировку WIN
CL:=AMemo.Lines.Count;
CS:=String(Buffer)+#0;
if fsDuration<>'' then begin
if fsProgress <>'' then begin
If vsSpeed<>'' then
{ F_M3U8toMP4.Caption:=
'M3U8 to MP4 ( Progress : ' + fsProgress+' )'+
// F_M3U8toMP4.Caption:= F_M3U8toMP4.Caption+
' Speed= '+vsSpeed+' kb/s';
}
// SendMessage(AMemo.Handle,EM_REPLACESEL,0,integer(@CS[1]));
end
else
With AMemo do
if Lines[Lines.Count-1] <>'' then begin
Lines.Add('');
Lines.Add('Duration ='+fsDuration);
Lines.Add('');Lines.Add('');
end;
end else begin
SendMessage(AMemo.Handle,EM_REPLACESEL,0,integer(@CS[1]));
AMemo.SelStart:=Length(AMemo.Lines.Text);
//ReadInputStream(CS);
//AMemo.Refresh;
{ if WMainForm <> Nil then
wnmainform.WMainForm.CmdBox
.Write(WinCPToUTF8(String(Buffer)));
}
end;
{ if WMainForm <> Nil then
wnmainform.WMainForm.CmdBox
.Write(WinCPToUTF8(String(Buffer)));
}
//GetDuration(CS);
// GetFFTime(CS);
//GetFFVideo(CS);
{F_M3U8toMP4.CmdBox
//Add( WinCPToUTF8(String(Buffer));
.Write(WinCPToUTF8(String(Buffer)));}
{ if AMemo.VertScrollBar<> nil then
if CL<>AMemo.Lines.Count then //AMemo.VertScrollBar.Position:=
begin
AMemo.SelStart:=Length(AMemo.Lines.Text);
// if AMemo.Lines.Count >200 then AMemo.Lines.Delete(0);
// AMemo.SelStart:=Length(AMemo.Lines.Text);
// AMemo.Refresh;
end; }
// то что прочитали приписали к тексту в мемо
Application.ProcessMessages;
// обработали очередь сообщений
// Until ((Apprunning <> WAIT_TIMEOUT) or (avail < 0));
Until Process_stop;
// прервемся когда процесс завершится
// F_M3U8toMP4.Caption :='M3U8 to MP4';
End;
FreeMem(Buffer); // освободили буфер
{WAIT_TIMEOUT
WAIT_OBJECT_0 = 0;
WAIT_ABANDONED_0 = $80;
WAIT_TIMEOUT = $102;
WAIT_IO_COMPLETION = $c0;
WAIT_ABANDONED = $80;
WAIT_FAILED = $ffffffff;
MAXIMUM_WAIT_OBJECTS = $40;
MAXIMUM_SUSPEND_COUNT = $7f;
}
//PostMessage(Handle, WM_QUIT, 0, 0);
// GetExitCodeProcess(processInfo.dwProcessId
//GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,processInfo.dwProcessId);
//TerminateProcess(processInfo.hProcess, 0);
{ if FindWindow(nil,PChar(Slots[i-1].GUID))<>0 then
SendMessage(FindWindow(nil,PChar(Slots[i-1].GUID)),WM_CLOSE,0,0)
else
TerminateProcess(hProcess, NO_ERROR);
//.kill }
// KillTask('ffmpeg.exe');
Application.ProcessMessages;
AMemo.Lines.Add('');
If fsVideo<>'' Then begin
AMemo.Lines.Add(fsVideo) ;
{
Int:=TIniFile.Create(ExtractFilePath(paramstr(0))+ ListMFName);
Int.WriteString(F_M3U8toMP4.FF_NS,'FFMPEG_LocalFile',F_M3U8toMP4.FF_NF);
Int.Free;
}
end
Else
begin
KillProcessTree( ProcessInfo.dwProcessId);
{
Int:=TIniFile.Create(ExtractFilePath(paramstr(0))+ ListMFName);
Int.DeleteKey(F_M3U8toMP4.FF_NS,'FFMPEG_LocalFile');
Int.Free;
}
end;
{ then
Amemo.Lines.add('Дерево процессов успешно завершено ')
else
Amemo.Lines.add('Ошибка завершеня ');
}
Application.ProcessMessages;
CloseHandle(ProcessInfo.hProcess); // закрыли все хендлы
CloseHandle(ProcessInfo.hThread);
CloseHandle(OutReadPipe);
CloseHandle(OutWritePipe);
CloseHandle(InReadPipe);
CloseHandle(InWritePipe);
CloseHandle(ErrReadPipe);
CloseHandle(ErrWritePipe);
End;
Amemo.Lines.Add('');
Amemo.Lines.Add('==== процесс завершён ====');
//' + FormatDateTime('dd.mm.yyyy h:mm:ss:zzz am/pm',dt) + '} ====');
// конец.
End;