• ベストアンサー

VC++ スレッドからDoModalへ

いまさらですがVC++6.0でつまづいています MFCです AdlgクラスのダイアログのOnButtonA() からXXXスレッドを起動し そのXXXスレッドではcountを+1しつづけます。 そして別のダイアログ DDD10をDoModalで起動しそのDDD10 内のTextBoxの値にcount値を反映させて表示しようとしました 下記ソース内のAfxMessageBox(tmp);ではcount値は 更新されますが DDD10ダイアログ内のテキストボックス の値が変更されません m_gui_xfr_totalはDDD10のテキストボックスにつけた メンバー名です どなたかアドバイスをお願いします void ADlg::OnButtonA() { DDD10 dlg10 ; CWinThread *pThread = AfxBeginThread(XXX_thread_entry,(LPVOID *)this); dlg10.DoModal() ; } void XXX_Thread(){ CString tmp; unsigned int count=0; DDD10 dlg10; while(1){ count++; tmp.Format("%d",count); dlg10.m_gui_xfr_total.Format(tmp); AfxMessageBox(tmp); Sleep(1000); } }

質問者が選んだベストアンサー

  • ベストアンサー
  • takoashi
  • ベストアンサー率39% (21/53)
回答No.2

スレッドごしのコントロールアクセスには制限がありますなんて、いうより、 OnButtonAで定義されている dlg10 と スレッド内で定義されている  dlg10 は違うオブジェクトですよ。

C_is_Best
質問者

お礼

redfox63さんへの補足に書きましたように おかげさまでうまくいきました 今回はオブジェクトが違うとの指摘が 助かりました

C_is_Best
質問者

補足

オブジェトの基本が理解できてませんでした 指摘ありがとうございます。 ということでまずはスレッドごしに挑戦する前に 以下のようにDDD10からスレッドを起動して DDD10のテキストボックスの表示が変化するかを 見てみました。 DDD10のテキストボックスm_gui_xfr_totalの表示が 1秒毎に1→2→3→4→5と変化するのを期待した のですが 1 と表示されたままで 変化しません でした。 ご指摘願います DDD10::DDD10(CWnd* pParent /*=NULL*/) : CDialog(DDD10::IDD, pParent) { CString tmp; unsigned int count=0; //{{AFX_DATA_INIT(DDD10) m_gui_xfr_total = _T("12345678"); //}}AFX_DATA_INIT CWinThread *pThread = AfxBeginThread(XFR_Monitor_thread_entry,(LPVOID *)this); } public: static UINT XFR_Monitor_thread_entry(LPVOID v) { ((DDD10*)v)->XFR_Monitor_Thread(); return 0; } class DDD10 : public CDialog { void XFR_Monitor_Thread(){ CString tmp; unsigned int count=0; while(1){ count++; m_gui_xfr_total.Format("%d",count); if(count==5)break; Sleep(1000); } }

その他の回答 (4)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

クラス間でもやり方は一緒です まずスレッドに渡すデータの構造体を定義します 今回の場合カウント用の変数とダイアログのウィンドウハンドルがあれば十分でしょう メッセージのやり取りにウィンドウのハンドルが必要になるため DDD10クラスからスレッド起こす必要があるでしょう typdef struct tagData {   int nData;   HWND hWnd; } TAGDATA, *LPTAGDATA; DDD10クラスに TAGDATA型のメンバー変数を準備 TAGDATA m_TagData; スレッドとのメッセージを定義します static UINT msgCount = RegisterWindowMessage( "MyCount" ); DDD10クラスのメッセージマップに ON_REGISTERES_MESSAGE( msgCount, OnMyMessage ) を追加 ハンドラを定義 afx_msg LRESULT DDD10::OnMyMessage( WPARAM wParam, LPARAM lParam) {   // wParamに次に表示するデータが設定されている   m_gui_xfr_total.Format("%d",(int)wParam);   UpdateData( FALSE ); } スレッドのメインルーチンを void XFR_Monitor_Thread(LPVOID pPram){   unsigned int count=0;   HWND hWnd = ((LPTAGDATA)pParam)->hWnd;   // カウントの初期値があるなら   // count = ((LPTAGDATA)pParam)->nData;   while(1){     count++;     PostMessage( hWnd, msgcount, count, 0 );     if(count==5)break;     Sleep(1000);   } } スレッド起動は DDDクラスの OnInitDialogあたりで m_TagData.nData = 0; m_TagData.hWnd = this->m_hWnd; AfxBeginThread( XFR_Monitor_Thread, &m_TagData ); といった具合でしょう

C_is_Best
質問者

お礼

初心者にとってはかなりの難関です 教えて頂いた内容をすこしづつ理解しながら 実験していきたいと思います 具体的なソースでの回答ありがとうございます

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.4

基本的にやり方が違いますよ ワーカスレッドとメインスレッドとのやり取りには 1) RegisterWindowMessageなどで共通のメッセージを定義しておいて 2) スレッド側からPostMessageでwParamyやlParamでデータを送信 3) 受け側のダイアログのメッセージマップにRegisterWindowMessageで設定したメッセージのマクロとハンドラを実装 4) ハンドラ内で クラス変数(CString型)の内容を送信データから構築 UpdateDataで変数とコントロールの内容を更新 といた具合でしょう DoDataExchangeの中でスレッド起動はうまくないと思いますよ DoDataExchangeは双方向で呼ばれます 変数をコントロールへと、コントロールから変数への2種類です スレッドの起動は別の適切な関数に移動しましょう ボタンのクリックで起動するとか、ダイアログのインスタンス化する際のコンストラクタでやるとか

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

