コマンドラインから起動されたときはコマンドラインアプリケーションとして動作させたい

CMD.EXEから起動したときにはそのアプリケーションをコマンドラインアプリケーションとして、それ以外の例えばExplorerなどから起動した場合にはGUIアプリケーションとして動作するようなものを組みたいと思っていろいろ調べたのですが、あまりうまい方法がなく、その場しのぎ的な方法であきらめよう…というメモです。

まず、起動元が CMD.EXE なのかそれ以外なのかの判断には、TH32CS_SNAPPROCESS を指定して CreateToolhelp32Snapshot を呼び出し、PROCESSENTRY32.szExeFile を見て自分の親プロセスが "cmd.exe" かどうかを確認することで判断できます。
つぎに、エントリポイントですが、Visual C++ などのコンパイラを使ってWin32アプリケーションを生成した場合、エントリポイントが _tmain のときはコンソールアプリケーション、エントリポイントが WinMain のときはGUIアプリケーションのコードが生成されます。これらのコンソールアプリケーションとGUIアプリケーションの違いは、PEヘッダ内の IMAGE_OPTIONAL_HEADER32->Subsystem が IMAGE_SUBSYSTEM_WINDOWS_CUI に設定されているか、IMAGE_SUBSYSTEM_WINDOWS_GUI に設定されているかで決まります。

コンソールアプリケーションをCMD.EXE上で起動させた場合、C:\> のようなコマンドプロンプトはアプリケーションが終了するまで次のプロンプトを表示しませんが、GUIアプリケーションを起動させた場合はアプリケーションの終了を待たずにプロンプトが表示されます。

C:\>[]cl[]<ENTER> … コマンドラインアプリケーションの起動
[]Microsoft[](R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 …[]コマンドライン[][]アプリケーション[]の表示する[]メッセージ[]
[]Copyright[] (C) []Microsoft[] []Corporation[].  All rights reserved.

使い方: []cl[] [ []オプション[]... ] []ファイル[]名... [ /link []リンク[] []オプション[]... ]
C:\> …次のプロンプト
C:\>notepad<ENTER> … GUIアプリケーションの起動
C:\> …次のプロンプトは即座に表示
…というわけで、WinMain で始まる GUIアプリケーションから AttachConsole を使ってコンソールにアタッチした場合にはプロンプトが正しく表示されません。コンソールで正しくプロンプト表示させるためには _tmain から始まる IMAGE_OPTIONAL_HEADER32->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI なコンソールアプリケーションとしてコードを作成しなくてはいけません。 一方で、コンソールアプリケーションを Explorer から起動した場合には、無条件にコマンドプロンプトのウィンドウが開いてしまいます。そこで、Explorerから起動させたときにはGUIアプリケーションらしくふるまうためには、起動時にコマンドプロンプトを非表示にしてやる必要があります。
if( IsGUI() ){ // 親プロセスが cmd.exe でなければTRUE
    ShowWindow( GetConsoleWindow(), SW_HIDE );
    // Run as GUI application
これにより、Explorer から起動されたときにはコンソールウィンドウは一瞬だけ表示されますが、以降はGUIアプリケーションのようにふるまうことができます。 というわけで、「GUIアプリケーションとして実行したときに一瞬だけコンソールウィンドウが表示される」という問題は残りますが、とりあえず目的は何とか果たせたような果たせていないような…。