トップ回答者
無限ループのプログラムで、フォームのコントロールが消えます。

質問
-
VB6.0のフォームから、Vidual Studio 2008のC++のDLLの無限ループの関数を呼び出しています。
この時、フォームのコントロールがフォームの背景で消され見えなくなります。
別のフォームで覆い被さったりすると起こり易いですが、まれに何にもしていなくても起こる場合があります。
また、スクリーンセーバーに行き戻って来た時にもなります。この時はスクリーンセーバーの時の画面が残る場合もあります。(他のプログラムのフォームはチャンと描画されます)Vista グラフィック: ATI(TM) Radeon(R) HD 2400 XT 256MB は問題ありません。
XP グラフィック: オンボードのビデオコントローラー(Intel Q43) が問題です。OSの違いによるものでしょうか?
何らかのグラフィックボードが必要なんでしょうか?
その他に原因があるものでしょうか?
プログラムによる何らかの対応がありませんか?何か意見をお聞かせ願えればと思います。
回答
-
VB6.0のフォームから、Vidual Studio 2008のC++のDLLの無限ループの関数を呼び出しています。
この時、フォームのコントロールがフォームの背景で消され見えなくなります。
別のフォームで覆い被さったりすると起こり易いですが、まれに何にもしていなくても起こる場合があります。
また、スクリーンセーバーに行き戻って来た時にもなります。この時はスクリーンセーバーの時の画面が残る場合もあります。(他のプログラムのフォームはチャンと描画されます)Windows のプログラムはそんなものです。
ほかのウィンドウで上書きされたり、コンピュータのロックでかき消されたりした場合は、画面に書き直すことが必要になります。
この書き直す処理はメインスレッドで実行されますが、メインスレッドで無限ループの関数を呼び出していると、書き直し待ちのまま(白いまま)になります。この場合、重たい処理を別スレッドで実行するべきですが、VB6 ではスレッドの仕組みがないため、DLL 側で別スレッドにしてはどうかという提案が出ています。
(そもそも、無限ループさせるなという感想を持ちますが…)Vista グラフィック: ATI(TM) Radeon(R) HD 2400 XT 256MB は問題ありません。
XP グラフィック: オンボードのビデオコントローラー(Intel Q43) が問題です。
OSの違いによるものでしょうか?Vista で起きないのは、Vista 以降では Aero (正確には Desktop Window Manager)で描画内容をキャッシュしているおかげで、再描画がこれまでの Windows に比べて減っているためです。
(正確な表現ではないかもしれませんが、大まかな理解としては問題ないと思います)OS が違うから仕方がないのではなく、メインスレッドで重い処理を実行しないようにしていくべきです。
なお、Vista では画面が白くならないかもしれませんが、タイトルバーに「応答なし」と表示されていると思います。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 回答としてマーク クサキ 2010年4月28日 6:15
-
シングルスレッドのアプリケーションで、メッセージの処理を行わずに無限ループさせると画面更新などが行われず、質問のような状態になります。
無限ループ中ならそのループの中の処理しかしていないと思ってください。
ボタンのハンドラで無限ループさせてみればわかります。
また、無限ループの中にDoEvents(メッセージの処理をさせる)を呼んだ場合にどうなるかを比べるとわかりやすいと思います。
(ただしDoEventsでこの問題の対処にするのはダメです)スレッドは理解が難しそうに感じています。私にはまとまった時間をかけ勉強しないと分からないと
簡単に直すのは厳しいと思います。
思っていますが、もし、C++のソースの頭に何か書けくようなことで、そうなるようでしたら教えてください。
スレッドを起動してそちらで処理をさせるぐらいならそうでもないのかもしれませんが(元のソースが分からないのでわかりません)、起動したスレッドは止める必要もありますし、データの受け渡しとかがあればそこをどうするかなど、考えることが増えます。連続的な表示で、人間の指示で終わるようなプログラムは書くにはどういう風にするのがお勧めですか?
・タイマで定期的に表示を更新する。
・画面処理(UI)と異なるスレッドで行う。
・ループの処理中にメッセージを処理させる。
など、状況によって異なると思います。- 回答としてマーク クサキ 2010年4月28日 6:17
-
ループの処理中にメッセージを処理させる。
は、それでいいのですが、ループの処理中にメッセージを処理させると処理がネストされる可能性がある。ということを留意しておいてください。
MyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され、そこでもまた無限ループが起動され、そのなかのMyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され、そこでもまた無限ループが起動され、そのなかのMyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され・・・
みたいな!
基本的には勧めません。
- 回答としてマーク クサキ 2010年4月28日 6:18
すべての返信
-
VB6.0のフォームから、Vidual Studio 2008のC++のDLLの無限ループの関数を呼び出しています。
この時、フォームのコントロールがフォームの背景で消され見えなくなります。
別のフォームで覆い被さったりすると起こり易いですが、まれに何にもしていなくても起こる場合があります。
また、スクリーンセーバーに行き戻って来た時にもなります。この時はスクリーンセーバーの時の画面が残る場合もあります。(他のプログラムのフォームはチャンと描画されます)Windows のプログラムはそんなものです。
ほかのウィンドウで上書きされたり、コンピュータのロックでかき消されたりした場合は、画面に書き直すことが必要になります。
この書き直す処理はメインスレッドで実行されますが、メインスレッドで無限ループの関数を呼び出していると、書き直し待ちのまま(白いまま)になります。この場合、重たい処理を別スレッドで実行するべきですが、VB6 ではスレッドの仕組みがないため、DLL 側で別スレッドにしてはどうかという提案が出ています。
(そもそも、無限ループさせるなという感想を持ちますが…)Vista グラフィック: ATI(TM) Radeon(R) HD 2400 XT 256MB は問題ありません。
XP グラフィック: オンボードのビデオコントローラー(Intel Q43) が問題です。
OSの違いによるものでしょうか?Vista で起きないのは、Vista 以降では Aero (正確には Desktop Window Manager)で描画内容をキャッシュしているおかげで、再描画がこれまでの Windows に比べて減っているためです。
(正確な表現ではないかもしれませんが、大まかな理解としては問題ないと思います)OS が違うから仕方がないのではなく、メインスレッドで重い処理を実行しないようにしていくべきです。
なお、Vista では画面が白くならないかもしれませんが、タイトルバーに「応答なし」と表示されていると思います。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 回答としてマーク クサキ 2010年4月28日 6:15
-
> この場合、重たい処理を別スレッドで実行するべきですが、VB6 ではスレッドの
> 仕組みがないため、DLL 側で別スレッドにしてはどうかという提案が出ています。
スレッドは理解が難しそうに感じています。私にはまとまった時間をかけ勉強しないと分からないと
思っていますが、もし、C++のソースの頭に何か書けくようなことで、そうなるようでしたら教えてください。
>(そもそも、無限ループさせるなという感想を持ちますが…)
連続的な表示で、人間の指示で終わるようなプログラムは書くにはどういう風にするのがお勧めですか?
> なお、Vista では画面が白くならないかもしれませんが、タイトルバーに
> 「応答なし」と表示されていると思います。
VistaもXPも「応答なし」とはならず、タイトルは普通に表示されています。
> Vista で起きないのは、Vista 以降では Aero (正確には Desktop Window Manager)
> で描画内容をキャッシュしているおかげで、再描画がこれまでの Windows に
> 比べて減っているためです。
元々、2000やXPで問題なしで動いていたものです。
これまで、PCにはグラフィックボード(256MBなどメモリを持つ)を必ず装着していましが、
壊れてしまったので、チェック用だけに買ったグラフィクボード無しのPCのXPで起こっています。
グラフィクボード無しのせいかとも思いましたが、私の古いバージョンのもので動かしたら
問題なく動いています。ということで、私のプログラムを調べてみます。 -
シングルスレッドのアプリケーションで、メッセージの処理を行わずに無限ループさせると画面更新などが行われず、質問のような状態になります。
無限ループ中ならそのループの中の処理しかしていないと思ってください。
ボタンのハンドラで無限ループさせてみればわかります。
また、無限ループの中にDoEvents(メッセージの処理をさせる)を呼んだ場合にどうなるかを比べるとわかりやすいと思います。
(ただしDoEventsでこの問題の対処にするのはダメです)スレッドは理解が難しそうに感じています。私にはまとまった時間をかけ勉強しないと分からないと
簡単に直すのは厳しいと思います。
思っていますが、もし、C++のソースの頭に何か書けくようなことで、そうなるようでしたら教えてください。
スレッドを起動してそちらで処理をさせるぐらいならそうでもないのかもしれませんが(元のソースが分からないのでわかりません)、起動したスレッドは止める必要もありますし、データの受け渡しとかがあればそこをどうするかなど、考えることが増えます。連続的な表示で、人間の指示で終わるようなプログラムは書くにはどういう風にするのがお勧めですか?
・タイマで定期的に表示を更新する。
・画面処理(UI)と異なるスレッドで行う。
・ループの処理中にメッセージを処理させる。
など、状況によって異なると思います。- 回答としてマーク クサキ 2010年4月28日 6:17
-
for loop の中で、下のような2つの関数を使い、キーボードやマウスのイベントが
があれば、抜け出すようにたら、XPでも問題が発生しなくなりました。MyDoEvents(); ret = KeyboardMouseBreak(); if ( ret == ...
今回、上手く行っていなかったのは、MyDoEvents() がなかったせいで発生していました。
int KeyboardMouseBreak( void ) { unsigned int Status; int Ret = 0; MSG msg; HWND hWin = GetActiveWindow(); while ( PeekMessage( &msg, hWin, WM_KEYFIRST, WM_MOUSELAST, PM_REMOVE) ) { if ( msg.message == WM_RBUTTONDOWN ) { Ret = 2; return( Ret ); } if ( msg.message == WM_KEYDOWN ) { Status = GetKeyState( VK_ESCAPE ) ; if ( Status >= 0x8000 ){ Ret = BK_STATUS; return( Ret ); } } TranslateMessage( &msg ); DispatchMessage( &msg ); } return( Ret ) ; } void MyDoEvents( void ) { MSG msg; while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage(&msg); DispatchMessage(&msg); } }
この2つの関数のことは良く分かっていないのですが、
何とか、VB6.0のフォームからでも、C#のフォームからでも利用できるようにしたものです。
また、MyDoEvents() と名前を付けたのはVB6.0のDoEventsのような働きをしている
ようで、そう名づけています。(おかしいですか?)こんな感じのプログラムですが”ループの処理中にメッセージを処理させる。”に該当していませんか?
-
ループの処理中にメッセージを処理させる。
は、それでいいのですが、ループの処理中にメッセージを処理させると処理がネストされる可能性がある。ということを留意しておいてください。
MyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され、そこでもまた無限ループが起動され、そのなかのMyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され、そこでもまた無限ループが起動され、そのなかのMyDoEventsのDispatchMessageでボタンなどの何かの処理が呼び出され・・・
みたいな!
基本的には勧めません。
- 回答としてマーク クサキ 2010年4月28日 6:18