仅在从控制台运行时,在Windows中的GUI应用程序中使用控制台

时间:2013-04-11 15:31:09

标签: c++ windows console cout cin

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

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

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

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

是否有办法将Windows中的GUI应用程序连接到运行它的控制台,当且仅当它从控制台运行时才会运行?

4 个答案:

答案 0 :(得分:12)

  

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

这是您问题中的杀手细节。它很简单,只需首先调用AttachConsole(ATTACH_PARENT_PROCESS)来尝试连接到现有控制台。当您的程序从Explorer或桌面快捷方式等GUI程序启动时,这将失败。因此,如果它返回FALSE,则调用AllocConsole()来创建自己的控制台。

然而,

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

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

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

第三种选择是唯一合适的选择,而你不想要的那种,创建另一个永远使用控制台的EXE。像Java一样,javaw.exe vs java.exe。

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

答案 1 :(得分:1)

您可以在启动时检查CONSOLE_SCREEN_BUFFER_INFO(通过GetConsoleScreenBufferInfo)以确定您是否已在现有控制台中运行。如果缓冲区的位置是0,0,则从控制台外部运行。有关详细信息,请参阅此Microsoft Knowledgebase Article,其中介绍了该过程。

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分: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");