繁体   English   中英

如何有条件地启用控制台而不打开单独的控制台 window

[英]How to conditionally enable console without opening separate console window

我想创建一个 windows 应用程序,在正常情况下,它没有任何连接的终端,但在某些情况下可能有一个。 我尝试了两条不同的路线。 选项 A,创建一个普通的控制台应用程序,并有条件地调用FreeConsole()

int main()
{
    if (someCondition) {
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
    } else {
        FreeConsole();
        // normal operation
    }

    return 0;
}

和选项 B,创建一个基于 WinMain 的应用程序,并有条件地调用AllocConsole()

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
    if (someCondition) {
        AllocConsole();
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
    }
    else {
        // normal operation
    }
    
    return 0;
}

选项 A 的问题在于,它与 windows 应用程序的行为不完全相同,因为您可以在正常操作继续之前非常短暂地看到控制台 window 打开。 这不是一个大问题,但正如我所说,我更希望程序像普通的 windows 应用程序一样运行。

选项 B 的问题在于,如果从现有终端调用程序,它会打开一个单独的终端 window 并输出到该终端,而不是输出到调用它的终端。 这是一个更大的问题。

在没有上述任何一个问题的情况下,有条件地充当控制台程序或 windows 程序的适当解决方案是什么?

编辑

根据评论中的建议,我尝试使用AttachConsole function。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
    if (someCondition) {
        AttachConsole(ATTACH_PARENT_PROCESS);
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);    
        Sleep(3000);
        WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
        FreeConsole();
    }
    else {
        // normal operation
    }
    
    return 0;
}

这似乎是在正确的轨道上,但仍然缺少一些东西,因为我的 shell 提示立即打印出来,而不是等待程序完成。

不可能的。

AttachConsole不能 100% 工作,因为 cmd.exe 实际上会检查它即将启动的进程是否是 GUI 应用程序,并改变其行为。

使其工作的唯一方法是拥有两个程序; myapp.com 和 myapp.exe。 %PathExt% lists.com before.exe 这样您就可以制作一个console.exe 并重命名它。com 如果用户运行“myapp”,它将被执行(但如果用户键入“myapp.exe”则不会工作)。 如果您的程序不是很大,您可以只发布两个版本。 如果程序很大,您可以将大部分代码移动到 a.dll 或使 .com 成为一个小助手,它使用命令行参数和一些用于 stdin/stdout 的管道调用 the.exe。 Visual Studio 执行此操作 ( devenv.com )。

如果要检查是否已经存在控制台,请检查GetConsoleWindow()返回的 NULL 。 如果返回 null,则执行 AllocConsole 程序和其他设置(SetWindowLong、SetConsoleMode 等)

int main() 程序默认情况下不会创建控制台,如果通过 cmd/ps 运行,它们碰巧附加到控制台中。

一种方法如下:

BOOL WINAPI
AttachOrCreateConsole()
{
    if(AttachConsole(ATTACH_PARENT_PROCESS))
    {
        return TRUE;
    }

    return AllocConsole();
}

如果可用,这将使用父控制台,并在需要时回退到创建一个。

请注意,如果您这样做并且想要使用标准 C/C++ I/O 机制(stdin/std::cin、stdout/std::cout),您将需要完成将这些流关联到控制台句柄所需的工作. 有很多关于如何做到这一点的材料。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM