コマンドプロンプトの表示を抑制する


リンカのオプションSUBSYSTEMに値WINDOWSを指定することで、コマンドプロンプトの表示を抑制することができます。

はじめに

C言語でWin32APIなどを利用して、何も考えずに実行ファイルを生成すると、以下のようにコンソールが表示されてしまいます。

上記のようなコンソール表示はデバッグに役立ちますが、本番のアプリケーションでも表示されてしまうと見栄えがわるくなってしまうので、表示を抑制したい方もいると思います。
本記事ではそのような方を対象に、いくつかの抑制方法を紹介していきます。

ちなみに上記のアプリの作成には以下のコードを利用しています。

main.c
#include <windows.h>

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine,
    int nCmdShow
) {
    MessageBox(NULL, TEXT("Sample Text"), TEXT("Sample Window"), MB_OK);
    return 0;
}

IDEから指定する場合

たぶん一番メジャーな方法だと思います。

VisualStudio2019

プロジェクト(P) > プロパティ(P) > 構成プロパティ > リンカー > システム > サブシステム の値に Windows (/SUBSYSTEM:WINDOWS)を指定するとコマンドプロンプトの表示を抑制することができます。

また、これからプロジェクトを作成する場合は、Windows デスクトップ アプリケーションを選択すると、デフォルトでリンカの設定がWindows (/SUBSYSTEM:WINDOWS)になるのでおすすめです。

ビルドツールから指定する場合

MSBuild

(設定ファイルを直接弄ります)

プロジェクトファイルのProject要素にItemDefinitionGroup > Link > SubSystem要素を作成します。
値にはWindowsを指定します。

これだけでOKです。

Sample.vcxproj.diff
  <Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
      <ProjectConfiguration Include="Debug|Win32">
        <Configuration>Debug</Configuration>
        <Platform>Win32</Platform>
      </ProjectConfiguration>
    </ItemGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props" />
    <PropertyGroup>
      <ConfigurationType>Application</ConfigurationType>
      <PlatformToolset>v142</PlatformToolset>
    </PropertyGroup>
+   <ItemDefinitionGroup>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+     </Link>
+   </ItemDefinitionGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
    <ItemGroup>
      <ClCompile Include="main.c" />
    </ItemGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
  </Project>

CMake

CMakeLists.txtCMAKE_EXE_LINKER_FLAGSをセットする処理を追加するだけです。

CMakeLists.txt.diff
  cmake_minimum_required(VERSION 3.1)
  project(hello_world C)
+
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
+
  add_executable(main main.c)

コンパイラから指定する場合

小さなプロジェクトなら、こちらの方が手軽ですね。

CL

リンカオプション/linkを利用して、/SUBSYSTEM:WINDOWSを指定するとコマンドプロンプトの表示を抑制することができます。

 CL .\main.c user32.lib /link /SUBSYSTEM:WINDOWS

mingw32-gcc

リンカオプション-Wlを利用して、-subsystem,windowsを指定するとコマンドプロンプトの表示を抑制することができます。
ちなみにエントリポイントがWinMain(Windowsアプリケーション用のエントリポイント)ではなくmain(コンソールアプリケーション用のエントリポイント)でもコンパイルが通ります(CLの場合はリンカオプション/entry:mainCRTStartupが追加で必要)

gcc main.c -Wl,-subsystem,windows

リンカを直接利用する場合も、オプションSUBSYSTEMに値WINDOWSを指定することで、コマンドプロンプトの表示を抑制することができます。

おまけ

実行の途中で非表示にする

プログラムの実行途中で非表示にしたい場合は、FreeConsole();関数を利用します。
例えば、プログラムを実行してから3秒後にコンソールを非表示にしたい場合は、以下のようなコードに変更することで実現できます。

main.c.diff
  #include <windows.h>
-
- int WINAPI WinMain(
-     HINSTANCE hInstance,
-     HINSTANCE hPrevInstance,
-     LPSTR lpszCmdLine,
-     int nCmdShow
- ) {
+ int main() {
+     Sleep(3 * 1000);    // wait for 3 sec.
+     FreeConsole();      // free console.
      MessageBox(NULL, TEXT("Sample Text"), TEXT("Sample Window"), MB_OK);
      return 0;
  }

この場合は、リンカへ渡すオプションを指定する必要はありません。

参考

https://suzulang.com/vc-subsystem-windows-winmain/
https://docs.microsoft.com/ja-jp/cpp/build/walkthrough-using-msbuild-to-create-a-visual-cpp-project?view=vs-2019
https://stackoverflow.com/questions/33873735/correctly-set-visual-studio-linker-flag-subsystem-in-cmake
https://docs.microsoft.com/ja-jp/cpp/build/reference/cl-invokes-the-linker?view=vs-2019
https://docs.microsoft.com/ja-jp/cpp/build/reference/linker-options?view=vs-2019