微软将控制台和 GUI 应用程序设计为互斥的。这种短视意味着没有完美的解决方案。最流行的方法是拥有两个可执行文件(例如 cscript / wscript、java / javaw、devenv.com / devenv.exe 等),但是您已经表明您认为这是“作弊”。
您有两个选择 - 制作“控制台可执行文件”或“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 创建的,在它开始执行之前。您唯一能做的就是,在您的安装程序中,使用 SW_HIDE(即 0)的“显示命令”创建程序的快捷方式。这只会影响控制台,除非您在程序中故意尊重 STARTUPINFO 的 wShowWindow 字段,所以不要这样做。
我已经通过破解 cygwin 的“mkshortcut.exe”对此进行了测试。如何在您选择的安装程序中完成它取决于您。
当然,用户仍然可以通过在资源管理器中找到可执行文件并双击它来运行您的程序,绕过隐藏控制台的快捷方式并看到控制台窗口的短暂黑色闪烁。你对此无能为力。