C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: 画面切替をスムーズにしたい


(過去ログ 16 を表示中)

[トピック内 18 記事 (1 - 18 表示)]  << 0 >>

■6188 / inTopicNo.1)  画面切替をスムーズにしたい
  
□投稿者/ kyan (1回)-(2007/08/03(Fri) 17:34:52)

分類:[VB.NET/VB2005] 

VB2005です。
OS:XP Pro
メニュー画面からA画面を呼び出します。A画面が表示されたら、メニュー画面は終了します。
下記のイメージです。
[メニュー画面]
メニュー画面_Closed で、
hP = Process.Start("A画面.exe")
hP.WaitForInputIdle()
hP.Close()
hP.Dispose()

[A画面]
A画面_Load で
もろもろの初期処理後
Me.Show()
Me.Activate()
データベース読み込みなど。。。

(状況)
メニュー画面からA画面に切り替わる途中で、一瞬、裏画面が見えてしまいます。
@メニュー画面が終了する。
A裏(ディスクトップなど)が見える
BA画面が起動する。

つまり、A画面が表示しないうちに、WaitForInputIdle()が帰ってきてしまっていると思われます。
希望としては、Me.Activate()のところで、WaitForInputIdle()が帰ってきてほしい。
@メニュー画面が終了する。
AA画面が起動する。
同じEXE内で、フォームを切り替えているような動きにしたいわけです。

VB.NET 2003 の時は、上記の方法でスムーズに切り替わっていたのですが、
VB2005にしてから、どうもうまくいきません。

WaitForInputIdle() の後に
Call System.Threading.Thread.Sleep(1000)
で、無理やり、1秒待たせると、切り替わりはスムーズになりますが、
できれば、この方法は使いたくないです。

何かいい解決策をご教授ください。m(_)m

引用返信 編集キー/
■6190 / inTopicNo.2)  Re[1]: 画面切替をスムーズにしたい
□投稿者/ れい (28回)-(2007/08/03(Fri) 17:49:12)
No6188 (kyan さん) に返信
> 同じEXE内で、フォームを切り替えているような動きにしたいわけです。

A画面.exeも変更可能なのですか?
変更不可能なのですか?

変更可能ならプロセス間通信をきちんと行えばいいだけです。
いろいろ手はありますが、
Mutexを使うのが簡単かと思います。

A画面.exeが変更できないなら…
たぶん、プロセスがスタートしてまだ
メッセージキューが作成されてないから
WaitForInputIdleが
もどってきてしまうと思うので
戻り値を確認してみてください。
Trueになるまでループするといけるとおもいます。

VB2003で動いていたのはたまたまかと。

引用返信 編集キー/
■6192 / inTopicNo.3)  Re[2]: 画面切替をスムーズにしたい
□投稿者/ kyan (2回)-(2007/08/03(Fri) 17:56:30)
回答ありがとうございます。

No6190 (れい さん) に返信
> ■No6188 (kyan さん) に返信
>>同じEXE内で、フォームを切り替えているような動きにしたいわけです。
>
> A画面.exeも変更可能なのですか?
> 変更不可能なのですか?

変更可能です。

>
> 変更可能ならプロセス間通信をきちんと行えばいいだけです。
> いろいろ手はありますが、
> Mutexを使うのが簡単かと思います。

画面間の同期をとるように自作するということですね。
他に手がなければ、それでいきたいと思います。

>
> A画面.exeが変更できないなら…
> たぶん、プロセスがスタートしてまだ
> メッセージキューが作成されてないから
> WaitForInputIdleが
> もどってきてしまうと思うので
> 戻り値を確認してみてください。
> Trueになるまでループするといけるとおもいます。

戻り値は、TRUEが帰ってきています。

