我的Delphi控制台应用程序是否被重定向到文件或管道?如何检查?

11

我有一个控制台应用程序,需要在输出重定向(外部)到文件或管道(myapp.exe > Foo.bar)时禁用或启用某些操作。

如何检查我的Delphi控制台应用程序是否被重定向到文件或管道?


可能是重复的问题:如何检测Console.In(stdin)是否已被重定向? - David Heffernan
2个回答

13

你可以使用GetStdHandleGetFileType 函数。

首先,使用 GetStdHandle 函数检索控制台输出句柄,然后可以使用 GetFileType 函数检查句柄的类型。

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  SysUtils;


function ConsoleRedirected: Boolean;
var
  FileType : DWORD;
begin
  FileType:= GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
  Result  := (FileType=FILE_TYPE_PIPE) or (FileType=FILE_TYPE_DISK);
end;


begin
  try
    if ConsoleRedirected then
      Writeln('Hello From File')
    else
      Writeln('Hello Console');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

3
文档提到 File_Type_Char 通常是一个 LPT 设备或控制台,因此这个方法可能无法告诉你程序的输出是否被重定向到打印机,例如:myapp.exe > LPT1 - Rob Kennedy
2
确实如此,但这个提问者明确要求..被重定向到文件或管道..,所以他可以使用我回答中注释的代码:Result := (FileType=FILE_TYPE_PIPE) or (FileType=FILE_TYPE_DISK); - RRUZ
@RRUZ 更有可能的是,这两种重定向类型是他脑海中首先想到的。如果你相信这一点,那么我不知道为什么你要注释掉那个版本。 - David Heffernan
@DavidHeffernan,回答已编辑(抱歉,我当时脑子里有很多项目)。 - RRUZ
1
像往常一样,@Rob说得对。这个版本无法检测到所有的重定向,这也是我理解问题的方式。例如,myexe > nul将导致FILE_TYPE_CHAR。因此,除非有人能想出更好的检测所有形式重定向的方法,否则我会保留我的答案在这里。 - David Heffernan

9
我在这里提出的方法可能有点瑕疵,但我找不到更好的方式来检测标准输出是否被重定向到了屏幕控制台以外。使用 GetFileType 的方法无法检测到所有形式的重定向,因为某些重定向是指向类型为 FILE_TYPE_CHAR 的设备的。
调用 GetConsoleMode() 并传递标准输出句柄。如果 GetConsoleMode() 失败,则您的控制台已被重定向。
program RedirectionDetection;
{$APPTYPE CONSOLE}
uses
  Windows;

function ConsoleRedirected: Boolean;
var
  Mode: DWORD;
begin
  Result := not GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), Mode);
end;

begin
  if ConsoleRedirected then begin
    Writeln('I have been redirected');
  end else begin
    Writeln('I am a console');
    Readln;
  end;
end.

1
如果在控制台模式下,例如由于访问权限问题,GetConsoleMode 失败了怎么办? - kobik
2
@kobik 如果你没有访问自己的控制台,那就游戏结束了!! - David Heffernan
2
我所询问的是,这个语句是否属实:“如果 GetConsoleMode() 失败,则表示您的控制台已被重定向”。 - kobik
@kobik 这是一种广为人知的检测控制台重定向的方法。当然,您关于访问权限的评论也适用于任何其他方法。 - David Heffernan
2
我认为这样会更好:Result := not GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), Mode) and (GetLastError = ERROR_INVALID_HANDLE); - kobik
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接