ファイルに関する情報
フォルダに続き、ファイル処理を行う命令・関数の紹介を行います。
以前にファイルの存在確認と変数への読み込みを行いましたが、
今回はエクスプローラ、言い換えるとPCを管理する上で行える処理をHSPでやってしまいます。
まず、ファイルを起動する命令から。
exec 実行ファイル, モード, アクション
実行ファイル起動するファイルパスを指定する。
モード以下の方法で起動する。
0:ノーマル 2:最小化 16:関連付けたアプリケーションで開く 32:印刷
アクションレジストリに登録されたコンテキストメニュー文字列を指定する。
EXECuteの略であるexec命令は、エクスプローラ上の様々な操作開始に代わって実行するものです。
主にフォルダやファイルの実行、URLを開くことが出来るもので、
Windowsのスタートメニューにある「ファイル名を指定して実行」と同じ挙動をさせられます。
第1パラメータに起動させるファイルを指定しますが、
第2パラメータのモードをノーマル(省略)にする場合は、拡張子はexeのみ(拡張子の省略可能)が対象です。
指定できるモードは上記の通りで、テキストファイル等のドキュメントファイルを開く場合は、
モード16とすることで、指定したファイルの拡張子に関連付けられたアプリケーションで開けます。
例えばテキストファイルを開く場合に、通常はメモ帳等の特定エディタで編集しているが、
ココで起動させる場合だけはワードパッドで開かせたいと言う時は、モード16を使用するのではなく、
「exec "wordpad readme.txt"」のように実行パスの+半角スペース+ファイルパス指定することで、
先頭に書いたアプリケーションにコマンドラインとして送り、開くことが出来ます。
当然アプリケーション側がコマンドラインに対応してないと開けませんが、大半は対応させているようです。
尚、カレントフォルダは今までに紹介した他の命令でもフォルダパスを指定せずとも処理できましたが、
exec命令は他にもWindowsフォルダやSystemフォルダ、System32フォルダにある
ファイルをフォルダパスなしに実行させることが出来るようです。
ですので、上記のwordpadは通常、Windowsフォルダですが、ファイル名だけで実行できます。
同一ファイル名の場合に、フォルダパスを指定しない場合の優先順位は次の通り。
 「カレントディレクトリ」>「System32」>「System」>「Windows」
第3パラメータに書くのは、実行する動作を指定する文字列。
指定できる動作はファイルの種類によるが、大抵のものは次のコンテキストメニューを実行できるようです。

コマンド内容
editエディタで編集する。
explore指定したフォルダをエクスプローラで開く。「explorer」で起動させるものと同じ。
open関連付けたアプリケーションで開く。モード16と同じ。
print関連付けたアプリケーションの印刷機能で印刷する。モード32と同じ。
propertiesプロパティウィンドウを開く。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
	exe = "calc\nnotepad\nexplorer\nmspaint"
	name = "電卓\nメモ帳\nエクスプローラ\nペイント"
	screen 0, 300, 100
	title "ランチャー"
	objsize 100, 20
	pos  10, 10 : mes "実行ファイル"
	pos 150, 10 : combox index, 100, name
	pos  10, 40 : mes "起動"
	pos 150, 40 : button gosub "開始", *start
	notesel exe
	stop

*start
	noteget proc, index
	exec proc // 指定プログラムを実行する
	return

続いてファイル複製処理を行う命令を紹介します。
bcopy コピー元ファイル, コピー先ファイル
コピー元ファイルコピーする対象のファイルパスを指定する。
コピー先ファイル作成するファイルパスを指定する。
bcopy命令はBinaryCOPYの略で、使い方は至って簡単。
第1パラメータのファイルを第2パラメータの位置・名称として複製するというものです。
既に指定フォルダに指定ファイルがパスが存在する場合、上書保存してしまいます。
気をつけなければ、重要なファイルでも上書きしてしまいかねません。
既に存在する場合は、作成する前にダイアログを表示して本当に上書きしてよいか確認するとよいでしょう。
作成先名と同一名のフォルダが存在する場合は上書きされませんが、HSPのエラーで終了してしまいます。
こうならないようにするには、コピーする前にチェックロジックを入れるようにしましょう。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
	sdim file, 512, 2
	screen 0, 480, 70
	objsize 60, 20
	pos  10, 10 : mes "コピー元"
	pos 100, 10 : input file.0, 300, 20
	pos 410, 10 : button gosub "参照", *ref
	pos  10, 40 : mes "コピー先"
	pos 100, 40 : input file.1, 300, 20
	pos 410, 40 : button gosub "コピー", *copy
	stop

