Cześć.
Zwykle sobie radzę sam, ale tutaj słaba znajomość obsługi procesów i potoków mnie przerosła. Dlatego proszę o pomoc z przykładami kodów źródłowych. Jak wiadomo taki kod:
function ExecNewProcess(ProgramName : string; CmdShow : longword) : DWORD;
var
SI : TStartupInfo;
PI : TProcessInformation;
begin
ZeroMemory(@SI, SizeOf(SI));
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESHOWWINDOW;
SI.wShowWindow := CmdShow;
CreateProcess(nil, PChar(ProgramName), nil, nil, False, 0, nil, nil, SI, PI);
Result := PI.dwProcessId;
end;
Bez problemów wywoła nam polecenie z parametrami i zwórci PID wywołanego procesu, jeśli się on otworzy. A nawet jeśli zamkniemy program, który użył tego kodu, a inny wywołany proces nadal pracuje, to będzie to trwało nadal bez problemów.
Jednak ja chciałbym wywołać ukryte okno procesu, którym będzie rtmpdump.exe
przekierowany na VLC. Wszystko działa. Jednak zamknięcie programu, który go wywołał po sukcesywnym wywołaniu, powoduje że po jakimś czasie stream RTMP, który przekierowuje rtmpdump.exe
zapętla się. Tak jakby nie otrzymywał już nowych danych.
Jak widzicie zakomentowałem wszelkie CloseHandle
. Korzystałem zamiennie z tych kodów, które nieznacznie zmodyfikowałem. Kody są wygooglowane. A zależy na wychwyceniu mi zwróconego komunikatu przez rtmpdump.exe
, który następuje góra po kilku sekundach czasu od jego uruchomienia.
procedure CaptureConsoleOutput(const ACommand : string; AMemo : TMemo);
const
CReadBuffer = 2400;
var
DRead, DRunning : DWORD;
SaSecurity : TSecurityAttributes;
HRead, HWrite : THandle;
suiStartup : TStartupInfo;
piProcess : TProcessInformation;
pBuffer : array[0..CReadBuffer] of Char;
begin
SaSecurity.nLength := SizeOf(TSecurityAttributes);
SaSecurity.bInheritHandle := True;
SaSecurity.lpSecurityDescriptor := nil;
if CreatePipe(hRead, hWrite, @SaSecurity, 0) then
begin
FillChar(suiStartup, SizeOf(TStartupInfo), #0);
suiStartup.cb := SizeOf(TStartupInfo);
suiStartup.hStdInput := hRead;
suiStartup.hStdOutput := hWrite;
suiStartup.hStdError := hWrite;
suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
suiStartup.wShowWindow := SW_HIDE;
if CreateProcess(nil, PChar(ACommand), @SaSecurity,
@SaSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then
begin
repeat
dRunning := WaitForSingleObject(piProcess.hProcess, 100);
Application.ProcessMessages();
repeat
dRead := 0;
ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
pBuffer[dRead] := #0;
OemToAnsi(pBuffer, pBuffer);
AMemo.Lines.Add(string(pBuffer));
until (dRead < CReadBuffer);
until (dRunning <> WAIT_TIMEOUT);
//CloseHandle(piProcess.hProcess);
//CloseHandle(piProcess.hThread);
end;
//CloseHandle(hRead);
//CloseHandle(hWrite);
end;
end;
function GetDosOutput(CommandLine : string) : string;
var
SA : TSecurityAttributes;
SI : TStartupInfo;
PI : TProcessInformation;
StdOutPipeRead, StdOutPipeWrite : THandle;
WasOK : Boolean;
Buffer : array[0..255] of AnsiChar;
BytesRead : Cardinal;
Handle : Boolean;
begin
Result := '';
with SA do
begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
Handle := CreateProcess(nil, PChar(CommandLine),
nil, nil, True, 0, nil,
'C:\', SI, PI);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := Result + Buffer;
end;
if Length(Result) > 1000 then
begin
Windows.Beep(444, 555);
Break;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
finally
//CloseHandle(PI.hThread);
//CloseHandle(PI.hProcess);
end;
finally
//CloseHandle(StdOutPipeRead);
end;
end;
Jak można je poprawić? Czy w ogóle możliwe jest odebranie części zwróconych tekstów przez program konsolowy w ukrytym oknie, a następnie pozwolić mu działać nawet jeśli zamknie się program, który go wywołał?
Dodatkowe pytanie. Jeśli ktoś wie. Ewentualnie jak można odebrać własną aplikacją delphi potok początkowych komunikatów przed wysłanych danych, by później mogły dalej iść do VLC jak po użyciu przekierowania potoku przez parametr -o-| "C:\costam\sciezka\do\vlc\vlc.exe"
. Dodam, że niestety rtmpdump.exe
nie pozwala na zwrócenie wyników po wywołaniu z >> costam.txt
. Bo wtedy próbował bym z lamerskim zapisem pliku do %TEMP%
. Odczytem i usunięciem pliku tymczasowego. Ale taki plik ma zero bajtów.
Z góry dzięki za przykłady kodów i pomoc. Sorry za rozpisanie się jak to zwykle u mnie :)