win32 GUI应用程序,当调用为"app.exe --help"时将使用文本写入stdout

Jef*_*ffJ 21 windows

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

  • 在没有命令行参数的情况下调用时,它是一个常规的GUI应用程序
  • 指定可选的"--help"命令行参数会导致应用程序将使用文本写入stdout然后终止
  • 它必须是单个可执行文件.通过使控制台应用程序执行第二个可执行文件没有作弊.
  • 假设主应用程序代码是用C/C++编写的
  • 如果在指定"--help"时没有创建GUI窗口,则奖励积分.(即,短暂的窗口没有闪烁)

根据我的经验,控制台应用程序的标准visual studio模板没有GUI功能,而普通的win32模板不会将其stdout发送到父cmd shell.

Hug*_*len 22

微软设计的控制台和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);
}
Run Code Online (Sandbox Code Playgroud)

我用cygwin的gcc -YMMV和MSVC编译了它.

第二个问题是,从资源管理器运行时,您的程序将在一瞬间显示一个控制台窗口.没有编程方式,因为控制台是在应用程序启动时由Windows创建的,然后才开始执行.您可以做的唯一事情是,在安装程序中,使用SW_HIDE的"show command"(即0)创建程序的快捷方式.除非您故意在程序中使用STARTUPINFO的wShowWindow字段,否则这只会影响控制台,所以不要这样做.

我通过黑客攻击cygwin的"mkshortcut.exe"来测试这个.如何在您选择的安装程序中完成它取决于您.

用户当然可以通过在资源管理器中查找可执行文件并双击它,绕过控制台隐藏快捷方式并查看控制台窗口的简短黑色闪光来运行程序.你无能为力.

  • @IInspectable cmd.exe 等待控制台应用程序终止。它不等待 GUI 应用程序。尝试从命令提示符运行记事本。 (4认同)

Dmi*_*kin 13

您可以使用AllocConsole()WinApi函数为GUI应用程序分配控制台.您也可以尝试附加到父进程的控制台,AttachConsole()如果它已经有一个,这是有意义的.与重定向的完整代码stdout,并stderr以该控制台将是这样的:

if(AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
    freopen("CONOUT$", "w", stdout);
    freopen("CONOUT$", "w", stderr);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 有谁知道Windows调试工具中的gflags.exe如何达到预期的效果?它打开一个 GUI,当不带参数调用时,它使用 stdout/stderr,当带参数调用时,它不显示空控制台窗口,当通过双击从资源管理器启动时。但是,当从 cmd 使用 GUI 启动时,cmd 提示符会等待 GUI 关闭。所以它看起来像是一个控制台应用程序,但是当通过双击启动时,它如何设法抑制黑色的空cmd窗口? (2认同)

gab*_*ing 5

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

根据您对两个可执行文件的定义,这可能被认为是“作弊”,但它只需要程序员进行很少的更改,并且可以完成一个并忘记。此外,该解决方案没有休的解决方案的缺点,在休的解决方案中,控制台窗口会瞬间显示。

在 Windows 命令行中,如果您运行程序且未指定扩展名,则查找可执行文件的优先顺序将优先选择 .com 而不是 .exe。

然后,您可以使用技巧让“.com”成为 stdin/stdout/stderr 的代理,并启动同名的 .exe 文件。这提供了允许程序在从控制台调用时以命令行模式执行的行为(可能仅当检测到某些命令行参数时),同时仍然能够作为无需控制台的 GUI 应用程序启动。

有各种文章对此进行了描述,例如“如何将应用程序制作为 GUI 和控制台应用程序?” (请参阅下面链接中的参考资料)。

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

我希望这有帮助!