도스 프로그램을 실행하고, 그 화면 출력 결과를 읽어들이는 프로그램을 만들고 있습니다.
다행히 여기 Q&A에서 pipe를 이용해서 출력 결과를 받는 방법을 알게 되었는데요.
이 방법이 윈도우98에서는 잘 동작하지만, 윈도우2000에서는 잘 동작하지를 않습니다.
윈도우2000에서는 도스 프로그램이 실행도 잘되고, 출력 내용이 화면에 출력되지도 않는데도, pipe 핸들에 출력 결과가 저장되지를 않습니다.
아래는 여기 Q&A에 올려주셔서 제가 참고한 내용과 소스입니다.
일단 윈도우2000과 관계있을 UsingWinNT라는 함수가 없습니다.(전 델파이 5 사용합니다)
이게 이상하긴 하지만, 그 if문의 어느 경우를 실행시키더라도 결과에는 변함이 없습니다.
아무튼 이 소스를 윈2000에서 실행할 때 왜 pipe로 결과가 저장되지 않는지 알고 싶습니다.
아시는 분의 답변 부탁드리겠습니다.
=========================================
[팁] 도스 출력 바로바로 잡아오기
작성자 : 이정욱 (nort@nilex.co.kr)
김성동님의 홈에서 퍼왔습니다~
도스 프롬프트에서처럼 Redirect 명령을 이용해서 파일로 저장한 다음 그 파일을 읽어들이는 방법이 제일 쉽죠. 짐작하시겠지만 이 방법은 작업이 다 끝나야지만 출력을 볼 수 있다는 문제가 있죠..
또 다른 방법은 파이프를 이용하는겁니다.
CreateProcess 함수의 인자 중 TStartUpInfo 구조체의 hStdOutput, hStdError 핸들에 CreatePipe 함수로 생성된 WritePipe를 인자로 넣어주면 해당 명령의 출력이 이 Pipe로 Redirect됩니다. 그럼 ReadFile 함수의 파일 핸들을 ReadPipe로 해서 읽어들이면 읽어 들이면 됩니다.
자세한 건 아래 소스를 보시면 이해하실겁니다.
procedure RunDosCommand(Command : string; Output : TStrings);
var
hReadPipe : THandle;
hWritePipe : THandle;
SI : TStartUpInfo;
PI : TProcessInformation;
SA : TSecurityAttributes;
SD : TSecurityDescriptor;
BytesRead : DWORD;
Dest : array[0..1023] of char;
CmdLine : array[0..512] of char;
TmpList : TStringList;
S, Param : string;
Avail, ExitCode, wrResult : DWORD;
begin { Dos Application }
if UsingWinNT then
begin
InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@SD, True, nil, False);
SA.nLength := SizeOf(SA);
SA.lpSecurityDescriptor := @SD;
SA.bInheritHandle := True;
CreatePipe(hReadPipe, hWritePipe, @SA, 1024);
end else
CreatePipe(hReadPipe, hWritePipe, nil, 1024);
try
Screen.Cursor := crHourglass; { STARTUPINFO를 설정한다. }
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(TStartUpInfo);
SI.wShowWindow := SW_HIDE;
SI.dwFlags := STARTF_USESHOWWINDOW; { STARTF_USESTDHANDLES 를 빼면 PIPE로 입출력이 Redirect 되지 않는다. }
SI.dwFlags := SI.dwFlags or STARTF_USESTDHANDLES;
SI.hStdOutput := hWritePipe;
SI.hStdError := hWritePipe;
StrPCopy(CmdLine, Command); { Process를 생성한다. }
if CreateProcess(nil, CmdLine, nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, SI, PI) then
begin
ExitCode := 0;
while ExitCode = 0 do
begin
wrResult := WaitForSingleObject(PI.hProcess, 500);
{ Pipe에 출력된 내용이 있는 지 조사한다. }
if PeekNamedPipe(hReadPipe, nil, 0, nil, @Avail, nil) then
begin
if Avail > 0 then
begin
{ Redirect된 화면 내용을 출력 윈도에 내보낸다. }
TmpList := TStringList.Create;
try
FillChar(Dest, SizeOf(Dest), 0);
ReadFile(hReadPipe, Dest, Avail, BytesRead, nil);
TmpList.Text := StrPas(Dest);
Output.Lines.AddStrings(TmpList);
finally
TmpList.Free;
end;
end;
end;
{ WAIT_TIMEOUT이 아니면 루프를 마친다. }
if wrResult <> WAIT_TIMEOUT then
ExitCode := 1;
end;
{ 실행이 끝났다.. }
GetExitCodeProcess(PI.hProcess, ExitCode);
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
end;
finally
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
Screen.Cursor := crDefault;
end;
end;