引用返信 編集キー/
■6194 / inTopicNo.4)  Re[3]: 画面切替をスムーズにしたい
□投稿者/ れい (29回)-(2007/08/03(Fri) 20:25:17)
No6192 (kyan さん) に返信
> 回答ありがとうございます。
>
> ■No6190 (れい さん) に返信
>>■No6188 (kyan さん) に返信
> >>同じEXE内で、フォームを切り替えているような動きにしたいわけです。
>>
>>A画面.exeも変更可能なのですか?
>>変更不可能なのですか?
>
> 変更可能です。
>
>>
>>変更可能ならプロセス間通信をきちんと行えばいいだけです。
>>いろいろ手はありますが、
>>Mutexを使うのが簡単かと思います。
>
> 画面間の同期をとるように自作するということですね。
> 他に手がなければ、それでいきたいと思います。
>
>>
>>A画面.exeが変更できないなら…
>>たぶん、プロセスがスタートしてまだ
>>メッセージキューが作成されてないから
>>WaitForInputIdleが
>>もどってきてしまうと思うので
>>戻り値を確認してみてください。
>>Trueになるまでループするといけるとおもいます。
>
> 戻り値は、TRUEが帰ってきています。
>

んー
そうなるとちょっとめんどうですね。

私はWaitForInputIdleとかWM_ENTERIDLEはあまりそんなにあてにしてないので、
私でしたらMutexを使います。
アプリが2重起動しないようにしたりするのと同じような感じで。

本当はなにか正しい方法があるような気がします。
識者募集。
引用返信 編集キー/
■6195 / inTopicNo.5)  Re[4]: 画面切替をスムーズにしたい
□投稿者/ とっちゃん (177回)-(2007/08/03(Fri) 21:15:49)
とっちゃん さんの Web サイト
WaitForInputIdle() ですが、こいつは、プロセスのプライマリスレッドのメッセージキューに対して
メッセージ問い合わせAPI(GetMessage API など)が呼ばれたタイミングで、待機状態から復帰します。

.NET アプリでいえば、Application.Run() に到達した時点で、WaitForInputIdle() から帰ってくる
と思っていて差し支えありません(Run() が実際にメッセージループに到達するまでのタイムラグはありますがw)。

なので、画面が表示されたとか、特定のメッセージがキューに入ってきたとかではありません。
#ちなみに、メッセージキューができたでもないのでご注意を


もし、A画面.EXEを修正してというのであれば、Application.Run() に入る前に
あらかた初期化処理を行っておくという段取りにするのがよいです。
#いままでLoadでやっていた表示直前の処理をもっと前のコンストラクタの直後に行うということ

ここまで抜本的な改定はかなり難しいということであれば、メニューEXE側で待機状態の直後に
動きを入れるのではなく、復帰した時点で一度自身のCPU実行時間を明け渡してやる(=Sleep(0)を呼ぶ)でも
だいぶ状況が変わります。

もちろん、れいさんの書いているようにプロセス間通信を行って同期処理を入れるというのもアリです。
が、こちらは、プロセスが表示前に何らかの理由で終わってしまったなどがあった場合に
無限待ちしてしまう可能性があるなど、別のエラーフォローが必要になるので
かなり面倒です。

ま、そのあたりはすでに盛り込まれてるとは思いますけどw

引用返信 編集キー/
■6199 / inTopicNo.6)  Re[5]: 画面切替をスムーズにしたい
□投稿者/ kyan (3回)-(2007/08/04(Sat) 00:52:33)
回答ありがとうございます。

No6195 (とっちゃん さん) に返信
> WaitForInputIdle() ですが、こいつは、プロセスのプライマリスレッドのメッセージキューに対して
> メッセージ問い合わせAPI(GetMessage API など)が呼ばれたタイミングで、待機状態から復帰します。
>
> .NET アプリでいえば、Application.Run() に到達した時点で、WaitForInputIdle() から帰ってくる
> と思っていて差し支えありません(Run() が実際にメッセージループに到達するまでのタイムラグはありますがw)。
>
> なので、画面が表示されたとか、特定のメッセージがキューに入ってきたとかではありません。
> #ちなみに、メッセージキューができたでもないのでご注意を

上記の説明で現象が理解できました。納得です。

>
> もし、A画面.EXEを修正してというのであれば、Application.Run() に入る前に
> あらかた初期化処理を行っておくという段取りにするのがよいです。
> #いままでLoadでやっていた表示直前の処理をもっと前のコンストラクタの直後に行うということ

今は、作業できないので、来週月曜日に試してみます。
あとで、結果を報告します。

