C言語を学習するときに必ず最初に出会うことになるprintf()関数を使えば、テキストをコンソール上に表示できます。しかし、普段使っているグラフィカルなアプリケーションと同じように、ウィンドウを表示してその中に図形やコントロールを表示するには、アプリケーションを実行するシステムが公開しているAPIを利用しなければなりません。

本稿では、Windows アプリケーションの開発で必要となるWindows APIを毎回1つずつピックアップして、その機能や具体的な利用法について説明します。C言語を学習して次のステップに進みたい方や、逆に.NET FrameworkやJavaなどの仮想マシン上のアプリケーション開発経験者でネイティブのプログラミングを学習したい方に、参考にしていただければと思います。

現在、多くのアプリケーションが.NET Framerowkに移行していますが、こうした新しい仮想プラットフォームの背景にはWindows APIが使われています。既存のネイティブコードとの相互運用を検討する場合や、.NET Framework ではサポートされていない低水準な処理にはWindows APIの知識が今も求められます。また、ゲームやマルチメディアのような、ハードウェアの性能を最大限に発揮させなければならない分野では、今もC++とWindows APIの組み合わせは現役です。

C言語の学習および環境の構築は下記を参考にしてください
1.ゼロからはじめるC言語 - 環境構築編
2.ゼロからはじめるC言語 - 関数編
3.ゼロからはじめるC言語 - 型・定数編
4.ゼロからはじめるC言語 - 変数編
5.ゼロからはじめるC言語 - 選択編
6.ゼロからはじめるC言語 - 繰り返し編
7.ゼロからはじめるC言語 - 配列編
8.ゼロからはじめるC言語 - 構造体編
9.ゼロからはじめるC言語 - 自作関数編
10.ゼロからはじめるC言語 - ポインタ編

記念すべき第01回では、WindowsアプリケーションのエントリーポイントとなるWinMain()関数を紹介します。この関数はアプリケーションから呼び出すものではなく、main()関数のWindows版のようなもので、アプリケーション起動時にシステムから呼び出されます。よって、Windowsアプリケーションを開発するには、最初にWinMain() 関数を作成します。

WinMain() 関数

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

パラメータ

hInstance アプリケーションの現在のインスタンスハンドル。
hPrevInstance 常にNULL
lpCmdLine コマンドライン文字列
nCmdShow ウィンドウの表示状態

戻り値

任意のアプリケーション終了コード

この関数が受け取るhInstanceパラメータは、操作対象の実体を識別するためのハンドルと呼ばれる値です。現在で言うオブジェクトに相当するもので、Windows APIではハンドルによってアプリケーションやウィンドウなどを識別します。hPrevInstanceパラメータは、古い 16 ビットの Windows 3.x 時代に使われていたパラメータです。Windows 95 と Windows NT 以降では常に NULL が渡されるため、気にする必要はありません。

lpCmdLine パラメータは、コマンドラインから渡された NULL で終わる文字列が格納されています。この他に、GetCommandLine() 関数から文字列を受け取る方法もあります。通常、コマンドラインから文字列を受けるには GetCommandLine() 関数を使うべきでしょう。

最後の nCmdShow パラメータには、ウィンドウの表示方法を表す値が格納されています。このパラメータに指定される有効な値は SW_ から始まる定数として定義されています。このパラメータは、ウィンドウを生成した後、ウィンドウの表示状態を設定する ShowWindow() 関数に渡す値として利用できます。

WinMain() 関数の戻り値は、アプリケーションの終了コードです。ウィンドウを生成していない場合、通常は 0 を返します。ウィンドウを生成している場合、ウィンドウへの終了要求と共に終了コードが渡されるので、この値を戻り値として利用します。

初めて Windows API を学習するとき、標準の C 言語では見られなかった型に疑問を感じるかもしれません。例えば、lpCmdLine パラメータに渡されるのはコマンドライン文字列ですが、その型は char の配列やポインタではなく LPSTR です。しかし、これは typedef による char へのポインタへの別名にすぎません。同様に HINSTANCE のようなハンドルも、void へのポインタの別名です。これら Windows API 用のデータ型や、Windows API で提供される関数を呼び出すために Windows.h ヘッダファイルをインクルードしてください。

この関数の戻り値の直後、関数名の直前にある WINAPI というトークンは、関数の呼び出し規約を指定する修飾子の一種で、#define ディレクティブによって __stdcall に置き換えられます。関数の呼び出し規約とは、関数へのパラメータの渡し方などを定めたもので、例えば C 言語で作られた関数を、他の言語や開発ツールで作られたプログラムから呼び出すには、関数の呼び出し規約を一致させる必要があります。

WinMain() 関数を含め、多くの Windows API は__stdcall を呼び出し規約としています。一方、特に呼び出し規約を指定しなかった通常の関数は __cdecl という呼び出し規約が使われます。アプリケーションが起動されるとき、Windows システムは WinMain() 関数を __stdcall規約に従って呼び出します。

サンプル 01

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    return 0;
}

このサンプルは、WinMain() 関数から開始する Windows アプリケーションです。ウィンドウを生成するなどのコードは書いていないため、プログラムを実行しても何もせずに終了するだけです。面白みに欠けますが、Windows アプリケーション開発を学習するとき、すべてはここから始まります。

Visual C++ 2008 を使ってコンパイルする場合、プロジェクトの新規作成時に表示される「新しいプロジェクト」ダイアログから「空のプロジェクト」を選択してください。または「Win32 プロジェクト」を選択した後に表示されるダイアログの設定で「空のプロジェクト」を選択する形でもかまいません。他の設定でプロジェクトを作成すると、余分なコードが自動生成されてしまいます。自動生成されるコードは便利かもしれませんが、学習時には何も書かれていない状態からコードを書いたほうが本質に迫れます。

図01 「新しいプロジェクト」ダイアログ

「空のプロジェクト」を選択した場合、ソースファイルを手動で追加する必要があります。「プロジェクト」メニューの「新しい項目の追加」を選択して、「ソースファイル」フォルダに新しいファイルを追加してください。C++ ファイルでもかまいませんが、本シリーズの範囲では C 言語の機能しか使わないので、明示的に拡張子を *.c と入力することで C 言語としてコンパイルします。

図02 「プロジェクト」メニュー→「新しい項目の追加」ダイアログ

これで、上記のサンプルをコンパイルして実行できます。

図03 作成したソースファイル

あとは、この関数の中でウィンドウの生成や初期化処理を行い、目的のプログラムを構築していきます。Windows によって公開されている関数は無数にあるので、そのすべてを網羅することはできませんが、今後も本シリーズを通して、多くの Windows アプリケーションで共通して使われる基本的な関数や、特徴的な面白い機能などを紹介します。