*ref
	dialog "", 16, "コピー元ファイル"
	if stat : objprm 0, refstr
	return

*copy
	dirlist check, file.1, 5
	if stat {
		dialog "フォルダとして存在しているため、コピーできません。", 1
		return
	}
	dirlist check, file.1, 1
	if stat {
		dialog "既に存在しますが上書きコピーしますか?", 2
		if stat = 7 : return
	}
	bcopy file.0, file.1 // ファイルコピーする
	dialog "作成しました。"
	return
続いて、ファイル削除処理を行う命令を紹介します。
delete 削除ファイル
削除ファイル削除するファイルパスを指定する。
パラメータで指定したファイルを削除するdelete命令は、ゴミ箱に入れず、
元に戻すアンドゥ作業もありませんので、意図しないファイルを削除しないように注意してください。
また、指定できるのは1ファイルだけで、複数ファイル、またはフォルダごとの一括削除は行えませんので、
実現したい場合は他の方法で行ってください。
利用者に指定ファイルを削除させる場合、bcopy命令による上書きコピーの時と同様に、
削除前には確認メッセージを表示させると親切だと思いますよ。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	sdim file, 512
	screen 0, 480, 70
	objsize 60, 20
	pos  10, 10 : mes "削除ファイル"
	pos 110, 10 : input file, 300
	pos 410, 10 : button gosub "参照", *ref
	pos 410, 40 : button gosub "削除", *del
	stop

*ref
	dialog "", 16, "削除対象ファイル"
	if stat : objprm 0, refstr
	return

*del
	exist file
	if strsize = -1 {
		if file ! "" : dialog "[" + file + "]はファイルとして存在しません。"
	} else {
		dialog "[" + file + "]を本当に削除してよろしいですか?", 3
		if stat = 7 : return
		delete file // ファイルを削除する
		dialog "削除しました。"
		objprm 0, ""
	}
	return
exec命令のように他ファイルを実行する命令を紹介します。
exec命令と異なる点は、実行できるファイルが中間オブジェクトファイルだけであること、
実行と同時に、実行させた側のプログラムは終了されてしまうこと、です。
中間オブジェクトファイルとは、スクリプトをコンパイルして中間コードにしたオブジェクトファイルのこと。
つまり、中間オブジェクトファイルを実行し、元の実行側を終了するということは、
HSPの実行を中間オブジェクトファイルに移すということです。
run AXファイル, コマンドライン
AXファイルコンパイル済みの中間オブジェクトファイルを指定する。
コマンドライン中間オブジェクト実行時に取得できるコマンドラインを指定する。
第1パラメータにHSP実行の切替先AXオブジェクトを指定し、
第2パラメータに、AXオブジェクト起動時の「dir_cmdlineで取得できるコマンドライン」を指定します。
EXEを実行している時は内部で保持していた変数情報等がクリアされるので通常、
EXE1ファイルだけの実行で、外部の(またはパックした)AXファイルに処理を移しませんが、
例えば管理者も以前にやろうとしていた「機能毎にファイル自体を切り分ける」処理を施そうとした際に、
EXEを複数用意すると、ランタイムも各EXEに付加され重複してしまい無駄が出来てしまいます。
この場合にEXEを1つだけ用意しておき、そのEXEから機能毎のAXファイルを実行するようにすれば、
ランタイムはEXE1つだけで、機能毎に分けられたファイルにはランタイムが付かずサイズを抑えられます。
この説明ではイメージしにくいと思いますが、
run命令は複数のHSP実行ファイルを別プロセスで扱いたい場合に有効なのではないでしょうか?
例えば下記3つのスクリプトを、「runtest1.ax」「runtest2.ax」「runtest3.ax」で保存し、
4つ目のスクリプトを実行してみてください。

保存名【runtest1.ax】
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
	title "1つ目のAX実行内容"
	mes "1つ目のAXファイルに制御が移りました。\n"
	wait 500
	mes "ココではサンプルメッセージを表示させているだけですが、"
	wait 300
	mes "実際に使う時は行わせたい処理を記述した上でAXを作成してください。"
	wait 300
	mes "先ほどと同じ様にrun実行しますが、次からコマンドラインも使用します。"
	wait 300
	mes "\n説明は後程としまして、2つ目のAXへ処理を移します。"
	wait 500
	run "runtest2.ax", "from runtest1" // 不正起動用コマンドラインを付けて起動