DDXマクロが動作するようなコードが必要ですよ コントロールに割り当てた変数とコントロールの表示内容を整合させるために DDX_TextやDDX_Controlなどで行っているとおもいます CString型のクラスメンバーにデータを設定したなら UpdateDataを呼び出して DoDataExchangeが呼ばれるようにします 第一歩としてはダイアログの中のボタンを押したらテキストボックスの数値がカウントアップする といった物を作成してみましょう

C_is_Best
質問者

お礼

ありがとうございます 以下のようにスレッド起動処理をDoDataExchangeへ移動 void DDD10::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(DDD10) DDX_Text(pDX, IDC_EDIT1, m_gui_xfr_total); //}}AFX_DATA_MAP CWinThread *pThread = AfxBeginThread(XFR_Monitor_thread_entry,(LPVOID *)this); } そして class DDD10 : public CDialog { void XFR_Monitor_Thread(){ CString tmp; unsigned int count=0; xfr_test_end = 0; while(1){ if (xfr_test_end == 1)break; count++; m_gui_xfr_total.Format("%d",count); SetDlgItemText(IDC_EDIT1, m_gui_xfr_total); Sleep(1000); } } のようにSetDlgItemTextを利用しましたらうまくcount値が 1秒毎に変化するようになりました

C_is_Best
質問者

補足

それぞれのダイアログ内でのデータをテキストボックスへ 表示はできるようになり喜んでいたのですが 次なる難関が待ち構えておりました。 クラスの異なるスレッド間でのデータの受け渡しに難航しています 手法について ご教授願います

  • penta1331
  • ベストアンサー率64% (16/25)
回答No.1

>> dlg10.m_gui_xfr_total.Format(tmp); dlg10.m_gui_xfr_total.SetWindowText(tmp); じゃなくて?

