〜 ネットワーク 〜
サーバー上のリソース一覧を取得 (要WININET.DLL)

HSP3からHSPInet.DLLが標準で同梱されており、
このDLLの命令を使うことでインターネット上のデータを取り込むことが出来ます。
便利なものですが、作成した実行ファイルと共にDLLを同梱する必要があるので、
様々な理由により「なんとかDLLナシで実現できないか」と思う人たちの為の参考Tips。
HSPInet.DLLは、Windows標準搭載のWinInet.DLLのラッパーDLLなので、
WinInet.DLLのAPI関数を直接呼び出すことで、
HSPInet.DLLを同梱することなく実現させることが可能となります。

今回はFTPサーバーからリソース情報一覧を取得するftpdirlistftpdirlist2命令に取って代わる
API関数FtpFindFirstFileInternetFindNextFileを使ったサンプルモジュールを紹介します。
API関数FtpFindFirstFileに指定するのは第1引数から順に、「セッションハンドル」「URL」
「検索結果格納先」「オープン種別」「コールバック関数に渡すアプリケーション定義値」です。
インターネットハンドルについてはコチラを参照してください。
URLはディレクトリ名またはファイル名を格納した変数のポインタを指定しますが、
サーバ上のカレントディレクトリの最初のファイルを検索する場合はNULL(=0)を指定します。
検索結果格納先はWIN32_FIND_DATA構造体を指定します。
typedef struct WIN32_FIND_DATA {
DWORDdwAttributes;// ファイル属性
FILETIMEftCreate;// 作成日時
FILETIMEftLastAccess;// アクセス日時
FILETIMEftLastUpdate;// 最終更新日時
DWORDdwFileSizeHigh;// ファイルサイズ(上位32ビット)
DWORDdwFileSizeLow;// ファイルサイズ(下位32ビット)
DWORDdwReparse;// リパースタグ
DWORDdwReserved;// 予約済
TCHARcFileName;// ファイル名
TCHARcDosName;// 8.3形式のファイル名
}
オープン種別は以下のフラグ定数を指定します。
INTERNET_FLAG_SECURE0x00800000SSLやPCTを使用する
INTERNET_FLAG_DONT_CACHE0x04000000ローカル及びゲートウェイにデータをキャッシュしない
INTERNET_FLAG_EXISTING_CONNECT0x20000000可能な限り既存のサーバとの接続を再利用
INTERNET_FLAG_RAW_DATA0x40000000生のデータを返す
INTERNET_FLAG_RELOAD0x80000000キャッシュを無視して常にサーバからデータを取得
コールバックする値については0を指定しましょう。 戻り値はAPI関数InternetFindNextFileで必要な列挙ハンドルで、失敗ならNULL(=0)が返ります。 API関数InternetFindNextFileに指定する引数は、「列挙ハンドル」「検索結果格納先」です。 API関数FtpFindFirstFile実行で受け取られるハンドルとWIN32_FIND_DATA構造体を指定します。 戻り値は「実行成功したか否かの真偽値」で、失敗していたならERROR_NO_MORE_FILES(=0x0012)となるので、 失敗するまで何度も関数を実行し続けることで全てのファイルを取得することが出来ます。 尚、検索結果を格納するWIN32_FIND_DATA構造体のファイル属性は以下の組み合わせです。
FILE_ATTRIBUTE_READONLY0x0001書き込みや削除が行えない読取専用ファイル。
FILE_ATTRIBUTE_HIDDEN0x0002通常のディレクトリリスティングでは表示されない隠しファイル。
FILE_ATTRIBUTE_SYSTEM0x0004OSのシステムファイル。
FILE_ATTRIBUTE_DIRECTORY0x0010ディレクトリに関連している。
FILE_ATTRIBUTE_ARCHIVE0x0020バックアップや削除のためのマークとして使用するアーカイブファイル。
FILE_ATTRIBUTE_DEVICE0x0040予約済。
FILE_ATTRIBUTE_NORMAL0x0080特に属性を持たないファイル。
FILE_ATTRIBUTE_TEMPORARY0x0100必要がなくなった段階ですぐに削除すべき一時ファイル。
FILE_ATTRIBUTE_SPARSE_FILE0x0200未使用領域が多いか同じ値が長く続くスパースファイル。
FILE_ATTRIBUTE_REPARSE_POINT0x0400再解析ポイントが関連付けられているファイル。
FILE_ATTRIBUTE_COMPRESSED0x0800圧縮ファイル。
FILE_ATTRIBUTE_OFFLINE0x1000データがオフラインの記憶装置へ物理的に移動されたことを示すファイル。
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED0x2000「インデックスサービス」の対象ではないファイル。(Windows2000〜)
FILE_ATTRIBUTE_ENCRYPTED0x4000暗号化ファイル。
作成日時・アクセス日時・最終更新日時はコチラで紹介したFILETIME構造体です。 世界標準時間で取得しますので、必要ならば日本標準時に変換してください。 ファイルサイズは最大64ビットを上位・下位32ビットに分割して取得されます。 リパースタグは属性にFILE_ATTRIBUTE_REPARSE_POINTが含まれる場合に取得されるもので、 取得される再解析ポイントタグは次の通りです。
IO_REPARSE_TAG_HSM20x80000006
IO_REPARSE_TAG_SIS0x80000007
IO_REPARSE_TAG_DFS0x8000000A
IO_REPARSE_TAG_DFSR0x80000012
IO_REPARSE_TAG_MOUNT_POINT0xA0000003
IO_REPARSE_TAG_SYMLINK0xA000000C
IO_REPARSE_TAG_HSM0xC0000004
ファイル名には260バイト分、DOSファイル名には14バイト分確保されています。 このWIN32_FIND_DATA構造体分のメモリ318バイトを確保しておき、変数ポインタを指定します。 HSP2のユーザー定義命令lpeekについてはコチラを参照してください。

lpeek 取出先, 読込変数, インデクス
取出先取得した値の格納先を指定する。
読込変数4バイトコード取出元変数を指定する。
インデクス先頭を0バイトとした4バイト分の取出開始位置を指定する。

inetinit
[パラメータなし]インターネットサービスを開始するだけである為、パラメータは必要ない。

inetend
[パラメータなし]インターネットハンドルを解放するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

inetlogin サーバー, ユーザー情報, サービス, オプション
サーバーホストサーバーアドレスまたはIPアドレス文字列を指定する。
ユーザー情報ログインユーザー名とパスワードをコロンで区切った形式で指定する。
サービス接続するサービス(1:FTP 2:Gopher 3:HTTP)を指定する。
尚、省略すればFTP接続を行う。
オプションFTPでパッシブモード利用する時、HTTPでHTTPS通信する時は1を指定する。
それ以外の時は0または省略する。

inetlogout
[パラメータなし]サーバーとの接続を解除するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

inetdirlist 取出先, ディレクトリ, 取得情報
取出先取得した情報一覧格納先変数を指定する。
尚、内部でlpeek命令を使用している為、inetdirlistよりも前にlpeekを定義すること。
ディレクトリ取得対象ディレクトリを指定する。
取得情報以下の取得する情報コード値合計を指定する。尚、取得情報は1データ1行・タブ区切り。
0全てを取得する(+7と一緒)
+1ファイル名を取得
+2ファイルサイズを取得
+4最終更新日時を取得

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	ll_libload wininet, "wininet.dll"
	ll_getproc InternetOpen, "InternetOpenA", wininet
	ll_getproc InternetCloseHandle, "InternetCloseHandle", wininet
	ll_getproc InternetConnect, "InternetConnectA", wininet
	ll_getproc InternetFindNextFile, "InternetFindNextFileA", wininet
	ll_getproc FtpFindFirstFile, "FtpFindFirstFileA", wininet
	ll_libload kernel, "kernel32.dll"
	ll_getproc FileTimeToSystemTime, "FileTimeToSystemTime", kernel

