Last Update : 2009/03/xx
ファイル関連のサンプルスクリプトです。フォルダに関連した標準命令には、下のようなものがあります。
名称 | 説明 |
notesave命令 noteload命令 |
テキストファイルの作成出力・読み込み |
bsave命令 bload命令 |
バイナリファイルの作成出力・読み込み |
exist命令 | ファイルサイズの取得 ファイルの存在有無の確認 |
delete命令 | ファイルの削除 |
bcopy命令 | ファイルのコピー移動 |
dirlist命令 | 特定ファイルの一覧リストを取得 |
picload命令 | 画像ファイル(BMP/GIF/JPEG)の読み込み表示 |
bmpsave命令 | HSPのウィンドウ画面をBMPファイルで保存 |
mmload命令 mci命令 |
音楽・動画ファイルの読み込み |
まず本題の前に、ファイルの内容を16進数で表示する「バイナリエディタ」というプログラムを紹介しておきます。このバイナリエディタをある程度見られるようになってると、ファイル内の構造についての世界が少〜し広がるかと思います。
バイナリエディタは色々とリリースされていますが、「Stirling」というフリーソフトがWindows向けの定番になっているので、別途入手してください。(→参照、Vector バイナリエディタ)
- - - - -
下の画像はHSP3(HSP 3.x)に付属する画像ファイル(sample\demo\btn_hsptv.bmp)をバイナリエディタで開いたものです。左側の灰色部分が位置を示す16進数アドレス、中央がバイナリデータ、右側がアスキー文字エリア(メモ帳で開くと文字化けのようにずらずらと表示されるもの)です。バイナリデータにある2ケタ数値ひとつひとつが1バイト(byte)という単位になります。
「BMP フォーマット」あたりで検索すると、ビットマップ(Bitmap)の構造や仕様を掲載したページがヒットしますが、BMPファイルは、先頭2バイトが必ず「BM」(16進数で表すと0x4D42)という文字になっています。これを利用すれば、BMPファイルであるかの判定が可能です。
// BMPファイルであるかの簡易チェック (by Kpan) ; 適当に64バイトほど読み込み notesel buf noteload "sample\\demo\\btn_hsptv.bmp", 64 ; wpeek関数で先頭2バイトを取り出す value = wpeek(buf, 0) ; ファイルの先頭が「BM」(0x4D42)であるかをチェック if value != $4D42 : mes "BMPファイルではありません。" : stop ; strf関数で16進数表記に変換したものを表示。 mes "0x00〜0x01: 0x"+strf("%x", value)
// (おまけ)BMPファイルの先頭2バイトを文字で表示 notesel buf noteload "sample\\demo\\btn_hsptv.bmp", 64 ; peek関数で1バイトずつ取り出し、strf関数でキャラクタ文字変換 mes ""+strf("%c", peek(buf, 0))+" と "+strf("%c", peek(buf, 1))
さて、本題の画像の大きさサイズの取得です。Xサイズが「0x12〜0x15」、Yサイズが「0x16〜0x19」の範囲に格納されています。(上の画像の四角で囲っている部分)
// BMPファイルのイメージサイズを取得 (by Kpan) notesel buf noteload "sample/demo/btn_hsptv.bmp", 64 ; lpeek関数で4バイトそれぞれ取り出します。 sx = lpeek(buf, $12) ; 結果は 0x000000C8 sy = lpeek(buf, $16) ; 結果は 0x0000001A ; サイズを表示 (10進数) mes "サイズ(ピクセル): "+sx+" x "+sy+"
他の取得方法として、buffer命令で作成した仮想ウィンドウにpicload命令(モード0)で画像ファイルを読み込み、ginfo関数(タイプ12・13)からサイズを得ることも可能です。
細かい情報は、上のBMPファイルの説明を参照。
GIFファイルの仕様は、「GIF フォーマット」。サンプルは省略しますが、GIFファイルであるかの簡易チェックを行うには、先頭が「GIF89a」か「GIF87a」となっているので、lpeek関数で4バイト取り出し、「GIF8」(16進数で表すと0x38464947)であるかをチェックするといいでしょう。
GIFファイルはの画像の大きさは四角で囲ったXサイズが「0x06〜0x07」、Yサイズが「0x08〜0x09」に格納されてます。
// GIFファイルのイメージサイズを取得 (by Kpan) notesel buf noteload "sample\\demo\\onibtn.gif", 64 ; wpeek関数で2バイトそれぞれ取り出します。 sx = wpeek(buf, $06) ; 結果は 0x0088 sy = wpeek(buf, $08) ; 結果は 0x0032 ; サイズを表示 (10進数) mes "サイズ(ピクセル): "+sx+" x "+sy+"
// (おまけ)GIFファイルの先頭6バイトを文字で表示 notesel buf noteload "sample\\demo\\onibtn.gif", 64 repeat 6 mes strf("%c", peek(buf, cnt)) loop
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ファイルを表示してみることにします。まず、リソースエディタ「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。
HSP拡張プラグイン「hspext.dll」にfxren命令がありますが、プラグインを利用しないでファイル名を変更します。元のファイル名から指定された新たなファイル名に置き換えられます。拡張子部分や、フォルダ(ディレクトリ)名の変更も可能です。
これはVisual C++のランタイムライブラリ「msvcrt.dll」を利用したもので、初期のWindows 95を除いて標準でシステムに含まれてます。(初期のWindows 95の場合はIE 4以降が必要?)
// ファイル名変更サンプル (by Kpan) #uselib "msvcrt" #func rename "rename" str, str ; 第1パラに元のファイルパス、第2パラに変更後のファイルパス rename "C:\\hogehoge.txt", "C:\\変更_hogehoge.txt" ; 成功するとstatに0、失敗すると0以外 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
エクスプローラなどからチェックできるファイルの種類(ファイルタイプ)、アイコンイメージを取得します。Win32
API関数のSHGetFileInfo関数を利用します。
SHGetFileInfo関数について簡単に説明しておくと、第1パラが取得するファイルパス、第3パラがSHFILEINFO構造体のポインタ、第4パラがSHFILEINFO構造体のサイズ、第5パラが取得タイプです。SHFILEINFO構造体にアイコンハンドルとファイルタイプが返るので、Win32
API関数のDrawIcon関数でアイコンを描画、HSPのgetstr命令でファイルタイプ文字列を切り出してます。
// ファイルの種類・アイコンの取得 (by Kpan) #include "user32.as" #include "shell32.as" #define SHGFI_ICON $00000100 #define SHGFI_TYPENAME $00000400 ; 追加のアイコン取得タイプ #define SHGFI_LARGEICON $00000000 ; x32サイズ (デフォルト) #define SHGFI_SMALLICON $00000001 ; x16サイズ #define SHGFI_LINKOVERLAY $00008000 ; ショートカットアイコン #define SHGFI_SELECTED $0010000 ; 選択状態アイコン dim SHFILEINFO, 88 sdim filetype, 80 button "読み込み", *getfile stop *getfile dialog "", 16 if stat = 0 : stop SHGetFileInfo refstr, 0, varptr(SHFILEINFO), $160, SHGFI_ICON | SHGFI_TYPENAME redraw 0 color 255, 255, 255 boxf color ; アイコンイメージの描画 DrawIcon hdc, 0, 50, SHFILEINFO.0 ; アイコンハンドルの解放 DestroyIcon SHFILEINFO.0 pos 50, 50 mes refstr exist refstr mes ""+strsize+" Byte" ; ファイルタイプの取得 getstr filetype, SHFILEINFO, $110 mes filetype redraw
ZIP形式やLZH(LHA)形式は、ファイル圧縮の定番です。HSPは圧縮ファイルを解凍(展開)する能力は持ってません。そこで、解凍処理を専門に行う外部汎用ライブラリ(DLL形式)の力を借りることになります。HSP2ではこのような解凍を行うプラグインを扱うためのHSP拡張プラグイン(プラグインのためのプラグイン)というのがリリースされてましたが、HSP3ではわざわざそれを利用する必要性はほとんどないです。
ちなみに、外部プラグインは素のパソコンには当然入っていないので、各ユーザーに別途入手してもらって、Windowsのシステムフォルダなり実行ファイルと同じフォルダなりに置いてもらう形になります。(このページで紹介してるZIPとLZHの2ライブラリは、DLLファイル単体での配布が禁止されてるので注意)
まずは、ZIP形式を解凍するテキトーなサンプル。Windows XP〜環境では標準で圧縮と解凍の機能が用意されてますが、Windowsの世界でもっとも普及している超定番の圧縮形式です。shoda T.さんらによるZIPファイル解凍ライブラリ「unzip32.dll」を利用します。公式サイトは「統合アーカイバ・プロジェクト」。
// ZIPファイルの解凍サンプル (by Kpan) #uselib "unzip32" #func UnZip "UnZip" nullptr, str, int, int #func UnZipGetFileCount "UnZipGetFileCount" str #func UnZipGetVersion "UnZipGetVersion" ; unzip32.dllが存在するか簡易チェック if varptr(UnZipGetVersion) = 0 { dialog "unzip32.dll が見つからん" end } sdim filepath, 256 sdim outpath, 256 sdim szOutput,1024 ; ZIPファイルのパス (例、Cドライブの直下にある場合) filepath = "C:\\sample.zip" mes "ZIPファイル : "+filepath+"" ; 解凍したファイルの出力フォルダ outpath = "C:\\" mes "出力フォルダ : "+outpath+"" button "解凍", *unpack button "情報", *info button "ファイル数", *count button "バージョン", *version 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 UnZip "-lv \""+filepath+"\"", varptr(szOutput), 1024 dialog ""+szOutput stop ; ZIPファイル内に格納されているファイル数を取得 ; ファイルが存在しない、ZIPファイルでない、書庫が壊れている、ような場合は ; -1が返るので、書庫チェック的なこととして利用可。 *count UnZipGetFileCount filepath mes "ファイル数 : "+stat+" コ" stop ; unzip32.dllのバージョン取得 ; 戻り値は下のような感じで返る。 ; 75 -> Version 0.75 、100 -> Version 1.00 、540 -> Version 5.4 *version UnZipGetVersion value = stat value = wpeek(value) ; これがないと2回目以降に正しく取得できない mes "バージョン : "+value+" -> "+(value / 100)+"."+(value \ 100)+"" stop
ちなみに、MODプレーヤーサンプルでは別の「zlibwapi.dll」という汎用ライブラリを使ってZIPファイルを解凍してます。
LZH(LHA)形式を解凍するテキトーなサンプルです。まずは、上のZIPファイルの解凍の説明を参照してください。ZIPファイルの解凍処理とだいたい同じなので、コメントはほとんど端折ってます。
Windowsの世界では日本国内でのみ普及してる圧縮形式です。基本的に日本以外では使われてません。MiccoさんによるLZHファイル解凍/圧縮ライブラリ「unlha32.dll」を利用します。公式サイトは「Micco's Page」。
// LZHファイルの解凍サンプル (by Kpan) #uselib "unlha32" #func Unlha "Unlha" nullptr, str #func UnlhaGetFileCount "UnlhaGetFileCount" str #func UnlhaGetVersion "UnlhaGetVersion" ; unlha32.dllが存在するか簡易チェック if varptr(UnlhaGetVersion) = 0 { dialog "unlha32.dll が見つからん" end } sdim filepath, 256 sdim outpath, 256 sdim szOutput,1024 ; LZHファイルのパス filepath = "C:\\sample.lzh" mes "LZHファイル : "+filepath+"" ; 解凍したファイルの出力フォルダ outpath = "C:\\" mes "出力フォルダ : "+outpath+"" button "解凍", *unpack button "ファイル数", *count button "バージョン", *version stop ; LZHファイルの解凍 ; 正常に終了すればstatに0が、エラーなら0以外が返ります。 ; 細かいオプションはDLL同封の「COMMAND.TXT」参照 *unpack Unlha "e \""+filepath+"\" \""+outpath+"\"" mes stat stop ; LZHファイル内に格納されているファイル数を取得 ; 書庫が壊れているような場合は-1が返る *count UnlhaGetFileCount filepath mes "ファイル数 : "+stat+" コ" stop ; unlha32.dll のバージョン取得 *version UnlhaGetVersion value = stat value = wpeek(value) mes "バージョン : "+value+" -> "+(value / 100)+"."+(value \ 100)+"" 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 © 2005-2012 Kpan. All rights reserved.