2015.11.30.
石立 喬

Visual Studio Community 2015の使い方(3)

―― Win32 アプリケーションで、メニューを作成する ――

 Visual Studio Community 2015のVisual C++を使った、Win32コンソールアプリケーションについては、既に簡単に述べた。残りはWin32アプリケーションである。これは、Wiondows API (Application Programming Interfaces)を使うもので、より詳細なWindowsプログラムの知識が必要になる。
 最近のMicrosoftの方針は、
     Windowsフォームアプリケーション(.NET Frameworkを介する、易しい) ---- Visual C#、Visual Basic
     Win32アプリケーション(Windows OSに直接、やや面倒で難しい) -------- Visual C++
のようであるが、Visual Studio Community 2015のVisual C++のテンプレートを使用し、必要な箇所だけコードを修正、追加する方法を用いれば、比較的簡単にWin32アプリケーションを作成できる。
 旧バージョンの「Visual Studio 2012 Expressの易しい使い方」も十分参考になるので、利用されたい。

Win32
 Win32は、最新のOSに対応しているWindows APIで、Windowsを扱うプログラムは、必ずこれを使用する。ただし、これはWindowsに直結した低レベルのライブラリであるので、実用的には、Win32をラップ(wrap)した.NET FrameworkやMFC(Microsoft Foundation Classes)などの高水準のライブラリの方が多用される。これは、アセンブリ言語と高級言語の関係に似ている。
 アセンブリ言語に対すると同様に、Win32の必要性、習得の価値に対する疑問もあるが、Win32でないとできない処理や効率向上が可能で、.NET Frameworkの環境がなくても使用できるので、配布用には好適である。

win32の表記法
 テンプレート(ひな形)で与えられたプログラムの一部を修正、追加してプログラムを作成する場合、元のテンプレートの表記法に従わないと、プログラムが不揃いで、読みにくくなる。
 ここでは、ハンガリアン記法(Hungarian notation)と呼ばれ、特に、変数の頭に、型を表す小文字を付けるシステムハンガリアン記法が使われているので、それに倣った。ハンガリアン記法については、賛成しない人も多い。

Unicodeについて
 Win32は、原則としてUnicodeを扱うようになっている。たとえば、TextOut関数の場合、対象とする文字列は、L"Good Morning"のように、頭にLをつけなくてはいけない。Unicodeはワイド文字とも呼ばれ、Unicodeを明示的に示すTextOutWが使われることもある。ANSI型の文字を使用しないときの対応として、両者で使える、_T("文字列")を使うこともできるが、ここでは、Unicode専用に統一した。

Win32 アプリケーションのスケルトン作成方法
1)スタート画面から、「新しいプロジェクト」を選択する。
2)「新しいプロジェクト」ウィンドウで、左欄から、「Visual C++」→「Win32」を選択する。
3)右欄で、「Win32 プロジェクト」を選択し、「OK」をクリックする。
4)「Win32 アプリケーションウイザード」が開くので、「Windows アプリケーション」になっているのを確認して、「次へ」をクリックする。
5)次の画面では、デフォルトのまま(「空のプロジェクト」にチェックをつけない)「完了」をクリックする。

できたスケルトンの内容
 プロジェクト名は、デフォルトで「Win32Project1」となっており、図1に示すように、「Win32Project1.cpp」など、「Win32Project1」の一式のファイルができている。このまま、「ビルド」→「ソリューションのビルド」を行い、正常終了を確認して、「デバッグ」→「デバッグなしで開始」を実行すると、図2に示すウインドウが現れる。図2は、ウインドウのサイズをドラッグして縮小し、終了のために、「ファイル」メニューを選択したところを示す。


図1 できたスケルトンの内容



図2 Win32アプリケーションのスケルトンを実行した結果


Win32Project1.cpp(スケルトン)の内容
 この段階では、まだスケルトンの状態であるが、
    int APIENTRY WinMain ---------- 最初に実行されるエントリポイント
    ATOM MyRegisterClass --------- ウインドウの構成を登録
    BOOL InitInstance ------------- メインウインドウを作成
    LRESULT CALLBACK WndProc --- メッセージに対する処理を記述する、プログラムの主要部分
    INT_PTR CALLBACK About ------ バージョン情報
ができている。

◎ウィンドウの構成を決めるMyRegisterClass
 通常の用途では、これを変更する必要はない。


図3 MyRegisterClassの部分(デフォルト)