#module
#deffunc lpeek val, val, int
	mref write, 16 : mref read, 17 : mref index, 2
	wpeek tmp.0, read, index
	wpeek tmp.1, read, index + 2
	write = tmp.1 << 16 + tmp.0
	return

#deffunc inetinit
	mref stt, 64
	prm = 0, 0, 0, 0, 0
	agent = "hspbc"
	ll_getptr agent : ll_ret prm
	ll_callfunc prm, 5, InternetOpen@
	ll_ret hinet : stt = hinet
	return

#deffunc inetend onexit
	if hinet : ll_callfunc hinet, 1, InternetCloseHandle@
	return

#deffunc inetlogin str, str, int, int
	mref server, 32 : mref info, 33 : mref service, 2 : mref option, 3
	mref stt, 64
	instr i, info, ":"
	strlen i.1, info
	strmid user, info, , i
	strmid pass, info, i + 1, i.1 - i - 1
	if hinet = 0 : inetinit
	if user = "" : i.0 = 0 : else : ll_getptr user : ll_ret i.0
	if pass = "" : i.1 = 0 : else : ll_getptr pass : ll_ret i.1
	switch service
	case 2:  i.2 = 0x0002, 0 : swbreak
	case 3:  i.2 = 0x0003, 0 : swbreak
	default: i.2 = 0x0001, option ! 0 * 0x08000000
	swend
	ll_getptr server : ll_ret i.5
	prm = hinet, i.5, 0, i.0, i.1, i.2, i.3, 0
	ll_callfunc prm, 8, InternetConnect@
	ll_ret hsess : stt = hsess
	return

#deffunc inetlogout onexit
	if hsess : ll_callfunc hsess, 1, InternetCloseHandle@
	return	

#deffunc inetdirlist val, str, int
	mref lst, 24 : mref url, 33 : mref getinfo, 2
	dim wfd, 80
	prm = hsess
	ll_getptr url : ll_ret prm.1
	ll_getptr wfd : ll_ret prm.2
	ll_callfunc prm, 3, FtpFindFirstFile@
	ll_ret h
	if h {
		repeat
			sdim s, 400
			if getinfo & 1 ! 0 | (getinfo = 0) : getstr s, wfd, 44
			if getinfo & 2 ! 0 | (getinfo = 0) {
				if s ! "" : s += "\t"
				lpeek i, wfd
				if i & 0x0010 {
					s += "<DIR>"
				} else {
					lpeek i, wfd, 32 // 上位32ビットは無視(約4GB以下のみ)
					s += "" + i
				}
			}
			if getinfo & 4 ! 0 | (getinfo = 0) {
				dim j, 4
				lpeek i.0, wfd, 20
				lpeek i.1, wfd, 24
				ll_getptr i : ll_ret prm.0
				ll_getptr j : ll_ret prm.1
				ll_callfunc prm, 2, FileTimeToSystemTime@
				wpeek i.0, j.0
				wpeek i.1, j.0, 2
				wpeek i.2, j.1, 2
				wpeek i.3, j.2
				wpeek i.4, j.2, 2
				wpeek i.5, j.3
				if s ! "" : s += "\t"
				s += "" + i.0 + "/" + i.1 + "/" + i.2 + " " + i.3 + ":" + i.4 + ":" + i.5
			}
			if lst ! "" : lst += "\n"
			lst += s
			prm = h
			ll_getptr wfd : ll_ret prm.1
			ll_callfunc prm, 2, InternetFindNextFile@
			ll_ret i
			if i = 0 : break
		loop
	}
	return
#global

	server = "" : user = "" : pass = "" // 接続先を指定すること
	inetlogin server, user + ":" + pass
	sdim list, 1000
	inetdirlist list, "/"
	mesbox list, 640, 480
	stop

inetinit
[パラメータなし]インターネットサービスを開始するだけである為、パラメータは必要ない。

inetend
[パラメータなし]インターネットハンドルを解放するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

