まとめてファイルのコピーを行うアプリケーションにおいて、コピー中の状況を
プログレスバーを使用して表示しています。
WindowsXPまでは、このプログレスバーが
CProgressCtrl::SetPos()
で設定した値通りに正確に表示されていましたが、WindowsVistaになったら、お
かしな表示をするようになりました。
プログレスバーの更新速度がゆっくりの時は正確に表示されるのですが、更新速
度が速くなると、設定した値より小さな値を表示しています。
そして、CProgressCtrl::SetPos()の設定で100%に達して、プログレスバーを閉じ
る頃になっても、表示上は数%~10数%程度の値しかありません。
修正方法をご存じの方はいませんでしょうか。
よろしくお願いいたします。
再描画がされず10%以降変化しないのか
100を指定しているのに10と表示されるのか
どっち?
100を指定しているのに10と表示されるなら
Vistaのバグ?
でもいまさらそんなバグある?
wclrp ( 'o')さん、どうもです。
残念ながら、どっちかは分かりません。
CProgressCtrl::SetPos(5)
CProgressCtrl::SetPos(10)
:
CProgressCtrl::SetPos(100)
という更新をゆっくり行うと正常に表示されるからです。同じ更新を数秒ぐらいで行う
と、最初の5, 10辺りしか表示されません。
つまり、15以降の描画をする気があるんだけど、追いついていない(再描画されない)の
か、15以降の指定が無視されたのかは、プログレスバーのソースコードがない以上、不
明です。
> でもいまさらそんなバグある?
私も同感です。しかし、現象を見る限り、そう言いたくなってくるのも事実です。
もしかしたら、[ファイルのコピー]と[プログレスバーの更新]を同一スレッドで行って
いるために無理が生じているかもしれません。
一度、マルチスレッド化を行ってみたいと思います。
結果報告はまたさせていただきます。
> もしかしたら、[ファイルのコピー]と[プログレスバーの更新]を同一スレッドで行って
> いるために無理が生じているかもしれません。
> 一度、マルチスレッド化を行ってみたいと思います。
実は、昨日読んでいて言われているような事が気になりました。
Vistaは描画系がごっそり変わっているのでファイル処理の関係で
描画を後回しにされているのではないかなと。
ファイルコピー処理をどんな風に処理しているのかなと思ってました。
やり方にもよると思いますけれど、シングルスレッドで確実に描画を
させるのであれば、コピー処理を細分化してタイマーイベントを使って
毎回、OSの制御を返すようにしないとうまくいかないのではないかと
思います。
うーん
1. ファイルの処理関連をスレッド処理にする。
2.リアルタイムでなくなるかもしれないけど、
ある程度ファイル処理が進むまでプログレスバーを更新させない。
この2点行うと変わるんじゃないかと思いますが......
ファイル処理を優先させるのが大事だと思います。
う~ん??
当方で試してみたところ、どうやっても上記のような事は起こりませんが。。。
環境はVista(32bit) VS2005 SP1 MFCです (ダイアログアプリで実験)
因みに、
AeroをONにしてもOFFにしても同じ。
視覚テーマをVistaスタイル(緑色の立体プログレスバー)にしても
通常スタイル(ハイライトのプログレスバー)にしても同じ。
WindowsXPで正常に表示されていたのであれば一度、互換モードを
「Windows XP(ServicePack2)」
にして実行してみては?
メッセージループが別スレッドのようには読めないのですが、きちんと分けています
か?
確かメッセージループを受け持つスレッドで画面の更新をしても、描画メッセージ
が処理されるまでは確実に再描画されなかったように思います。
さらに描画メッセージのWM_PAINTはあらゆるメッセージの中で1、2を争うほど優
先度が低いとの話も聞いた覚えが有ります。
再描画域の問題も有る筈なので、再現は手間かも知れません。
「処理の合間合間にメッセージキューが空になるまでメッセージを処理する様書
く」「メッセージループスレッドとプログレスバーの更新等の処理スレッドを分け
る」ことはやっていますか?
やっているのならばのならこちらの誤解ですが、どうですか。
関係あるかどうか分かりませんが気になったことを。
アプリケーションウィザードの設定の
ユニコードライブラリを使用するのオンかオフかで、
ダイアログの見た目が変わります。
xpスタイルとvistaスタイル?
プログレスコントロールの見た目もかなり違います。
確認方法は
プログレスコントロールを貼り付け、メンバ変数を割り当てます
ボタン2つ追加して
1つめは
xxx.SetRange(0, 100);
xxx.SetPos(10);
2つめは
xxx.SetPos(100);
とします。
1つめのボタンを押し、2つ目のボタンを押し、動作を確認します。
ユニコードを使用しない方は、比較的SetPos()に忠実な動作のように見えます。
ユニコードを使用する方(デフォルトで緑色?)の方は
2つめのSetPos(100)で、SetPos(20)SetPos(30)SetPos(40)...SetPos(100)
とやったような動作をします。
この辺はOSのなんらかの設定が効いているのかもしれないし
昔も似たような動作だけど、すばやく増えていたので見えなかったのかもしれない
最近、プログレスコントロールを使ったら、アレって思ったもので。
> プログレスバーの更新速度がゆっくりの時は正確に表示されるのですが、更新速
> 度が速くなると、設定した値より小さな値を表示しています。
うーーん、
これを読む限りでは、プログレスバーの処理はうまくいっているんじゃないか
思います。
ただ、速い処理になった時にSetPos()で設定する数値が変化してないのでは?
位置データをPosと仮定
if(Pos == 10)
{
何らかのダミー処理
ここでブレイク
}
ここで止まりますか?
修正です(^^;
誤 if(Pos == 10)
正 if(Pos == 100)
※100は適切な値にして下さい。
追伸、
推測ですけど、
Vistaは、XPに比べてウインドウメッセージループの更新速度が遅いのかな?
私的にはVistaは表示の処理が重いのでXPの表示処理よりもスキップされる
閾値が低くてちょっと忙しくなると描画がスキップされてしまうのではないかと
思っていたりします。
中間報告です。
まず、みなさんの読み通り、プログレスバーが追従しない場合は、SetPos()の速度が速
い以外の条件がありました。
1つはWindows-XP用のルナスタイルのマニフェストがあててあり、このマニフェストを
消すと高速SetPos()でも追従するようになりました。
要は視覚テーマをVistaスタイル(緑色の立体プログレスバー)にしたときだけ追従しなく
なる感じです。
あと、マルチスレッド化ですが、かなり苦労しています。
本格的なマルチスレッドプログラミングは初めてで、メインスレッドと、ファイルコピ
ーを行うスレッド双方で複数のウィンドウを持ってしまっているため、うまくウィンド
ウ間の通信ができないようです。
もう少し頑張ってみます。
そんな感じです。
また、何か分かりましたら報告します。
マニフェスト絡みのようなので、こちらで試した
Vistaスタイルのマニフェスト(正常確認)を示しておきます。
<assembly xmlns=urn:schemas-microsoft-com:asm.v1 manifestVersion=1.0>
<assemblyIdentity version=1.0.0.0 processorArchitecture=x86
name=Microsoft.Winweb.HogeHoge.exe type=win32/>
<description>Description</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type=win32 name=Microsoft.Windows.Common-Controls
version=6.0.0.0 processorArchitecture=x86
publicKeyToken=xxxxxxxxxxxxxxxxxxx language=*/>
あと、ファイルコピーを別スレッドでするなら
コピーが1つ終わる度に、プログレスバーに対して
SendMessage(PBM_SETPOSかな?)を送ると簡単かもですね
ファイルコピーのスレッドはワーカースレッドにして
ウインドウは持たせないようにした方がすっきりすると思いますけれど、
何かコピースレッド側にウインドウを持たせないといけない訳があるんでしょうか?