
Windows XPとVC++ 6.0で
時間のかかる大量の計算をするプログラムを作っています。
計算部分はスレッド処理にして
進捗ダイアログ(CDialogにCProgressCtrlを貼り付けたもの)
を表示します。
・CWinAppのInitInstanceで計算処理開始(AfxBeginThread)
・計算処理内で進捗ダイアログをCreate
・計算の進み具合によって進捗ダイアログのプログレスバーを更新
上記の流れではうまくいっていたのですが
以下のように変更したところ、進捗ダイアログをCreateするところで
プログラムが応答なしになってしまうようになりました。
・メインダイアログ(モーダル)
・メインダイアログのAボタンクリックでダイアログAを開く(モーダル)
・ダイアログAの実行ボタンクリックで計算処理開始(AfxBeginThread)
・計算処理内で進捗ダイアログをCreate
・計算の進み具合によって進捗ダイアログのプログレスバーを更新
MFC Wizardでダイアログベースで作成、MFCの共有DLLを使用しています。
モーダルダイアログ→スレッド→CDialog.Createに
制限があったりするのでしょうか。
どうかご教授ください。
No.4ベストアンサー
- 回答日時:
スレッドを作成した側の待機処理ループの中にメッセージポンプを作成してやればよさそうですよ
pThread->ResumeThread();
do {
AfxGetApp()->PumpMessage();
} while( WaitForSingleObject( pThread->m_hThread, 0 ) != WAIT_OBJECT_0 );
といった具合で …
メインスレッド寝てしまっているので反応無しになるのかも
No.3
- 回答日時:
AttachThreadInputは根本的な解決になっていないようです
新規に MFCダイアログベースで起こしたプロジェクトで
1) モーダルダイアログを追加
2) このダイアログのボタンでワーカースレッドを起動
3) スレッド制御関数の中でプログレスバーダイアログを作成
といった具合にしてみましたが すんなり動いてしまいました
CProgressBarDlg dlg;
dlg.Create( リソースID, NULL );
であればすんなり動くようです
親ウィンドウのポインタを渡してしまうとアサーションが起きます
最終的には CDialog::CreateIndirectで AfxGetMainWnd()で親を探しているので同じようにスレッド制御関数でAfxGetMainWnd()を取得して渡してもアサーションです
一番最初にコーディングした際は 確かにダンマリモードになったんですが2回目以降ダンマリモードの状態が再現できない状態です
この回答への補足
#前回の投稿箇所を誤ってしまったようです。
↓の次の投稿になります。申し訳ありません。
> redfox63さん、ご回答ありがとうございます。
> 当方の環境はWindows XP SP2 + VC++ 6.0 SP6です。
> VC++ 6.0 SP5の環境を作って試してみたのですが
> やはり応答なしになってしまいました。
- - - - - - - - - - - - - - - - - - - - - - - - -
すみません、自己解決です。(というか諦め…)
スレッドの中でCProgrerss.Createを行わずに
呼び出し側のダイアログ(の実行ボタン)で
進捗ダイアログを作ることにしました。
BOOL CMainDlg::OnRun()
{
...
CProgressDlg dlg;
dlg.Create(IDD_PROGRESSDLG, this);
dlg.ShowWindow(SW_SHOW);
CALC_PARAMDATA ParamData;
CWinThread* pThread = NULL;
ParamData.i1 = n1;
ParamData.i2 = n2;
ParamData.pWnd = this;
pThread = AfxBeginThread(::CalcThreadFunc, &Param, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->ResumeThread();
do
{
// 進捗の度合い(グローバル変数)によって
// CProgressのプログレスバーを進める
// 進捗の度合いはスレッド内で更新
}
while(WaitForSingleObject(pThread->m_hThread, 0) !=WAIT_OBJECT_0);
delete pThread;
...
}
首記の「スレッドからダイアログを表示」については
まだ腑に落ちない点がありますが、
下記のサイトで
「MFCでは、スレッドまたいでの、CWndオブジェクトのポインタによるウインドウ操作は保証されていません」
と発言している方がいらっしゃいました。
http://homepage1.nifty.com/MADIA/vc/vc_bbs/20050 …
ちょっとMSDNを確認しようと思います。
redfox63さん、たくさんお時間を割いていただきまして恐縮です。
ありがとうございました。
redfox63さん、ご回答ありがとうございます。
当方の環境はWindows XP SP2 + VC++ 6.0 SP6です。
VC++ 6.0 SP5の環境を作って試してみたのですが
やはり応答なしになってしまいました。
ソースは以下のようになっています。
※最初の質問ではモーダルダイアログが2つありましたが
単純にするため1つにしました。その他諸々簡略化してあります。
※モーダル1つでも当方では同じ現象になります。
*MainApp.h
int CalcFunc(int i1, int i2);
typedef struct _CALC_PARAMDATA
{
int i1;
int i2;
CWnd* pWnd;
int ret;
} CALC_PARAMDATA ,*PCALC_PARAMDATA;
class CMainApp : public CWinApp
{
...
}
UINT CalcThreadProc(LPVOID pParam);
*MainApp.cpp
BOOL CMainApp::InitInstance()
{
...
CMainDlg dlg;
dlg.DoModal();
...
}
UINT CalcThreadProc(LPVOID pParam)
{
int i1 = ((PCALC_PARAMDATA)pParam)->i1;
int i2 = ((PCALC_PARAMDATA)pParam)->i2;
CWnd* pWnd = ((PCALC_PARAMDATA)pParam)->pWnd;
// ちなみに、ここでCProgressDlgをCreateしても
// 応答なしになります
int ret = CalcFunc(i1, i2, pWnd);
((PCALC_PARAMDATA)pParam)->ret = ret;
}
int CalcFunc(DWORD dw1, DWORD dw2, CWnd* pWnd)
{
CProgressDlg dlg;
dlg.Create(IDD_PROGRESSDLG, NULL);// またはpWnd
dlg.ShowWindow(SW_SHOW);
...
}
*MainDlg.cpp
BOOL CMainDlg::OnRun()
{
...
CALC_PARAMDATA ParamData;
CWinThread* pThread = NULL;
ParamData.i1 = n1;
ParamData.i2 = n2;
ParamData.pWnd = this;
pThread = AfxBeginThread(::CalcThreadFunc, &Param, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->ResumeThread();
do
{
}
while(WaitForSingleObject(pThread->m_hThread, 0) !=WAIT_OBJECT_0);
delete pThread;
...
}
No.2
- 回答日時:
おかしいですね … 当方の環境ですと動作してしまっているのですが
WinXP SP2 + VC++6.0 SP5の環境です
AfxGetThreadを AfxGetAppに変更してみてはいかがでしょう
別の手段として プログレスダイアログは ダイアログAのボタンクリックイベント内で生成して
スレッドプロークの引数に プログレスダイアログのアドレス(ポインタ)を渡すとか
他に引き渡すデータがあるなら 構造体にしてそのメンバーにプログレスダイアログポインタを持たすなどしてはいかがでしょう
No.1
- 回答日時:
親ウィンドウを探しにいって迷子になっているのでしょう
ワーカースレッドの場合 AttachThreadInputなどでアプリケーションスレッドをアタッチしてやればいいようです
スレッドプロークの中で
CProgressDlg dlg;
AttachThreadInput( ::GetCurrentThreadId(), AfxGetThread()->m_nThreadID, True);
dlg.Create( IDD_PROGRESSDLG, NULL );
dlg.ShowWindow( SW_SHOW );
while( 1 ) {
if ( 終了条件 )
break;
// 何かの処理
}
AttachThreadInput( ::GetCurrentThreadId(), AfxGetThread()->m_nThreadID, FALSE);
dlg.DestroyWindow();
といった具合で
この回答への補足
redfox63さん、ご回答ありがとうございます。
しかしAttachThreadInputでも同様の結果になってしまいました。。
GetCurrentThreadIdで取得した呼び出し側スレッドのIDと
AfxGetThreadで取得した現在実行中のスレッドのIDが
同じ値になっているのですが、そのことと何か関係がありますでしょうか。
また、「親ウィンドウを探しにいって迷子になっているのでしょう」をヒントに
Createの第二引数に親ウィンドウのハンドルを渡してみたのですが
そうするとDebugモードでは、Createの箇所でDebug Assertion Failedになってしまいます。
(wincore.cppの883行目)
hWndがウィンドウかどうかの判定で「ウィンドウでない」と見なされるようです。
CProgressDlg dlg;
AttachThreadInput(::GetCurrentThreadId(), AfxGetThread()->m_nThreadID, TRUE);
dlg.Create(IDD_PROGRESSDLG, hWnd);// ここで応答なし またはDebug Assertion Failed
dlg.ShowWindow(SW_SHOW);
...
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
VC++スレッドの正しい終了のさせかた
C言語・C++・C#
-
MFCのワーカースレッドとUIスレッドの使い分け
C言語・C++・C#
-
CString から LPCTSTRの型に変換
C言語・C++・C#
-
-
4
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
5
エディットボックスのフォントを変えたい
C言語・C++・C#
-
6
MFC ダイアログ上のID取得について
C言語・C++・C#
-
7
CFileDialogの最初のディレクトリ設定
C言語・C++・C#
-
8
PostMessageの連続送信
C言語・C++・C#
-
9
ラベル(スタティックテキスト)内での改行。
C言語・C++・C#
-
10
テキストボックスからフォーカス外す
C言語・C++・C#
-
11
画面を強制的に再描画させる方法
C言語・C++・C#
-
12
DLLでダイアログ
C言語・C++・C#
-
13
VC++におけるCStringの変換
C言語・C++・C#
-
14
VC++のコンボボックスの各項目の背景色と文字色を変える方法
C言語・C++・C#
-
15
string→CStringの型変換について
C言語・C++・C#
-
16
別のDLLのダイアログを・・・
C言語・C++・C#
-
17
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
18
リストコントロールの列幅を固定にする
C言語・C++・C#
-
19
CStringの文字列検索&抜き出しについて
C言語・C++・C#
-
20
MFC モーダルダイアログ表示中に
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
VBAで関数をつくる
-
変化させるセルが変化しない
-
PHPとJavaでSHA256の結果を同じ...
-
スレッド処理からダイアログを...
-
排他的論理和 BCC(水平パリテ...
-
matlabで計算終了
-
VBAの再計算が反映されない件に...
-
パルスを時間(m/min)の計算につ...
-
EXCELなどで「返す」という表現
-
引き放し法による除算アルゴリ...
-
VBA入力フォームで労働時間の計...
-
エクセルマクロで計算結果の値...
-
太陽の位置計算のプログラムを...
-
モジュラス103の計算とは何でし...
-
チェックデジット計算できる関...
-
入射角反射角
-
「評価」「評価値」という言葉...
-
電卓でmodの計算
-
VBAで一時的にオーバーフローを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
VBAの再計算が反映されない件に...
-
EXCELなどで「返す」という表現
-
matlabで計算終了
-
排他的論理和 BCC(水平パリテ...
-
変化させるセルが変化しない
-
モジュラス103の計算とは何でし...
-
傾いた四角形内の範囲の条件式
-
VBAで関数をつくる
-
[急募]Pythonについてです。
-
数値計算の高速化 (cos, sin, exp)
-
C言語についての質問です。 ル...
-
切り上げたい
-
DLL(VC++で作った)で稼動中の...
-
CとFORTRANの計算速度はどちら...
-
趣味で「乗換案内」みたいなソ...
-
CGIの実行権限(ディスク容...
-
エクセルで特定のセルのみを任...
-
functionを含んだプログラムを...
-
時間差を求める
おすすめ情報