运行 C++ 应用程序时摆脱黑色控制台窗口

Posted

技术标签:

【中文标题】运行 C++ 应用程序时摆脱黑色控制台窗口【英文标题】:Getting Rid of Black Console Window When Running C++ Application 【发布时间】:2012-01-08 02:18:25 【问题描述】:

我正在使用 Netbeans 7.1 来玩弄我找到的 AI 教程 here。

编辑:我正在使用 GCC 编译器。

我已经让一切正常,但我似乎无法让应用程序与 Windows 子系统一起编译和运行...该应用程序似乎是为 Windows API 正确编写的,并且源代码附带的可执行文件该网站上的文件启动时不会产生我自己的可执行文件创建的黑色控制台窗口。

我尝试将-mwindows 添加为链接器的选项,并且我尝试了-Wl,-subsystem,windows。这些都不适合我。我在下面提供了 main.cpp。

#define WIN32_LEAN_AND_MEAN

#include <windows.h> 

#include <stdlib.h>
#include <time.h>


#include "utils.h"
#include "CController.h"
#include "CTimer.h"
#include "resource.h"
#include "CParams.h"


// edited this out, still not working

// #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")

///////////////////////GLOBALS ////////////////////////////////////

char*           szApplicationName = "Smart Sweepers v1.0";
char*           szWindowClassName = "sweeper";


//The controller class for this simulation
CController*    g_pController    = NULL; 

//create an instance of the parameter class.
CParams   g_Params;

//---------------------------- Cleanup ----------------------------------
//
//  simply cleans up any memory issues when the application exits
//-----------------------------------------------------------------------
void Cleanup()

    if (g_pController) 

        delete g_pController;

//-----------------------------------WinProc-----------------------------
//
//-----------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, 
                                        UINT msg, 
                            WPARAM wparam, 
                            LPARAM lparam)

    //these hold the dimensions of the client window area
    static int cxClient, cyClient;

    //used to create the back buffer
    static HDC        hdcBackBuffer;
    static HBITMAP  hBitmap;
    static HBITMAP  hOldBitmap; 


    switch(msg)
       
        case WM_CREATE: 
        
            //seed the random number generator
            srand((unsigned) time(NULL));

            //get the size of the client window
            RECT rect;
            GetClientRect(hwnd, &rect);

            cxClient = rect.right;
            cyClient = rect.bottom;

            //setup the controller
            g_pController = new CController(hwnd);

                //create a surface for us to render to(backbuffer)
            hdcBackBuffer = CreateCompatibleDC(NULL);

            HDC hdc = GetDC(hwnd);

            hBitmap = CreateCompatibleBitmap(hdc,
                                                            cxClient,
                                                            cyClient);
            ReleaseDC(hwnd, hdc);

            hOldBitmap = (HBITMAP)SelectObject(hdcBackBuffer, hBitmap); 
         

        break;

        //check key press messages
        case WM_KEYUP:
        
            switch(wparam)
            

                case VK_ESCAPE:
                
                    PostQuitMessage(0);
                

                break;

                case 'F':
                    
                        g_pController->FastRenderToggle();
                    

                    break;

        //reset the demo
        case 'R':
          
             if (g_pController)
             
               delete g_pController;
             

             //setup the new controller
                   g_pController = new CController(hwnd);
          

          break;

            //end WM_KEYUP switch
        

        break;

        //has the user resized the client area?
        case WM_SIZE:
        
            cxClient = LOWORD(lparam);
            cyClient = HIWORD(lparam);

            //resize the backbuffer accordingly
            SelectObject(hdcBackBuffer, hOldBitmap);

            HDC hdc = GetDC(hwnd);

            hBitmap = CreateCompatibleBitmap(hdc,
                                                             cxClient,
                                                             cyClient);
            ReleaseDC(hwnd, hdc);

            hOldBitmap = (HBITMAP)SelectObject(hdcBackBuffer, hBitmap); 
         

        break;

        case WM_PAINT: 
        
      PAINTSTRUCT ps;

          BeginPaint(hwnd, &ps);

            //fill our backbuffer with white
            BitBlt(hdcBackBuffer,
             0,
             0,
             cxClient,
             cyClient,
             NULL,
             NULL,
             NULL,
             WHITENESS);

            //render the mines and sweepers
            g_pController->Render(hdcBackBuffer);

            //now blit backbuffer to front
            BitBlt(ps.hdc, 0, 0, cxClient, cyClient, hdcBackBuffer, 0, 0, SRCCOPY); 

            EndPaint(hwnd, &ps);
         

        break;

        case WM_DESTROY: 
        
            SelectObject(hdcBackBuffer, hOldBitmap);

            //clean up our backbuffer objects
            DeleteDC(hdcBackBuffer);
            DeleteObject(hBitmap); 

      // kill the application, this sends a WM_QUIT message 
            PostQuitMessage(0);
         

        break;

        default:break;

    //end switch

    // default msg handler 
    return (DefWindowProc(hwnd, msg, wparam, lparam));

