HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2008
1230
わっしいタスクバーの「すべてを閉じる」をすると、終了時の処理を2回する8解決


わっしい

リンク

2008/12/30(Tue) 13:15:06|NO.22097

私が以下に示します現象は、

・ウインドウを2つ開く。
・終了時に「大きさが可変であるウインドウID = 1 の大きさや表示位置(システム変数)を
ファイルに保存する」という処理がある。

というスクリプトの場合、
画面下のタスクバーの「すべてを閉じる」で終了させますと、
「終了時の処理に2回来て、システム変数の値がおかしい」
というものです。


なぜ「終了時の処理に2回来る」という起こるのでしょうか?
さらにこの現象は、終了時の処理に wait 命令を置きますと起こらなくなります。
これもなぜなのでしょうか?
わかる方、ご教授をおねがい致します。


下に挙げましたサンプルスクリプトでやってみます。
終了時にファイルをつくりますので、テスト用のフォルダ内で行われたほうがよいかもしれません。

これを起動しまして(スクリプトエディタから又は実行ファイルどちらでもいいです)、
まずはウインドウ右上のクローズボタンで終了させてください。
SAVEDATA0 というファイルが作られます。
これは問題ありません。

つぎに、同じように起動します。
SAVEDATA0 の内容が「ウインドウ0」に表示されます。

こんどは画面下のタスクバーのアイコンを右クリックしますと出てきます
「すべてを閉じる」で終了させてみてください。

「すべてを閉じる」は、デスクトップ上に複数のウインドウ(フォルダやテキストエディタなど)
が開いていると、現れるようになります。
環境によっては現れないかもしれません(私の環境は WindowsXP SP2 です)。

すると、SAVEDATA0 と SAVEDATA1 の2つのファイルが作られます。

これは、下のサンプルスクリプトの *exit_routine 以下に2回来たということになります
(「2回来た」ということを示すために、下のサンプルスクリプトでは
作成するファイルのファイル名に番号を付けるようにしています)。

さらにもういちど同じように起動しますと、
SAVEDATA0 の内容が「ウインドウ0」に、SAVEDATA1 の内容が「ウインドウ1」に表示されます。
しかし SAVEDATA1 の内容がおかしな値になっています。

私の環境では、
winx = 12
winy = 4215791
wx1 = 0
wy1 = 10814592
になっていました。

ファイル名につけた番号から、SAVEDATA1 の方があとに作られています。
通常は、終了時に保存するファイル名は1つですので、
上の例は「保存するファイルは、システム変数のおかしな値のほうで上書きされる」
ということを示してもいます。


この現象は、終了時の処理に wait 命令を置くと、発生しなくなります。

ラベル *exit_routine の下のコメント(wait 命令)を復活させて、
SAVEDATA0 と SAVEDATA1 を消去して、
同じようにタスクバーの「すべてを閉じる」で終了させてみてください。

こんどは SAVEDATA0 しか作られません。
終了時の処理には1回しか来ていないことになります。
もういちど起動させますと、ファイル内容もおかしな値にはなっていません。


;サンプルスクリプト==============================================================

;ウインドウを2つ作る-----------------------------------
#define WIN_SIZE_X 200
#define WIN_SIZE_Y 300

#define WIN0_X1 0
#define WIN0_Y1 0

#define WIN1_X1 220
#define WIN1_Y1 0

screen 0, WIN_SIZE_X, WIN_SIZE_Y, 0, WIN0_X1, WIN0_Y1
title "ウインドウ0"
color 0, 0, 0
boxf 0, 0, WIN_SIZE_X - 1, WIN_SIZE_Y - 1

screen 1, WIN_SIZE_X, WIN_SIZE_Y, 0, WIN1_X1, WIN1_Y1
title "ウインドウ1"
color 0, 0, 0
boxf 0, 0, WIN_SIZE_X - 1, WIN_SIZE_Y - 1
;---------------------------------------------------------


;ファイルを読み込んで、表示-----------------------------------
dim savedata, 4

exist "SAVEDATA0"
if (strsize == 16) {
bload "SAVEDATA0", savedata
gsel 0
color 255, 255, 255
pos 0, 0
mes "winx = " + savedata(0)
mes "winy = " + savedata(1)
mes " wx1 = " + savedata(2)
mes " wy1 = " + savedata(3)
}