>
> ここまで抜本的な改定はかなり難しいということであれば、メニューEXE側で待機状態の直後に
> 動きを入れるのではなく、復帰した時点で一度自身のCPU実行時間を明け渡してやる(=Sleep(0)を呼ぶ)でも
> だいぶ状況が変わります。
>
> もちろん、れいさんの書いているようにプロセス間通信を行って同期処理を入れるというのもアリです。
> が、こちらは、プロセスが表示前に何らかの理由で終わってしまったなどがあった場合に
> 無限待ちしてしまう可能性があるなど、別のエラーフォローが必要になるので
> かなり面倒です。

ありがとうございました。参考になりました〜〜
引用返信 編集キー/
■6200 / inTopicNo.7)  Re[5]: 画面切替をスムーズにしたい
□投稿者/ れい (30回)-(2007/08/04(Sat) 00:55:30)
No6195 (とっちゃん さん) に返信
> WaitForInputIdle() ですが、こいつは、プロセスのプライマリスレッドのメッセージキューに対して
> メッセージ問い合わせAPI(GetMessage API など)が呼ばれたタイミングで、待機状態から復帰します。
>
> なので、画面が表示されたとか、特定のメッセージがキューに入ってきたとかではありません。
> #ちなみに、メッセージキューができたでもないのでご注意を

あれれ?
私はよく理解してないようですね。

「GetMessageが呼ばれて且つメッセージキューが空の時」
に戻ると思ってたんですが、
そうではなく、
「GetMessageが呼ばれた時」
に戻るのでしょうか?

それとも、
「最初にGetMessageが呼ばれた時」(=メッセージキューが作成された時)
はキューは空だから
すでに待ってるWaitForInputIdleがあれば、
ここで戻るという意味でしょうか?

でも最後のはありえないし、とっちゃんさんに否定されてもいますね。

A画面.exeのメッセージキューが出来てから、
メッセージループに入る前、なにかいろいろ初期化している間に
WaitForInputIdleが呼ばれてしまっているので戻り値trueで即復帰するのかと思いましたが、
違うのかな?あってるのかな?

(最近人の言うことが一回で理解できません。やばいな…。
引用返信 編集キー/
■6212 / inTopicNo.8)  Re[6]: 画面切替をスムーズにしたい
□投稿者/ kyan (4回)-(2007/08/06(Mon) 11:25:59)
とっちゃんさんのご意見をもとに、改造実施してみましたが、結論をいいますと、どうもうまくいかないです。
<実施内容>
A画面(メニューから呼ばれる画面)で、Application.Run の前に
イニシャル処理、フォームの表示を行うようにしました。
下記参照

<STAThread()> _
Protected Shared Sub Main()
Application.EnableVisualStyles()
Application.DoEvents()
Dim frm As New frmTEST
Call frm.Init() '←これは、イニシャル処理(自作のサブ)
frm.Show()
Application.DoEvents()
Application.Run(frm)
End Sub

結果は、Form_Load でイニシャル処理、フォームの表示を行った時と変わらず、バックが表示されてしまいました。

あと、メニュー画面で、WaitForInputIdle() 後、Sleep(0) を入れてみました。
これも、入れる前と後で、特に変化はないようです。

何が悪いのか教えてください〜><

お助けください m(_)m
引用返信 編集キー/
■6218 / inTopicNo.9)  Re[1]: 画面切替をスムーズにしたい
□投稿者/ まどか (353回)-(2007/08/06(Mon) 13:18:33)
> [メニュー画面]
> メニュー画面_Closed で、

そもそも「閉じた後で」やってますね。
FormClosingでやるとか。
#FormClosedではなくClosedでやってるからというオチはあり?
引用返信 編集キー/
■6220 / inTopicNo.10)  Re[6]: 画面切替をスムーズにしたい
□投稿者/ とっちゃん (178回)-(2007/08/06(Mon) 13:45:48)
とっちゃん さんの Web サイト
No6200 (れい さん) に返信

> 「GetMessageが呼ばれて且つメッセージキューが空の時」
> に戻ると思ってたんですが、
> そうではなく、
> 「GetMessageが呼ばれた時」
> に戻るのでしょうか?
>
もっと正確に書けば、メッセージキューに問い合わせが行われるタイミングで
(GetMessageだけでなく、PeekMessage や MsgWaitFor... などもあります)
WaitForInputIdle の待ちが解除状態になります。

