6

我的应用程序是一个 GUI 应用程序,它通过终端(通过 cout)提供有用的(尽管是可选的)信息。

在 Windows 中,我要么出现控制台(通过编译为控制台应用程序,或动态分配它),要么没有。

我的意图是使用控制台,如果它是从控制台运行的,但如果不是,则完全忽略控制台。(基本上是在 Linux 和 OS X 中发生的事情)。

我不希望重定向到文件(并且在使用 cin 的情况下,无论如何这不是一个可行的解决方案)。

有没有办法将 Windows 中的 GUI 应用程序附加到运行它的控制台,当且仅当它是从控制台运行的?

4

4 回答 4

16

在使用 cin 的情况下,无论如何这不是一个可行的解决方案

这是您问题中的杀手级细节。这在纸上很简单,只需首先调用 AttachConsole(ATTACH_PARENT_PROCESS) 来尝试附加到现有控制台。当您的程序从诸如资源管理器之类的 GUI 程序或桌面快捷方式启动时,这将失败。因此,如果它返回 FALSE,则调用 AllocConsole() 来创建您自己的控制台。

然而,使用cin是一个问题。命令处理器会注意您的 EXE 并检查它是控制台模式应用程序还是 GUI 应用程序。它会在您的情况下检测 GUI 应用程序,然后等待该过程完成。它再次显示提示并等待输入。然后,您还将等待输入,但您会输,命令处理器首先到达那里。您的输出还与命令提示符混合在一起,这是很容易解决的问题。

有一个简单的解决方法,您的用户应该启动您的程序,start /wait yourapp告诉命令处理器等待该过程完成。问题是:没有人使用它。并且用户不会意识到当他们键入输入时会发生什么,打算将其输入您的程序,但它实际上是由命令处理器解释的。产生神秘的错误信息或格式化硬盘。

只有两种好方法可以解决这个无法解决的问题。将您的程序构建为控制台模式应用程序,并在您发现要显示 GUI 时调用 FreeConsole()。或者总是调用 AllocConsole()。这些都不是很好的选择。第一种方法是 Java JVM 在 Windows 上使用的方法。针对 JVM 提出的最古老的错误之一,使 Java 程序员完全无法从闪烁的控制台窗口中获取信息。

第三种选择是唯一不错的选择,并且您不想要的选择创建另一个始终使用控制台的 EXE。像 Java 一样,javaw.exe 与 java.exe。

一个技巧是可能的,您可以将该文件从“yourapp2.exe”重命名为“yourapp.com”。当用户在命令行提示符下键入“yourapp”时,它将首先被选中,桌面快捷方式仍然可以指向“yourapp.exe”。Visual Studio 使用了这个技巧,devenv.com vs devenv.exe。

于 2013-04-11T17:36:51.913 回答
2

您可以在启动时检查CONSOLE_SCREEN_BUFFER_INFO(通过GetConsoleScreenBufferInfo)以确定您是否已从现有控制台中运行。如果缓冲区的位置是 0,0,那么您是从控制台外部运行的。有关详细信息,请参阅描述该过程的Microsoft 知识库文章。

为了使其工作,您需要将您的应用程序编译为控制台应用程序(使用/SUBSYSTEM:CONSOLE),然后如果应用程序启动了一个新控制台(0,0 处的缓冲区),则将您自己与控制台分离。这将导致程序在从命令行启动时正确“附加”到调用控制台。

于 2013-04-11T15:35:35.627 回答
0

正如其他人指出的那样,您必须创建一个控制台应用程序和一个窗口应用程序。所以,你最终会得到console.exeand app.exe。为了使其在命令行中不那么明显,您可以像devenv一样利用 PATHEXT 技巧。如果文件的扩展名在 PATHEXT 环境变量中,则 cmd.exe 将文件视为命令。COM 默认情况下存在,因此您可以将 console.exe 重命名为 app.com,从而允许该命令app启动附加到当前控制台的控制台应用程序。

注意:当然,如果需要,控制台应用程序可以显示 GUI。

app.com 和 app.exe 之间的构建差异取决于您的构建系统,但它可能只是设置输出类型的一个属性。使用 msbuild(对于 .vcxproj 文件),这只是另一个构建配置的问题。

于 2013-04-13T12:00:39.437 回答
0

您可以在控制台中创建一个应用程序,使用 argc 获取一行并打印它;

////
int main(int argc, char *argv[])
{
    //here print argv....using cout or printf
}

将文件保存为应用程序文件夹中的 console.exe。现在在您的应用程序中,如果您想在控制台中查看任何行,您可以调用命令

system("console.exe this is the line i want to print and see in console");
于 2013-07-31T10:56:09.643 回答