ポップアップだけの単純な Windows プログラムのビルド

これまで開発環境説明をしてきましたが、一般的な C/C++ プログラミングにも そのまま適用できる内容が主でした。

今回から、いよいよ Windows プログラミングらしいコードを書いてみましょう!

今までオーソドックスな C 言語しかしてなかった人にとっては、聞いたことの無い キーワードがたくさん出てくるかもしれませんが、頑張って読んでください!

尚、開発環境は Visual Studio と最新の Windows SDK を使うことを想定しています。

1.まずはビルドしてみよう!

最初に実際に手元でプログラムが作れるかどうか、試してみましょう。

次のコードを helloworld.cpp という名前で保存してください。

#include <windows.h>

int WINAPI WinMain (
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow ) {

        MessageBox(
                NULL,
                TEXT("Hello, world!"),
                TEXT("Hello"),
                MB_OK | MB_ICONINFORMATION );

        return 0;
}

プログラミング言語は C 言語です。しかし、main 関数がありません。これで本当に動くのでしょうか?

それから WinMain という関数名の前に、 WINAPI という見慣れぬものが書いてますね。

さらに HINSTANCELPSTRTEXT とはなんでしょうか?

Windows のプログラミングに慣れていない人にとっては、たくさん疑問が出てきたと思います。

基本的な C 言語を習っただけの段階では、こうした点は習わないので、疑問が出るのは当然です。

ここに、標準的な C 言語と Windows 向けのプログラミングのギャップがあります。この講座の目的はまさに、このギャップを埋めるためのものですから、 おいおい説明していくつもりです。

はじめは、「ふ~ん、こんなのがあるのか」程度に眺めておいてください。

次に、以下の内容を makefile という名前で保存してください。 ファイル名には拡張子がつかないので、気をつけてくださいね。

TARGETNAME=helloworld
OUTDIR=.\chk
LINK=link.exe

ALL : "$(OUTDIR)\$(TARGETNAME).exe"

"$(OUTDIR)" :
    @if not exist "$(OUTDIR)\\" mkdir "$(OUTDIR)"

CPPFLAGS=\
        /nologo\
        /W4\
        /Fo"$(OUTDIR)\\"\
        /Fd"$(OUTDIR)\\"\
        /c\
        /Zi\
        /DUNICODE\
        /D_UNICODE\

LINKFLAGS=\
        user32.lib\
        /nologo\
        /subsystem:windows\
        /pdb:"$(OUTDIR)\$(TARGETNAME).pdb"\
        /out:"$(OUTDIR)\$(TARGETNAME).exe"\
        /DEBUG

LINKOBJS= \
        "$(OUTDIR)\$(TARGETNAME).obj"

"$(OUTDIR)\$(TARGETNAME).exe" : "$(OUTDIR)" $(LINKOBJS)
    $(LINK) $(LINKFLAGS) $(LINKOBJS)

.cpp{$(OUTDIR)}.obj:
   $(CPP) $(CPPFLAGS) $<

リンカオプションでサブシステムが windows に設定されていることに注意してください。

上記の helloworld.cppmakefile は同じディレクトリに保存してください。

Visual Studio または Windows SDK のコマンドプロンプトを開き、 上記ファイルを保存したディレクトリに移動し、nmake コマンドを実行すれば、 chk というサブディレクトリ内に helloworld.exe が出来ます。

helloworld.exe を実行すると、ポップアップメッセージが出てきます。

たったこれだけの小さいプログラムですが、ちゃんとした Windows プログラムです。

2.ビルドコマンドの補足

ビルド出力になにやらいろいろと書いてあるでしょうから、簡単に補足しておきます。

おそらく、以下のようなメッセージが表示されたのではないでしょうか?

> nmake

Microsoft (R) Program Maintenance Utility Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.

        cl  /nologo /W4 /Fo".\chk\\" /Fd".\chk\\" /c /Zi /DUNICODE /D_UNICODE "helloworld.cpp"
helloworld.cpp
helloworld.cpp(7): warning C4100: 'nCmdShow': unreferenced formal parameter
helloworld.cpp(6): warning C4100: 'lpCmdLine': unreferenced formal parameter
helloworld.cpp(5): warning C4100: 'hPrevInstance': unreferenced formal parameter
helloworld.cpp(4): warning C4100: 'hInstance': unreferenced formal parameter
        link.exe  user32.lib /nologo /subsystem:windows /pdb:".\chk\helloworld.pdb" /out:".\chk\helloworld.exe" /DEBUG ".\chk\helloworld.obj"
>

まずはこの部分から...

Microsoft (R) Program Maintenance Utility Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.

これは nmake プログラム自身が出力するバージョン情報です。 出力したくなければ、nmake のオプションとして /nologo オプションをつけると表示されなくなります。

        cl  /nologo /W4 /Fo".\chk\\" /Fd".\chk\\" /c /Zi /DUNICODE /D_UNICODE "helloworld.cpp"

この行は、makefile の内容に従って実行されたコマンドです。

ちなみに、コマンドそのものは表示したくない場合は、次のように @ をつければ非表示になります。

"$(OUTDIR)\$(TARGETNAME).exe" : "$(OUTDIR)" $(LINKOBJS)
    @$(LINK) $(LINKFLAGS) $(LINKOBJS)

.cpp{$(OUTDIR)}.obj:
    @$(CPP) $(CPPFLAGS) $<
helloworld.cpp(7): warning C4100: 'nCmdShow': unreferenced formal parameter
helloworld.cpp(6): warning C4100: 'lpCmdLine': unreferenced formal parameter
helloworld.cpp(5): warning C4100: 'hPrevInstance': unreferenced formal parameter
helloworld.cpp(4): warning C4100: 'hInstance': unreferenced formal parameter

これらの行は、cl (C/C++ コンパイラ) が出力したワーニング (警告) メッセージです。

エラーではありませんが、良いプログラムを作りたい方は、こうしたコンパイラが出力してくれる警告にも注意すると良いでしょう。

ここでは、「参照されないパラメータがありますよ、これでいいんですか?」 という警告なのですが、ここではパラメータは本当に使わないので放っておいても 構いません。

ちなみに、この警告は makefile 内で指定した警告レベル /W4 を /W3 にすれば出てこなく なります。しかし、警告レベルを落としてしまうと、必要な警告も消えてしまうかも しれません。

ですから、「参照されなくてよい」ということが確認されていて、警告メッセージを 消したいパラメータについては、UNREFERENCED_PARAMETER マクロを使って「参照」 することによって、警告メッセージを消せばよいです。

#include <windows.h>

int WINAPI WinMain (
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow ) {

	UNREFERENCED_PARAMETER(hInstance);
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
        UNREFERENCED_PARAMETER(nCmdShow);

        MessageBox(
                NULL,
                TEXT("Hello, world!"),
                TEXT("Hello"),
                MB_OK | MB_ICONINFORMATION );

        return 0;
}

尚、UNREFERENCED_PARAMETER マクロは winnt.h で定義されています。 なぜか、MSDN には記載が無いようですが、Windows SDK 等で広く利用されているマクロです。

通常はドキュメントされていない機能は使うべきではないのですが、このマクロに 関しては定義も次のように簡単なものですし、以後 SDK から消えたとしても自分で 定義すれば良いだけですから、使って良いと思います。

#define DBG_UNREFERENCED_PARAMETER(P)      (P)

上のプログラムをビルドして実行すれば、確かにポップアップが表示されて、動作は確認できたと思います。

でも、main 関数はどこだ?とか、疑問は残ったことと思います。

次の記事では、まずは WinMain について説明していきます。

WinMain とは何か?