如何确定我是否正在运行控制台应用程序?(在Win32上使用Delphi)

10

我有一个常见的单元,会将一些日志记录到 GExperts 调试器和/或 OutputDebugString 中。我要在控制台应用程序中使用它,因此我希望它能够通过 writeln() 输出到标准输出。
主可执行文件已经有 {$APPTYPE CONSOLE},但我不认为这对我有帮助。日志例程将从多个地方调用:

  1. 主控制台应用程序,该程序将链接到 BPL,
  2. 来自“需要”第一个 bpl 的另一个 BPL,以及......
  3. 从静态链接该单元的 DLL。

BPL 和 DLL 将在没有 {$APPTYPE CONSOLE} 指令可见性的情况下构建,因此我不能使用 IFDEF 条件编译。BPL 和 DLL 需要能够进行选择,具体取决于主应用程序是常规 WinApp 还是控制台应用程序。

一个丑陋的解决方法是使用可执行文件的名称。例如:

if (UpperCase(ExtractFileName(ParamStr(0))) = 'MYCONSOLEAPP.EXE')  then ...

但我不想这样做,因为我可能会有其他的控制台应用程序...

我宁愿拥有一个名为AmIAConsoleApp的神奇函数:boolean; 有类似的东西吗? 我在这个项目中使用的是Delphi2005。

更新:我发现我有点重复了这个问题,但我想调查一下Delphi社区,看是否有更好的方法。


1
有几个好心的、看起来很有帮助的答案建议使用System.IsConsole。这些答案已被发布者删除,但我觉得将其包含在讨论中是有价值的。以下是为什么它不起作用的原因:根据文档,System.IsConsole返回true,表示“如果编译为控制台应用程序,则为真”。我并没有将其编译为控制台应用程序(主应用程序是,但DLL不是)。所以,根据调用记录器的位置,我得到了不同的结果。 - Chris Thornton
2个回答

17

调用 GetStdHandle(Std_Output_Handle)。如果它成功并返回零,则表示没有可写入的控制台。其他返回值表示进程已连接到控制台,因此您可以写入它(尽管在控制台程序中记录消息可能不是最理想的方式,因为它们会干扰正常输出)。类似于这样:

function IAmAConsoleApp: Boolean;
var
  Stdout: THandle;
begin
  Stdout := GetStdHandle(Std_Output_Handle);
  Win32Check(Stdout <> Invalid_Handle_Value);
  Result := Stdout <> 0;
end;

3
这个答案还涵盖了分配而不是控制台类型的应用程序的情况。因此,我认为这是正确的答案,即使问题是错误的(最终目的是输出到控制台,而不是找出可执行文件如何链接)。 - Sertac Akyuz
好的,明天我会试一下。谢谢。 - Chris Thornton

1

使用构造函数注入,在创建实例时注入记录器。这里有一个简单的例子。

你提出的解决方案只适用于这两种情况下测试应用程序是否为控制台应用程序。构造函数注入的解决方案几乎没有更多的代码,并且可以在任何需要输出的地方使用。


你的意思是类似于 X := TY.Create(MyLogger) 吗?然后控制台应用程序提供了一个使用 Writeln 的记录器,而 GUI 应用程序则提供另一个记录器,甚至是 nil?这是一个好主意(虽然这个术语对我来说是新的),在这种情况下我已经多次使用过(例如需要 ICharProvider 的词法分析器/解析器:控制台测试应用程序提供了一个从一组字符串常量中获取字符的 ICharProvider,而真正的应用程序提供了一个从 IDE 编辑器中获取字符的 ICharProvider)。 - Rudy Velthuis
1
@Rudy,是的,就是这个意思。 - Craig Stuntz

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