与平台无关的方法来检查Writeln到输出是否可以安全使用?

时间:2014-04-25 07:49:41

标签: delphi console freepascal

对于较新的Delphi版本,有OSX和Android支持,是否有一种独立于平台的方法来检测WritelnOutput是否可以安全使用?

输出文档包含说明

的说明
  

大多数进程没有标准输出文件,并且写入   输出引发错误。 Delphi程序有一个标准的输出文件if   它们作为控制台应用程序链接。

我的主要目标是为日志记录提供独立于平台的回退,但要避免在没有控制台(stdout)时出现任何操作系统错误。

例如:如此检查IsConsole是否足够:

procedure Log(const Msg: string);
begin
  if LoggingFrameworkAvailable then
  begin
    // use the logging framework to output the log message
  end if System.IsConsole then
  begin
    // fallback to stdout logging
    WriteLn(Msg);
  end;
end;

所以问题可以改写:"如果Output为True,Delphi应用程序是否可以安全地使用IsConsole?"。

因为它是一个后备日志方法,如果日志消息是"不可见"它对我来说没问题。 (重定向到/ dev / null),只要保证代码在没有错误的情况下跨平台运行。

如果是,此代码是否也可以安全地使用Free Pascal? (见Can a Windows GUI program written in Lazarus create a console and write to it at runtime?

3 个答案:

答案 0 :(得分:2)

不是最终答案,而是根据平台独立POSIX C API function编写{$ IFDEF}平台相关调用

int fileno (FILE *stream)

  

..此函数返回与流stream关联的文件描述符。如果检测到错误(例如,如果流无效)或者流不对文件执行I / O,则fileno返回-1

     

...

     

在unistd.h中还定义了符号常量,用于属于标准流stdin,stdout和stderr的文件描述符...

     

STDOUT_FILENO ..此宏的值为1,它是标准输出的文件描述符。

     

STDERR_FILENO ..此宏的值为2,它是标准错误输出的文件描述符。

因此,如果对应于Console输出的流的fileno平台独立请求返回2或1,那么您不会被重定向,如果它返回-1,那么您的输出没有结束

对于Delphi和Free Pascal以及Virtual Pascal和GNU Pascal,确切的代码可能会有所不同。 请查看您感兴趣的目标平台的运行时库,例如

答案 1 :(得分:1)

在深入了解System.pas之后,我想出了这个解决方案:

function CanWriteln: Boolean;
begin
{$IFOPT I+}
  {$DEFINE IOCHECK_ON}
  {$I-}
{$ENDIF}
  if TTextRec(Output).Mode <> fmClosed then
    Result := True
  else
  begin
    Rewrite(Output);
    Result := IOResult = 0;
  end;
{$IFDEF IOCHECK_ON}
  {$I+}
{$ENDIF}
end;

仅在具有不同设置的Windows上进行了测试({$ APPTYPE CONSOLE},&#34;生成控制台应用程序&#34;设置,AllocConsole)但在所有情况下都正常工作。

答案 2 :(得分:-2)

我会利用异常机制。

这样的事情:

type
  trilean = (dunno, yes, no);

  TLogger = class(TSomething)
  private
    class var FConsoleIsSafe: trilean;
    function GetConsoleIsSafe: boolean;
  public
    property ConsoleIsSafe: boolean read GetConsoleIsSafe; 
  ....

implementation

function TLogger.GetConsoleIsSafe: boolean;
begin
  if (FConsoleIsSafe = dunno) then try
    WriteLn('test'); 
    FConsoleIsSafe:= yes;
  except
    FConsoleIsSafe:= no;
  end;
  Result:= (FConsoleIsSafe = yes);
end;