dポイントプレゼントキャンペーン実施中!

現在MFCを用いてWebカメラからのキャプチャを行うソフトを作成しています。
環境はVisual Studio 2005です。

ソフトウェアはダイアログ形式で、”Capture"と"停止"のボタン、そして1つPictureControlを配置し、"Capture"ボタンが押されたらWebカメラからの映像をPictureControlに表示し、"停止"ボタンが押されたらキャプチャを終了するというものです。

少し長くなってしまうのですがよろしくお願いします。

開発当初、ダイアログクラスのメンバ変数にbool型の Cap_Flag を追加し、コンストラクタにより初期値を false に設定するようプログラムを組みました。 そして "Capture"ボタンが押され、そのイベントハンドラが呼び出された時に、 Cap_Flag を true に設定しキャプチャを行う関数を実行するようにしました。
キャプチャを行う関数の中では、 Cap_Flag をチェックし true に設定されている間キャプチャを行うよう while( Cap_Flag == true ) としてキャプチャを行います。 その後 "停止"ボタン が押されれば、そのボタンに対するイベントハンドラ内で Cap_Flag に false を設定し、キャプチャを終了しようと考えました。

この設計では確かに "Capture"ボタンが押されればキャプチャが行われ、PictureControlに映像が表示されるのですが、これらのキャプチャ処理は "Capture"ボタン のイベントハンドラ内で実行しているため、キャプチャを行っている間、つまり while( Cap_Flag == true ) となっている間は永遠に実行状態になっているため "Capture"ボタン が押されっぱなしの状態になり、"停止"ボタンを押すことが出来なくなってしまいます。また無理に "停止"ボタン を押そうとすると固まってしまうため、うまく"Capture"と"停止"を行うことが出来ない状況です。

改善策として、オリジナルのメッセージを作成しメッセージマップでそのオリジナルの命令に対してキャプチャを行う関数が呼び出されるよう設定しました。よって、 "Capture"ボタンが押されたときに呼び出されるイベントハンドラ内で Cap_Flag を true に設定し、オリジナルのメッセージを送信して、そのメッセージに対応するキャプチャを行う関数を呼び出すようプログラムを組みなおしました。
このように組みなおした理由は、"Capture"ボタンが押されたときに呼び出されるイベントハンドラ内の処理は、Cap_Flag を true に設定することと、オリジナルのメッセージを送信することのみで、イベントハンドラ内ではキャプチャを行う関数は実行されず、 実際に "Capture"ボタン が押されたとしても、押された状態ではなくすぐに基の状態(表示)にもどるだろうと考えたためです。

ですが、このように変更しても "Capture"ボタンのイベントハンドラ内でキャプチャ処理を行っていることと同様に "Capture"ボタンが押されっぱなしの状態になり、"停止"ボタンを押すことが出来ません。

どのようにプログラムを組めば、実際にキャプチャを行っている間でも、"Capture"ボタンが押された状態にならず "停止"ボタン を押すことができるようになるでしょうか?

参考になるアドバイス、またはウェブページをご紹介いただけれたらと思います。
よろしくお願い致します。

A 回答 (3件)

afx_msg void myThreadExit( WPARAM wParam, LPARAM lParam )



LRESULT myThreadExit( WPARAM wParam, LPARAM lParam )
でした ・・・
関数を抜ける時には
return S_OK;
など リザルトコードを返してください
    • good
    • 0
この回答へのお礼

返信が遅れてしまい申し訳ありませんでした。

とても分かりやすいアドバイスをありがとうございます。
無事実装が完了し、正常に動作させることができました。

本当にいろいろとありがとうございました。

お礼日時:2008/10/09 09:24

スレッドプロシージャは 外部関数にしたほうがいいでしょう


クラスのメンバーでやるなら static関数にしないとまずいです … お勧めはしませんが

AfxBeginThread( Csample3::ImageCapture, this );
として呼び出し
ヘッダーでの宣言は
static UINT ImageCapture( LPVOID );
といった具合になります

キャプチャー関数へ渡すのは thisポインターよりも
必要なデータの構造体のほうがいいでしょう
画面のキャプチャーサイズ
描画用のコントロールのハンドル
親ウィンドウのハンドル : Csample3Dlgのハンドル(m_hWnd)
スレッドを抜けるためのフラグ
スレッドが終了したことを知らせるメッセージ : RegisterWindowMessageなどで取得する

単純な外部関数として
UINT ImageCapture( LPVOID lpparam )
{
  LPMYSTRUCT pmySTruct = (LPMYSTRUCT)lpParam;
  while( !pmyStruct->bDone ) {
    // キャプチャー処理
  }
  PostMessage( pmyStruct->hParent, pmyStruct->uMsgExit, 0, 0 );
  return 0;
}
といた具合のほうがいいように思います

DLG側でスレッドの終了を感知する関数を追加
afx_msg void myThreadExit( WPARAM wParam, LPARAM lParam )
{
  //必要な後処理
  // CWinThread変数の開放など
}

メッセージマップに
ON_REGISTERED_MESSAGE( m_myREGMSG, myThreadExit )
を追加

メンバー変数として
static UINT m_myREGMSG;
を追加

CPPファイルに
UINT CsampleDlg::m_myREGMSG = RegisterWindowMessage( _T("MyThread_Exit") );
といった具合でしょう
    • good
    • 0

普通はキャプチャーを別スレッドに仕立てて使うようにすると思いますよ



メインスレッドの中でボタンのクリックイベントから抜けないなら
CWinThreadクラスのPumpMessageメソッドを適当な頻度で呼びましょう

ループ処理のをしていると思いますので適当なカウンタを設けて
このカウンタが20回とかカウントしたら呼び出すとかして見ましょう
  if ( nCnt % 20 == 0 ) {
    AfxGetApp()->PumpMessage();
    nCnt = 0;
  }
  nCnt++;
といった具合です
    • good
    • 0
この回答へのお礼

返信ありがとうございました。
おっしゃられた通り、

AfxGetApp()->PumpMessage();

をループ文の中で実行した所、クリックイベントから抜け出し正常に終了することができました。ありがとうございます。

ですが、”普通はキャプチャーを別スレッドに仕立てて使うようにすると思いますよ” この一文も気になったので、スレッドを立ててキャプチャを行うようプログラムを組み替えました。

ですが、以下のような問題が生じてしまいました。
プロジェクト名は "Sample3" となっているため、それぞれのヘッダファイルやソースファイルはこのプロジェクト名が記載されています。
そして

CWinThread* m_pThread = AfxBeginThread(&Csample3Dlg::ImgCapture, (LPVOID)this);

としてスレッドを立てました。ちなみにキャプチャスレッドはCsample3Dlgクラス内で、

UINT ImgCapture(LPVOID pParam);

というように定義されています。
この手順で一応はスレッドが立ち上がると考えたのですが、コンパイルすると以下のようなエラーが出てしまいます。

エラー2error C2665: 'AfxBeginThread' : 2 オーバーロードのどれも、すべての引数の型を変換できませんでした

このエラーに対処すべく、色々と検索をかけて調べてみたところどうやら文字コードに依存して出てくるエラーだと分かり、文字コードを "マルチバイトコード" に変更したのですが、それでもこのエラーを取り除くことができませんでした。 

何が問題なのでしょうか? 
連続の質問で恐縮ですが、もしご理解いただけたらアドバイスをお願いしたいと思います。よろしくお願いいたします。

お礼日時:2008/10/06 21:06

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!