で、その後適切なタイミング(要するにまってる側にCPU時間が割り当てられる)で
動き始めます。

現在のWin32 は、CPUが一つでもタイムスライスを小さくしているので
ほぼ並行して走ります。

なので、結果的にはGetMessage() が呼ばれた直後くらいのタイミングで
動き始めるという形になります。

ちなみに、メッセージキューができるのはもっと手前で、
CreateWindow されたタイミング(がほとんど)と言ってよいでしょう。

WaitForInputIdleは、キューが作られたじゃなくて、
キューに問い合わせに行けるようになった(=通常のメッセージループに入ったと解釈)
でもう待ってなくてもいいだろう!
という形で用意されています。

このあたりは昔の名残ですが、昔はアプリ起動時のウィンドウの作られ方が

CreateWindow();
ShowWindow();
UpdateWindow();

メッセージループへ
という流れだったことから考えれば至極当然ではないかと思われます。
.NET だからどうとかなんてのが考慮されるとすれば、もっとOSのそれも
かなり深い部分でテコ入れされない限りは無理でしょう。


> A画面.exeのメッセージキューが出来てから、
> メッセージループに入る前、なにかいろいろ初期化している間に
> WaitForInputIdleが呼ばれてしまっているので戻り値trueで即復帰するのかと思いましたが、
> 違うのかな?あってるのかな?
>
A画面exe はそれはそれで独自のプロセスであるというのも同期処理では重要です。
コンテキストの基本分割単位はプロセス単位ですので、優先順位の高い(アクティブな)プロセスに
より多くのCPU時間が割り当てられます。

また、待機状態になることで優先順位が下がるということもありません(これも重要)。
なので、どのタイミングで処理が走り始めるのか、いつ待機状態にするのか、などなど
結構微妙なタイミング調整は発生しえますよ。

極端な話、ウィンドウがあっても見えないままいろいろやってるソフトもありますし
ウィンドウを作る前にいろいろやるものもある。

引用返信 編集キー/
■6221 / inTopicNo.11)  Re[2]: 画面切替をスムーズにしたい
□投稿者/ とっちゃん (179回)-(2007/08/06(Mon) 13:49:09)
とっちゃん さんの Web サイト
No6218 (まどか さん) に返信
>>[メニュー画面]
>>メニュー画面_Closed で、
>
> そもそも「閉じた後で」やってますね。
> FormClosingでやるとか。
> #FormClosedではなくClosedでやってるからというオチはあり?

No6212 でまだ遅いってのは、まどかさん指摘の問題でしょう。
Closed ってことはウィンドウ閉じちゃった「あと」になるので、
当然画面からは「すでに消えている」タイミングになります。

なので、消える前に動き始めていないと、消える->でるのタイムラグは減りませんよ。

引用返信 編集キー/
■6227 / inTopicNo.12)  Re[3]: 画面切替をスムーズにしたい
□投稿者/ まどか (354回)-(2007/08/06(Mon) 14:27:34)
個人的にはプロセス同士に依存性を持たせたり、完璧を求め小細工をしたりをしないほうがよいと思っています。
#基本は「あとはまかせたぞ」
それより小細工したせいで起動先がアクティブにならない(前面だがタイトルバー色が薄い)現象のほうが弊害が大きいと思います。

ショートカット2つをダブルクリックした後にどちらが前面になるかはわからない、というのが大前提ですし、
これを解決するにはとっちゃんさんの言われるようにOSが仕組みとして提供しない限り無理ではないでしょうか。
で、Sleepで十分な間隔をあけるのが一番現実的な解だったり。。。
引用返信 編集キー/
■6229 / inTopicNo.13)  Re[4]: 画面切替をスムーズにしたい
□投稿者/ kyan (5回)-(2007/08/06(Mon) 15:09:01)
2007/08/06(Mon) 15:45:24 編集(投稿者)


とっちゃん、まどかさん、いろいろご指摘ありがとうございます。

Form_Closing でやっても結果は同じでした。

いろいろトライしてみたのですが、満足いく結果が出なかったので、
結局、れいさんの回答にならって、プロセス間同期処理を自作しました。

以下は、自己レスです・・・

自分の場合、Semaphore を使いました。下記にイメージだけ

