How do I run a command-line program in Delphi?

前端 未结 2 796
梦毁少年i
梦毁少年i 2020-11-30 04:37

I need to execute a Windows \"find\" command from a Delphi software. I\'ve tried to use the ShellExecute command, but it doesn\'t seem to work. In C, I\'d use t

相关标签:
2条回答
  • 2020-11-30 05:15

    Variant 1 (using the "advanced" CreateProcess):

    This will run a 'DOS' program and retrieve its output:

    function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string;  { Run a DOS program and retrieve its output dynamically while it is running. }
    var
      SecAtrrs: TSecurityAttributes;
      StartupInfo: TStartupInfo;
      ProcessInfo: TProcessInformation;
      StdOutPipeRead, StdOutPipeWrite: THandle;
      WasOK: Boolean;
      pCommandLine: array[0..255] of AnsiChar;
      BytesRead: Cardinal;
      WorkDir: string;
      Handle: Boolean;
    begin
      Result := '';
      with SecAtrrs do begin
        nLength := SizeOf(SecAtrrs);
        bInheritHandle := True;
        lpSecurityDescriptor := nil;
      end;
      CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SecAtrrs, 0);
      try
        with StartupInfo do
        begin
          FillChar(StartupInfo, SizeOf(StartupInfo), 0);
          cb := SizeOf(StartupInfo);
          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), StartupInfo, ProcessInfo);
        CloseHandle(StdOutPipeWrite);
        if Handle then
          try
            repeat
              WasOK := windows.ReadFile(StdOutPipeRead, pCommandLine, 255, BytesRead, nil);
              if BytesRead > 0 then
              begin
                pCommandLine[BytesRead] := #0;
                Result := Result + pCommandLine;
              end;
            until not WasOK or (BytesRead = 0);
            WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
          finally
            CloseHandle(ProcessInfo.hThread);
            CloseHandle(ProcessInfo.hProcess);
          end;
      finally
        CloseHandle(StdOutPipeRead);
      end;
    end;
    

    Variant 2:

    Capture console output in [Realtime] and how it in a TMemo:

    procedure CaptureConsoleOutput(const ACommand, AParameters: String; AMemo: TMemo);
     const
       CReadBuffer = 2400;
     var
       saSecurity: TSecurityAttributes;
       hRead: THandle;
       hWrite: THandle;
       suiStartup: TStartupInfo;
       piProcess: TProcessInformation;
       pBuffer: array[0..CReadBuffer] of AnsiChar;      <----- update
       dRead: DWord;
       dRunning: DWord;
     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 + ' ' + AParameters), @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;
    

    Source: delphi.wikia.com

    0 讨论(0)
  • 2020-11-30 05:27

    An example using ShellExecute():

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ShellExecute(0, nil, 'cmd.exe', '/C find "320" in.txt > out.txt', nil, SW_HIDE);
      Sleep(1000);
      Memo1.Lines.LoadFromFile('out.txt');
    end;
    

    Note that using CreateProcess() instead of ShellExecute() allows for much better control of the process.

    Ideally you would also call this in a secondary thread, and call WaitForSingleObject() on the process handle to wait for the process to complete. The Sleep() in the example is just a hack to wait some time for the program started by ShellExecute() to finish - ShellExecute() will not do that. If it did you couldn't for example simply open a notepad instance for editing a file, ShellExecute() would block your parent app until the editor was closed.

    0 讨论(0)
提交回复
热议问题