ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2024年3月29日(金) 17:50

全ての表示時間は UTC+09:00 です




新しいトピックを投稿する  トピックへ返信する  [ 3 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2005年6月04日(土) 10:33 
オフライン

登録日時: 2005年6月04日(土) 10:09
記事: 72
以前に投稿した(↓)コマンドライン引数を分離する関数をクラスにしました。
http://www.discoversoft.net/wforum/wfor ... =past#1603

2005. 6/11編集
旧掲示板WebForumが閉鎖されたので、過去ログ集BackSearchABのトピック番号を書いておきます。
 目次:1715-コマンドライン引数
 タイトル:Re^6: コマンドライン引数
 投稿時間:2004/05/03(Mon) 15:59


Iteratorパターンを使ったらわりとすっきりしたので、投稿してみます。
ついでにロジックの方も見直してみました。少し分かり易くなった...かな?

---以下ソース
コード:
'コマンドライン引数を1つずつ切り出すクラス
Declare Function GetLongPathName Lib "kernel32" Alias "GetLongPathNameA" (lpszShortPath As BytePtr, lpszLongPath As BytePtr, cchBuffer As DWord) As DWord
TypeDef BOOL = Long

Class CommandLineArgumentsIterator
	lpCmdLineArgs As BytePtr
	lpCurrentPos As BytePtr
	szCurrentArg[ELM(MAX_PATH)] As Byte

Protected
	Function HasShortFileName() As BOOL
		Dim osver As OSVERSIONINFO
		osver.dwOSVersionInfoSize=SizeOf(OSVERSIONINFO)
		GetVersionEx(osver)
		If osver.dwPlatformId=VER_PLATFORM_WIN32_WINDOWS Then
			HasShortFileName=TRUE
		Else
			HasShortFileName=FALSE
		End If
	End Function

	Sub ConvertToLongFileName(lpArg As BytePtr)
		Dim buffer[ELM(MAX_PATH)] As Byte
		GetLongPathName(lpArg, buffer, MAX_PATH)
		lstrcpy(lpArg, buffer)
	End Sub

Public
	Sub CommandLineArgumentsIterator(lpStr As BytePtr)
		lpCmdLineArgs=lpStr
		lpCurrentPos=lpCmdLineArgs
	End Sub

	Function HasNext() As BOOL
		If lpCurrentPos[0]<>NULL Then
			HasNext=TRUE
		Else
			HasNext=FALSE
		End If
	End Function

	Function GetNext() As BytePtr
		Dim i As Long, j As Long
		Dim c As Byte
		Dim bDqrt As BOOL

		If lpCurrentPos[0]=Asc(Ex"\q") Then
			bDqrt=TRUE
		Else
			bDqrt=FALSE
		End If

		'"の有無によって初期位置・終端文字を変更する
		If bDqrt Then
			i=1: c=Asc(Ex"\q")
		Else
			i=0: c=Asc(" ")
		End If
		'パラメータひとつ分を抽出する
		j=0
		While (lpCurrentPos<>c  And lpCurrentPos<>NULL And j<MAX_PATH)
			szCurrentArg[j]=lpCurrentPos
			i=i+1: j=j+1
		Wend
		szCurrentArg[j]=NULL

		'長いファイル名に変換する
		If(HasShortFileName() And bDqrt=FALSE) Then
			ConvertToLongFileName(szCurrentArg)
		End If

		'次のパラメータの位置を格納
		Select Case lpCurrentPos
			Case Asc(Ex"\q")
				Select Case lpCurrentPos[i+1]
					Case NULL
						lpCurrentPos=lpCurrentPos+i+1	' "Param1"\0
					Case Asc(" ")
						lpCurrentPos=lpCurrentPos+i+2	' "Param1"_?Param2?...
				End Select
			Case Asc(" ")
				lpCurrentPos=lpCurrentPos+i+1	' Param1_?Param2?...
			Case NULL
				lpCurrentPos=lpCurrentPos+i	' Param1\0
		End Select
		GetNext=szCurrentArg
	End Function

	Sub Reset()
		lpCurrentPos=lpCmdLineArgs
	End Sub
End Class


---使用法
コード:
Dim arg As CommandLineArgumentsIterator(GetCommandLine())

While arg.HasNext()
	Dim buf As BytePtr
	buf=arg.GetNext()
	MessageBox(0, buf, "", MB_OK)
Wend


通報する
ページトップ
投稿記事Posted: 2005年9月25日(日) 15:59 
オフライン

登録日時: 2005年6月04日(土) 10:09
記事: 72
↑コマンドライン引数を分解するクラスの分解アルゴリズムの見直し、メソッドの追加・変更を行いました。
主な変更点・仕様は次の通り。

1.分解アルゴリズム(GetNext()メソッド)見直しについて
●前回のはエクスプローラでD&D起動したときに渡されるコマンドライン文字列を解析した結果から、それに見合うようコーディングしたが、
 今回はコマンドラインインタプリタ(cmd.exe)の分解手順を「ダブルクォーテーションの外側にあるスペースを引数の区切り文字として扱う」
 と仮定し、それに従いコーディングした。
●エクスプローラからのD&D、関連付けによる実行はもちろん、コマンドラインからの複数のダブルクォーテーションを持つ場合
 スペースが入るフォルダのみダブルクォーテーションで括った場合にも対応。
●lpCurrentPosをBytePtr+添え字による配列アクセスからポインタ扱いとすることで多少コードをスリム化。
●引数間に余分なスペースがあってもOK。
●あと対応が必要といえば、Unicode、DBCS(全角文字)などがありますが、現状で特に問題ないため放置してます。(--);
 不具合等あれば対応したいので御報告ください。m(__)m

2.追加・変更されたメソッドについて
●PublicメソッドGetCommandLine(), GetCurrentPos()を追加。詳細は下記のリファレンスを参照してください。
●内部関数(Protectメソッド)を前の2つからConvertToLongFileName()1つに集約。


各メソッドのリファレンスも付けました↓
Sub CommandLineArgumentsIterator(lpStr As BytePtr)
説明:コンストラクタ
引数:lpStr …コマンドライン引数の文字列を指定します。
GetCommandLine()関数(API)で取得したり、PathGetArgs()関数で引数部分のみ取り出したものを指定できます。

Function HasNext() As BOOL
説明:次の引数があるかないかを返します。Iteratorパターン。
戻り値:次の引数があるときはTRUE(=1)、ないときはFALSE(=0)。

Function GetNext() As BytePtr
説明:引数を1つ分離しそれを返します。Iteratorパターン。
   実行後、内部変数lpCurrentPosが次の引数の位置に移り、バッファszCurrentArgに分離した引数が格納されます。
戻り値:バッファszCurrentArgへのポインタが返ります。分離した引数をBytePtr文字列として使えます。

Sub Reset()
説明:次の引数の位置をコンストラクタで指定された文字列のアドレス位置に戻します。

Function GetCommandLine() As BytePtr
説明:コンストラクタで指定したコマンドライン引数の文字列を返します。

Function GetCurrentPos() As BytePtr
説明:次に分離されるの引数以下の文字列を返します。

コード:
TypeDef BOOL = Long

'コマンドライン引数を1つずつ切り出すクラス
Class CommandLineArgumentsIterator
	lpCmdLineArgs As BytePtr

Protected
	lpCurrentPos As BytePtr
	szCurrentArg[ELM(MAX_PATH)] As Byte

	Sub ConvertToLongFileName(lpStr As BytePtr)
		Dim osver As OSVERSIONINFO

		osver.dwOSVersionInfoSize=SizeOf(OSVERSIONINFO)
		GetVersionEx(osver)
		If osver.dwMajorVersion=4 Then	'Windows 95/98/Me、Windows NT4.0
			Dim buffer[ELM(MAX_PATH)] As Byte
			GetLongPathName(lpStr, buffer, MAX_PATH)
			lstrcpy(lpStr, buffer)
		End If
	End Sub

Public
	Sub CommandLineArgumentsIterator(lpStr As BytePtr)
		lpCmdLineArgs=lpStr
		lpCurrentPos=lpCmdLineArgs
	End Sub

	Function HasNext() As BOOL
		If lpCurrentPos[0]<>NULL Then
			HasNext=TRUE
		Else
			HasNext=FALSE
		End If
	End Function

	Function GetNext() As BytePtr
		Dim i=0 As Long

		'引数ひとつ分を抽出する
		While (lpCurrentPos[0]<>Asc(" ") And lpCurrentPos[0]<>NULL And i<MAX_PATH-1)
			If lpCurrentPos[0]=Asc(Ex"\q") Then		'ダブルクォーテーションの内側
				'ダブルクォーテーションを読み飛ばす
				lpCurrentPos=lpCurrentPos+1
				'次のダブルクォーテーションまで読み込む
				While (lpCurrentPos[0]<>Asc(Ex"\q") And lpCurrentPos[0]<>NULL And i<MAX_PATH-1)
					szCurrentArg=lpCurrentPos[0]
					i=i+1: lpCurrentPos=lpCurrentPos+1
				Wend
				If lpCurrentPos[0]=Asc(Ex"\q") Then lpCurrentPos=lpCurrentPos+1
			Else	'ダブルクォーテーションの外側
				szCurrentArg=lpCurrentPos[0]
				i=i+1: lpCurrentPos=lpCurrentPos+1
			End If
		Wend
		szCurrentArg=NULL

		'長いファイル名に変換する
		ConvertToLongFileName(szCurrentArg)

		'次の引数の位置を格納(余分なスペースを読み飛ばす)
		While lpCurrentPos[0]=Asc(" ")
			lpCurrentPos=lpCurrentPos+1
		Wend
		GetNext=szCurrentArg
	End Function

	Sub Reset()
		lpCurrentPos=lpCmdLineArgs
	End Sub

	Function GetCommandLine() As BytePtr
		GetCommandLine=lpCmdLineArgs
	End Function

	Function GetCurrentPos() As BytePtr
		GetCurrentPos=lpCurrentPos
	End Function
End Class


使用例:
こちらもただ使うだけから引数をまとめて表示するようグレードアップしました。
PathGetArgsを使い引数部分のみ表示するようにしています。

コード:
Declare Function GetLongPathName Lib "kernel32" Alias "GetLongPathNameA" (lpszShortPath As BytePtr, lpszLongPath As BytePtr, cchBuffer As DWord) As DWord
Declare Function PathGetArgs Lib "shlwapi" Alias "PathGetArgsA" (psz As BytePtr) As BytePtr

Dim arg As CommandLineArgumentsIterator(PathGetArgs(GetCommandLine()))
Dim str As String
Dim buf As String
Dim i As Long

If arg.HasNext() Then
	i=1
Else
	MessageBox(0, "ファイルをドロップしてください。", "CommandLineArgumentsIterator", MB_OK)
	ExitProcess(0)
End If

While arg.HasNext()
	buf=Str$(i) + "個目:" + arg.GetNext() + Ex"\n"
	str=str+buf
	i=i+1
Wend

MessageBox(0, str, "CommandLineArgumentsIterator", MB_OK)
ExitProcess(0)


最後に編集したユーザー Tomorrow [ 2005年10月09日(日) 16:27 ], 累計 3 回

通報する
ページトップ
投稿記事Posted: 2005年9月25日(日) 16:03 
オフライン

登録日時: 2005年6月04日(土) 10:09
記事: 72
C言語のmain()関数みたいにargc, argvによるコマンドライン引数へのアクセスを望む声もあったので、作ってみました。
内部で上のCommandLineArgumentsIteratorクラスの機能を使用しているので、そちらも同じsbpファイルにでも入れておいてください。

Function argc() As Long
で要素数が返り、

Function argv(num As Long) As BytePtr
で指定した要素番号に該当するコマンドライン引数が返ります。

コード:
'コマンドライン引数を配列として扱うクラス
Class CommandLineArgV
	list As *BytePtr
	size As Long
	argbuf[ELM(MAX_PATH)] As Byte

Public
	Sub CommandLineArgV(lpStr As BytePtr)
		Dim argitr As CommandLineArgumentsIterator(lpStr)
		size=0

		'引数の数を調べる
		While argitr.HasNext()
			size=size+1
			argitr.GetNext()
		Wend

		'各引数の位置を格納
		list=malloc(size*SizeOf(BytePtr))
		argitr.Reset()
		Dim i=0 As Long
		While argitr.HasNext()
			list=argitr.GetCurrentPos()
			argitr.GetNext()
			i=i+1
		Wend
	End Sub

	Sub ~CommandLineArgV()
		free(list)
	End Sub

	Function argc() As Long
		argc=size
	End Function

	Function argv(num As Long) As BytePtr
		'インデックスエラー
		If num>=size Then
			argv=NULL
			Exit Function
		End If
		'位置[num]にある引数を取り出して返す
		Dim argitr As CommandLineArgumentsIterator(list[num])
		If argitr.HasNext() Then
			lstrcpy(argbuf, argitr.GetNext())
		Else
			argbuf[0]=NULL
		End If
		argv=argbuf
	End Function
End Class


使用例です。上のIteratorのものと同じ挙動をします。

コード:
Declare Function GetLongPathName Lib "kernel32" Alias "GetLongPathNameA" (lpszShortPath As BytePtr, lpszLongPath As BytePtr, cchBuffer As DWord) As DWord
Declare Function PathGetArgs Lib "shlwapi" Alias "PathGetArgsA" (psz As BytePtr) As BytePtr

Dim arg As CommandLineArgV(PathGetArgs(GetCommandLine()))
Dim str As String
Dim buf As String
Dim i As Long

If arg.argc()=0 Then
	MessageBox(0, "ファイルをドロップしてください。", "CommandLineArgumentsIterator", MB_OK)
	ExitProcess(0)
End If

For i=0 To arg.argc()-1
	buf=Str$(i+1) + "個目:" + arg.argv(i) + Ex"\n"
	str=str+buf
Next

MessageBox(0, str, "CommandLineArgV", MB_OK)
ExitProcess(0)


通報する
ページトップ
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 3 件の記事 ] 

全ての表示時間は UTC+09:00 です


オンラインデータ

このフォーラムを閲覧中のユーザー: DotBot & ゲスト[14人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by ocean