メニュー画面
Semaphore を作成。初期値=0、最大値=1で作成

A画面を起動する
Sleep(0) '不要かも?
WaitOne(5000, False) で待機。←5秒をタイムアウトとする。呼び出し画面が無応答の場合を考慮

A画面
Me.Show()
Me.Activate()

の後で、

Semaphore をオープン(オープンできない場合を考えて、Try Catch しておく)

Semaphore のRelease

めんどくさい方法ですが、悩んでる時間がないので、上記でやることにしました。

どうもありがとうございました。m(_)m

解決済み
引用返信 編集キー/
■6235 / inTopicNo.14)  Re[7]: 画面切替をスムーズにしたい
□投稿者/ れい (33回)-(2007/08/06(Mon) 15:56:43)
No6220 (とっちゃん さん) に返信
> ■No6200 (れい さん) に返信
>
>>「GetMessageが呼ばれて且つメッセージキューが空の時」
>>に戻ると思ってたんですが、
>>そうではなく、
>>「GetMessageが呼ばれた時」
>>に戻るのでしょうか?
>>
> もっと正確に書けば、メッセージキューに問い合わせが行われるタイミングで
> (GetMessageだけでなく、PeekMessage や MsgWaitFor... などもあります)
> WaitForInputIdle の待ちが解除状態になります。

読解力がなくて申し訳ないんですが、
これは後者を肯定する返事でしょうか?
つまり、メッセージキューが空でなくても、
WaitForInputIdleは戻るということですか?

MSDN Process.WaitForInputIdleより。
>関連付けられたプロセスがアイドル状態になるまで、Process コンポーネントを無期限に待機させます。
>(略
>WaitForInputIdle を使用して、メッセージ ループがアイドル状態に戻るまで、アプリケーションの処理を強制的に待機させます。
>(略
>プロセスがメッセージ ループ内部のメッセージを待機している状態をアイドル状態と呼びます。

この説明はだと私にはキューが空でないときは空になるまで待機するように読めます。


引用返信 編集キー/
■6237 / inTopicNo.15)  Re[8]: 画面切替をスムーズにしたい
□投稿者/ れい (34回)-(2007/08/06(Mon) 16:22:05)
No6235 (れい さん) に返信
> ■No6220 (とっちゃん さん) に返信
>>■No6200 (れい さん) に返信
>>
> >>「GetMessageが呼ばれて且つメッセージキューが空の時」
> >>に戻ると思ってたんですが、
> >>そうではなく、
> >>「GetMessageが呼ばれた時」
> >>に戻るのでしょうか?
> >>
>>もっと正確に書けば、メッセージキューに問い合わせが行われるタイミングで
>>(GetMessageだけでなく、PeekMessage や MsgWaitFor... などもあります)
>>WaitForInputIdle の待ちが解除状態になります。
>
> 読解力がなくて申し訳ないんですが、
> これは後者を肯定する返事でしょうか?
> つまり、メッセージキューが空でなくても、
> WaitForInputIdleは戻るということですか?

試してみました。

WaitForInputIdleは
プロセスが始まって初めて、空のメッセージキューに読み取りがあるまで待つようです。
一回戻ると、それ以降はキューにメッセージがあってもなくても直ちに戻ります。

ですから、メッセージループに入っても、
すぐに戻るわけではないようですし、
GetMessageを呼べば処理が戻るわけでもないようです。

ウィンドウを作ると(RegisterClass、CreateWindowなどを呼ぶと)
キューにWM_CREATEとかWM_PAINTなどが溜まるので、
これらをメッセージループで処理し、キューが空になった時に
WaitForInputIdleは処理がもどります。

私はずっと空のキューに読み取りがあったときに戻るのだと思っていました。
つまり、起動時以外にもプロセスが暇かどうかチェックできるのではないかと。
この仕様だと、起動処理が終了したかどうかのチェックしかできませんね。

No6220 (とっちゃん さん) に返信
>ちなみに、メッセージキューができるのはもっと手前で、
>CreateWindow されたタイミング(がほとんど)と言ってよいでしょう。

User32.dllやgdi32.dllが初めて呼ばれた際に作られますから、
普通はRegisterClassでは?
引用返信 編集キー/
■6244 / inTopicNo.16)  Re[8]: 画面切替をスムーズにしたい
□投稿者/ とっちゃん (180回)-(2007/08/06(Mon) 20:04:47)
とっちゃん さんの Web サイト
>プロセスが始まって初めて、空のメッセージキューに読み取りがあるまで待つようです。
ほぅ、なるほど。おいらの認識がちょっと甘かったみたいです。すいませんでした。



