win32 GUI应用程序将用法文本写入标准输出,当被调用为“app.exe –help”

如何创build一个执行以下操作的Windows应用程序:

  • 在没有命令行参数的情况下调用它是一个常规的GUI应用程序
  • 指定可选的“–help”命令行参数将导致应用程序将用法文本写入标准输出,然后终止
  • 它必须是单个可执行文件。 没有作弊的控制台应用程序执行第二个可执行文件。
  • 假设主应用程序代码是用C / C ++编写的
  • 如果在指定“–help”的情况下没有创buildGUI窗口,则奖励点数。 (即,从短暂的窗口不闪烁)

根据我的经验,控制台应用程序的标准visual studio模板没有GUIfunction,正常的win32模板不会将其stdout发送到父级cmd shell。

微软设计的控制台和GUI应用程序是互斥的。 这种短视意味着没有完美的解决方案。 最流行的方法是有两个可执行文件(例如,cscript / wscript,java / javaw,devenv.com / devenv.exe等),但是你已经表明你认为这是“作弊”。

你有两个选择 – 使一个“控制台可执行”或“gui可执行文件”,然后使用代码来尝试提供其他行为。

  • 可执行的GUI:

cmd.exe将假定你的程序没有控制台I / O,所以在继续之前不会等待它终止,在交互模式下(即不是批处理)意味着显示下一个(“ C:\> ”)提示,从键盘读取。 所以,即使你使用AttachConsole,你的输出也会和cmd的输出混合在一起,如果你尝试输入,情况会变得更糟。 这基本上是一个非起动器。

  • 控制台可执行

相反,没有什么可以阻止控制台可执行文件显示GUI,但有两个问题。

首先,如果你从没有参数的命令行运行它(所以你需要GUI), cmd在继续之前仍然会等待它终止,这样特定的控制台在这段时间内将不可用。 这可以通过启动相同的可执行文件的第二个进程来克服(你认为这个作弊吗?),将DETACHED_PROCESS标志传递给CreateProcess()并立即退出。 然后新的进程可以检测到它没有控制台并显示GUI。

这里有C代码来说明这种方法:

 #include <stdio.h> #include <windows.h> int main(int argc, char *argv[]) { if (GetStdHandle(STD_OUTPUT_HANDLE) == 0) // no console, we must be the child process { MessageBox(0, "Hello GUI world!", "", 0); } else if (argc > 1) // we have command line args { printf("Hello console world!\n"); } else // no command line args but a console - launch child process { DWORD dwCreationFlags = CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS; STARTUPINFO startinfo; PROCESS_INFORMATION procinfo; ZeroMemory(&startinfo, sizeof(startinfo)); startinfo.cb = sizeof(startinfo); if (!CreateProcess(NULL, argv[0], NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &startinfo, &procinfo)) MessageBox(0, "CreateProcess() failed :(", "", 0); } exit(0); } 

我用cygwin的gcc编译了它 – 使用MSVC的YMMV。

第二个问题是,当从资源管理器运行时,你的程序将在一瞬间显示一个控制台窗口。 没有编程的方法,因为控制台是在Windows启动时在Windows开始执行之前创建的。 你唯一能做的就是在你的安装程序中用SW_HIDE的“显示命令”(即0)创建程序的快捷方式。 这只会影响控制台,除非你在程序中故意地遵守STARTUPINFO的wShowWindow字段,所以不要那样做。

我已经通过黑客cygwin的“mkshortcut.exe”进行了测试。 如何在您选择的安装程序中完成它取决于您。

用户仍然可以通过在资源管理器中查找可执行文件并双击它,绕过控制台隐藏快捷方式并查看控制台窗口的简短黑色闪存来运行程序。 没有什么可以做的。

您可以使用AllocConsole() WinApi函数为GUI应用程序分配一个控制台。 您也可以尝试使用AttachConsole()附加到父进程的控制台,如果它已经有一个,这是有道理的。 stdoutstderr重定向到控制台的完整代码将如下所示:

 if(AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){ freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); } 

我在Pidgin源代码中找到了这种方法(请参阅pidgin / win32 / winpidgin.c中的WinMain()

我知道我的答案是晚了,但我认为这种情况的首选技术是“.com”和“.exe”方法。

这可能会被认为是“欺骗”你定义的两个可执行文件,但它只需要很少的程序员部分的变化,可以做一个,忘了。 此外,这个解决方案没有Hugh的解决方案的缺点,你有一个控制台窗口显示一瞬间。

在命令行的窗口中,如果运行程序并且不指定扩展名,则在查找可执行文件时的优先顺序将优先于.exe而不是.exe。

然后你可以使用技巧来让“.com”成为stdin / stdout / stderr的代理,并启动同名的.exe文件。 这样做的行为允许程序在调用控制台(可能只有在检测到某些命令行参数时)时以命令行模式执行预制,同时仍然可以作为不具有控制台的GUI应用程序启动。

有各种各样的文章描述这样的“如何使一个应用程序作为GUI和控制台应用程序? (请参阅下面的链接参考)。

我在google代码上托管了一个名为dualsubsystem的项目,它更新了这种技术的旧的codeguru解决方案,并提供了源代码和工作示例二进制文件。

我希望这是有帮助的!