2006. szeptember 25., hétfő

Capturing all of the Output from a Console application (16 bit)


In my article "Capturing all of the Output from a Console application (32 bit)" posted a function for retrieving all of the output of a console application. Unfortunately, though it worked fine on 32-bit apps it did not work well with 16-bit apps. This was not a problem with the code, but rather a bug in Windows (http://support.microsoft.com/support/kb/articles/Q150/9/56.ASP). But how can this be done?


Here is new function I have been working on which seems to do the trick.  It bypasses the problem with 16-bit apps by directing windows to send the output to a text file, and then reads it back in, deletes the file, and sends the result back to you.  Be careful when calling this with command.com.  Because it waits on the process infinitely it will hang on this because command.com waits for user input...

Special thanks to Theo Bebekis for his help on this.

If you have questions or comments please email me  at johnwlong@characterlink.net, I have not had a chance to thoroughly test this version so any feed back would be helpful.

function GetConsoleOutput(const CommandLine: string): string;
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutFile, AppProcess, AppThread: THandle;
  RootDir, WorkDir, StdOutFileName: string;
  FUNC_NAME = 'GetConsoleOuput';
    StdOutFile := 0;
    AppProcess := 0;
    AppThread := 0;
    Result := '';

    // Initialize dirs
    RootDir := ExtractFilePath(ParamStr(0));
    WorkDir := ExtractFilePath(CommandLine);

    // Check WorkDir
    if not (FileSearch(ExtractFileName(CommandLine), WorkDir) <> '') then
      WorkDir := RootDir;

    // Initialize output file security attributes
    FillChar(SA, SizeOf(SA), #0);
    SA.nLength := SizeOf(SA);
    SA.lpSecurityDescriptor := nil;
    SA.bInheritHandle := True;

    // Create Output File
    StdOutFileName := RootDir + 'output.tmp';
    StdOutFile := CreateFile(PChar(StdOutFileName),
      CREATE_ALWAYS, // Always create it
      FILE_ATTRIBUTE_TEMPORARY or // Will cache in memory
      // if possible

    // Check Output Handle
    if StdOutFile = INVALID_HANDLE_VALUE then
      raise Exception.CreateFmt('Function %s() failed!' + #10#13 +
        'Command line = %s', [FUNC_NAME, CommandLine]);

    // Initialize Startup Info
    FillChar(SI, SizeOf(SI), #0);
    with SI do
      cb := SizeOf(SI);
      wShowWindow := SW_HIDE;
      hStdInput := GetStdHandle(STD_INPUT_HANDLE);
      hStdError := StdOutFile;
      hStdOutput := StdOutFile;

    // Create the process
    if CreateProcess(nil, PChar(CommandLine), nil, nil,
      True, 0, nil,
      PChar(WorkDir), SI, PI) then
      WaitForSingleObject(PI.hProcess, INFINITE);
      AppProcess := PI.hProcess;
      AppThread := PI.hThread;
      raise Exception.CreateFmt('CreateProcess() in function %s() failed!'
        + #10#13 + 'Command line = %s', [FUNC_NAME, CommandLine]);

    StdOutFile := 0;

    with TStringList.Create do
      Result := Text;

    // Close handles
    if StdOutFile <> 0 then
    if AppProcess <> 0 then
    if AppThread <> 0 then

    // Delete Output file
    if FileExists(StdOutFileName) then


Nincsenek megjegyzések:

Megjegyzés küldése