◎メインウィンドウを作成するInitInstance関数
 ウィンドウの名称、タイトル名、サイズ、親ウィンドウや子ウィンドウの有無などを設定してウィンドウを作成し、表示する。タイトル名szTitleは、デフォルトでは、プロジェクト名に設定されている。


図4 InitInstanceの部分(デフォルト)


◎実行内容を記述するWinProc関数
 メッセージを受け取って、処理をする部分で、WM_COMMAND(メニューやボタンなどGUIへの対応)とWM_PAINT(ウィンドウ上への描画)が中心である。GUIを新たに追加するには、それに応じてWM_COMMAND内のcaseを増やす。処理と結果の表示はWM_PAINTのBeginPaint()とEndPaint()の間に記述する。


図5 プログラムの中心となるWndProcの部分(デフォルト)


メニューの作成と動作の設定
 ここでは、プロジェクト名をWin32Project1(一例)として説明する。
◎メニューの作成方法
 ウィンドウの上部にあるメニューバーにメニューを追加するには、以下の記述が必要である。
 1)Win32Project1.rcのリソースファイルにメニューキャプションを記述し、対応するID名を付ける。
   リソースファイルを編集するには、下記の手順が必要である。
   ・ソリューションエクスプローラーで、「Win32Project1.rc」を右クリックする。
   ・「ファイルを開くアプリケーションの選択」をクリックする。
   ・「プログラムから開く」ウィンドウが開くので、図6のように選択し、「規定値として設定」→「OK」をクリックする。
   ・エディタウィンドウにWin32Project1.rcが表示される。


図6 リソースファイル編集のために設定が必要なウィンドウ


 2)Resource.hのヘッダファイルに、上記で設定したID名を定義して登録する。
◎メニューを選択した時の動作の設定
 メニューをクリックした結果を反映させるには、以下の記述が必要である。
 1)Win32Project1.cppのWndProcのWM_COMMANDに、メニューのID名をcaseとして記述する。
 2)上記のcaseから呼び出されるMenuSelected関数(ユーザー作成、名称は一例)を作成する。
 3)前記のMenuSelected関数をプロトタイプ宣言しておく。
 4)メニュー選択の種類をMenuSelected(一例)に渡すために、グローバル変数nMenuType(一例)を設定しておく。

メニューの動作の説明
 図7のフローチャートにより説明する。
 1)メニューが選択されると、messageがWM_COMMANDとして送られる。
 2)n番目のサブメニューが選ばれた場合はIDM_SMnが送られ、case文により、nがnMenuTypeに設定され、InvalidateRect関数でWM_PAINTを呼び出す。
 3)WM_PAINTのcase文で、MenuSelected関数が呼び出されて、引数のnMenuTypeに応じた処理が行われる。


図7 サブメニューを選択してから実行するまでの流れ


サブメニューを選択すると、それを画面に表示するプログラム
 プログラムは、下記から成っている。
 1)Win32Project1.rcのリソースファイルに作成するメニューを記述し、ID名を付けて対応させる(図8)。
 2)Resource.hで、IDM_SM1などを、201〜203で定義する(図9)。
 3)選ばれたメニューの種類を表すnMenuTypeを、グローバル変数として宣言する(図10)。
 4)メニューが選択された時の処理を記述する(図11)。
 5)InvalidateRect関数に対する処理をcase WM_PAINTの内に記述する(図12)。
 6)MenuSelected関数を記述し(図13)、プロトタイプ宣言しておく(図14)。
 なお、InitInstanceで、ウィンドウはデフォルトのままとした。


図8 Win32Project1.rcの「メニュー」部分に「メインメニュー1」他を記述した



図9 Resource.hの最初の部分で、「IDM_SM1」などのID名を定義する



図10 Win32Project1.cppの頭の部分に、グローバル変数nMenuTypeを追加する



図11 選ばれたサブメニューの種類に応じて、nMenuTypeを設定して、WM_PAINTを呼び出す



図12 選ばれたサブメニューの種類を引数として与え、MenuSelected関数を呼び出す 



図13 選ばれたサブメニューの種類に応じて、異なった文字列を表示する



図14 作成したMenuSelected関数のプロトタイプ宣言を行う


得られた結果
 作成したプログラムを実行すると、図15の結果が得られた。ここで紹介したプログラムは、選択したサブメニューに応じて、異なる文字列を描画するという非常に簡単なものであるが、MenuSelected関数内の内容を変えることにより、複雑な処理も可能である。


図15 サブメニュー2を選択した結果を示す




「Visual C++の勉強部屋」(目次)