>User32.dllやgdi32.dllが初めて呼ばれた際に作られますから、
>普通はRegisterClassでは?
いや、USER/GDIのAPIが呼ばれたからキューを作るということはないです。
メッセージキューは、ないとその後の処理が困るものを呼び出して初めてキューが作られます。

なので極端な話、ウィンドウを作らずに、GetMessage() してもキューは作られます。
#そうじゃなきゃ、OLEサーバーとか困っちまいますからw

ですが、SendMessage/PostMessage で自分以外のスレッドのウィンドウあてにメッセージを送っても
キューが作成されることはないと思います(キューの有無を判断する方法がないのでわかりませんが)。

後者は、ワーカースレッドで不必要にキューを作らないようにしておかないと、
たくさんのスレッドを作成するプログラムで、必要のないキューを山ほど作り上げてしまう
ということから考えても、ほぼ確実と言えます。

ま、実装詳細がわからんので、本当のところどうなのか?というのはわからんのですが。

引用返信 編集キー/
■6247 / inTopicNo.17)  Re[9]: 画面切替をスムーズにしたい
□投稿者/ れい (35回)-(2007/08/06(Mon) 22:00:19)
No6244 (とっちゃん さん) に返信
> >User32.dllやgdi32.dllが初めて呼ばれた際に作られますから、
> >普通はRegisterClassでは?
> いや、USER/GDIのAPIが呼ばれたからキューを作るということはないです。
> メッセージキューは、ないとその後の処理が困るものを呼び出して初めてキューが作られます。
>
> なので極端な話、ウィンドウを作らずに、GetMessage() してもキューは作られます。
> #そうじゃなきゃ、OLEサーバーとか困っちまいますからw
>
> ですが、SendMessage/PostMessage で自分以外のスレッドのウィンドウあてにメッセージを送っても
> キューが作成されることはないと思います(キューの有無を判断する方法がないのでわかりませんが)。

キューがあるかないかは、
他のスレッドからPostThreadMessageを呼べばわかります。
キューがなければGetLastErrorがERROR_INVALID_THREAD_IDを返します。

この方法で調べてみたのですが、
驚いたことに、
SendMessageやPostMessgeでもRegisterClassでもキューが作成されています。

>後者は、ワーカースレッドで不必要にキューを作らないようにしておかないと、
>たくさんのスレッドを作成するプログラムで、必要のないキューを山ほど作り上げてしまう
>ということから考えても、ほぼ確実と言えます。

たくさんのワーカースレッドを使うときには
SendMessageやPostMessageで通信してはいけない
ということのようです。
引用返信 編集キー/
■6268 / inTopicNo.18)  Re[10]: 画面切替をスムーズにしたい
□投稿者/ とっちゃん (181回)-(2007/08/07(Tue) 11:23:53)
とっちゃん さんの Web サイト
No6247 (れい さん) に返信
> キューがあるかないかは、
> 他のスレッドからPostThreadMessageを呼べばわかります。
> キューがなければGetLastErrorがERROR_INVALID_THREAD_IDを返します。
>
あら、そうなんですか。そいつは知らんかった...

> この方法で調べてみたのですが、
> 驚いたことに、
> SendMessageやPostMessgeでもRegisterClassでもキューが作成されています。
>
えっと、RegisterClass はいずれウィンドウが作られるであろうことから考えれば
その時点でキューを起こしちゃっても問題はないでしょうけど...

SendやPostでもキューが作られちゃうんですか?HWND = NULL ということはないですよね?
#HWND=NULLだと自スレッドにも当てられちゃうので...

> たくさんのワーカースレッドを使うときには
> SendMessageやPostMessageで通信してはいけない
> ということのようです。
がーん(T_T)
ってことは、寿命の長いスレッドからメッセージ投げちゃうのはやばいということですね。

覚えておこ( ..)φメモメモ
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -