OnTimerについて


matsu  2006-05-20 07:24:12  No: 61896

OS:Windows XP Pro SP2
VS.NET2003

SDIアプリの起動時にダイアログをモードレスで表示し、ダイアログは起動時に
タイマーイベントを発生させます。
<CxxxApp.h>
#include "CxxxDlg.h"
UINT ThreadProc(LPVOID pParam);

class CxxxApp : public CWinApp
{
public:
        UINT nEndThread;

<CxxxApp.cpp>
コンストラクタで
        nEndThread = 0;

UINT ThreadProc(LPVOID pParam)
{
        CxxxDlg* pDlg = (CxxxDlg*)pParam;
        pDlg->Create(IDD_DIALOG1);
        while(1){
            if(theApp.nEndThread == 1){
                pDlg->DestroyWindow();
                break;
            }
        }
        return 0;
}

InitInstanceの先頭から
        CxxxDlg* pDlg = new CxxxDlg;
        AfxBeginThread(ThreadProc, pDlg);

        Sleep(5000);
        nEndThread = 1; // 終了合図
            ・
            ・
            ・
        m_pMainWnd->SetForegroundWindow();

<CxxxDlg.h>
public:
UINT m_nIDTimer;
long iCount;

<CxxxDlg.cpp>
コンストラクタで
        lCount = 0;
デストラクタで
        ::KillTimer(NULL, m_nIDTimer);
メッセージマップ
        ON_WM_TIMER()
OnInitDialogで
        this->ShowWindow(SW_SHOW);
        m_nIDTimer = SetTimer(1, 1000, NULL);
OnTimerで
        if(lCount % 2)
                GetDlgItem(IDC_STATIC1)->ShowWindow(SW_HIDE);
        else
                GetDlgItem(IDC_STATIC1)->ShowWindow(SW_SHOW);
        lCount += 1;

        CDialog::OnTimer(nIDEvent);

IDC_STATIC1のCaptionは「テスト」Visible true
「文字を点滅させる」です。
アプリ起動時にダイアログが表示され、ダイアログ消滅後メインフォームが
表示されますが、ダイアログが表示されている間、何も表示されません。
どのようにすれば、アプリ起動途中でダイアログを表示し、ダイアログの中の文字を
点滅させられるのでしょうか。

よろしくお願いします。


matsu  2006-05-20 08:26:15  No: 61897

matsuです。

UINT ThreadProc(LPVOID pParam)
{
    CxxxDlg* pDlg = (CxxxDlg*)pParam;
    pDlg->Create(IDD_DIALOG1);

//// ここから変更
        MSG msg;
        while(::GetMessage(&msg, 0, 0, 0))
        {
                ::DispatchMessage(&msg);
                if(theApp.nEndThread == 1)
                {
                        pDlg->DestroyWindow();
                        break;
                }
        }
    return 0;
}

で希望の動作が実現できました。ただ、スレッドはあまり詳しくないのですが、
これで良いのでしょうか?


スナナ  2006-05-22 22:59:45  No: 61898

原因は作成したワーカースレッドにメッセージループが無いためだと思うのですが、そもそも別スレッドにする理由はあるのでしょうか?
何をしたいかによりますが、どうしても別スレッドにするならユーザインターフェーススレッドの方がスマートかもしれませんね。
ちなみに排他処理が入っていません。同期オブジェクトで排他処理を行ってください。
また、メッセージループにはTranslateMessage()も入れておきましょう。


matsu  2006-05-24 08:10:38  No: 61899

スナナさん、いつもありがとうございます。

一応、完成型として以下を作成しました。
UINT ThreadProc(LPVOID pParam)
{
    CxxxDlg* pDlg = (CxxxDlg*)pParam;
    pDlg->Create(IDD_DIALOG1);

//// ここから変更
    MSG msg;
    BOOL bFlag;
    while(bFlag = ::GetMessage(&msg, NULL, 0, 0) != 0)
    {
        if(!bFlag)
           break;
        else {
           ::TranslateMessage(&msg);
           ::DispatchMessage(&msg);
           if(theApp.nEndThread == 1)
              break;
        }
    }
    pDlg->DestroyWindow();

    return 0;
}

「排他処理」は使ったことが無くてやり方が分からないのですが、
スレッドをたてる場合は、必ず、必要なのでしょうか?
別スレッド側は、ダイアログを表示して終了するだけですが。

よろしくお願いします。


スナナ  2006-05-25 00:23:13  No: 61900

排他処理は入れた方が安全です。
例えば
if(theApp.nEndThread == 1)
    break;
文のコンパイル結果が
mov eax, ....
cmp eax, 1
jne ...
のようにコンパイルされたとして、
movとcmpの間でスレッドが切り替わり、
他のスレッドでtheApp.nEndThreadの値が変更されたとしたら意図しない動きになってしまいます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






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