Click here to Skip to main content
15,886,873 members
Articles / Programming Languages / C++
Tip/Trick

VC++: Convert Console Project to Non-Console

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
18 Feb 2024MIT2 min read 6.8K   105   5   12
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


Written By
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

In recent years, he shifted focus to software safety research. His hobby is writing a free C++ DirectX photo slideshow application which can be viewed here.

Comments and Discussions

 
QuestionWindows app vs. Console app - summary of differences which have not been addressed Pin
Stacy Dudovitz4-Feb-24 17:32
professionalStacy Dudovitz4-Feb-24 17:32 
QuestionStackoverflow post with more details about this approach Pin
Richard Chambers31-Jan-24 18:43
Richard Chambers31-Jan-24 18:43 
AnswerRe: Stackoverflow post with more details about this approach Pin
Shao Voon Wong31-Jan-24 20:32
mvaShao Voon Wong31-Jan-24 20:32 
AnswerRe: Stackoverflow post with more details about this approach Pin
Shao Voon Wong6-Feb-24 18:02
mvaShao Voon Wong6-Feb-24 18:02 
I have added the code to parse the lpCmdLine before passing to main in the article and source code download as suggested by you to make the proper solution. Thank you for your suggestion.
QuestionSeveral problems with this approach Pin
Stacy Dudovitz31-Jan-24 10:35
professionalStacy Dudovitz31-Jan-24 10:35 
AnswerRe: Several problems with this approach Pin
Richard Chambers31-Jan-24 18:33
Richard Chambers31-Jan-24 18:33 
AnswerRe: Several problems with this approach Pin
Shao Voon Wong1-Feb-24 20:40
mvaShao Voon Wong1-Feb-24 20:40 
GeneralRe: Several problems with this approach Pin
Stacy Dudovitz4-Feb-24 0:38
professionalStacy Dudovitz4-Feb-24 0:38 
GeneralRe: Several problems with this approach Pin
Richard Chambers4-Feb-24 8:50
Richard Chambers4-Feb-24 8:50 
GeneralRe: Several problems with this approach Pin
Shao Voon Wong6-Feb-24 18:06
mvaShao Voon Wong6-Feb-24 18:06 
AnswerRe: Several problems with this approach Pin
Shao Voon Wong6-Feb-24 18:07
mvaShao Voon Wong6-Feb-24 18:07 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA30-Jan-24 11:18
professionalȘtefan-Mihai MOGA30-Jan-24 11:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.