exist "SAVEDATA1"
if (strsize == 16) {
bload "SAVEDATA1", savedata
gsel 1
color 255, 255, 255
pos 0, 0
mes "winx = " + savedata(0)
mes "winy = " + savedata(1)
mes " wx1 = " + savedata(2)
mes " wy1 = " + savedata(3)
}
;---------------------------------------------------------


onexit goto *exit_routine ;クローズボタンを押されたときの飛び先をセット

fileno = 0


;メインループ------------------------------------
while
wait 20
wend
;-------------------------------------------------


*exit_routine
; wait 10

;システム変数をファイルに保存------------------------------------
dim savedata, 4

gsel 1 ;ウインドウID = 1 の
savedata(0) = ginfo_winx ;縦横サイズ
savedata(1) = ginfo_winy ;
savedata(2) = ginfo_wx1 ;表示位置 左上(x, y)
savedata(3) = ginfo_wy1 ;

bsave "SAVEDATA" + fileno, savedata ;を保存
fileno += 1
;---------------------------------------------------------


end

;サンプルスクリプト==============================================================



この記事に返信する


シモン

リンク

2008/12/30(Tue) 14:47:17|NO.22098

確認してみました。
確認環境:Windows2000 SP4+最新パッチ+TaskbarMod2K
XPと同等にウインドウがグループ化されると考えてください。

状況が再現されましたので単純化して実験してみました。


/* ;メインループ------------------------------------ while wait 20 wend ;------------------------------------------------- */ stop


起動してタスクバーの「すべてを閉じる(TaskBarModの場合グループをすべて閉じる)」で終了しました。

すると、以下のようになりました。
(何度か行いましたが再現性あり)

  ウインドウ0が閉じる

  少しタイムラグ(1秒ぐらい:環境によってはもっと早いかも?)

  ウインドウ1が閉じる。



waitのヘルプを見ると(ご存知だとは思いますが)
  HSPでは、他のWindowsタスクに処理時間を渡すために長い時間ループが起こる
  可能性がある場所にはwaitかawait命令を入れることを推奨しています。

なので、まさに上の状況で終了時に「長い時間のループ」が発生しているのではないでしょうか?



わっしい

リンク

2008/12/30(Tue) 17:10:09|NO.22099

テストとアドバイスをしていただき、ありがとうございました。

私もやってみました。
少しタイムラグがあって閉じるのは、何10回かに1回でしたが、ありました。
ですがそれ以外のときは、ほぼ同時に閉じているように見えました。

シモンさんにアドバイスいただいたこともふくめて考えますと、以下のことが言えそうです。

スクリプト内の wait 命令の箇所で、
HSPや Windows が他のWindowsタスクに処理を渡したりその他いろんなことを行って、
ふたたび wait 命令のつぎの行へもどって来たときは、
終了時の処理を呼ぶのが1回になる。

ここから先は wait 命令によってHSPや Windows が他のWindowsタスクに処理を渡すこと
以外に何をおこなっているかがわからなければ、
終了時の処理を2回呼ぶ原因が分からないかもしれません。


もう1つサンプルスクリプトを挙げます。
開くウインドウを3つにしただけです。

同じように「すべてを閉じる」で終了させてみてください。
wait がある場合は SAVEFILE0 しか作られませんが(正常終了)、
wait がない場合は SAVEFILE0〜2 の3つが作られ、SAVEFILE2 のみ
システム変数が変な値になっています。

これはシモンさんによる変更(メインループをコメントにして、stop のみにする)
をした場合でも同じでした。

このことから以下のようなことが予想されるのですが、いかがでしょうか?

wait なしで「すべてを閉じる」をしたばあい、ウインドウIDの高いほうから閉じていく。
上の例ですと、
1.ウインドウ2を閉じるまえに終了時の処理を呼び、ウインドウ2を閉じる。
2.ウインドウ1を閉じるまえに終了時の処理を呼び、ウインドウ1を閉じる。
3.ウインドウ0を閉じるまえに終了時の処理を呼び、ウインドウ0を閉じる。

3.のとき、gsel 1 のシステム変数を保存しようとしているが、
ウインドウID = 1 はすでに2で閉じているから、おかしな値が得られた。

wait を入れると、HSPや Windows によって何らかの処理が追加され、
1.が終わった時点ですべてのウインドウが閉じられる。


