HSP3 あれこれ <ファイル>

Last Update : 2007/12/xx

XREA.COMのs206サーバー内のサイトは、Yahoo!検索からペナルティを受け、検索結果で常に下位にランク付けされてしまうので、Yahoo!経由向けに用意したHSPミニ講座内のページです。このページは「http://lhsp.s206.xrea.com/hsp_file.html」の昔のものです。

BMPファイルのイメージサイズを知る

まず本題の前に、ファイルの内容を16進数で表示する「バイナリエディタ」というプログラムを紹介しておきましょう。このバイナリエディタをある程度見られるようになってると、ファイル内の構造についての世界が少〜し広がるかと思います。

バイナリエディタは色々とリリースされていますが、「Stirling」というソフトがWindows用の定番になっているので、別途入手してください。(→参照ページ Vector - バイナリエディタ)

- - - - -

下の画像は、HSP3(HSP 3.x)に付属している画像ファイル(sample/demo/btn_hsptv.bmp)をバイナリエディタで読み込んだものです。左側(濃い灰色部分)が位置を示す16進数アドレス、中央がバイナリデータ、右側がアスキー文字エリア(メモ帳で開くと文字化けのようにずらずらと表示されるもの)です。バイナリデータにある16進数の2ケタ数値ひとつひとつが1バイト(byte)という単位になります。

