さて、今回からはもう少しまともにプログラムを作ることにしたい。といってもこちらは凝り始めるときりが無いし、別にWin32環境でのプログラムの作り方を説明するのが主眼ではないので、ほどほどのところまで作りこんだものをご紹介する程度に留めておきたいと思う。
具体的には、こんな感じで立ち上がるものとした(Photo01)。操作はメニューのみにまとめており、File(Photo02)/ Transfer(Photo03)/ Settings(Photo04~07)/ Help(Photo08,09)を実装している。
さて、これの作り方であるが、まずはVisual Studio.NET 2010 Expressを立ち上げて新規プロジェクトを生成する(Photo10)。ここで、これまでとは異なり"Win32 プロジェクト"を選択する。するとウィザードが立ち上がるわけだが(Photo11)、最初は「次へ」を選択してみよう。ここで多少オプションが選べるようになっている(Photo12)。
Photo11: ウィザード。慣れると次の画面は要らないので、ここで「完了」を選べば楽、という事だろう。 |
Photo12: 追加指定。普通はあまり無いが、DLLを作る必要があるなんて場合にはここで指定することになる。 |
ウィザードが完了すると、自動的にスケルトンのコードが生成され(Photo13)、これをビルドして(Photo14)実行すると、とりあえず立ち上がる(Photo15)。この時点で「ファイル」と「ヘルプ」は出来ており、終了とダイアログ表示までは自動的に完成している。あとはこれに肉付けをしてゆくわけだ。
さて、肉付けの第一歩は(このあたりは人によっていろいろあるだろうが筆者の場合は)まずメニューの作成である。まずメニューの項目名を決め、ついでその項目名(オブジェクト名)に対するcallbackを記述してゆく、という方法が合理的であると思う。というわけで、今は「ファイル」と「ヘルプ」しかないメニューをPhoto01~09の様な構造に変えてゆくことにする。
実はここでVisual Studio.NET 2010 Expressの制限がモロに出てくる。Visual Studio.NT 2010 Professionalの場合、リソースエディタと呼ばれるツールがあり、これを使うことで画面から対話式にメニューを簡単に作ることが出来る(Photo16)。このリソースエディタで生成されたコードは.RCという拡張子を持つリソースファイルに収められ、これをVisual Studio.NET 2010が読み込んで実際のWindowsのプログラムに反映する形だ。
Photo16: たとえばメニューの場合、IDC_MY80LEDというMenu Objectが生成されるので、ここにSubmenuをどんどん対話式に追加してゆき、後で各項目のプロパティを必要なものに変更する、という形。 |
ところがVisual Studio.NET 2010 Expressにはリソースエディタが付属していない。このため利用者は、手でリソースファイルを書き換える必要がある。といっても、実はそれほど難しくない。List 1に書き換え前(つまり最初のスケルトンの状態)、List 2に書き換え後(つまりリソースエディタで書き換え後)のメニューの定義である。実はこの部分以外一切いじっておらず、逆に言えば生成された80LED.RCのうち、List 1の様になっている部分をエディタなどでList 2の様に書き換えれば、それでメニューが生成されるという仕組みだ。
ついでにここで簡単に説明しておこう。Win32のアプリケーションは、基本的には初期設定が終わった後は、GetMessage()という関数をひたすら呼びながら無限ループを繰り返しているだけである。ただ何か操作があると、たとえばメニューで転送速度として19200bpsが選択されると、IDM_SPEED_19200というメッセージ番号(この番号は先ほどリソースエディタで定義したもの)を持って割り込み(Windows用語ではMessage)がやってきて、制御がWinProc()というcallback関数(Messageの処理を専門に行う関数)に渡される。なので、後はWinProc()の中に「IDM_SPEED_19200がやってきたら、転送速度を19200bpsに設定する」という処理を追加すれば済むことになる。
ただこの方式だと、「んじゃ一定間隔ごとにCPUの負荷をどうやって取得するの?」という疑問があろう。前回の例ではSleep()を使って一定期間待機していたが、Win32のアプリケーションではこれは許されない。そこで、一定期間ごとにMessageを発するTimerを仕掛け、このTimerのMessage到着のタイミングでCPU負荷を取得、それを画面表示すると共にArduinoにパケットを送るという処理をする形となる。次回もう少し、実際のコードをみてみたい。
(続く)
List 1:
/////////////////////////////////////////////////////////////////////////////
//
// メニュー
//
IDC_MY80LED MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "アプリケーションの終了(&X)", IDM_EXIT
END
POPUP "ヘルプ(&H)"
BEGIN
MENUITEM "バージョン情報(&A)...", IDM_ABOUT
END
END
List 2:
IDC_MY80LED MENU
BEGIN
POPUP "File(&F)"
BEGIN
MENUITEM "Exit(&X)", IDM_EXIT
END
POPUP "Transfer"
BEGIN
MENUITEM "Start", IDM_XFER_START
MENUITEM "Stop", IDM_XFER_STOP
END
POPUP "Settings..."
BEGIN
POPUP "Port"
BEGIN
MENUITEM "COM1:", IDM_PORT_COM1
MENUITEM "COM2:", IDM_PORT_COM2
MENUITEM "COM3:", IDM_PORT_COM3
MENUITEM "COM4:", IDM_PORT_COM4
MENUITEM "COM5:", IDM_PORT_COM5
MENUITEM "COM6:", IDM_PORT_COM6
MENUITEM "COM7:", IDM_PORT_COM7
MENUITEM "COM8:", IDM_PORT_COM8
END
POPUP "Speed"
BEGIN
MENUITEM "300bps", IDM_SPEED_300
MENUITEM "600bps", IDM_SPEED_600
MENUITEM "1200bps", IDM_SPEED_1200
MENUITEM "2400bps", IDM_SPEED_2400
MENUITEM "4800bps", IDM_SPEED_4800
MENUITEM "9600bps", IDM_SPEED_9600
MENUITEM "19200bps", IDM_SPEED_19200
MENUITEM "38400bps", IDM_SPEED_38400
END
POPUP "Refresh"
BEGIN
MENUITEM "0.1sec", IDM_Refresh_100
MENUITEM "0.2sec", IDM_Refresh_200
MENUITEM "0.5sec", IDM_Refresh_500
MENUITEM "1sec", IDM_Refresh_1000
END
END
POPUP "Help(&H)"
BEGIN
MENUITEM "About(&A)...", IDM_ABOUT
END
END