;サンプルスクリプト その2===========================================================

;ウインドウを3つつくる-----------------------------------
#define WIN_SIZE_X 200
#define WIN_SIZE_Y 300

#define WIN0_X1 0
#define WIN0_Y1 0

#define WIN1_X1 220
#define WIN1_Y1 0

#define WIN2_X1 440
#define WIN2_Y1 0

screen 0, WIN_SIZE_X, WIN_SIZE_Y, 0, WIN0_X1, WIN0_Y1
title "ウインドウID = 0"
color 0, 0, 0
boxf 0, 0, WIN_SIZE_X - 1, WIN_SIZE_Y - 1

screen 1, WIN_SIZE_X, WIN_SIZE_Y, 0, WIN1_X1, WIN1_Y1
title "ウインドウID = 1"
color 0, 0, 0
boxf 0, 0, WIN_SIZE_X - 1, WIN_SIZE_Y - 1

screen 2, WIN_SIZE_X, WIN_SIZE_Y, 0, WIN2_X1, WIN2_Y1
title "ウインドウID = 2"
color 0, 0, 0
boxf 0, 0, WIN_SIZE_X - 1, WIN_SIZE_Y - 1
;---------------------------------------------------------


;ファイルを読み込んで、表示-----------------------------------
dim savedata, 4

exist "SAVEDATA0"
if (strsize == 16) {
bload "SAVEDATA0", savedata
gsel 0
color 255, 255, 255
pos 0, 0
mes "winx = " + savedata(0)
mes "winy = " + savedata(1)
mes " wx1 = " + savedata(2)
mes " wy1 = " + savedata(3)
}

exist "SAVEDATA1"
if (strsize == 16) {
bload "SAVEDATA1", savedata
gsel 1
color 255, 255, 255
pos 0, 0
mes "winx = " + savedata(0)
mes "winy = " + savedata(1)
mes " wx1 = " + savedata(2)
mes " wy1 = " + savedata(3)
}

exist "SAVEDATA2"
if (strsize == 16) {
bload "SAVEDATA2", savedata
gsel 2
color 255, 255, 255
pos 0, 0
mes "winx = " + savedata(0)
mes "winy = " + savedata(1)
mes " wx1 = " + savedata(2)
mes " wy1 = " + savedata(3)
}
;---------------------------------------------------------


onexit goto *exit_routine ;クローズボタンを押されたときの飛び先をセット

fileno = 0


;メインループ------------------------------------
while
wait 20
wend
;-------------------------------------------------

;stop


*exit_routine
; wait 20

;システム変数をファイルに保存------------------------------------
dim savedata, 4

gsel 1 ;ウインドウID = 1 の
savedata(0) = ginfo_winx ;縦横サイズ
savedata(1) = ginfo_winy ;
savedata(2) = ginfo_wx1 ;表示位置 左上(x, y)
savedata(3) = ginfo_wy1 ;

bsave "SAVEDATA" + fileno, savedata ;を保存
fileno += 1
;---------------------------------------------------------


end

;サンプルスクリプト その2===========================================================



シモン

リンク

2008/12/30(Tue) 19:03:55|NO.22100

私の環境は世代で考えると二世代前の骨董品なので…

ところで、メインループをコメントアウトして確認したところ、
私の環境では、なぜかウインドウ1が最初に閉じます。

起動して閉じてから次に起動したとき
///////////////
ウインドウ0に

winx = 200
winy = 300
wx1 = 0
wy1 = 0

///////////////
ウインドウ1とウインドウ2

winx = 12
winy = 4215791
wx1 = 0
wy1 = 1396408

///////////////

*exit_routine の終了処理

gsel 0

に変更した場合

起動して閉じてから次に起動したとき
///////////////
ウインドウ0とウインドウ1

winx = 200
winy = 300
wx1 = 0
wy1 = 0

///////////////
ウインドウ2

winx = 12
winy = 4215791
wx1 = 0
wy1 = 1396408

///////////////

*exit_routine の終了処理

gsel 2

に変更した場合
起動して閉じてから次に起動したとき
///////////////
ウインドウ0とウインドウ1とウインドウ2

winx = 200
winy = 300
wx1 = 0
wy1 = 0

///////////////

