카테고리 없음
[시스템] DOS 명령어 실행하고 실시간 결과 받아오기
쇼핑스크래퍼2
2023. 8. 30. 08:28
// DOS 명령어 실행하고 결과 받아오는 일반적인 예제들은 DOS 명령어의 실행이
// 끝난 후 화면 출력을 보여주지만 아래 예제는 DOS 명령어를 실행하고 발생하는
// 화면 출력을 바로바로 출력하는 실시간성 캡쳐 예제입니다
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure GetDosOutput(cmd: String; OutputMemo: TMemo);
const
BufSize = $4000;
type
TPipeHandles = record
hRead,
hWrite: DWORD;
end;
procedure ClosePipe(var Pipe: TPipeHandles);
begin
with Pipe do
begin
if hRead <> 0 then CloseHandle (hRead);
if hWrite <> 0 then CloseHandle (hWrite);
hRead := 0;
hWrite := 0;
end;
end;
procedure ReadPipe(var Pipe: TPipeHandles);
var
ReadBuf: array[0..BufSize] of Char;
BytesRead: Dword;
begin
// 파이프에 읽을 데이터가 있는지 검사
if PeekNamedPipe(Pipe.hRead, nil, 0, nil, @BytesRead, nil) and
(BytesRead > 0) then // 읽을 데이터가 있다
begin
ReadFile(Pipe.hRead, ReadBuf, BytesRead, BytesRead, nil);
if BytesRead > 0 then
begin
ReadBuf[BytesRead] := #0;
OutputMemo.SelText := ReadBuf;
OutputMemo.Perform(EM_SCROLLCARET, 0, 0);
end;
end;
end;
var
ProcessInfo: TProcessInformation;
StartupInfo: TStartupInfo;
SecAttr: TSecurityAttributes;
PipeStdOut: TPipeHandles;
PipeStdErr: TPipeHandles;
dwExitCode: DWORD;
begin
SecAttr.nLength := SizeOf(SecAttr);
SecAttr.lpSecurityDescriptor := nil;
SecAttr.bInheritHandle := TRUE;
with PipeStdOut do // 표준 출력(stdout) 파이프
if not CreatePipe (hRead, hWrite, @SecAttr, BufSize) then
ShowMessage('STDOUT pipe 를 만들 수 없습니다');
try
with PipeStdErr do // 표준 에러(stderr) 파이프
if not CreatePipe (hRead, hWrite, @SecAttr, BufSize) then
ShowMessage('STDERR pipe 를 만들 수 없습니다');
except
ClosePipe(PipeStdOut);
raise;
exit;
end;
try
FillChar(StartupInfo,SizeOf(StartupInfo), 0);
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
hStdOutput := PipeStdOut.hWrite;
hStdError := PipeStdErr.hWrite;
wShowWindow := SW_HIDE;
end;
if CreateProcess(
nil, PChar(Cmd), @SecAttr, @SecAttr, true,
DETACHED_PROCESS or NORMAL_PRIORITY_CLASS,
nil, nil,
StartupInfo, ProcessInfo) then
begin
dwExitCode := STILL_ACTIVE;
Screen.Cursor := crHourglass;
try
repeat
// 두번쨰 파라미터가 0이면 즉시 리턴
WaitForSingleObject(ProcessInfo.hProcess, 0);
GetExitCodeProcess(ProcessInfo.hProcess, dwExitCode);
Application.ProcessMessages;
ReadPipe(PipeStdOut);
ReadPipe(PipeStdErr);
until dwExitCode <> STILL_ACTIVE; // 아직 실행중이면 반복
if not GetExitCodeProcess(ProcessInfo.hProcess, dwExitCode) then
ShowMessage('exit code 를 읽어올 수 없습니다');
if dwExitCode <> 0 then // 정상 종료가 아니면...
raise Exception.Create('Exit code ' + IntToStr(dwExitCode));
finally
Screen.Cursor := crDefault;
if dwExitCode = STILL_ACTIVE then
TerminateProcess(ProcessInfo.hProcess, 1);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
ProcessInfo.hProcess := 0;
end;
end
else
ShowMessage(Cmd+' 명령어 실행을 위한 프로세스 생성 실패');
finally
ClosePipe(PipeStdOut);
ClosePipe(PipeStdErr);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
GetDosOutput(Edit1.Text, Memo1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// 실행할 DOS 명령어
Edit1.Text := 'ping www.howto.pe.kr';
end;
end.