作業中というメッセージを表示する
ここまでは、処理中の表現をマウスカーソルだけに頼ってきました。時間が2~3秒程度の処理であればこれでも十分ですが、それを超えるような時間のかかる処理となるとそうもいきません。そこで時間がかかる処理を行っていることをより具体的に意思表示するためにダイアログを表示することにします。
ダイアログを表示する
BusyLoop3を改めて確認してみると、ウィンドウを無効化してる状態をダイアログが表示される期間とすることができれば問題はなさそうに思えます。まずはその前提でダイアログを用意することにしましょう。
まずはダイアログテンプレートです。
IDD_WAIT DIALOGEX 0, 0, 268, 25 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION CAPTION "しばらくお待ちください..." FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CTEXT "作業中です。しばらくお待ちください...",IDC_STATIC, 4,4,260,16,SS_CENTERIMAGE END
イメージは次のようになります。
続いて、今回のモードレスダイアログ用に用意したダイアログプロシージャです。
INT_PTR CALLBACK DlgProc_Simple(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { return FALSE; }
上記がそろえば、ダイアログを作ることができます。BusyLoopV3を改造し、モードレスダイアログを表示するようにしたものが下記のものとなります。
void BusyLoopModeless( HWND hwnd, DWORD dwTime ) { HWND hwndDlg = NULL; if( hwnd != NULL ){ EnableWindow( hwnd, FALSE ); hwndDlg = CreateDialog( hInst, MAKEINTRESOURCE(IDD_WAIT), hwnd, DlgProc_Simple); if( hwndDlg != NULL ){ ShowWindow( hwndDlg, SW_SHOWNORMAL ); UpdateWindow( hwndDlg ); } } while( dwTime > 0 ){ PumpMessage(); // メッセージを処理してから待機カーソルにする DWORD dwWait = ( dwTime > 1000 ) ? 1000 : dwTime ; CSimpleWaitCursor waitCursor; DWORD dwStart = GetTickCount(); while( (GetTickCount()-dwStart) < dwWait ); dwTime -= dwWait; } if( hwndDlg != NULL ){ DestroyWindow( hwndDlg ); } if( hwnd != NULL ){ EnableWindow( hwnd, TRUE ); } }
モードレスダイアログなので、オーナーウィンドウを無効化する必要がある点は変わりありません。ウィンドウの無効化・有効化と、ダイアログの作成・破棄のタイミングをいろいろいじってみると動作が変わります。この記事では本題から外れるため、特に触れるようなことはしませんが、モードレスダイアログの場合、ダイアログ破棄のタイミングでいろいろと処理をする必要が出る場合もあるため、意図しないところで処理が煩雑になるという問題があります。その場合は順番を変えてみるなど、いろいろ試してみてください。
実際に動かしてみましょう。タスクマネージャを起動して、パフォーマンスタブに切り替え、グラフの画面が見える状態にしたまま、マウスでキャプション上で左ボタンをダウンしてドラッグ状態にしてください。しばらく(最大1秒程度)待っていると、マウスカーソルが通常の矢印カーソルに戻ると同時に、CPUの利用量が変わったのではないでしょうか。
CPUパワーを利用する
ここまでの部分は、16bit時代と変わらないいわば古い技法です。行儀が悪いというほどではないため今でも十分利用可能ですが、ユーザー操作に迅速に反応するためにはどうしてもメッセージ処理を随所に挟む必要があるので、処理効率があがりませんし、本来のロジックの合間に別の処理を挟む形になるため、メンテナンス性の低いプログラムソースになってしまいがちです。
また、動作を見て分かるように、本来の処理に集中させたい作業時間をメッセージ処理にとられてしまうため(ドラッグ処理など)、CPUパワーが余っているかどうかにかかわりなく、処理を行うことができないという状況が発生することがあります。せっかく全力で作業していた部分を応答なしに見えてしまうからという理由だけで全力を出さないのは、もったいない話です。
Win32では、CPUパワーを余すことなく使うために、マルチスレッドという1つのプログラム内で、複数同時に実行する仕組みが用意されています。後編では、このマルチスレッド技術を利用して、メッセージ処理と本来の作業を別々に進行させる方法と、VS2010で導入された同時実行ライブラリを利用した方法を紹介したいと思います。