【问题标题】:C++ Windows: How to close a console window?C++ Windows:如何关闭控制台窗口?
【发布时间】:2014-04-11 21:20:00
【问题描述】:

除了主 Win32 窗口之外,我还使用“AllocConsole()` 打开了一个控制台窗口。控制台窗口在主窗口之前打开。

当我关闭主窗口并且程序从主函数返回时,控制台保持打开状态(进程也是如此)。它实际上卡在了ntdll 的某个地方,正如调试器在从 Visual Studio 2012 暂停程序时显示的那样。

通过单击X 按钮将其关闭会退出该进程,但使用FreeConsole() 将其关闭则不会,该进程仍无窗口工作。

CloseWindow(GetConsoleWindow()) 不会关闭它,它会最小化它(!?!)。

PostMessage(GetConsoleWindow(),WM_QUIT,0,0) 关闭窗口,但进程仍在工作(视觉上,这与 "FreeConsole()` 相同)。

有时程序会以正确的方式退出,但每次点击X 按钮都有效。

我该如何做与单击X 按钮相同的操作?

【问题讨论】:

  • 您不必关闭控制台窗口,当您从主线程返回并退出主线程(以及其他线程)时,它应该会自行消失。如果你没有做一些讨厌的事情,那么控制台窗口不是你的程序卡住的原因。您的程序可能会在没有控制台窗口的情况下挂起,但首先让我们在不分配控制台的情况下进行尝试。卡在 ntdll 中并不一定意味着您的控制台窗口负责,它可能是应用程序的 gui/logic 部分之前完成的某些操作的最终结果。
  • @AlexFarber 据我所知,每个进程只能有一个控制台窗口,但我可能错了。
  • @Vladivarius CloseWindow() 有望最小化窗口(查看文档),它是来自黑暗时代的古老功能,并且被赋予了一个可怕/令人困惑的名称。如果要模拟按下窗口的 X 按钮,请向窗口发送WM_CLOSE 消息。
  • 那么,您有带有附加控制台的 Windows 应用程序吗?也许你可以通过将应用程序类型更改为 SUBSYSTEM:Console 来获得相同的效果。在这种情况下,您不需要使用 AllocConsole。
  • @pasztorpisti 发表您对 WM_CLOSE 的评论作为答案(或者更好的是,两个 cmets),它起作用了。这就是我想要做的,只是感到困惑并改用 WM_QUIT -.- 另外,程序的其余部分可能有问题,因为 nvoglv32.dll 线程仍在运行并且调用堆栈刚刚成熟,可以调用它并且ntdll。一定是一个非常讨厌的 OpenGL 泄漏:/

标签: c++ windows console exit


【解决方案1】:
#include <windows.h>

HWND myConsole = GetConsoleWindow(); //window handle
ShowWindow(myConsole, 0); //handle window

我最终使用的解决方案是将 Linker->System->SubSystem 设置为“Windows (/SUBSYSTEM:WINDOWS)”而不是“Console (/SUBSYSTEM:CONSOLE)”。这使得控制台甚至不会出现,从而避免了闪烁。第二个解决方案对我来说更好,它使第一个过时了。

【讨论】:

    【解决方案2】:

    您需要使用FreeConsole 销毁WM_DESTROY 消息中的控制台。我通常在一个包含我的控制台的类中完成这一切。这样它可以在构造函数中将输入/输出重定向到控制台,在析构函数中重置输入/输出,以及分别分配/销毁控制台。

    但是,不使用类或任何包装器,它可以如下完成..

    例子:

    #include <windows.h>
    #include <streambuf>
    #include <fstream>
    #include <iostream>
    
    std::streambuf *CinBuffer, *CoutBuffer, *CerrBuffer;
    std::fstream ConsoleInput, ConsoleOutput, ConsoleError;
    
    void RedirectIO()
    {
        CinBuffer = std::cin.rdbuf();
        CoutBuffer = std::cout.rdbuf();
        CerrBuffer = std::cerr.rdbuf();
        ConsoleInput.open("CONIN$", std::ios::in);
        ConsoleOutput.open("CONOUT$", std::ios::out);
        ConsoleError.open("CONOUT$", std::ios::out);
        std::cin.rdbuf(ConsoleInput.rdbuf());
        std::cout.rdbuf(ConsoleOutput.rdbuf());
        std::cerr.rdbuf(ConsoleError.rdbuf());
    }
    
    void ResetIO()
    {
        ConsoleInput.close();
        ConsoleOutput.close();
        ConsoleError.close();
        std::cin.rdbuf(CinBuffer);
        std::cout.rdbuf(CoutBuffer);
        std::cerr.rdbuf(CerrBuffer);
        CinBuffer = NULL;
        CoutBuffer = NULL;
        CerrBuffer = NULL;
    }
    
    LRESULT __stdcall WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
        switch(Msg)
        {
            case WM_CREATE:
                AllocConsole();
                RedirectIO();
                std::cout<<"HELLO CONSOLE!"<<std::endl;
                break;
    
            case WM_DESTROY:
                std::cout<<"BYE-BYE CONSOLE!"<<std::endl;
                ResetIO();
                FreeConsole();
                PostQuitMessage(0);
                return 0;
    
            default:
                return DefWindowProc(Hwnd, Msg, wParam, lParam);
        }
        return 0;
    };
    
    int main()
    {
        WNDCLASSEX WndClass =
        {
            sizeof(WNDCLASSEX), CS_DBLCLKS, WindowProcedure,
            0, 0, GetModuleHandle(NULL), LoadIcon(NULL, IDI_APPLICATION),
            LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1),
            NULL, "WindowClass", LoadIcon (NULL, IDI_APPLICATION)
        };
    
        if(RegisterClassEx(&WndClass))
        {
            HWND WindowHandle = CreateWindowEx(0, "WindowClass", "Window Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, GetModuleHandle(NULL), NULL);
            if(WindowHandle)
            {
                MSG msg = {NULL};
                ShowWindow(WindowHandle, SW_SHOWDEFAULT);
                while(GetMessage(&msg, NULL, 0, 0))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
        }
    }
    

    【讨论】:

    • 这正是我正在做的事情(你对 WM_DESTROY 的想法)并且它没有退出进程:/ 看起来问题出在我设置控制台的方式上,现在当我有从你那里复制的。事实上,我很惊讶我的代码在从 stackoverflow xD 以外的其他地方复制粘贴后似乎可以正常工作
    【解决方案3】:

    使用PostMessage(wnd, WM_CLOSE, 0, 0) 关闭控制台窗口,但问题可能出在程序中的其他地方,即使这可以作为修补程序使用。当您从 main()WinMain() 返回时,控制台窗口应自动关闭/消失。

    【讨论】:

    • @Vladivarius 谢谢! :-)
    • 我认为值得注意的是,运行控制台的“HANDLE wnd”可以通过“wnd = GetConsoleWindow()”获取。很好用,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-01-15
    • 2015-01-28
    • 2012-10-14
    • 2012-05-02
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多