从命令行启动的GUI应用程序如何写入StdOut? [英] How do I write to StdOut from a GUI app started from the command line?

查看:207
本文介绍了从命令行启动的GUI应用程序如何写入StdOut?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Delphi 7中编写一个标准的Windows应用程序。



如果我正在编写一个控制台应用程序,我可以调用以下命令输出到cmd行或输出文件。

  writeln('Some info'); 

如果我从我从标准的GUI应用程序这样做,我从命令行启动我得到一个错误。

  I / O错误105 

这个问题必须有一个简单的解决方案。基本上我希望我的应用有两种模式,一种GUI模式和一种非GUI模式。如何正确设置,以便我可以回到cmd窗口?

解决方案

这个问题非常相似(如果不是完全相同)作为我想要完成的事情。我想检测我的应用程序是否从cmd.exe执行,并将输出发送到父控制台,否则会显示一个gui。这里的答案帮助我解决了我的问题。以下是我作为实验提出的代码:



ParentChecker.dpr

 程序ParentChecker; 

使用
Vcl.Forms,
SysUtils,
PsAPI,
Windows,
TLHelp32,
主要在主。 pas'{frmParentChecker};

{$ R * .res}

函数AttachConsole(dwProcessID:Integer):Boolean;标准外部kernel32.dll;
函数FreeConsole():Boolean;标准外部kernel32.dll;

函数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);
如果HandleSnapShot<> INVALID_HANDLE_VALUE然后
begin
EntryParentProc.dwSize:= SizeOf(EntryParentProc);
如果Process32First(HandleSnapShot,EntryParentProc)then
begin
CurrentProcessId:= GetCurrentProcessId();
repeat
如果EntryParentProc.th32ProcessID = CurrentProcessId,然后
begin
ParentProcessId:= EntryParentProc.th32ParentProcessID;
HandleParentProc:= OpenProcess(PROCESS_QUERY_INFORMATION或PROCESS_VM_READ,False,ParentProcessId);
如果HandleParentProc<> 0则
begin
ParentProcessFound:= True;
SetLength(ParentProcPath,BufferSize);
GetModuleFileNameEx(HandleParentProc,0,PChar(ParentProcPath),BufferSize);
ParentProcPath:= PChar(ParentProcPath);
CloseHandle(HandleParentProc);
结束
休息;
结束
直到不是Process32Next(HandleSnapShot,EntryParentProc);
结束
CloseHandle(HandleSnapShot);
结束
如果ParentProcessFound then Result:= ParentProcPath
else Result:='';
结束

函数IsPrime(n:Integer):Boolean;
var
i:整数;
begin
结果:= False;
如果n <2则退出;
结果:= True;
如果n = 2然后退出;
i:= 2;
而i<(n div i + 1)do
begin
if(n mod i)= 0 then
begin
结果:= False;
退出;
结束
Inc(i);
结束
结束

var
i:整数;
ParentName:String;

begin
ParentName:= GetParentProcessName()。ToLower;
删除(ParentName,1,ParentName.LastIndexOf('\')+ 1);
如果ParentName ='cmd.exe'然后
开始
AttachConsole(-1);
Writeln('');
for i:= 1 to 100 do IsPrime(i)Then Writeln(IntToStr(i)+'is prime');
FreeConsole();
end
else
begin
Application.Initialize;
Application.MainFormOnTaskbar:= True;
Application.CreateForm(TfrmParentChecker,frmParentChecker);
frmParentChecker.Label1.Caption:='从'+ ParentName执行;
Application.Run;
结束
结束。

Main.pas(带标签的表单):



单位主要是$

  

接口

使用
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
{私人声明}
public
{公开声明}
end;

var
frmParentChecker:TfrmParentChecker;

执行

{$ R * .dfm}

结束。

这允许我从命令提示符运行我的GUI应用程序,并将输出显示到我的应用程序启动。否则,它将运行应用程序的完整GUI部分。



从控制台窗口输出的示例:

  I:\Delphi\Tests and Demos\ParentChecker\Win32\Debug> start / wait ParentChecker.exe 

2是素数
3是主要的
5是素$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $%优惠
29是素$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ prime prime prime prime prime prime prime prime prime prime prime prime prime
59是主要的
61是素
67是素
71是素
73是素
79是素
83是素
89是素数
97是素数

I:\Delphi\Tests和Demos\ParentChecker\Win32\Debug>


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.

writeln('Some info');

If I do this from my standard GUI app that I have started from the command line I get an error.

I/O Error 105

There must be a simple solution to this problem. Basically I want my app to have two modes, a GUI mode and a non-GUI mode. How do I set it up correctly so I can write back to the cmd window?

解决方案

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>

这篇关于从命令行启动的GUI应用程序如何写入StdOut?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