SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Windowsアプリケーションで「処理中」を表現する

時間のかかる処理で「処理中」を表現する(後編)

Windowsアプリケーションで処理中を表現する様々な方法

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード WaitSample_2.zip (137.4 KB)

モードレスダイアログを使って終了を待つ

 サンプルを動かしてみて分かるように、スレッドに切り出しても、待機してしまったのでは「(応答なし)」を解決できません。まずは、前編最後の手法と同じモードレスダイアログを利用した方法を使って待機します。前編とは異なり処理ループが無くなっているので、全体の構造が少し変わっています。

モードレスダイアログ待機版
#include <process.h>
void ThreadBusyLoopModeless( 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 );
    }
  }
  //  別スレッド化した時間のかかる処理
  {
    unsigned thrdaddr;
    HANDLE hThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0,
        BusyLoopThProcEx, &dwTime, 0, &thrdaddr ) );
    if( hThread != NULL ){
      bool  bLoop = true;
      do{
        DWORD dwResult = MsgWaitForMultipleObjects( 1, &hThread, FALSE, INFINITE, QS_ALLINPUT );
        switch( dwResult ){
          case WAIT_OBJECT_0:  //  スレッド終了を検出
            bLoop = false;
            break;
          case WAIT_OBJECT_0+1:  //  メッセージを処理(PeekMessage が FALSEになるまでメッセージを処理する必要がある)
            PumpMessage();
            break;
        }
      }while( bLoop );
      CloseHandle( hThread );
    }
  }
  //  ダイアログ破棄
  if( hwndDlg != NULL ){
    ShowWindow( hwndDlg, SW_HIDE );
    DestroyWindow( hwndDlg );
  }
  if( hwnd != NULL ){
    EnableWindow( hwnd, TRUE );
  }
}

 サンプルを動かしてみると分かりますが、前編とは異なり反応の悪さはなくなったと思います。改めて見てみるとメインスレッド側の処理は、特別なことをしてるわけではありません。単にモードレスダイアログをモーダルダイアログのように見せかけて、そこで終了を待つという形に落ち着いています。これであれば、何も自分で煩雑な処理を行わずとも、最初からモーダルダイアログにしてしまえばもっとすっきりしたコードになるのではないでしょうか。

モーダルダイアログを利用して待機する

 モーダルダイアログはモードレスダイアログとは異なり、オーナーウィンドウを自動的に無効にしてくれるという特典があります。モードレスダイアログでは自前のコードで同様のことを行いましたが、OSによっては、処理終了時にアクティブにならないなどいくつかの不具合に見える現象があります。モーダルダイアログを利用している場合はこのようなことは発生しませんので、モーダルダイアログに切り替えることができれば、余計な作業を減らせます。

 また、モーダルダイアログはモードレスダイアログとは異なり逐次処理ができません。そのため、WM_INITDIALOGメッセージで、スレッドを作成するように切り替えます。モーダルダイアログは呼び出し元から情報を与えることができないと思っている人が多いようですが、DialogBoxParam APIというWM_INITDIALOGのLPARAMに情報を渡せるAPIがあるため、、これを利用してスレッド情報も渡します。サンプルでは、スレッド関数までは外に切り出していませんが、より汎用的なものにするのであれば、スレッド関数も外部から渡すようにすることで、汎用的な待機ダイアログにすることも可能です。この辺りは、実務の状況に合わせて適切に作り変えてもらえればと思います。

モーダルダイアログ待機版
class CThreadParamDlg
{
public:
  CThreadParamDlg( DWORD dwTime )
    :  m_hwndDlg( NULL )
    ,  m_workTime( dwTime )
  {
  }
public:
  HWND  m_hwndDlg;
  DWORD  m_workTime;
};
void _cdecl BusyLoopThProcDlg( void* param )
{
  CThreadParamDlg* pParam = static_cast( param );

  DWORD dwStart = GetTickCount();
  while( (GetTickCount()-dwStart) < pParam->m_workTime );

  PostMessage( pParam->m_hwndDlg, WM_COMMAND, MAKEWPARAM( IDOK, 0 ), 0 );  //  処理終了はOKメニュー風に通知
}
INT_PTR CALLBACK DlgProc_Modal(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch( message ){
    case WM_INITDIALOG:
      {
        CSimpleWaitCursor  wait;
        CThreadParamDlg*  pParam = reinterpret_cast( lParam );
        pParam->m_hwndDlg = hDlg;
        if( _beginthread( BusyLoopThProcDlg, 0, pParam ) == -1 ){
          EndDialog( hDlg, IDABORT );
        }
      }
      return TRUE;
    case WM_COMMAND:
      if( LOWORD(wParam) == IDOK ){
        EndDialog( hDlg, LOWORD(wParam) );
        return TRUE;
      }
      break;
  }
  return FALSE;
}
void ThreadBusyLoopModal( HWND hwnd, DWORD dwTime )
{
  CThreadParamDlg  param( dwTime );
  DialogBoxParam( hInst, MAKEINTRESOURCE(IDD_WAIT), hwnd, DlgProc_Modal, reinterpret_cast<LPARAM>( &param ) );
}

 動作そのものは、モードレスダイアログ版と変わりありませんが、モーダルダイアログにすることで、全体的にすっきりしたと思います。

次のページ
並列ライブラリを利用する

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Windowsアプリケーションで「処理中」を表現する連載記事一覧
この記事の著者

とっちゃん(トッチャン)

Microsoft MVP for Development Tools Visual C++Windows Installer 系を中心にオンライン/オフラインで活動しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/5352 2010/08/05 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング