windows win32 GUI 应用程序,在作为“app.exe --help”调用时将使用文本写入标准输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/54536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
win32 GUI app that writes usage text to stdout when invoked as "app.exe --help"
提问by JeffJ
How do I create a windows application that does the following:
如何创建执行以下操作的 Windows 应用程序:
- it's a regular GUI app when invoked with no command line arguments
- specifying the optional "--help" command line argument causes the app to write usage text to stdout then terminate
- it must be a single executable. No cheating by making a console app exec a 2nd executable.
- assume the main application code is written in C/C++
- bonus points if no GUI window is created when "--help" is specified. (i.e., no flicker from a short-lived window)
- 在没有命令行参数的情况下调用时,它是一个常规的 GUI 应用程序
- 指定可选的“--help”命令行参数会导致应用程序将使用文本写入标准输出然后终止
- 它必须是单个可执行文件。通过使控制台应用程序 exec 成为第二个可执行文件,不会作弊。
- 假设主要应用程序代码是用 C/C++ 编写的
- 如果在指定“--help”时未创建 GUI 窗口,则加分。(即,没有来自短暂窗口的闪烁)
In my experience the standard visual studio template for console app has no GUI capability, and the normal win32 template does not send its stdout to the parent cmd shell.
根据我的经验,控制台应用程序的标准 Visual Studio 模板没有 GUI 功能,普通的 win32 模板不会将其标准输出发送到父 cmd shell。
回答by Hugh Allen
Microsoft designed console and GUI apps to be mutually exclusive. This bit of short-sightedness means that there is no perfect solution. The most popular approach is to have two executables (eg. cscript / wscript, java / javaw, devenv.com / devenv.exe etc) however you've indicated that you consider this "cheating".
Microsoft 设计的控制台和 GUI 应用程序是相互排斥的。这一点短视意味着没有完美的解决方案。最流行的方法是拥有两个可执行文件(例如 cscript / wscript、java / javaw、devenv.com / devenv.exe 等),但是您已经表明您认为这是“作弊”。
You've got two options - to make a "console executable" or a "gui executable", and then use code to try to provide the other behaviour.
您有两个选择 - 制作“控制台可执行文件”或“gui 可执行文件”,然后使用代码尝试提供其他行为。
- GUI executable:
- GUI可执行文件:
cmd.exe
will assume that your program does no console I/O so won't wait for it to terminate
before continuing, which in interactive mode (ie not a batch) means displaying the next ("C:\>
") prompt
and reading from the keyboard. So even if you use AttachConsole your output will be mixed
with cmd
's output, and the situation gets worse if you try to do input. This is basically a non-starter.
cmd.exe
将假设您的程序没有控制台 I/O,因此在继续之前不会等待它终止,这在交互模式下(即不是批处理)意味着显示下一个 (" C:\>
") 提示并从键盘读取。因此,即使您使用 AttachConsole,您的输出也会与cmd
的输出混合,如果您尝试进行输入,情况会变得更糟。这基本上是一个非启动器。
- Console executable:
- 控制台可执行文件:
Contrary to belief, there is nothing to stop a console executable from displaying a GUI, but there are two problems.
与信念相反,没有什么可以阻止控制台可执行文件显示 GUI,但有两个问题。
The first is that if you run it from the command line with no arguments (so you want the GUI),
cmd
will still wait for it to terminate before continuing, so that particular
console will be unusable for the duration. This can be overcome by launching
a second process of the same executable (do you consider this cheating?),
passing the DETACHED_PROCESS flag to CreateProcess() and immediately exiting.
The new process can then detect that it has no console and display the GUI.
第一个是,如果你从没有参数的命令行运行它(所以你想要 GUI),
cmd
在继续之前仍然会等待它终止,所以特定的控制台在这段时间内将无法使用。这可以通过启动同一可执行文件的第二个进程来克服(你认为这是作弊吗?),将 DETACHED_PROCESS 标志传递给 CreateProcess() 并立即退出。然后新进程可以检测到它没有控制台并显示 GUI。
Here's C code to illustrate this approach:
下面是说明这种方法的 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);
}
I compiled it with cygwin's gcc - YMMV with MSVC.
我用 cygwin 的 gcc - YMMV 和 MSVC 编译了它。
The second problem is that when run from Explorer, your program will for a split second display a console window. There's no programmatic way around this because the console is created by Windows when the app is launched, before it starts executing. The only thing you can do is, in your installer, make the shortcut to your program with a "show command" of SW_HIDE (ie. 0). This will only affect the console unless you deliberately honour the wShowWindow field of STARTUPINFO in your program, so don't do that.
第二个问题是,当从资源管理器运行时,您的程序将在一瞬间显示一个控制台窗口。没有编程方式可以解决这个问题,因为控制台是在应用启动时由 Windows 创建的,然后才开始执行。您唯一能做的就是在安装程序中,使用 SW_HIDE(即 0)的“显示命令”创建程序的快捷方式。这只会影响控制台,除非您特意在程序中使用 STARTUPINFO 的 wShowWindow 字段,所以不要这样做。
I've tested this by hacking cygwin's "mkshortcut.exe". How you accomplish it in your install program of choice is up to you.
我通过破解 cygwin 的“mkshortcut.exe”对此进行了测试。如何在您选择的安装程序中完成它取决于您。
The user can still of course run your program by finding the executable in Explorer and double-clicking it, bypassing the console-hiding shortcut and seeing the brief black flash of a console window. There's nothing you can do about it.
用户当然仍然可以通过在资源管理器中找到可执行文件并双击它来运行您的程序,绕过隐藏控制台的快捷方式并看到控制台窗口的短暂黑色闪烁。你对此无能为力。
回答by Dmitry Markin
You can use AllocConsole()
WinApi function to allocate a console for GUI application. You can also try attaching to a console of a parent process with AttachConsole()
, this makes sense if it already has one. The complete code with redirecting stdout
and stderr
to this console will be like this:
您可以使用AllocConsole()
WinApi 函数为 GUI 应用程序分配一个控制台。您还可以尝试使用 附加到父进程的控制台,AttachConsole()
如果它已经有一个,这是有道理的。与重定向的完整代码stdout
,并stderr
以该控制台将是这样的:
if(AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
I found this approach in the Pidginsources (see WinMain()
in pidgin/win32/winpidgin.c)
我在Pidgin源中找到了这种方法(参见WinMain()
pidgin/win32/winpidgin.c)
回答by gabeiscoding
I know my answer is coming in late, but I think the preferred technique for the situation here is the ".com" and ".exe" method.
我知道我的答案来晚了,但我认为针对这种情况的首选技术是“.com”和“.exe”方法。
This may be considered "cheating" by your definition of two executables, but it requires very little change on the programmers part and can be done one and forgot about. Also this solution does not have the disadvantages of Hugh's solution where you have a console windows displayed for a split second.
根据您对两个可执行文件的定义,这可能被视为“欺骗”,但它对程序员来说几乎不需要任何更改,并且可以完成一个而忘记。此外,此解决方案没有 Hugh 解决方案的缺点,即您会在瞬间显示控制台窗口。
In windows from the command line, if you run a program and don't specify an extension, the order of precedence in locating the executable will prefer a .com over a .exe.
在来自命令行的 Windows 中,如果您运行一个程序并且没有指定扩展名,则定位可执行文件的优先顺序将优先于 .com 而不是 .exe。
Then you can use tricks to have that ".com" be a proxy for the stdin/stdout/stderr and launch the same-named .exe file. This give the behavior of allowing the program to preform in a command line mode when called form a console (potentially only when certain command line args are detected) while still being able to launch as a GUI application free of a console.
然后你可以使用技巧让“.com”成为 stdin/stdout/stderr 的代理并启动同名的 .exe 文件。这提供了允许程序在从控制台调用时以命令行模式执行的行为(可能仅当检测到某些命令行参数时),同时仍然能够作为没有控制台的 GUI 应用程序启动。
There are various articles describing this like "How to make an application as both GUI and Console application?" (see references in link below).
有很多文章描述了这一点,比如“如何将应用程序制作为 GUI 和控制台应用程序?” (请参阅下面链接中的参考资料)。
I hosted a project called dualsubsystem on google codethat updates an old codeguru solution of this technique and provides the source code and working example binaries.
我在 google 代码上托管了一个名为dualsubsystem的项目,该项目更新了该技术的旧codeguru解决方案,并提供了源代码和工作示例二进制文件。
I hope that is helpful!
我希望这是有帮助的!