「バイナリエディタでBMPファイル内を表示」之図 (Let's HSP!)

BMP フォーマット」あたりで検索すると、ビットマップ(Bitmap)の構造や仕様を掲載したページがヒットしますが、BMPファイルは、先頭2バイトが必ず「BM」(0x4D42)となっています。これを利用すれば、BMPファイルであるかの簡易的な判定が可能です(拡張子チェックでも十分でしょうが)。[0x424D ではないので注意]

;	BMPファイルであるかの簡易チェック (by Kpan)

;	読み込んだファイルを格納しておくためのバッファを確保します。
;	(ファイル全体を読み込んでおく必要はないので適当に64バイト確保
	sdim buf

;	ファイルを読み込みます
	bload "sample/demo/btn_hsptv.bmp", buf

;	wpeek関数で先頭2バイト取り出します。
	h = wpeek(buf, 0)

;	ファイルの先頭が「BM」(0x4D42)であるかを確認。
	if h != $4D42 : mes "BMPファイルではありません。" : stop

;	strf関数で16進数表記に変換したものを表示。
	mes "0x00〜0x01: 0x"+strf("%x", h)

で、本題の画像のサイズ取得。Xサイズが0x12〜0x15バイト、Yサイズが0x16〜0x19バイトに格納されています。(上の画像の四角で囲っている部分)

;	BMPファイルのイメージサイズを取得 (by Kpan)

	sdim buf
	bload "sample/demo/btn_hsptv.bmp", buf

;	lpeek関数で4バイトそれぞれ取り出します。
	sx = lpeek(buf, $12) ; 結果は 0x000000C8
	sy = lpeek(buf, $16) ; 結果は 0x0000001A

;	サイズを表示 (10進数)
	mes "サイズ(ピクセル): "+sx+" x "+sy+"

他の取得方法として、buffer命令で作成した仮想ウィンドウにpicload命令で画像ファイルを読み込み、関数の「ginfo (12)」と「ginfo (13)」からサイズを得ることも可能です。

^

GIFファイルのイメージサイズを知る

細かい情報は、上のBMPファイルの説明を参照。

GIFファイルの仕様は、「GIF フォーマット」。サンプルは省略しますが、GIFファイルであるかの簡易チェックを行うには、先頭が「GIF89a」か「GIF87a」となっているので、lpeek関数で4バイト取り出し、「GIF8」(0x38464947)であるかを見るといいでしょう。[0x47494638 ではないので注意]

「バイナリエディタでGIFファイル内を表示」之図 (Let's HSP!)

四角で囲った0x06〜0x07にXサイズ、0x08〜0x09にYサイズが格納されています。

;	GIFファイルのイメージサイズを取得 (by Kpan)

	sdim buf
	bload "sample/demo/onibtn.gif", buf

;	wpeek関数で2バイトそれぞれ取り出します。
	sx = wpeek(buf, $06) ; 結果は 0x0088
	sy = wpeek(buf, $08) ; 結果は 0x0032

;	サイズを表示 (10進数)
	mes "サイズ(ピクセル): "+sx+" x "+sy+"

^

ファイルをごみ箱に移動する

HSPのdelete命令は、ごみ箱を経由しないでそのままファイルがドライブから削除されます。ファイルをごみ箱に移動する形での削除を行ってみます。

;	ごみ箱直行サンプルソース (by Kpan)

#uselib "shell32"
#func SHFileOperation "SHFileOperationA" int

	sdim filepath, 256

	dialog "", 16
	if stat = 0 : stop

;	このサンプルではあまり意味がないけど、ファイル存在の確認を。
	exist refstr
	if strsize = -1 : stop

;	ファイルパスはフルパスでなければなりません。
	filepath = refstr

;	SHFILEOPSTRUCT構造体、SHFileOperation関数
	SHFILEOPSTRUCT = hwnd, $03, varptr(filepath), 0, $10 | $40
	SHFileOperation varptr(SHFILEOPSTRUCT)

^

自分自身のファイル名を取得

自分自身のファイルパスのディレクトリ(フォルダ)部分は、標準のdirinfo関数 or システム変数dir_exe で取得できますが、ファイル名の部分は取得できません。Windows APIを使うと、自分自身の完全なフルパスを取得できます。ファイル名の部分だけを取り出すには、HSPのgetpath関数で。

;	フルパス取得サンプルソース (by Kpan)
;	(注) エディタの[HSP]メニューのHSP拡張マクロを使用する]を要有効。

#uselib "kernel32"
#func GetModuleFileName "GetModuleFileNameA" int, int, int

;	実行ファイルのフルパス文字列用変数のための領域を適当に確保
	sdim filepath, 256

	GetModuleFileName , varptr(filepath), 256

	mes filepath
	mes getpath(filepath, 8)

^

実行ファイル内のHTMLファイルを表示

実行ファイル内に埋め込んだHTMLファイルを表示してみることにします。まず、リソースエディタ「Resource Hacker」を別途入手してください。海外製ですが、日本語表記版も公開されているフリーウェアです。

(1) 「Resource Hacker」を起動し、HSP本体に存在する hsprt ファイル、または runtime フォルダの *.hrt ファイルを読み込みます。
(2) [アクション]メニューの[新しいリソースを追加する]を選択し、[リソースを含むファイルを開く]ボタンを押して、埋め込みたいHTMLファイルを選択します。(ここで読み込んだHTMLファイル自体の名前は以後の作業で全く関係なし)
(3) [リソースの種類]に「23」を、[リソース名]に任意のHTMLファイル名(ここでは HOGE.HTML)を、[リソースの言語]は、適当に「1033」とでも入力し、[リソースを追加する]ボタンを押します。
(4) [ファイル]メニューの[名前を付けて保存する]を選択し、必ず *.hrt という拡張子で保存します(ここでは hogehoge.hrt)。出力されたファイルは、runtime フォルダに置いておいてください。

これで下準備は完了。ひとまず、埋め込んだHTMLファイルをexec命令によりブラウザで開いてみるサンプルコードです。exec命令で指定するファイル名は、「res://(自分自身の完全なフルパス)/(埋め込んだHTMLファイル名*)」という形式になります。(*正確には、[リソース名]で指定した名前)

で、この自身自身の実行ファイルの完全なフルパス指定に、上のトピックス「自分自身のファイル名を取得」が使えるわけです。実行ファイル名の書き換えが絶対に行われないという前提に立てば、「res://"+dirinfo (1)+"\\*.exe/(埋め込んだHTMLファイル名)」も一応可能ですが。。。

;	先ほど出力したランタイムファイルを指定。
#packopt runtime "hogehoge.hrt"

#uselib "kernel32"
#func GetModuleFileName "GetModuleFileNameA" int, int, int

	sdim exepath, 256
	GetModuleFileName , varptr(exepath), 256

	button "おーぷん", *a
	stop

*a
	exec "res://"+exepath+"/hoge.html" , 16

なお、HSPスクリプトエディタ上ではHTMLページは表示されないので、必ず「実行ファイル自動作成」により生成した実行ファイル自体をチェックしてください。

ちなみに、ウィンドウ内にオブジェクトとしてHTMLページを表示する場合は、axobj命令だと、開くURLアドレスを同様に「res://〜」形式で指定すればOK。

^

ファイル名の変更

拡張プラグインhspext.dllによるfxren命令がありますが、ファイル名の変更です。元のファイル名から指定された新たなファイル名に置き換えられます。フォルダ(ディレクトリ)名の変更も可能です。

Visual C++ランタイムライブラリ msvcrt.dll を利用したものもので、このランタイムは初期のWindows 95を除いて標準でシステムに含まれています。(初期のWindows 95の場合はIE 4以降?

;	ファイル名変更サンプル (by Kpan)

#uselib "msvcrt"
#func rename "rename" str, str

;	第1パラに元のファイルパス、第2パラに変更後のファイルパス
;	(例として、Cドライブ直下のテキストファイルを変更
	rename "C:\\hogehoge.txt", "C:\\変更_hogehoge.txt"

;	成功するとstatに0、失敗すると-1
	mes stat
;	初期のWindows 95でも確実にというなら crtdll.dll で

#uselib "crtdll"
#func rename "rename" str, str

^

ファイルの属性変更

HSP拡張プラグインhspext.dllで用意されているfxaset命令とほとんど同じです。Win32 APIのSetFileAttributes関数でファイルの属性を変更してみる。

#uselib "kernel32"
#func SetFileAttributes "SetFileAttributesA" str, int

	exist "hoge.txt"
	if strsize = -1 : stop

;	読み取り専用(第2パラのモード指定はfxaset命令の説明をそのまま参照)
	SetFileAttributes "hoge.txt", $1

;	システム変数statに0=失敗、0以外=成功(fxaset命令と異なる)
	mes stat

^

圧縮ファイルの解凍 (ZIPファイル)

ZIP形式やLZH(LHA)形式は、ファイル圧縮の定番です。HSPには、このような圧縮ファイルを標準命令で解凍(展開)する能力はありません。そこで、圧縮ファイルの解凍を専門に行う外部プラグイン(DLL形式)の力を借りることになります。HSP2ではこのような解凍を行うプラグインを扱うための拡張プラグイン(プラグインのためのプラグイン)というのがリリースされていましたが、HSP3ではわざわざ拡張プラグインを利用する必要性はほとんどないでしょう。

ちなみに、解凍を行う外部プラグインは素のPCには当然入っていないので、別途入手してもらって、Windowsのシステムフォルダなりに置いておくという形になります。(逆の「ファイルの圧縮」については、扱ったことがないので触れません。)

まずは、ZIP形式を解凍するテキトーなサンプルです。Windows XP/Vista環境では標準で圧縮、解凍の機能が用意されているように、Windowsの世界でもっとも普及している圧縮形式です。shoda T.氏ら(公式サイト「統合アーカイバ・プロジェクト」)によるZIPファイル解凍ライブラリ unzip32.dll を利用します。(MODプレーヤーサンプルでは別のzlibwapi.dllライブラリを利用)

;	ZIPファイルの解凍サンプルソース (by Kpan)

#uselib "unzip32"
#func UnZip "UnZip" nullptr, str, int, int
#cfunc UnZipGetFileCount "UnZipGetFileCount" str
#cfunc UnZipGetVersion "UnZipGetVersion"

#uselib "kernel32"
#cfunc GetModuleHandle "GetModuleHandleA" str

;	ZIPファイルのパス (例、Cドライブの直下にある場合)
	filepath = "C:\\sample.zip"
	mes "ZIPファイル : "+filepath+""

;	解凍したファイルの出力フォルダ
	outpath = "C:\\"
	mes "出力フォルダ : "+outpath+""

	button "解凍", *unpack
	button "情報", *info
	button "ファイル数", *count
	button "バージョン", *version

;	unzip32.dll がPCに導入されているかをチェックします。
;	GetModuleHandle関数を呼び出し、statに0が返ると未導入。
	if GetModuleHandle("unzip32") = 0 {
		dialog "unzip32.dll がないでー!", 1 : end
	}

	stop

;	ZIPファイルの解凍
;	正常に終了すればstatに0が、エラーなら0以外が返ります。
;	オプションとして、--i、-n、-o、-P*****、というようなものがあり、
;	詳細はDLL同封の UNZIP32D.TXT を参照のこと。たとえば解凍状況
;	ダイアログ非表示なら、
;	(ex) UnZip "--i \""+filepath+"\" 〜
;
;	ちなみに、パスが「\"」(つまり「"」)で括られていますが、これは仮に
;	パスにスペースが含まれていても正しく処理できるようにするため。
*unpack
	UnZip "\""+filepath+"\" \""+outpath+"\"", ,

	mes "解凍 : "+stat+""
	stop

;	ZIPファイル内の情報をszOutputに出力 (解凍処理なし)
;	ファイルの内容の一覧表示 (-l、-lv、-v) や ファイルのCRCチェック (-t)
;	なんかがあります。
*info
	sdim szOutput,1024
	UnZip "-lv \""+filepath+"\"", varptr(szOutput), 1024

	dialog ""+szOutput+""
	stop
	

;	ZIPファイル内に格納されているファイル数を取得
;	ファイルが存在しない、ZIPファイルでない、書庫が壊れている、
;	ような場合は -1 が返るので、書庫チェック的なこととして利用可。
*count
	filecount = UnZipGetFileCount(filepath)

	mes "ファイル数 : "+filecount+" コ"
	stop

;	unzip32.dll のバージョンを取得
;	戻り値は以下のような感じで返ります。
;	75 -> Version 0.75 、100 -> Version 1.00 、540 -> Version 5.4
*version
	ver = UnZipGetVersion ()
	ver = wpeek(ver, 0) ; これがないと2回目以降に正しく取得できない

	ver_major = ver / 100
	ver_minor = ver \ 100

	mes "バージョン : "+ver+" -> "+ver_major+"."+ver_minor+""
	stop

^

圧縮ファイルの解凍 (LZHファイル)

まずは、上のZIPファイルの解凍の説明を参照。ZIPファイルの解凍処理とだいたい同じなので、コメントはほとんど端折ってます。

LZH(LHA)形式を解凍するテキトーなサンプルです。Windowsの世界では基本的に日本国内でのみ普及してる圧縮形式です。Micco氏(公式サイト「Micco's Page」)によるLZHファイル解凍/圧縮ライブラリ unlha32.dll を利用します。

;	LZHファイルの解凍サンプルソース (by Kpan)

#uselib "unlha32"
#func Unlha "Unlha" nullptr, str
#cfunc UnlhaGetFileCount "UnlhaGetFileCount" str
#cfunc UnlhaGetVersion "UnlhaGetVersion"

#uselib "kernel32"
#cfunc GetModuleHandle "GetModuleHandleA" str

;	LZHファイルのパス
	filepath = "C:\\sample.lzh"
	mes "LZHファイル : "+filepath+""

;	解凍したファイルの出力フォルダ
	outpath = "C:\\"
	mes "出力フォルダ : "+outpath+""

	button "解凍", *unpack
	button "ファイル数", *count
	button "バージョン", *version

;	unlha32.dllがあるかチェック
	if GetModuleHandle("unlha32") = 0 : dialog "ない", 1 : end

	stop

;	LZHファイルの解凍
;	正常に終了すればstatに0が、エラーなら0以外が返ります。
;	細かいオプションはDLL同封の COMMAND.TXT 参照。
*unpack
	Unlha "e \""+filepath+"\" \""+outpath+"\""
	stop

;	LZHファイル内に格納されているファイル数を取得
;	書庫が壊れているような場合は -1 が返る。
*count
	filecount = UnlhaGetFileCount(filepath)

	mes "ファイル数 : "+filecount+" コ"
	stop

;	unlha32.dll のバージョン取得
*version
	ver = UnlhaGetVersion()
	ver = wpeek(ver, 0)

	ver_major = ver / 100
	ver_minor = ver \ 100

	mes "バージョン : "+ver+" -> "+ver_major+"."+ver_minor+""
	stop

^

拡張したファイルを開く/保存するダイアログ

dialog命令 のタイプ16/17は、ファイルの開く(オープン)ダイアログと保存(セーブ)ダイアログの表示です。このdialog命令は、Windows APIの GetOpenFileName関数 と GetSaveFileName関数 を呼び出しており、HSPではその機能の一部分しか利用していません。この関数で登場する「OPENFILENAME構造体」については、ちょくとさんの該当ページを参照。ボリューム多し・・・、部分的にしか把握できん。(^-^;

HSP2のllmod.asモジュールにより利用できたmultiopen命令(HSP3ならllmod3)もこの関数を呼び出しています。

と言うわけで、この関数を直に利用して、HSPのdialog命令よりも「ちょこっとだけ」機能をパワーアップさせたファイルの開く/保存ダイアログを表示してみるHSP3(HSP 3.x)用ソースモジュールです。

dialog命令との違いは、(1)[ファイルの種類]の項目でリストボックスに複数の拡張子を用意できる、(2)ダイアログのタイトル名に任意の文字列を指定できる、(3)[ファイル名]の項目に任意の文字列を指定できる、(4)初期フォルダのパスを指定できる、といったところ。一方、開くダイアログで選択できるファイル数は、dialog命令と同じ1つのみで、一度に複数のファイルを選択できる処理は用意されていません。

ダウンロード (ファイル編)

^

Copyright © Kpan. All rights reserved.