我的应用程序是一个GUI应用程序,通过terminal(通过cout)有帮助(虽然是可选的)信息。
在Windows中,我有一个控制台出现(通过编译为一个控制台应用程序,或dynamic分配),或者我不。
我的意图是使用控制台,如果它正在从控制台运行,但完全忽略控制台,如果它不是。 (基本上在Linux和OS X中会发生什么)。
我不希望redirect到一个文件(在使用cin的情况下,这不是一个可行的解决scheme)。
是否有一种方法可以将Windows应用程序中的GUI应用程序附加到从中运行的控制台,当且仅当从控制台运行时?
而在使用cin的情况下,这不是一个可行的解决方案
这是你问题中的杀手细节。 这很简单,首先调用AttachConsole(ATTACH_PARENT_PROCESS)来尝试附加到现有的控制台。 当程序从资源管理器或桌面快捷方式等GUI程序启动时,将会失败。 所以如果它返回FALSE,那么调用AllocConsole()来创建你自己的控制台。
但是使用cin是一个问题。 命令处理器注意你的EXE,并检查它是控制台模式的应用程序还是GUI应用程序。 它将在您的案例中检测到一个GUI应用程序,然后不等待该过程完成。 它会再次显示提示并等待输入。 然后你也会等待输入,但是你会失败,命令处理器首先到达那里。 您的输出也与命令提示符混合在一起,这个简单的问题就解决了。
有一个简单的解决方法,你的用户应该启动你的程序start /wait yourapp
告诉命令处理器等待过程完成。 问题是:没有人使用过。 用户不会意识到键入输入时会发生什么情况,而是打算将其写入您的程序中,但实际上却是由命令处理程序进行解释。 产生一个神秘的错误信息或格式化硬盘驱动器。
解决这个无法解决的问题只有两个好办法。 或者将您的程序构建为控制台模式应用程序,并在您确定要显示GUI时调用FreeConsole()。 或者总是调用AllocConsole()。 这些不是很好的选择。 第一种方法是Windows上的Java JVM使用的方法。 对JVM提出的最老的错误之一,并从闪烁的控制台窗口驾驶Java程序员完全batty。
第三个选择是唯一的体面的一个,你不想要的,创建另一个将永远使用控制台的EXE。 像Java一样,javaw.exe vs java.exe。
一个技巧是可能的,您可以将该文件从“yourapp2.exe”重命名为“yourapp.com”。 当用户在命令行提示符下键入“yourapp”时,会首先选择它,桌面快捷方式仍然可以指向“yourapp.exe”。 Visual Studio使用这个技巧,devenv.com vs devenv.exe。
您可以在启动时检查CONSOLE_SCREEN_BUFFER_INFO
(通过GetConsoleScreenBufferInfo
)以确定您是否已经从现有控制台中运行。 如果缓冲区的位置是0,0,则从控制台外部运行。 有关详细信息,请参阅描述该过程的Microsoft知识库文章 。
为了达到此目的,需要将应用程序编译为控制台应用程序(使用/SUBSYSTEM:CONSOLE
),然后在应用程序启动新控制台(缓冲区为0,0)的情况下将自己从控制台分离。 这将使程序在从命令行启动时正确地“附加”到调用控制台。
正如其他人指出,你必须创建一个控制台应用程序和一个窗口应用程序。 所以,你最终会用console.exe
和app.exe
。 为了让它在命令行中不太明显,你可以利用像devenv一样的PATHEXT技巧。 如果其扩展名位于PATHEXT环境变量中,则cmd.exe将文件视为命令。 COM是默认的,所以你可以重命名为app.com的console.exe,允许命令app
启动附加到当前控制台的控制台应用程序。
注意:当然,如果需要,控制台应用程序可以显示GUI。
app.com和app.exe之间的构建差异取决于您的构建系统,但它可能只是设置输出类型的一个属性。 使用msbuild(对于.vcxproj文件),这只是另一个构建配置的问题。
您可以在控制台中创建一个应用程序,使用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");