エントリーポイント

  今更VC++ > エントリーポイント

エントリーポイントとは

C言語またはC++言語では、ユーザープログラムの開始を必ず「main」という関数を用意しなければならない。 それをエントリーポイントと呼ぶようだ。

これは、Visual C++ においても、ほぼ同じである。 しかし、「main」はコンソールアプリ向けではある。 Widnowsのグラフィカルユーザーインターフェイスにおいては、「WinMain」がエントリーポイントになる。 ただ、Windows2000以後はOS自体が文字をUnicodeという文字対応機能で作成されており、「wWinMain」「wmain」 というエントリーポイント名で作成することになっている。 自動生成したソースコードも先頭に「w」が付く「wWinMain」となっている。 「(プロジェクト名).cpp」を開くと「wWinMain」があるはずだ。

例1 サンプルコード(抜粋)

// Win32Project3.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "Win32Project3.h"

#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING];                  // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING];            // メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。

   ※以下略
		

wWinMainの引数の意味だが、OSからアプリに引き渡される情報で以下の通りとなる。

引数 意味
hInstance HINSTANCE OSが割り当てた番号
hPrevInstance HINSTANCE 0固定。 16ビット時代の互換のため残っている。 重複起動チェックに用いられてた。
lpCmdLine LPWSTR コマンドラインやショートカットなどで、指定されたオプション文字列。 コンパイルの設定によって文字コードが変わる。
nCmdShow int 起動時のウィンドウ表示形式。  通常は、そのまま「ShowWindow」APIの第二引数に使用する。 

いよいよプログラムの中身を見ていく。

例2 サンプルコード(抜粋)

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。

    // グローバル文字列を初期化しています。
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WIN32PROJECT3, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // アプリケーションの初期化を実行します:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT3));

    MSG msg;

    // メイン メッセージ ループ:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}
		

wWinMain関数は、上記「例2」の内容となる。 コードを上から見ていく。

UNREFERENCED_PARAMETER(...);
行の先頭にこの記述がある。 引数は、wWinMain関数の中で使用していない引数である。 必ず書かなければならないものでもないが、コンパイルするとワーニング(警告)に扱われる。
LoadStringW(...);
リソースから文字列を読み込む機能である。 タイトルバーにアプリケーションの文字列を設定するために使用したり 後で出てくるクラスの文字列に使用する。 わざわざリソースに持つ必要が感じられないが、 例えば、作成したアプリを英語化する場合、リソースを書き換えるだけで、ソースコードに あまり手を入れず対応できるなどに利用されると思う。
MyRegisterClass(hInstance);
後に出てくるユーザー関数。 主にOSに対しての登録を行うと思われる。
InitInstance (hInstance, nCmdShow);
後に出てくるユーザー関数。 ここで、アプリの外観のウィンドウが生成と表示をおこなう。
LoadAccelerators(...);
おそらく、キーボード操作におけるショートカットキーの設定をリソースから読み込むものと思われる。 このアプリの場合、「alt」+「/」、「alt」+「?」の操作でバージョン情報のダイアログが表示できる。 後で説明するTranslateAccelerator関数で使用される。
GetMessage(&msg, nullptr, 0, 0)
メッセージを受け取る関数。 WindowsではマルチタスクとGUIを実現するためにOSからメッセージというものを各アプリに 送ることによって実現している。 OSから自アプリに必要なメッセージが送られてくるまでここで止まる格好になる。
TranslateAccelerator(msg.hwnd, hAccelTable, &msg)
ショートカットキーをメニューに対応させる処理を行う。
TranslateMessage(&msg);
仮想キーメッセージを文字メッセージに変換する。
DispatchMessage(&msg);
おそらく、後で説明するユーザー関数「WndProc」にGetMessageで取得したメッセージを引き渡す。
return (int) msg.wParam;
OSに処理結果を返す。 返しても何も意味はないが、バッチファイルのErrorLevel、子プロセスの戻り値に使えると思われる。
以上、大まかな流れではあるが、これが基本的なコードになる。 ここに手を入れる必要はあまりないかもしれない。 ただ、ゲームなどリアルタイムに処理を行うは少し工夫が必要かもしれない。