MFCのスレッド実行中のコマンド処理

[戻る]
猫柳 [E-Mail] 2007/01/26(金) 14:47:40
今勉強中の初心者の者です。
Visual Studio2005(MFC)でダイアログベースのスレッドを使ったfile copyのプログラム
を作成しています。
サイズの大きなファイルをcopyしながらプログラスバーを更新していきます。
スレッドを起動してcopyのプログラムを実行します。そしてコピー状況をプログレスバ
ーに表示するプログラムです。

基本的なプログラムの動作は問題なく、コピー状況にあわせてプログレスバーが更新さ
れますが、
メッセージが処理できないようです。途中でwindowを移動したり、最小化することがで
きません。なぜでしょうか?

void CnewoneDlg:: copyfile()
{
//省略
    while(k > 0){256バイトづつコピーループ
        ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
        WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
    //    k、counter 変数の更新計算
    }
    //hf1, hf2クローズ、スレッド終了処理。
}
UINT CnewoneDlg::CopyThread( LPVOID pParam )
{ //threadからcopyプログラムを呼び出し
//    copyfile()の呼び出し
}

void CnewoneDlg::OnBnClickedButton1()
{//ボタンコマンド

    // スレッド開始
    m_pCopythread = AfxBeginThread( CopyThread, this );// 
    LPMSG Msg = NULL;
    
    while(mProgress.SetPos(counter) <100){ //100% コピーするまで
        if(PeekMessage(Msg,NULL,0,0,PM_REMOVE) != 0)
            DispatchMessage(Msg);
    }// 
}

ぬふや 2007/01/26(金) 16:32:00
    while(mProgress.SetPos(counter) <100){ //100% コピーするまで
        if(PeekMessage(Msg,NULL,0,0,PM_REMOVE) != 0)
            DispatchMessage(Msg);
    }// 
ここが問題で、消して良い。
ここでわざわざメッセージループする必要は無いし、ループの仕方も間違ってい
る。
メッセージループはMFCが用意しているし、アクセラレータ用の処理もあるから特
に必要が無ければ自分では書かないほうが良い。
そして、PeekMessageをSleepその他無しで回したら、CPU負荷が100%になって
ファイルコピースレッドにも悪影響が出る。

ついでに、「LPMSG Msg = NULL;」は駄目。
PeekMessageは構造体を確保してくれるAPIではないし、もしそうなら引数は
LPMSGへのポインタになる。
PeekMessageは構造体は自分で用意する必要があります。

そして、「while(mProgress.SetPos(counter) <100)」はスレッドを分けた意味
を完全に無くしています。

正しく動作させたいなら、
void CnewoneDlg:: copyfile(){//省略
    while(k > 0){
        ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
        WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
    //    k、counter 変数の更新計算

    }//hf1, hf2クローズ、スレッド終了処理。
}
void CnewoneDlg::OnBnClickedButton1(){
    m_pCopythread = AfxBeginThread( CopyThread, this );
}

ぬふや 2007/01/26(金) 16:32:01
    while(mProgress.SetPos(counter) <100){ //100% コピーするまで
        if(PeekMessage(Msg,NULL,0,0,PM_REMOVE) != 0)
            DispatchMessage(Msg);
    }// 
ここが問題で、消して良い。
ここでわざわざメッセージループする必要は無いし、ループの仕方も間違ってい
る。
メッセージループはMFCが用意しているし、アクセラレータ用の処理もあるから特
に必要が無ければ自分では書かないほうが良い。
そして、PeekMessageをSleepその他無しで回したら、CPU負荷が100%になって
ファイルコピースレッドにも悪影響が出る。

ついでに、「LPMSG Msg = NULL;」は駄目。
PeekMessageは構造体を確保してくれるAPIではないし、もしそうなら引数は
LPMSGへのポインタになる。
PeekMessageは構造体は自分で用意する必要があります。

そして、「while(mProgress.SetPos(counter) <100)」はスレッドを分けた意味
を完全に無くしています。

正しく動作させたいなら、
void CnewoneDlg:: copyfile(){//省略
    while(k > 0){
        ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
        WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
    //    k、counter 変数の更新計算

    }//hf1, hf2クローズ、スレッド終了処理。
}
void CnewoneDlg::OnBnClickedButton1(){
    m_pCopythread = AfxBeginThread( CopyThread, this );
}

ぬふや 2007/01/26(金) 16:39:17
投稿失敗。

正しく動作させたいなら、
void CnewoneDlg:: copyfile(){//省略
    while(k > 0){
        ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
        WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
    //    k、counter 変数の更新計算
    mProgress.SetPos(counter);
    }//hf1, hf2クローズ
    //スレッド終了処理。
}
void CnewoneDlg::OnBnClickedButton1(){
    m_pCopythread = AfxBeginThread( CopyThread, this );
    //ボタン連打を回避する場合はm_pCopythreadが有効か調べた上でスレッ
ドを開始して、ボタンを無効にする。

}

ぬふや 2007/01/26(金) 16:39:16
投稿失敗。

正しく動作させたいなら、
void CnewoneDlg:: copyfile(){//省略
    while(k > 0){
        ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
        WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
    //    k、counter 変数の更新計算
    mProgress.SetPos(counter);
    }//hf1, hf2クローズ
    //スレッド終了処理。
}
void CnewoneDlg::OnBnClickedButton1(){
    m_pCopythread = AfxBeginThread( CopyThread, this );
    //ボタン連打を回避する場合はm_pCopythreadが有効か調べた上でスレッ
ドを開始して、ボタンを無効にする。

}

猫柳 [E-Mail] 2007/01/26(金) 17:02:02
[[解決]]
いろいろありがとうございます。
うまくいきました。
まだまだスレッドの使い方が慣れていないようですね。

・・・・・
        if(PeekMessage(Msg,NULL,0,0,PM_REMOVE) != 0)
            DispatchMessage(Msg);
この部分は最初はなくて、うまくいかなくて付け加えていましたが、
更に深みにはまっていたわけですね。
・・・・

スレッドに対する本がAPIに関する本しかなかったので、直してる間にいつの間にかこう
なってしまったようです。

古いスレッドには追加発言できません。