Search code examples
cwindowsgtk3clcompileoptions

How to hide console window from Windows Gtk C programs compiled with cl


Due to unstable and unreliable mingw / MSYS2 behaviours on Windows 11 (x86_64), I have decided to use the Windows-native cl compiler bundled with Visual Studio to compile Gtk 3 programs written in C. I am using Gtk 3 built with the gvsbuild script. My Gtk 3 test program compiles successfully with the cl compiler, using a compiler command-file / response-file for the compile and linker options, but when I run the compiled Gtk 3 program, I get a console window behind it.

Image of Gtk test program with console behind it

I have searched tirelessly on StackOverflow as well as the rest of the internet and have not found a solution that addresses my cl-specific situation.

I have tried using /SUBSYSTEM:WINDOWS which causes a compiler error because the compiler can't find WinMain hidden by Gtk. I have tried /D"subsystem,windows", /Dmwindows as well as /Dsubsystem=gui with and without the - in front, but none solve the issue.

I have also tried this bit of code, which causes a huge amount of errors because the compiler can't find Windows-specific code hidden by Gtk:

#ifdef _WIN32
AllocConsole();
ShowWindow(GetConsoleWindow(), SW_HIDE);
#endif

Here is the test program:

#include <gtk/gtk.h>

static void activate (GtkApplication * app, gpointer user_data)
{
  GtkWidget * window;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Hello internet from Gtk Windows!");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
  gtk_widget_show_all (window);
}

int main (int argc, char ** argv)
{
  GtkApplication * app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

I've elected not to post the compiler command-file contents as it's quite lengthy.

For those who may answer "Just use mingw, MSYS2, cygwin, etc" I'd rather stay with a cl-specific solution please.

Is there a cl-specific option for suppressing the console window when compiling and running C Gtk 3 programs on Windows?


A big thanks to Tony Lee for the recommendation! This code is working properly after specifying /SUBSYSTEM:WINDOWS in the linker options:

#include <gtk/gtk.h>

static void activate (GtkApplication * app, gpointer user_data)
{
  GtkWidget * window;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Hello internet from Gtk Windows!");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
  gtk_widget_show_all (window);
}

#ifdef _WIN32
int WinMain (void * hInstance, void * hPrevInstance, char ** argv, int nCmdShow)
#else
int main (int argc, char ** argv)
#endif
{
  GtkApplication * app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), 0, argv);
  g_object_unref (app);

  return status;
}

It should be noted that I had to put a zero for the argc value in g_application_run(), so that's another (minor) issue I'll have to figure out later, but if your Gtk program doesn't need to process command-line arguments, it's fine.


Solution

  • The VS 2022 help on /SUBSYSTEM under Windows says to use it when:

    The application doesn't require a console, probably because it creates its own windows for interaction with the user.

    Which is exactly what's required here - There's a Raymon Chen article called "WinMain is just the conventional name for the Win32 process entry point" so when the OP found it undefined, it just needed to be declared instead of main. It documents the WinMain prototype as:

    WinMain(HINSTANCE *, HINSTANCE *, char *, int)

    However, MS documents the WinMain prototype without the * on HINSTANCE in an article called "WinMain: The Application Entry Point" as

    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);

    You could include Windows.h but it doesn't appear there's a requirement to use hInstance and hPrevInstance so void * should work as a substitute.