上の結果を見ると
私の環境ではウインドウ1>0>2

という感じでウインドウが閉じているようですね(^^;


どの場合も0回目の正常に値がとれているときには
指定したウインドウの値が取れているようですから

まったく予想されている通りなのだとおもいます。



わっしい

リンク

2008/12/30(Tue) 21:59:56|NO.22107

再びためしてくださいまして、ありがとうございます。


これまでのことをまとめておきます。

今回こちらで挙げさせていただきました問題点は以下のようなものです。

・ウインドウを2つ以上開いている。
・「onexit goto *exit_routine」をつかって、終了時にシステム変数
(ginfo_winx/y と ginfo_wx1/y1)を参照(さらにはファイル保存)している。
というスクリプトでは、
「タスクバーの”すべてを閉じる”で終了」した場合に、
そのシステム変数の正常な値が得られない。

回避方法は、
・「*exit_routine」の次の行に「wait 20」を置く。
です。


>ところで、メインループをコメントアウトして確認したところ、
>私の環境では、なぜかウインドウ1が最初に閉じます。
私も同じようにやってみました。
ウインドウが閉じるのに時間差があるときは、
なぜかたまにしか起きなかったのですが(2回まで起こしました)、
その2回ともウインドウ2が最初に閉じていました。


前に書きました私の予想が間違っているかもしれないですが、以下このまま考えていきます。

シモンさんの環境で試してくださいました3通りの結果と私のとを比べてみます。

(*exit_routine 内の)gsel 1 のとき…
シモンさんの環境:
SAVEFILE1 と SAVEFILE2 が変な値
私の環境:
SAVEFILE2 のみ変な値

gsel 0 のとき…
シモンさんの環境:
SAVEFILE2 のみ変な値
私の環境:
3ファイルとも正常な値

gsel 2 のとき…
シモンさんの環境:
3ファイルとも正常な値
私の環境:
SAVEFILE1 と SAVEFILE2 が変な値


これらから以下のことが言えます。

1.環境によってウインドウが閉じられる順番がちがう
(シモンさんの環境では ID = 1→0→2、私の環境では ID = 2→1→0)。
2.どちらの環境でも、最初に保存するときは、正常な値が得られている。

シモンさんが試してくださったおかげで、1.のような貴重なことを知ることができました。
私の環境の結果だけでは予想もしていないことでした。
ありがとうございました。

また2.から、2つ目の回避方法としまして
「*exit_routine 以下では、来た回数をカウントして、最初のときのみファイル保存する」
という手も考えられますが、
そのほかさまざまな環境で試していないので、2.はまだ断言できないように思えます。
よって、この2つ目の回避方法は使わないほうがいいかと思いますが、どうでしょうか?


また、今回挙げました問題点は、
「終了のしかたによっては、2回以上終了処理に来て、正常なシステム変数が得られないことがある」
というHSPのバグのようにも思えますが、どうでしょうか?



シモン

リンク

2008/12/30(Tue) 23:09:11|NO.22108

この現象をHSPのバグと判断するには情報が足りないのではないかと思います。

このように考える理由は、

1.私の環境が特殊である。

2.状況を見ると「タスクバーの”すべてを閉じる”で終了」した場合に、
ウインドウズがごく短時間に「ウインドウ」に対してその数だけ
終了コードを連続して投げていることが問題の本質のような気がする。

HSPでいえばrepeatもしくはwhile中にwaitなしで「終了命令」を
「Windows」が一気に投げているのではないかということです。

3.回避方法がある。


もし、上の2の予想通りだとすると、
他のプログラム言語でも同じことが起きる可能性がありますよね。
他のプログラム言語でも発生するなら「Windows」のバグかも?です。

もしかしたら、他の言語で組まれて発生しないことは確認済みなのかもしれませんが…

> 回避方法は、
> ・「*exit_routine」の次の行に「wait 20」を置く。
> です。

ちなみに、私の環境では、
「*exit_routine」の次の行に「wait 1」(10ms)
でも正常動作しました。


「タスクバーの”すべてを閉じる”で終了」する
ということは、ソフトを終了するのですから
回避方法の「wait」命令を入れればいいのではないかと思います。
なにか、「wait」命令をはさむとまずいことが発生するのでしょうか?



わっしい

リンク

2008/12/31(Wed) 02:08:40|NO.22110

私が回避方法としまして「wait 命令を入れる」と書きましたが、
wait を入れておりますと再起動または電源OFFのシャットダウン処理が
中断されるようになります。

HELPの onexit の項をよく読んでおりませんでした
(シモンさんをはじめ、皆さますみませんでした)。

シャットダウン処理を中断されたくない場合は「wait 命令を入れる」は使えないようです。


なお、これまでに挙げました「サンプルスクリプト」と「サンプルスクリプト その2」を
起動させ、Windows を再起動させますと、
前者は SAVEFILE0〜1 が、後者は SAVEFILE0〜2 がつくられ、
どれも正常な ウインドウID = 1 の大きさと位置が保存されていました。

つまり、再起動のときも”終了時の処理”を3回呼んではいるが、
「すべてを閉じる」のときのようにシステム変数が変な値になっていない、
ということです。

ですが「タスクバーで”すべてを閉じる”」をしたときは、
システム変数が変な値になっていました。


なぜ「タスクバーで”すべてを閉じる”」のときは、システム変数が変な値になることが
あるのでしょうか?
やはり、この時だけは ウインドウID = 1 のウインドウが閉じられているからなのでしょうか。

逆に言いますと「特定のウインドウID のウインドウが存在しているかどうか」を知る方法は
あるのでしょうか?

わかる方、ご教授くださいませ。


質問がタイトルと変わってしまいましたので、とりあえずこの質問は「解決」にしておきます。



シモン

リンク

2008/12/31(Wed) 04:31:06|NO.22111

私も「onexit」のヘルプをよく読んでいなかったので
時間を取らせてしまったかもしれません。
これを書き込んでいるときには同じ結果にたどり着いた後だと思いますが、書いておきます。


問題は、「onexit」が「タスクバーで”すべてを閉じる”」したときに
「ウインドウの数だけ終了の命令が飛んでくる=ウインドウの数だけ割り込み発生」
なのではと考えました。

確認環境1
Windows2000 SP4+最新パッチ+TaskBarMod2K

確認環境2
IBM ThinkPad R40
OS:WindowsXP Pro SP3


以下の部分だけ変えてEXE実行ファイルを作成して実験

//////////////
*exit_routine
; wait 20

//////////////
*exit_routine
onexit 0 ;一時的に割り込みを停止

必要なら「end」の前に「onexit 1」をつける
//////////////

二つの確認環境で同じ結果になりました。

「wait」のほうは再起動失敗、
SAVEDATA0のみ作成されている。
データ内容OK


「onexit」は再起動成功!
SAVEDATA0のみ作成されている。
データ内容OK

つまり、Windowsによる割り込みを一時停止させればいいのですよね。

それと、再起動するなどの情報は最初に書いておかないと…

「わっしい」さん、今回は私の方も勉強させていただきました、
どうもありがとうございました。



わっしい

リンク

2008/12/31(Wed) 15:10:06|NO.22119

二つの環境での動作チェック、ありがとうございました。
シモンさんに試していただいたことと、これまでのことをまとめておきます。


onexit 命令で終了処理をつけた場合、以下の2つに注意。


1.screen 命令でウインドウを2つ以上つくる場合、その数だけ終了処理に飛ぶことがある。
・タスクバーの「すべてを閉じる」のとき
・シャットダウン(再起動または電源OFF)のとき

対策:
1−A.終了処理の最初に「onexit 0」で割り込み禁止にし、2回目以降の割り込みを禁止する。
1−B.終了処理自体を、何回行ってもいいような作りにしておく。


2.終了処理内で取得する環境変数 ginfo_winx/y と ginfo_wx1/y1 が変な値のときがある。

対策:
2−A.終了処理の1回目の環境変数の値のみをつかう(3種の環境で確認)。
2−B.終了処理内で環境変数を得ることはやめて、メインループなどで先に取得しておく。


(私的には、HSPや Windows のシステムに依存している感じの対策は、
今後のHSPのバージョンアップなどで動作が変わるおそれがあると思うので、
1−A・2−Aよりは1−B・2−Bの対策のほうを取ったほうがいいかもしれません。)


シモンさんへ。
私一人ではとうてい発見できなかったことまで知ることができました。
ありがとうございました!



ONION software Copyright 1997-2021(c) All rights reserved.