2013-04-11 113 views
4

我的应用程序是一个GUI应用程序,它通过终端(通过cout)提供有用的信息(尽管是可选的)。在Windows中使用GUI应用程序中的控制台,仅当它从控制台运行时

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

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

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

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

+0

可能重复://计算器.com/questions/447352 /如何知道我们是在一个控制台还是一个窗口的应用程序) – wallyk 2013-04-11 15:35:47

+1

如果您的应用程序正在运行,您是否只想打印到控制台?一?你可以使用'cout',如果程序没有从控制台启动,它将被忽略。 – 2013-04-11 15:36:53

+0

@ slavik262我不会在Windows上花太多时间,但是从以前的经验来看,如果它不是控制台应用程序,则打印到控制台时会被忽略。这跟cout,stdout,printf等有关系吗? – latreides 2013-04-11 15:50:39

回答

9

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

这是你的问题的杀手细节。这很简单,首先调用AttachConsole(ATTACH_PARENT_PROCESS)来尝试附加到现有的控制台。当您的程序从资源管理器或桌面快捷方式等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。

+0

今天特别起泡。我认为Java和Python都选择单独的可执行文件选项javaw和pythonw。这是保持理智的唯一方法。 – 2013-04-11 21:09:37

+0

虽然不是我所希望的,但这是解决所有问题的最佳,最完整的答案。我希望没有这种牺牲是可行的。接受,谢谢。 – latreides 2013-04-12 05:26:59

1

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

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

+0

虽然这绝对是我需要的答案的一部分,但它不是完整的(当我从内存中回想以前将应用程序移植到Windows)时打印到控制台,并且我在Windows的控制台中运行我的GUI应用程序,打印命令只是...消失。 – latreides 2013-04-11 15:54:30

+0

@latreides如果你不需要它,你需要让你的应用程序成为一个控制台应用程序并释放控制台 - 编辑我的答案并提供更多细节。 – 2013-04-11 16:03:36

+0

@latreides,恐怕他是对的 - 如果你不是首先将它创建为控制台应用程序,那么将'cin'和'cout'连接到控制台所需的启动代码将被跳过。但要知道是否有控制台,您应该使用['GetConsoleWindow'](http://msdn.microsoft.com/en-us/library/ms683175(VS.85).aspx)而不是'GetConsoleScreenBufferInfo'。 – 2013-04-11 16:09:29

0

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

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

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

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"); 
[如何知道我们是否是在一个控制台或窗口的应用程序?(HTTP的
相关问题