//end WinProc


//-----------------------------------WinMain-----------------------------------------
//  Entry point for our windows application
//-----------------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hinstance,
                              HINSTANCE hprevinstance,
                              LPSTR lpcmdline,
                              int ncmdshow)


    WNDCLASSEX winclass; 
    HWND       hwnd;     
    MSG        msg;      

    // first fill in the window class stucture
    winclass.cbSize       = sizeof(WNDCLASSEX);
    winclass.style            = CS_HREDRAW | CS_VREDRAW;
    winclass.lpfnWndProc    = WindowProc;
    winclass.cbClsExtra     = 0;
    winclass.cbWndExtra     = 0;
    winclass.hInstance      = hinstance;
    winclass.hIcon            = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_ICON1));
    winclass.hCursor          = LoadCursor(NULL, IDC_ARROW); 
    winclass.hbrBackground= NULL; 
    winclass.lpszMenuName   = NULL;
    winclass.lpszClassName= szWindowClassName;
    winclass.hIconSm      = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_ICON1));


    // register the window class
    if (!RegisterClassEx(&winclass))
    
        MessageBox(NULL, "Error Registering Class!", "Error", 0);
    return 0;
    

    // create the window (one that cannot be resized)
    if (!(hwnd = CreateWindowEx(NULL,                                   
                                              szWindowClassName,                        
                                              szApplicationName,                        
                                              WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
                              GetSystemMetrics(SM_CXSCREEN)/2 - CParams::WindowWidth/2,
                              GetSystemMetrics(SM_CYSCREEN)/2 - CParams::WindowHeight/2,                                    
                                              CParams::WindowWidth,
                              CParams::WindowHeight,                
                                              NULL,                                 
                                              NULL,                             
                                              hinstance,                                
                                              NULL)))   
    
    MessageBox(NULL, "Error Creating Window!", "Error", 0);
        return 0;
    

    //Show the window
    ShowWindow(hwnd, SW_SHOWDEFAULT );
    UpdateWindow(hwnd);

    //create a timer
    CTimer timer(CParams::iFramesPerSecond);

    //start the timer
    timer.Start();

    // Enter the message loop
    bool bDone = FALSE;

    while(!bDone)
    

        while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 
        
            if( msg.message == WM_QUIT ) 
            
                //Stop loop if it's a quit message
                bDone = TRUE;
             

            else 
            
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            
        

        if (timer.ReadyForNextFrame() || g_pController->FastRender())
           
          if(!g_pController->Update())
            
                //we have a problem, end app
                bDone = TRUE;
            

            //this will call WM_PAINT which will render our scene
            InvalidateRect(hwnd, NULL, TRUE);
            UpdateWindow(hwnd);
                       

    //end while


    // Clean up everything and exit the app
    Cleanup();
    UnregisterClass( szWindowClassName, winclass.hInstance );

    return 0;

 // end WinMain

【问题讨论】:

你得到什么错误/为什么你不能让它编译? 似乎问题不是错误——而是应用程序最终被编译为控制台子系统,因此即使它不需要控制台窗口,也会得到一个控制台窗口。显然只是链接器选项错误。为了解决这个问题,了解幕后使用的编译器很重要。我猜是海湾合作委员会? 【参考方案1】:

这似乎有点奇怪,但是 windows 子系统应用程序使用 WinMainCRTStartup 作为入口点。所以下面这行看起来不一致:

#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")

应该是"/SUBSYSTEM:windows /ENTRY:WinMainCRTStartup""/SUBSYSTEM:console /ENTRY:mainCRTStartup"

另一方面,我从未尝试使用 gcc 制作 Windows 应用程序。它可能会完全忽略这个#pragma...无论如何,尝试将其注释掉,看看会发生什么。一般来说,编译器应该能够在没有编译时间参数的情况下选择正确的入口点。

【讨论】:

我把它放在那里试图解决问题,它没有用。我忘记了我将它包含在我的 OP 的源代码中,但是,无论注释是否存在,或者我是否使用您提供的字符串,该应用程序仍然使用控制台启动。 我应该尝试切换到 minGW 还是什么? 我会,只是出于原则。 Cygwin 不适合原生 Windows 应用程序。它专为需要让人相信它们在 *nix 中运行的程序而设计。 好吧,我不知道。希望能解决它,我换掉它们后会回来发帖 好的,虽然从技术上讲不能直接解决我的问题,但切换到 minGW 已经为我解决了这个问题,我的应用程序现在启动起来非常像。谢谢大家。超,如果你回答而不是评论,你会得到“接受的答案”

以上是关于运行 C++ 应用程序时摆脱黑色控制台窗口的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 4 中摆脱 UIPopoverController 中奇怪的黑色导航栏

使用 Pyinstaller 冻结 Python 程序时摆脱控制台输出

隐藏控制台窗口

通过 C++ 运行命令时隐藏控制台窗口

使用 Dev C++ 时不会出现控制台窗口

用来调式跟踪的控制台输出调试输出