処理の中断

VC++ でモードレスダイログから実行中の処理を中断します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 新規プロジェクトを作成して、メニューを設定して下さい。
    キャプションID
    ファイル(&F) 親メニュー
    タイマの開始(&S) IDM_START
    アプリケーションの終了(&X)IDM_EXIT
  2. ページ先頭の画像を参考にして Dialog Box を作成して下さい。
    BOXIDキャプション
    DialogBoxIDD_DIALOG1 中断
    Button IDCANCEL キャンセル
  3. ID_TIMER はタイマのIDです。
    hCancelDlg; は処理の中断を指示する DialogBox のハンドルです。
    bCancel は処理の中断を通知するフラグです。
        #define     ID_TIMER    32767
        HWND        hCancelDlg;
        BOOL        bCancel = TRUE;
        
  4. CALLBACK 関数の WM_PAINT: です。
    bCancel が TRUE のときは、タイマを止めて親ウインドウにフォーカスを設定します。
    GetLocalTime() で時刻を取得して TextOut() で表示します。
        {   PAINTSTRUCT ps;
            HDC         hdc;
            SYSTEMTIME  STime;
            char        buf[256];
    
            switch(msg)
            {   case WM_PAINT:
                    hdc = BeginPaint(hWnd,&ps);
                    if (bCancel)
                    {   KillTimer(hWnd,ID_TIMER);
                        EnableWindow(g_hWnd,TRUE);
                        SetFocus(g_hWnd);
                    }
                    GetLocalTime(&STime);
                    wsprintf(buf,"時刻は %2d時%2d分%2d 秒",STime.wHour,STime.wMinute,STime.wSecond);
                    TextOut(hdc,100,50,buf,strlen(buf));
                    EndPaint(hWnd,&ps);
                    break;
        
  5. メニューから IDM_START: が呼ばれたときの処理です。
    CreateDialog() で DialogBox を生成します。
    bCancel を FALSE(タイマで現在時刻を表示中)に設定します。
    ShowWindow() で中断 DialogBox を表示します。
    EnableWindow() で親ウィンドウから入力できないようにします。
    SetTimer() でタイマを設定して、現在時刻の表示を開始します。
            case IDM_START:
                hCancelDlg = CreateDialog(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),
                             g_hWnd,(DLGPROC)CancelProc);
                bCancel= FALSE;
                ShowWindow(hCancelDlg,SW_SHOW);
                EnableWindow(g_hWnd,FALSE);
                SetTimer(hWnd,ID_TIMER,300,NULL);
                break;
        
  6. WM_TIMER: では InvalidateRect() で WM_PAINT: で画面を再描画します。
            case WM_TIMER:
                InvalidateRect(hWnd,NULL,TRUE);
                break;
        
  7. WM_DESTROY: では bCancel==FALSE のときはタイマを止めて DialogBox を破棄します。
            case WM_DESTROY:
                if (bCancel==FALSE)
                {   KillTimer(hWnd,ID_TIMER);
                    bCancel= TRUE;
                    DestroyWindow(hCancelDlg);
                }
                PostQuitMessage(0);
                return 0L;
        
  8. 処理を中断するダイアログのプロシージャです。
    IDCANCEL がクリックされると bCancel に TRUE をセットして DialogBox を破棄します。
        LRESULT CancelProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {
            switch(msg)
            {   case WM_INITDIALOG:
                    SetFocus(hWnd);
                    return TRUE;
                case WM_COMMAND:
                    if (LOWORD(wp) == IDCANCEL)
                    {   bCancel = TRUE;
                        DestroyWindow(hCancelDlg);
                        return TRUE;
                    }
                    break;
                default:
                    break;
            }
            return FALSE;
        }
        
  9. プログラムを起動すると現在時刻が表示されます。
    メニューから「タイマの開始」を選ぶと、中断 DialogBox が表示されて時刻が刻まれます。
    DialogBox のキャンセルボタンをクリックすると時刻が停止します。

【演習】

  1. プログラムを完成させて下さい。
  2. 制御がプロセスに長時間占有されるようなプログラムでは反応が遅れます。
    次のプログラムを作成して DialogBox の表示や中断の反応が遅れることを確認して下さい。
            case WM_CREATE:
                hCancelDlg = CreateDialog(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),
                             g_hWnd,(DLGPROC)CancelProc);
                bCancel= FALSE;
                ShowWindow(hCancelDlg,SW_SHOW);
                EnableWindow(g_hWnd,FALSE);
                break;
            case WM_PAINT:
                hdc = BeginPaint(hWnd,&ps);
                wsprintf(buf,"COUNT= %d",count);
                TextOut(hdc,100,50,buf,strlen(buf));
                PostMessage(g_hWnd,WM_COMMAND,(WPARAM)IDM_COUNT,(LPARAM)0);
                EndPaint(hWnd,&ps);
                break;
            case WM_COMMAND:
                switch(LOWORD(wp)) 
                {   case IDM_COUNT:
                        {   int  i;
                            EnableWindow(g_hWnd,FALSE);
                            for(i=0; i<100; i++)
                            {   Sleep(50);
                                if (count>5 || bCancel) PostQuitMessage(0);
                            }
                            count++;
                            EnableWindow(g_hWnd,TRUE);
                            InvalidateRect(hWnd,NULL,TRUE);
                            return 0;
                        }
                }
                break;
        

超初心者のプログラム入門(Win32API C++)