ということで前回に引き続き80LED.cppの中身の説明である。実行ファイルを含むソースファイル一覧は381回の記事の中にリンクを用意している。ちなみに一箇所重大なバグを発見、これを修正したバージョンと入れ替えたので(詳細は今回説明する)、すでに入手された方にはお手数だがダウンロードしなおしていただきたい。

前回はWM_TIMERまで説明したので、今度はWM_COMMANDである。メニュー操作を行った場合に発生するのがこのWM_COMMANDで、なのでここで諸々のパラメータ変更とか設定をつかさどる形になる。

WM_COMMANDの場合、WndProc()の第二引数のwParamの下16bitがID、上16bitがEventということになっている。このEventであるが、マウス操作によりメニュー項目が直接操作された場合は0、ショートカットキー(Windowsの用語ではアクセラレータ、となる。たとえばこの画面で、「File」→「Exit」は「Altキー」+[X]でも代用できる。この設定をアクセラレータと呼ぶ)の場合は1が入る事になっているが、プログラム的にはどちらで操作されても別に差をつける必要がないので、そういうわけで上位16bitは無視し、下位16bitだけで処理を定めている。

実際のプログラムの方は? というと、もうこれは見ていただければお分かりの通りである。こまかくtransferFlagという変数をチェックしているが、これはArduinoにデータを送っている時はTRUEが、通信をやめているとFALSEが設定されているFlagである。今通信を行っている最中にCOMポートとか通信速度を変更することは出来ない(というか、通信できなくなる)から、これを確実に行うためにまずTransferFlagがTRUEかどうか確認、FALSEの場合のみパラメータを変更し、かつSetTitleでタイトルバーの表示を書き換えている(逆にTRUEだった場合は何もしないで終了)。ただし更新期間を変更するIDM_Refresh_100~IDF_Refresh_1000に関しては、別に通信パラメータが書き換わるわけではないので有効である。この場合、まず既存のTimerをKillTimer()で一度破棄、ついで新しい更新間隔を設定してSetTimer()を呼び出すのだが、この再にTIMER_IDに同じものを指定するのがポイントである(でないと、WM_TIMERの処理の中でトラップされない)。Start/Stopの処理はそれぞれIDM_XFER_START/IDM_XFER_STOPの処理でハンドリングする。IDM_XFER_STARTの方は、すでに通信中(transferFlagがTRUE)でなければOpenRS232C()を呼び出して通信ポートの設定を行うわけだが、いきなりここでバグを発見してしまった。最初に配布したもののソースでは、

case IDM_XFER_START:
    if ( !transferFlag )
    {
        if(!OpenRS232C(&hCOM, portStr[portIndex], baudrate))
        {
            transferFlag = FALSE;
        }
    }
    break;

となっているが、ここは実際には

case IDM_XFER_START:
    if ( !transferFlag )
    {
        transferFlag = TRUE;
        if(!OpenRS232C(&hCOM, portStr[portIndex], baudrate))
        {
            transferFlag = FALSE;
        }
    }
    break;

としなければならない。要するにtransferFlagにTRUEを設定する箇所がどこにも無いので、このままだと一度転送をやめると二度と転送できなくなる(何でいままで気がつかなかったのだろう?)。ということでお詫びして訂正する。すでにリンク先の80LED.ZIPの中身はこれを修正した80LED.cpp及び、修正を反映した80LED.exeになっている。逆にIDM_XFER_STOPの方はポートをCloseしてtransferFlagをFALSEにするだけである。

最後が描画に関わる部分である。前回の最後でも触れたが、Windowにテキストを送っても、すぐに画面が書き変わる事は保障されていないので、書き換えを確実にするためには自分で再描画を掛ける必要がある。この目的でInvalidateRect()を呼び出したわけだが、このInvalidateRect()を呼び出すことで、WM_PAINT Messageが発生する。もっともやってることは簡単で、BeginPaint()~EndPaint()の中でDrawText()を呼び出すだけである。先に指定したunicodeBuf[]は、ここで利用されて描画される形だ。

さて、以上でプログラムの説明はおおむね終了である。About()はデフォルトそのままで一切変更していない。

(続く)