How do I write to StdOut from a GUI app started from the command line?

后端 未结 8 2270
一向
一向 2021-02-09 05:52

I am writing a standard windows app in Delphi 7.

If I was writing a console app, I can call the following to output to the cmd line or output file.

write         


        
8条回答
  •  轮回少年
    2021-02-09 06:40

    This question is very similar (if not exactly the same) as something I was trying to accomplish. I wanted to detect if my app was executed from a cmd.exe and send output to the parent console, otherwise it would display a gui. The answers here helped me solve my issue. Here is the code I came up with as an experiment:

    ParentChecker.dpr

    program ParentChecker;
    
    uses
      Vcl.Forms,
      SysUtils,
      PsAPI,
      Windows,
      TLHelp32,
      Main in 'Main.pas' {frmParentChecker};
    
    {$R *.res}
    
    function AttachConsole(dwProcessID: Integer): Boolean; stdcall; external 'kernel32.dll';
    function FreeConsole(): Boolean; stdcall; external 'kernel32.dll';
    
    function GetParentProcessName(): String;
    const
      BufferSize = 4096;
    var
      HandleSnapShot: THandle;
      EntryParentProc: TProcessEntry32;
      CurrentProcessId: THandle;
      HandleParentProc: THandle;
      ParentProcessId: THandle;
      ParentProcessFound: Boolean;
      ParentProcPath: String;
    begin
      ParentProcessFound:=False;
      HandleSnapShot:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
      if HandleSnapShot<>INVALID_HANDLE_VALUE then
      begin
        EntryParentProc.dwSize:=SizeOf(EntryParentProc);
        if Process32First(HandleSnapShot,EntryParentProc) then
        begin
          CurrentProcessId:=GetCurrentProcessId();
          repeat
            if EntryParentProc.th32ProcessID=CurrentProcessId then
            begin
              ParentProcessId:=EntryParentProc.th32ParentProcessID;
              HandleParentProc:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,False,ParentProcessId);
              if HandleParentProc<>0 then
              begin
                ParentProcessFound:=True;
                SetLength(ParentProcPath,BufferSize);
                GetModuleFileNameEx(HandleParentProc,0,PChar(ParentProcPath),BufferSize);
                ParentProcPath:=PChar(ParentProcPath);
                CloseHandle(HandleParentProc);
              end;
              Break;
            end;
          until not Process32Next(HandleSnapShot,EntryParentProc);
        end;
        CloseHandle(HandleSnapShot);
      end;
      if ParentProcessFound then Result:=ParentProcPath
      else Result:='';
    end;
    
    function IsPrime(n: Integer): Boolean;
    var
      i: Integer;
    begin
      Result:=False;
      if n<2 then Exit;
      Result:=True;
      if n=2 then Exit;
      i:=2;
      while i<(n div i + 1) do
      begin
        if (n mod i)=0 then
        begin
          Result:=False;
          Exit;
        end;
        Inc(i);
      end;
    end;
    
    var
      i: Integer;
      ParentName: String;
    
    begin
      ParentName:=GetParentProcessName().ToLower;
      Delete(ParentName,1,ParentName.LastIndexOf('\')+1);
      if ParentName='cmd.exe' then
      begin
        AttachConsole(-1);
        Writeln('');
        for i:=1 to 100 do if IsPrime(i) then Writeln(IntToStr(i)+' is prime');
        FreeConsole();
      end
      else
      begin
        Application.Initialize;
        Application.MainFormOnTaskbar:=True;
        Application.CreateForm(TfrmParentChecker, frmParentChecker);
        frmParentChecker.Label1.Caption:='Executed from '+ParentName;
        Application.Run;
      end;
    end.
    

    Main.pas (form with label):

    unit Main;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, RzLabel;
    
    type
      TfrmParentChecker = class(TForm)
        Label1: TLabel;
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      frmParentChecker: TfrmParentChecker;
    
    implementation
    
    {$R *.dfm}
    
    end.
    

    This allows me to run my GUI app from a command prompt and display output to the same console where my app was launched. Otherwise, it will run the full GUI part of the app.

    Example output from console window:

    I:\Delphi\Tests and Demos\ParentChecker\Win32\Debug>start /wait ParentChecker.exe
    
    2 is prime
    3 is prime
    5 is prime
    7 is prime
    11 is prime
    13 is prime
    17 is prime
    19 is prime
    23 is prime
    29 is prime
    31 is prime
    37 is prime
    41 is prime
    43 is prime
    47 is prime
    53 is prime
    59 is prime
    61 is prime
    67 is prime
    71 is prime
    73 is prime
    79 is prime
    83 is prime
    89 is prime
    97 is prime
    
    I:\Delphi\Tests and Demos\ParentChecker\Win32\Debug>
    

提交回复
热议问题