保存名【runtest2.ax】
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
	if dir_cmdline ! "from runtest1" : end // 不正実行処理の制御
	title "2つ目のAXファイル"
	mes "2つ目のAXファイルに制御が移りました。\n"
	wait 500
	mes "もし、利用者がAXファイルの存在や扱い方を知っており、"
	wait 300
	mes "1つ目のAXを実行せず、不正に2つ目以降から実行させようとしても、"
	wait 300
	mes "このサンプルプログラムのように起動時チェックを設けていると、"
	wait 300
	mes "トラップ用コマンドラインを知らない限りは実行を防ぐことが可能です。"
	wait 300
	mes "\n次のAXへ処理を移します。"
	wait 500
	run "runtest3.ax", "from runtest2" // 不正起動用コマンドラインを付けて起動

保存名【runtest3.ax】
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
	if dir_cmdline ! "from runtest2" : end // 不正実行処理の制御
	title "3つ目のAXファイル"
	mes "3つ目のAXファイルに制御が移りました。\n"
	wait 500
	mes "プログラムをAXファイルとして複数に分けるメリットを説明します。"
	wait 300
	mes "例えば、追加パックや追加シナリオ機能の実現や、"
	wait 300
	mes "最近はブロードバンドが主流なのでメリットは少ないですが"
	wait 300
	mes "修正箇所のみを手直ししたフィックス版を公開する際に"
	wait 300
	mes "肥大化したEXEを再度まるまるダウンロードしてもらうのではなく"
	wait 300
	mes "数キロ〜数十キロバイトのAXのみを修正ファイルとして公開すると"
	wait 300
	mes "ナローバンドの人には喜ばれるかもしれません"
	wait 300
	mes "以上で「runテスト」を終了します。"
	wait 500
	end

初めに実行するメインプログラム【untitled (テストでは保存しなくても構いません) 】
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
	title "HSPBC 複数AXファイルの実行テスト"
	mes "これから複数のAXファイルに切り分けたプログラムのテストを行います。"
	wait 300
	mes "run命令でウィンドウ制御が別ウィンドウへ移る際にチラつきますが、"
	wait 300
	mes "なんか良い対処法を考えてみてください。"
	wait 300
	mes "それでは、始まり始まり〜。。。"
	wait 300
	run "runtest1.ax" // 中間オブジェクトファイル起動

この章の最後として、パス文字列から一部を取得する関数を紹介します。
取得値 = getpath(対象文字列, モード)
取得値指定した対象文字列を指定モードで処理した結果文字列の受取先を指定する。
対象文字列ファイルパス形式の文字列または文字列型変数を指定する。
モード取得モード(後述)を指定する。
第1パラメータの文字列から、第2パラメータに指定した下記のモードの形に変換した文字列を返します。
モード処理内容対象文字列例( A:\BC\DEF.GHI )
0処理せずにそのまま渡す。A:\BC\DEF.GHI
1ファイル名のみ(拡張子除く)渡す。A:\BC\DEF
2拡張子のみ渡す。.GHI
8フォルダ名を除いて渡す。DEF.GHI
16小文字に変換して渡す。a:\bc\def.ghi
32フォルダ名のみ渡す。A:\BC
複数の処理を同時に行いたい時は、モード値の合計を指定してください。
但し、ファイル名のみ(=1)と拡張子のみ(=2)の合計値3を指定すると、0と同じ文字列コピー、
拡張子のみ(=2)とフォルダ名のみ(=32)の合計値34を指定すると、2と同じ拡張子のみ、
フォルダ名を除く(=8)とフォルダ名のみ(=32)の合計値40を指定すると、8と同じとなります。
getpath関数は単純に、文字列の最後尾から最も近いピリオドまでを拡張子として、
最後尾から最も近い¥マークまでをファイル名として判断しています。
第1パラメータに指定する文字列または文字列型変数には、必ずしもファイルのパスでなくとも構いません。
ファイルパスの一部取り出し以外にはあまり用途がないような関数ですが、
小文字に変換するモードはファイルパスに関係なく利用価値がありますよね?
但し、getpath関数は元々がファイルパス向けの文字列を指定するようになっていますので、
最大256バイトまでの文字列しか返しませんので気をつけましょう。
以下のサンプルは、読み込もうとしているファイルが画像かをチェックするプログラムです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
	sdim list, 32
	admit = "jpg", "gif", "bmp", "ico"
	foreach admit
		if cnt : list += ";*."
		list += admit.cnt
	loop
	dialog list, 16, "読み込める画像"
	if stat {
		ok = 0
		foreach admit
			tmp = getpath(refstr, 2 + 16) // 選択ファイルの拡張子を小文字にして抽出
			if strmid(tmp, 1, 256) = admit.cnt {
				ok = 1
				break
			}
		loop
		if ok {
			picload refstr, 1
		} else {
			dialog "読み込める画像を選択してください"
		}
	}