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を実行。

どうでしょう…?
ちゃんと動いてますか?

関連記事

  1. ファイルを分けて開発する 動機 HSPで作る時って普通は1個のファイルでガリガリ書いて...
  2. スキップしない待機 概要 on~系の命令はstop, wait, await命令...
  3. font命令の速度 概要 HSPのFONT命令はその昔「重いのでメインループ内で...
  4. HSP3でのデザインパターン 概要  ソフトウェア開発にはデザインパターン(設計パターン)...
  5. 再帰とローカル変数 調査環境   HSP3での再帰の実装について真面目に調べてみ...
  6. HSP3でのビットシフト 算術シフトって初めて聞きました  HSP3のビットシフトにつ...
  7. テキストデータの読み込み もくじ 新情報を加えたら量が増えてきたので目次を作りました。...