Delphi 独立于平台的检查Writeln-to-Output是否可以安全使用的方法?

Delphi 独立于平台的检查Writeln-to-Output是否可以安全使用的方法?,delphi,console,freepascal,Delphi,Console,Freepascal,对于具有OSX和Android支持的较新的Delphi版本,是否有独立于平台的方法来检测to是否可以安全使用 输出文档包含一个注释 大多数进程没有标准的输出文件,并且无法写入 输出引发错误。如果需要,Delphi程序有一个标准输出文件 它们作为控制台应用程序链接 我的主要目标是为日志记录提供独立于平台的回退,但要避免在不存在控制台(stdout)时可能出现的任何操作系统错误 例如:这样检查是否足够: 因此,问题可以重新表述为:“如果是真的,Delphi应用程序是否总是安全地使用?” 因为它是一

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

输出文档包含一个注释

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

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

例如:这样检查是否足够:


因此,问题可以重新表述为:“如果是真的,Delphi应用程序是否总是安全地使用?”

因为它是一种回退日志方法,所以如果日志消息是“不可见的”(重定向到/dev/null),那么对我来说就可以了,只要代码能够保证跨平台运行而不会出错


如果是,此代码是否也可以安全地使用免费Pascal?(请参阅)

我将使用异常机制

大概是这样的:

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;

不是最终答案,但将{$IFDEF}依赖于平台的调用写入基于平台的Independent POSIX

int fileno(文件*流)

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

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

标准文件号。。此宏的值为1,这是标准输出的文件描述符

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

因此,如果与控制台输出相对应的流的
fileno
的平台独立请求返回2或1,则不会重定向,如果返回-1,则输出没有结束

Delphi和Free Pascal、Virtual Pascal和GNU Pascal的确切代码可能会有所不同。 去看看你感兴趣的目标平台的运行库,例如


在深入研究
系统.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;
函数CanWriteln:Boolean;
开始
{$IFOPT I+}
{$DEFINE IOCHECK_ON}
{$I-}
{$ENDIF}
如果TTextRec(输出).fm模式关闭,则
结果:=真
其他的
开始
重写(输出);
结果:=IOResult=0;
结束;
{$IFDEF IOCHECK_ON}
{$I+}
{$ENDIF}
结束;

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

IsConsole将为连接到控制台的GUI应用程序返回false。也许你需要一个额外的间接层。允许您的代码客户端提供一个输出设备,您的代码将写入该设备。我认为为Android编写支持控制台的应用程序没有任何意义。日志应该通过写入日志文件而不是stdout来完成。我还想知道代码是否只会被编译到您控制的程序中。因为如果是库代码,那么如果库代码开始在标准输出上写入,库的使用者可能会感到不安。为什么不使用异常机制呢?你只需要打一次电话,这样就不会有速度问题。这是破坏性的。它导致输出显示在控制台上。人们可能更喜欢没有副作用的测试。
Write(“”)
这样就没有副作用了?
Write(“”)
不会触发任何IO错误,因为没有什么可做的。更糟糕的是,它可能会调用具有任意句柄作为参数的系统函数。由此造成的麻烦可能无法挽回。经验法则:如果某个东西可能导致访问冲突或类似的“损坏”系统错误,则不要尝试恢复,而是恢复到故障保护并中止。在Windows上,我认为您应该调用GetStdHandle来测试是否连接了输出设备。在Unix平台上,您可以调用等效的API。我认为问题是关于一种独立于平台的方式。要做到这一点,需要使用特定于平台的代码,那会是什么?我写的函数没有任何依赖于平台的代码。我可能弄错了。我只认为getmem返回初始化内存是有文档记录的。Afaik只初始化自动全局变量。如果您知道它在文档中的位置,请毫不犹豫地提及它。总是很难区分Delphi语言和Delphi语言实现。Fileno假定以libc为中心的I/O(文件*)。免费的Pascal基于基于句柄的系统函数实现自己的、Pascal编写的I/O。与此等效的是Getfilehandle(),但它仅从textrec/filerec返回句柄,因此在某种程度上减少了Stefan的解决方案,具有相同的限制(假设标准描述符在不使用时初始化)。
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;