Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

VC++: Convert Console Project to Non-Console

3.67/5 (5 votes)
18 Feb 2024MIT2 min read 8.1K   121  
Make a console program not to show the console screen
This tip guides Visual C++ developers on converting a Console project to hide the console screen.

This short write-up is a tip on making console program not to show console. As such, it is not eligible to participate in the CodeProject monthly article competition.

This tip is written in response to the Q&A question posted by Eduardo Quintana from Brazil. I encountered this same problem many years back when I downloaded an OpenGL tutorial that launched a console window before opening an OpenGL window. Having a console is extremely useful to log the messages to screen for troubleshooting but as a final product, only the OpenGL window should be shown to the user. In this tip, I'll show you how to convert a Visual C++ Console project not to show the console screen.

Firstly, to open Project Properties dialog, right-click on the project in the Solution Explorer and select Properties at the bottom of the pop-up menu or you can type Alt+Enter key. Select the Linker->System on the tree on the left panel. Then, change the Configuration dropdown to All Configurations and Platform dropdown to All Platforms. Finally, change the Subsystem from Console (/SUBSYSTEM:CONSOLE) to Windows (/SUBSYSTEM:WINDOWS) as shown on the screenshot.

  • Configuration: All Configurations
  • Platform: All Platforms
  • Subsystem: Windows (/SUBSYSTEM:WINDOWS)

Select Windows Subsystem

Then, you can rebuild the project, but you will encounter this linker error.

error LNK2019: unresolved external symbol WinMain referenced in function 
               "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)

The solution is to add WinMain function and include Windows.h. Console program starts from main while Windows program begins from WinMain. You can call your original main from WinMain.

C++
#include <Windows.h>

// Your original main function
int main()
{
    // your original code here
    return 0;
}

int __stdcall WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nShowCmd
)
{
    // You can use OutputDebugStringA to log your
    // debug message to your Visual Studio debugger
    // or Sysinternals DebugView
    OutputDebugStringA("Hello World!\n");

    return main(); // call your main() here
}

If you do not wish to include the heavy duty Window.h to bring in the WinMain, you can declare WinMain as such. I cannot do it here as I need the OutputDebugStringA from that header.

C++
#define HINSTANCE void*
#define LPSTR const char*
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                      LPSTR lpCmdLine, int nShowCmd);

Rebuild your project. It should run without a console window. If you need to forward lpCmdLine to your main, you can use ParseCmdlineA for ASCII or ParseCmdlineW for Unicode version. Both take care of command argument specified in quotes. Unfortunately, lpCmdLine does not contain the path of executable which I have to separately retrieve using GetModuleFileNameA. This feature is suggested by Richard Chambers to make the solution complete.

C++
void ParseCmdlineW(const wchar_t* cmdLine,
    std::vector<wchar_t*>& vecArgs, std::wstring& holder)
{
    // implementation not shown
}

void ParseCmdlineA(const char* cmdLine,
    std::vector<char*>& vecArgs, std::string& holder)
{
    // implementation not shown
}

#ifdef UNICODE
    #define ParseCmdlineT ParseCmdlineW
#else
    #define ParseCmdlineT ParseCmdlineA
#endif

int main(int argc, char* argv[])
{
    // print out the cmd args in debugger
    for (int i = 0; i < argc; ++i)
    {
        OutputDebugStringA(argv[i]);
        OutputDebugStringA("\n");
    }

    return 0;
}

int __stdcall WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nShowCmd
)
{
    std::vector<char*> vecArgs;
    std::string holder;
    char executablePath[MAX_PATH];
    DWORD res = GetModuleFileNameA(
        NULL,
        executablePath,
        MAX_PATH
    );
    if (res != 0)
    {
        vecArgs.push_back(executablePath);
        ParseCmdlineA(lpCmdLine, vecArgs, holder);
    }

    return main((int)vecArgs.size(), vecArgs.data());
}

Alternate Solutions: Hide the Console or Make a Window Service

In the article comment section, Stacy Dudovitz gives two solutions: either move the console window offscreen and hide it or make your application a Windows service. Marius Bancila has written an excellent Windows service article: Interact with Windows Services in C++; You can use it as a guide to write your service.

C++
#include <Windows.h>

// suggested by Stacy Dudovitz
int main()
{
    // move the window offscreen, then hide it
    HWND hwnd = ::GetConsoleWindow();
    ::SetWindowPos(hwnd, NULL, 5000, 5000, 0, 0, 0);
    ::ShowWindow(hwnd, SW_HIDE);

    // application code here 
    //     .....

    return 0;
}

History

  • 19th February, 2024: Added solution if user does not want to include Windows.h for WinMain
  • 7th February, 2024: Added alternate solutions by Stacy Dudovitz. Added HideConsole project download
  • 30th January, 2024: First release

License

This article, along with any associated source code and files, is licensed under The MIT License