Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Capture CMD output

Posted on 2010-01-13
5
Medium Priority
?
2,444 Views
Last Modified: 2012-05-08
I need to make application where can wach logs files using unix command  tail, trough plink , example I create form with richedit, then with button execute  :

plink.exe root@192.168.2.13 -pw password tail -f /emu/app/log/app.log

and all text in CMD capturing to TRichEdit and with button stop I can stop this capture!!

0
Comment
Question by:KarlisB
  • 2
  • 2
5 Comments
 
LVL 3

Expert Comment

by:Freddy1990
ID: 26306658
I'm pretty sure you can't execute unix commands on a windows pc...

But with this you'll be able to run a command and capture the output:
http://delphi.about.com/cs/adptips2001/a/bltip0201_2.htm
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26309294
This procedure will capture the output of a console in real time (it wont wait until the command is finished before showing the results) and output it to a memo, you can easily modify it to output to a richedit component.
procedure CaptureConsoleOutput(DosApp : string;AMemo : TMemo); 
const 
  ReadBuffer = 1048576;  // 1 MB Buffer 
var 
  Security            : TSecurityAttributes; 
  ReadPipe,WritePipe  : THandle; 
  start               : TStartUpInfo; 
  ProcessInfo         : TProcessInformation; 
  Buffer              : Pchar; 
  TotalBytesRead, 
  BytesRead           : DWORD; 
  Apprunning,n, 
  BytesLeftThisMessage, 
  TotalBytesAvail : integer; 
begin 
  with Security do 
  begin 
    nlength              := SizeOf(TSecurityAttributes); 
    binherithandle       := true; 
    lpsecuritydescriptor := nil; 
  end; 

  if CreatePipe (ReadPipe, WritePipe, @Security, 0) then 
  begin 
    // Redirect In- and Output through STARTUPINFO structure 

    Buffer  := AllocMem(ReadBuffer + 1); 
    FillChar(Start,Sizeof(Start),#0); 
    start.cb          := SizeOf(start); 
    start.hStdOutput  := WritePipe; 
    start.hStdInput   := ReadPipe; 
    start.dwFlags     := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; 
    start.wShowWindow := SW_HIDE; 

    // Create a Console Child Process with redirected input and output 

    if CreateProcess(nil      ,PChar(DosApp), 
                     @Security,@Security, 
                     true     ,CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS, 
                     nil      ,nil, 
                     start    ,ProcessInfo) then 
    begin 
      n:=0; 
      TotalBytesRead:=0; 
      repeat 
        // Increase counter to prevent an endless loop if the process is dead 
        Inc(n,1); 
         
        // wait for end of child process 
        Apprunning := WaitForSingleObject(ProcessInfo.hProcess,100); 
        Application.ProcessMessages; 

        // it is important to read from time to time the output information 
        // so that the pipe is not blocked by an overflow. New information 
        // can be written from the console app to the pipe only if there is 
        // enough buffer space. 

        if not PeekNamedPipe(ReadPipe        ,@Buffer[TotalBytesRead], 
                             ReadBuffer      ,@BytesRead, 
                             @TotalBytesAvail,@BytesLeftThisMessage) then break 
        else if BytesRead > 0 then 
          ReadFile(ReadPipe,Buffer[TotalBytesRead],BytesRead,BytesRead,nil); 
        TotalBytesRead:=TotalBytesRead+BytesRead; 
      until (Apprunning <> WAIT_TIMEOUT) or (n > 150); 

      Buffer[TotalBytesRead]:= #0; 
      OemToChar(Buffer,Buffer); 
      AMemo.Text := AMemo.text + StrPas(Buffer); 
    end; 
    FreeMem(Buffer); 
    CloseHandle(ProcessInfo.hProcess); 
    CloseHandle(ProcessInfo.hThread); 
    CloseHandle(ReadPipe); 
    CloseHandle(WritePipe); 
  end; 
end; 

Open in new window

0
 
LVL 4

Accepted Solution

by:
urban_smurf earned 2000 total points
ID: 26309792
After reviewing the above code some more, i have found a few problems..
The best way to do this in REAL TIME would be to use a .dll found at http://www.codeproject.com/KB/threads/CaptureConsole.aspx?msg=2908569
it is compatable with delphi and is easy to use.
0
 
LVL 16

Expert Comment

by:CodedK
ID: 26313274
Hi KarlisB,
There are a few ways to do this.

Approach 1:   (Author:      Marco Pipino)



//Approach 1:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
mCommand: string;
mOutputs: string;


implementation

{$R *.dfm}
function ExecuteCommand(CommandLine:string):string;
var
PROC: TProcessInformation;
Ret: LongBool;
START: TStartupInfo;
SA: TSecurityAttributes;
hReadPipe: THandle;
hWritePipe: THandle;
dBytesRead: DWORD;
sBuff: array[0..255] of Char;
begin
if Length(CommandLine) > 0 then
mCommand := CommandLine;
if Length(mCommand) = 0 then
begin
MessageBox(0, PChar('Command Line empty.'), PChar('Error'), MB_ICONEXCLAMATION);
Exit;
end;
SA.nLength := SizeOf(TSecurityAttributes);
SA.bInheritHandle := TRUE;
SA.lpSecurityDescriptor := nil;
Ret := CreatePipe(hReadPipe, hWritePipe, @SA, 0);
if not Ret then
begin
MessageBox(0, PChar('CreatePipe() failed.'), PChar('Error'), MB_ICONEXCLAMATION);
Exit;
end;
FillChar(START ,Sizeof(TStartupInfo), #0);
START.cb := SizeOf(TStartupInfo);
START.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
START.hStdOutput := hWritePipe;
START.hStdError := hWritePipe;
Ret := CreateProcess(nil, PChar(mCommand), @SA, @SA, TRUE, NORMAL_PRIORITY_CLASS, nil, nil, START, PROC);
if Ret <> TRUE then
begin
MessageBox(0, PChar('File or command not found.'), PChar('Error'), MB_ICONEXCLAMATION);
Exit;
end;
Ret := CloseHandle(hWritePipe);
mOutputs := '';
repeat
Ret := ReadFile(hReadPipe, sBuff, 255, dBytesRead, nil);
mOutputs := mOutputs + Copy(sBuff, 1, dBytesRead);
until Ret = FALSE;
Ret := CloseHandle(PROC.hProcess);
Ret := CloseHandle(PROC.hThread);
Ret := CloseHandle(hReadPipe);
ExecuteCommand := mOutputs
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(ExecuteCommand('netstat'));
end;
end.

Open in new window

0
 
LVL 16

Expert Comment

by:CodedK
ID: 26313288
Approach 2: (Joe Donth)
It works by running cmd.exe with the command to be run passed in CommandLine with the current directory optionally passed in the Work. The command is run and the output is returned as a string.

Hope this will help you.

function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..255] of AnsiChar;
  BytesRead: Cardinal;
  WorkDir: string;
  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;
    WorkDir := Work;
    Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
                            nil, nil, True, 0, nil,
                            PChar(WorkDir), 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;
        until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
      finally
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
    CloseHandle(StdOutPipeRead);
  end;
end;

//To test it, drop a TMemo, a TEdit and a TButton on a form. 
//Set the button's click event handler as follows:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Text := GetDosOutput(Edit1.Text);
end;

Open in new window

0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
Kernel Data Recovery is a renowned Data Recovery solution provider which offers wide range of softwares for both enterprise and home users with its cost-effective solutions. Let's have a quick overview of the journey and data recovery tools range he…
Suggested Courses
Course of the Month15 days, 23 hours left to enroll

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question