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

时间:2008-09-10 16:07:59

标签: windows

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

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

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

3 个答案:

答案 0 :(得分:22)

Microsoft设计的控制台和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编译了它 - YMMV和MSVC。

第二个问题是,从资源管理器运行时,您的程序将暂时停止运行 显示控制台窗口。这是没有程序化的方法,因为控制台是 在应用程序启动时由Windows创建,在它开始执行之前。你唯一能做到的 您可以在安装程序中使用“show command”创建程序的快捷方式 SW_HIDE(即0)。除非您刻意遵守STARTUPINFO的wShowWindow字段,否则这只会影响控制台 在你的程序中,所以不要这样做。

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

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

答案 1 :(得分:13)

您可以使用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()

答案 2 :(得分:4)

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

这可能被你的两个可执行文件的定义视为“作弊”,但它对程序员部分的要求很少,可以做一个而忘记了。此解决方案也没有Hugh解决方案的缺点,您可以在一秒钟内显示控制台窗口。

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

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

有各种文章描述如“如何将应用程序同时作为GUI和控制台应用程序?” (参见下面链接中的参考文献)。

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

我希望这有用!