Q&A

  • NT에서 pipe가 잘 동작안합니다.
도스 프로그램을 실행하고, 그 화면 출력 결과를 읽어들이는 프로그램을 만들고 있습니다.

다행히 여기 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;



0  COMMENTS