oncmd命令に関するお話
概要
HSPにはWindowメッセージを取得して割り込み実行を行ってくれるoncmd命令というやつがいます。
ここではこれについて取り扱ってみたいと思います。
onexitとの組み合わせ
oncmd命令の仲間にonexit命令というものがあります。
設定しておくと、終了時に指定したサブルーチンを実行してくれる便利な命令です。
しかしこの命令、oncmd命令と一緒に使うと不具合を引き起こすことがあります。
まずはこれを実行して体験してみてください。
実行したら何もせず終了してください。
#define WM_COMMAND 0x0111
; button "",*exit ;回避策(3)フォーカスをinputからはずしてから終了すればエラーは起きない。
input a
onexit goto *exit
; onexit gosub *exit ;回避策(1)
oncmd gosub *l_On_WM_COMMAND, WM_COMMAND
stop
;###############################################################################
; #Error 10 サブルーチン外のreturnは無効です
*exit
; oncmd 0 ;回避策(4)
; wait 0 ;回避策(2)
end
*l_On_WM_COMMAND
return
; プロセスが残る
;*exit
; end
終了すると、「サブルーチン外のreturnは無効です」
のエラーメッセージが出てきたと思います。
見た目は何の変哲も無いように見えるスクリプトなので困ったものですね。
最後の「プロセスが残る」と書かれた方のサブルーチン「*exit」を有効にして実行するとエラーメッセージは出なくなりますが、
終了してもプロセスが残ってしまいタスクマネージャから終了させないといけなくなりますので注意してください。
この場合何もメッセージが出ないので、ついバグ回避成功と思ってしまいます。エラー出るよりひどい状態なんで注意してください。
原因
end命令が実行されるとウィドウ内のオブジェクトが削除されます。
このタイミングでoncmd命令のジャンプ先にジャンプしてしまうのが原因のようです。
細かい動きまでは分かりませんでした。
対策
原因はぼんやりとしかわかりませんが、対策はいくつか見つかりましたのでご紹介します。
上のスクリプト内にコメントで記載しています。
- 回避策(1)
- gosubにするとなぜかきちんと終了してくれます。謎です。
returnしないでいいんだろうか。 - 回避策(2)
- dialog命令でもいいようです。
oncmd命令はstopやwaitが実行中にメッセージを見にいくので、そのあたりが原因だと推測されます。が…謎です。 - 回避策(3)
- オブジェクトの内容が変更(フォーカスが移動)されるとジャンプするので、フォーカスを内容変更がない別のオブジェクトに変更してやることで回避しています。
いつでも使える手ではありませんし、確実にジャンプしないとも言い切れないので使えない手ですね。 - 回避策(4)
- oncmd命令を無効にすることでジャンプしないようにしています。
確実にジャンプしなくなるはずなのでこれが無難な対応策だと思います。
結局endの直前に「oncmd 0」するのが一番確実なような気がします。
ウィンドウ2個使ってみる
oncmd命令ってほんというと使い慣れてないんですが、button同様なオブジェクトとして使うようです。
実際に使ってみましょう。
#define WM_COMMAND 0x0111
; Windowsメッセージ割り込み設定
oncmd 0 ;割り込みを停止
;オブジェクトの配置中は割り込みを発生させない
;オブジェクト配置後にoncmdオブジェクトを配置しなおせばこれは必要ないと思います。
onexit goto *exit
; window 0
input a
oncmd gosub *l_On_WM_COMMAND_0, WM_COMMAND
; window 1
screen 1
title "id = 1"
input b
oncmd gosub *l_On_WM_COMMAND_1, WM_COMMAND
oncmd 1 ;oncmdを有効にする
stop
;###############################################################################
; 終了時に実行されます。
*exit
oncmd 0 ;割り込みを停止
;end実行時に割り込みが発生しないようにするため、
;割り込みを止める。
end
; 入力ボックスの内容が変更されると割り込みが発生してここが実行されます。
*l_On_WM_COMMAND_0
mes "0"
return
*l_On_WM_COMMAND_1
mes "1"
return
安全に終了するよう書いてみました。
今度はちゃんと終了するはずです。
「oncmd goto」ではなく「oncmd gosub」に変更。
end前にoncmd 0を実行。
どうでしょう…?
ちゃんと動いてますか?