inetlogin サーバー, ユーザー, パスワード, サービス, オプション
サーバーホストサーバーアドレスまたはIPアドレス文字列を指定する。
ユーザーログインユーザー名を指定する。
パスワードログインパスワードを指定する。
サービス接続するサービス(1:FTP 2:Gopher 3:HTTP)を指定する。
尚、省略すればFTP接続を行う。
オプションFTPでパッシブモード利用する時、HTTPでHTTPS通信する時は1を指定する。
それ以外の時は0または省略する。

inetlogout
[パラメータなし]サーバーとの接続を解除するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

取出先 = inetdirlist(ディレクトリ, 取得情報)
取出先取得した情報一覧格納先変数を指定する。
ディレクトリ取得対象ディレクトリを指定する。
取得情報以下の取得する情報コード値合計を指定する。尚、取得情報は1データ1行・タブ区切り。
0全てを取得する(+7と一緒)
+1ファイル名を取得
+2ファイルサイズを取得
+4最終更新日時を取得

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#uselib "wininet.dll"
#cfunc	global InternetOpen "InternetOpenA" sptr, int, int, int, int
#func	global InternetCloseHandle "InternetCloseHandle" int
#cfunc	global InternetConnect "InternetConnectA" int, sptr, int, int, int, int, int, int
#cfunc	global InternetFindNextFile "InternetFindNextFileA" int, var
#cfunc	global FtpFindFirstFile "FtpFindFirstFileA" int, str, var, int, int
#uselib "kernel32.dll"
#func	global FileTimeToSystemTime "FileTimeToSystemTime" var, var

#module
#deffunc inetinit
	hinet = InternetOpen("hspbc")
	return hinet

#deffunc inetend onexit
	if hinet : InternetCloseHandle hinet
	return

#deffunc inetlogin str server, str user, str pass, int service, int option, local i, local s
	if hinet = 0 : inetinit
	s = user, pass
	if user = "" : i.0 = 0 : else : i.0 = varptr(s.0)
	if pass = "" : i.1 = 0 : else : i.1 = varptr(s.1)
	switch service
	case 2:  i.2 = 0x0002, 0 : swbreak
	case 3:  i.2 = 0x0003, 0 : swbreak
	default: i.2 = 0x0001, (option ! 0) * 0x08000000
	swend
	hsess = InternetConnect(hinet, server, , i.0, i.1, i.2, i.3)
	return hsess

#deffunc inetlogout onexit
	if hsess : InternetCloseHandle hsess
	return

#defcfunc inetdirlist str url, int getinfo, local i, local j, local h, local s, local rstr
	sdim rstr, 4096
	dim wfd, 80
	h = FtpFindFirstFile(hsess, url, wfd)
	if h {
		repeat
			sdim s, 400
			if (getinfo & 1) ! 0 | getinfo = 0 : getstr s, wfd, 44
			if (getinfo & 2) ! 0 | getinfo = 0 {
				if s ! "" : s += "\t"
				if lpeek(wfd) & 0x0010 {
					s += "<DIR>"
				} else {
					s += str(lpeek(wfd, 32)) // 上位32ビットは無視(約4GB以下のみ)
				}
			}
			if (getinfo & 4) ! 0 | getinfo = 0 {
				dim j, 4
				i = lpeek(wfd, 20), lpeek(wfd, 24)
				FileTimeToSystemTime i, j
				i = wpeek(j), wpeek(j, 2), wpeek(j.1, 2), wpeek(j.2), wpeek(j.2, 2), wpeek(j.3)
				if s ! "" : s += "\t"
				s += "" + i.0 + "/" + i.1 + "/" + i.2 + " " + i.3 + ":" + i.4 + ":" + i.5
			}
			if rstr ! "" : rstr += "\n"
			rstr += s
			if InternetFindNextFile(h, wfd) = 0 : break
		loop
	}
	return rstr
#global

	server = "" : user = "" : pass = "" // 接続先を指定すること
	inetlogin server, user, pass
	sdim list, 1000
	list = inetdirlist("/")
	mesbox list, 640, 480