関連するQ&A

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。

  • [VC++] AfxBeginThreadで生成したスレッドの監視方法について

    お世話になります。 VC++でスレッドプログラムを作っています。 AfxBeginThreadでワーカースレッドを作成し、その中でダイアログを表示する プログラムです。 問題は、ワーカースレッドがある処理状態に至ったことを メインスレッドで検知したいのですが、それがうまく いかないということです。 コードの概略をしめします。 <メインスレッド側> void CTestApp::OnTest() {   CTestDlg dlg;   dlg.IsContinue = FALSE;   pThread = AfxBeginThread(TestDlg::Thread, (void*)&dlg);   while (!dlg.IsContinue) { // <----問題:このループ処理を抜けれない!    Sleep(0);   } } <ワーカースレッド側> UINT TestDlg::Thread(LPVOID pParam){   TestDlg* pDlg = (TestDlg*)pParam;   pDlg->Create(TestDlg::IDD);   pDlg->ShowWindow(SW_SHOW);     pDlg->IsContinue = TRUE; //<--ここでフラグを変更しているのに。   while(pDlg->IsContinue) {    MSG msg;    if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {      ::TranslateMessage(&msg);      ::DispatchMessage(&msg);    }   }   pDlg->DestroyWindow();   return 0; } ---- メインスレッドのSleep(0)で待つのを AfxGetApp()->PumpMessage()に変更すると ループを抜けるようなのですが、どうも納得できません。 上記のプログラムで問題、もしくはプロジェクトの 設定等に不備がある可能性がありましたら 御教授いただけたら幸いです。 よろしくおねがいいたします。

  • マルチスレッドのスレッド数を増やしたい

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問概略> CWinThread*を使って無限ループのスレッドを作ったのですが、 無限ループのスレッドをもう一つ作り、同時に実行しようとするとアクセスバイオレーションのエラーでます。 複数スレッドの作り方を教えていただけますと幸いです。 <質問詳細> 現状の正常に実行できるソースの必要最小限を書きます。 <.h> class CMyDlg : public CDialog{ public:   static UINT ThreadFunc( LPVOID pParam );   void Thread(); // スレッドの処理 protected:   CWinThread* m_pThread;//スレッドのアドレス }; <.cpp> void CMyDlg::OnButton(){   m_pThread = AfxBeginThread( ThreadFunc, this );   for(;;) /*無限ループ処理1*/ ; } UINT CMyDlg::ThreadFunc( LPVOID pParam ){   ((CMyDlg*)pParam)->Thread();   return 0; } void CMyDlg::Thread(){   for(;;) /*無限ループ処理2*/ ; } これに、 void CMyDlg::Thread2(){   for(;;) /*無限ループ処理3*/ ; } のようなスレッドを追加したいのですが全然出来ません。 宜しければご指摘お願い致します。

  • メッセージボックスが表示されないのですが?

    WIN98 VC++6.0 MFCにて mmmというプロジェクト名でウィザードに従いダイアログベースのPGを作りました。 下記のようにコードの2箇所にAfxMessageBox("3",MB_OK);を追加しましたが、どちらもメッセージボックスが表示されません。 どうしてなのでしょうか? お分かりも方是非教えてください。 ************************** BOOL CMmmApp::InitInstance() { AfxEnableControlContainer(); #ifdef _AFXDLL Enable3dControls(); #else Enable3dControlsStatic(); #endif CMmmDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); AfxMessageBox("3",MB_OK);//■追加 if (nResponse == IDOK) { AfxMessageBox("3",MB_OK);//■追加 } else if (nResponse == IDCANCEL) { } // ダイアログが閉じられてからアプリケーションのメッセージ ポンプを開始するよりは、 // アプリケーションを終了するために FALSE を返してください。 return FALSE; }

  • DLLでダイアログ

    VC++6.0にてMFCを使うDLLを作成しています。 関連HPを参考になんとかDLLを作ることが出来ました。 そこで今度はDLL側でダイアログボックスを作成して表示させようとしたところうまくいきません。 エラーも無くスルーされてしまいます。 こういう使い方は出来ないのでしょうか。 ↓DLL関数のソースファイルです。 ---------------------------------------------- #include "StdAfx.h" #include "Defs.h" #include "Func.h" #include "resource.h" #include "testdlg.h" #include "dlg2.h" int WINAPI DllFunc( CString &p_rcStr, CWnd *p_pcWnd ) { TestDlg dlg; Cdlg2 dlg2; dlg.ps = p_rcStr; dlg2.DoModal();//なにも出ない AfxMessageBox(p_rcStr);//コレはOK dlg.DoModal();//何もでない return TRUE; } --------------------------------------------

  • 変数の代入について

    ダイアログベースで、ダイアログ1からダイアログ2を開きダイアログ1のエディットボックスのデータをダイアログ2に表示する下記コードを教わりました。 変更後のようにしても問題ないと思いましたが、'dlg' は定義されていない識別子です。とエラーが出ます。 どうしてなのかお教えていただきたいのですが、 よろしくお願いします。 <変更前> CSubDlg dlg2; dlg2.m_strText = strText; dlg2.DoModal(); <変更後> void CSubDlg::OnPaint() { m_strText = dlg.strText; ちなみにdlgはウィザードが作ったコードで、 CMainDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); ダイアログ1のことだと思うのですが。。。。 ************************** メインダイアログとしてCMainDlgを例にしますが、かなり割愛します。 このダイアログには、Editが貼り付けられているとします。Editコントロールに割り当てたIDをIDC_EDIT_INPUTだと仮定します。 DDXとかのデータ変換を使う方法もありますが、ここでは単にデータを取得します。 // // OKボタンが押された時の処理 // void CMainDlg::OnOK() { // データの取得 CString strText; GetDlgItemText(IDC_EDIT_INPUT, strText); CSubDlg dlg2; dlg2.m_strText = strText; dlg2.DoModal(); } class CSubDlg : pbulic CDialog { public: CString m_strText; // 親から渡される文字列を格納する変数 ・ ・ ・ ・ ・ }; あとは、CSubDlgのOnPaintでテキストを描画します。 void CSubDlg::OnPaint() { // テキストをクライアント領域の中央に描画 CRect rect; GetClientRect(rect); CPaintDC dc(this); dc.TextOut(m_strText, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); }

  • ダイアログの表示、非表示の切り替えについて

    環境 WIN98 VC++6.0 MFC SDIにて 1.ポップアップメニューの”ダイアログ作成”をクリックすると、 void CMainFrame::OnKNew() { CInput dlg; int iID = dlg.DoModal(); } として、ダイアログを作成します。 2.次に、ダイアログのボタン押し下げにてダイアログを非表示にします。 void CInput::OnButton1() { ShowWindow(SW_HIDE); } このようなコードにおいて、非表示状態での”ダイアログ作成”クリックでは非表示から表示に切り替えることを実現するにはどのようにすれば良いのでしょうか? よろしくお願いいたします。

  • SendMessage();の使い方

    よろしくお願いします。 <環境> WIN98 VC++6.0 MFC SDIにてウィンドウをクリックすると、モードレスダイアログ1とモーダルダイア ログ2が開くようにしました。 void CMy222View::OnLButtonDown(UINT nFlags, CPoint point) { CDlg1 *dlg; dlg = new CDlg1; dlg->Create(IDD_DIALOG1); dlg->ShowWindow(SW_SHOW); CDlg2 dlg2; dlg2.DoModal(); CView::OnLButtonDown(nFlags, point); } ダイアログ2のボタン押し下げにてダイアログ1のボタン1を押し下げたいのですが 、どのようにすれば実現できるのでしょうか? void CDlg2::OnButton2() { SendMessage(); //■ここの書き方が分かりません CDialog::OnOK(); } 宜しくお願いいたします。

  • 複数のダイアログの作成について

    環境 WIN98 VC++6.0 MFC SDIにて 1.メニューの”ダイアログ作成”をクリックすると、 void CMainFrame::OnKNew() { CInput dlg; int iID = dlg.DoModal(); } として、ダイアログを作成します。 2.次に、ダイアログのボタン押し下げにてダイアログを非表示にします。 void CInput::OnButton1() { ShowWindow(SW_HIDE); } このようなコードにおいて、一旦非表示にした後で、また”ダイアログ作成”メニューにてダイアログを作成した場合、 1.これは新たに2個目のダイアログが作られたのでしょうか? 2.それとも、単に最初に作られたダイアログが非表示から表示状態になっただけでしょうか? 3.それとも、最初のダイアログの上に2個目のダイアログが上書きされてしまうのでしょうか? 以上よろしくお願いします。

  • 親ウィンドウの変数の変更

    以下のようにクライアント領域をダブルクリックして、モーダルダイアログを表示し ダイアログからCPPPViewのメンバ変数flgを変更しましたが、 CPPPView内では変更結果が反映させていません。 どうしてなのでしょうか? またどうすれば変更されるようになりますか? void CPPPView::OnLButtonDblClk(UINT nFlags, CPoint point) {    CHenkouDlg dlg;    dlg.DoModal();           //  ここではflgが99になっていない    CView::OnLButtonDblClk(nFlags, point); } void CHenkouDlg::OnOK() {    CPPPView* my = (CPPPView*)GetParent();    my->flg=99;    CDialog::OnOK(); }

専門家に質問してみよう