スレッドで DialogBox を表示する

起動されたスレッドから DialogBox を表示します。
DialogBox のキャンセルボタンでメインプログラムを終了します。

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

プロジェクトの説明

  1. 新規プロジェクト(Th_Dialog)を作成して下さい。
    キャンセルボタン(IDCANCEL) を配置した DialogBox を作成して下さい。
  2. ID_TIMER はタイマーのIDです。
    DATA はスレッドに渡すパラメータの構造体の宣言です。
    DATA Data; でグローバル領域に構造体を確保しています。
    今回は使いませんが、スレッドから起動した DialogBox のハンドルを hDlg に取得しています。
    hDlg はメインプログラムからスレッドを停止するときなどに必要になります。
    DlgProc() はスレッドから起動される DialogBox の CALLBACK 関数です。
    DWORD Thread(LPVOID); はスレッドで起動する関数の宣言です。
        #include    "resource.h"
        #define     ID_TIMER    (WM_APP + 0)
    
        typedef struct
        {   HWND        hWnd;
            HINSTANCE   hInst;
            HWND        hDlg;
            LRESULT     (CALLBACK *DlgProc)(HWND,UINT,WPARAM,LPARAM);
            BOOL        end;
        }   DATA,       *PDATA;
    
        DATA        Data;
        HANDLE      hThread;
    
        LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
        LRESULT CALLBACK    DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
        DWORD   WINAPI      Thread(LPVOID);
        
  3. WinMain() ではサイズを設定してウインドウを表示するだけです。
  4. CALLBACK 関数です。
    スレッドのIDと時刻を表示するための領域を定義します。
    スレッドで使う領域は CALLBACK 関数も含めて Data 構造体で渡します。
    CreateThread(); でスレッドを生成します。
        LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {   PAINTSTRUCT ps;
            HDC         hdc;
            DWORD       threadID;
            SYSTEMTIME  STime;
            char        buf[256];
    
            switch(msg)
            {
                case WM_CREATE:
                    Data.hWnd = hWnd;
                    Data.end = FALSE;
                    Data.DlgProc= DlgProc;
                    hThread = CreateThread(NULL, 0,
                        (LPTHREAD_START_ROUTINE)Thread,(LPVOID)&Data,
                        0, (LPDWORD)&threadID);
                    SetTimer(hWnd,ID_TIMER,300,NULL);
                    break;
        
  5. WM_TIMER: ではスレッドが終了するとタイマを停止してプログラムを終了します。
    起動中は InvalidateRect() でウインドウに時刻を表示します。
            case WM_TIMER:
                if (Data.end)
                {   KillTimer(hWnd,ID_TIMER);
                    PostMessage(hWnd,WM_CLOSE,0,0);
                    return 0L;
                }
                InvalidateRect(hWnd,NULL,TRUE);
                break;
        
  6. WM_PAINT: でウインドウに時刻を表示します。
            case WM_PAINT:
                hdc = BeginPaint(hWnd,&ps);
                GetLocalTime(&STime);
                wsprintf(buf,"時刻は %2d時%2d分%2d 秒",STime.wHour,STime.wMinute,STime.wSecond);
                TextOut(hdc,50,20,buf,strlen(buf));
                EndPaint(hWnd,&ps);
                break;
        
  7. WM_CLOSE: でプログラムを終了します。
    マルチスレッドでは、スレッドの終了を確認してからメインプログラムを終わらせて下さい。
    終了手順を確認するためにメッセージボックスを表示しています。
    CloseHandle(hThread) でスレッドを閉じます。
            case WM_CLOSE:
                if(CloseHandle(hThread) != 0)
                    MessageBox(NULL, "ハンドルクローズ成功", "成功!", MB_OK);
                DestroyWindow(hWnd);
                break;
            case WM_DESTROY:
                PostQuitMessage(0);
                return 0L;
        
  8. Thread で動作する関数です。
    パラメータで渡された構造体のポインタを設定します。
    スレッドは独立した一個のプログラムとして起動します。
    従ってメインで定義された必要なデータは PDATA で受け取らなければなりません。
    DialogBox の CALLBACK 関数のアドレスも PDATA で渡されます。
    DialogBoxParam() で起動して、DialogBox から制御が戻るとスレッドを終了します。
        DWORD  WINAPI  Thread(LPVOID param)
        {   PDATA       pData;
    
            pData = (PDATA)param;
            DialogBoxParam(pData->hInst,MAKEINTRESOURCE(IDD_DIALOG1),pData->hWnd,
                           (DLGPROC)pData->DlgProc,(LPARAM)pData);
            pData->end= TRUE;
            ExitThread(0);
            return 0L;
        }
        
  9. DialogBox の CALLBACK 関数です。
    今回は使いませんが WM_INITDIALOG: で DialogBox のハンドルを格納します。
    IDCANCEL で DialogBox を終了します。
        LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
        {   PDATA       pData;
            switch(msg)
            {   case WM_INITDIALOG:
                    pData= (PDATA)lp;
                    pData->hDlg= hDlg;
                    break;
                case WM_COMMAND:
                    if (LOWORD(wp)==IDCANCEL)
                    {   PostMessage(hDlg,WM_CLOSE,0,0);
                        return TRUE;
                    }
                    break;
                case WM_CLOSE:
                    EndDialog(hDlg,0);
                    return TRUE;
            }
            return FALSE;
        }
        

【演習】

  1. プログラムを完成させて下さい。

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