続・UWSCで構造体がもうあんまり怖くないmodule

これの続き

そもそもなんで連想配列作って渡すとかいう面倒な設計したのか
耐えられなくなって書きなおした
でもやっぱ構造体の定義書くのはめんどくさいのであった
あと対応する型は必要になったら書き足すとして、最低限必要なものだけにしといた

Module内でDictionaryいっぱい使った!
これ絶対後で見たときわかんなくなるな!
コメント書いとこう…

module Struct
	procedure Struct
	fend
	
	//---------------------------------------------------------------------
	// *構造体定義関数群*
	// 
	// 1. DefineStruct()で名前を決めて
	// 2. DefineMember()でメンバを定義して
	// 3. StructAlloc()でメモリを確保
	//    または
	// 3. AttachStruct()で存在する構造体と構造体定義を結びつける
	// 
	// ※DLL関数の引数が構造体の場合はStructAlloc()して帰ってきた
	//  構造体のポインタを渡すようにする
	// ※DLL関数が戻り値で構造体を返してくる場合はAttachStruct()して
	//  構造体定義と戻り値の構造体を結びつけることでメンバにアクセス
	//  出来るようになる
	//---------------------------------------------------------------------

	// 引数:
	//   structName: 定義する構造体名
	// 戻り値 :
	//   bool、存在する構造体名だとfalse
	function DefineStruct(structName)
		if hashStruct[structName, HASH_EXISTS]
			result = false
			_setErrorMessage("DefineStruct(): この名前は既に使われています [" + structName + "]")
		else
			hashStruct[structName] = CreateOleObj("Scripting.Dictionary")
			result = true
		endif
	fend
	
	// 引数:
	//   structName: DefineStruct()した構造体名
	//   memberName: 定義するメンバ名
	//   type      : 定義するメンバの型、TYPE_定数で指定
	//   bufferSize: メンバのサイズ、char型(TYPE_CHAR)かstring型(TYPE_PTRSTRING)の時のみ使用
	// 戻り値 :
	//   bool、存在するメンバ名や、不正な定義だとfalse
	function DefineMember(structName, memberName, type, bufferSize = 0)
		select type
			case TYPE_CHAR
				if val(bufferSize, 0) then
					size = bufferSize
				else
					_setErrorMessage("DefineMember(): char型のサイズが0、または不正な値 [" + bufferSize + "]")
					result = false
					exit
				endif
			case TYPE_PTRSTRING
				bufferSize = val(bufferSize, -1)
				select bufferSize
					case 0
						size = STRING_BUFFER_SIZE
					case -1
						size = 0
						_setErrorMessage("DefineMember(): string型のサイズが不正 [" + bufferSize + "]")
						result = false
						exit
					default
						size = bufferSize
				selend
			default
				size = _getSize(type)
				if size = 0 then
					_setErrorMessage("DefineMember(): " + GetErrorMessage())
					result = false
					exit
				endif
		selend
		if hashStruct[structName].Exists(memberName) then
			result = false
			_setErrorMessage("DefineMember(): 既に定義されています [" + memberName + "]")
		else
			sa = safearray(0, 1)
			sa[0] = type
			sa[1] = size
			hashStruct[structName].item(memberName) = sa
			result = true
		endif
	fend
	
	// 引数:
	//   structName: DefineStruct()した構造体名
	// 戻り値 :
	//   構造体のアドレス、失敗時は0
	function StructAlloc(structName)
		if hashStruct[structName, HASH_EXISTS] then
			structSize = _getSizeOfDefinedStruct(structName)
			if structSize then
				result = _memoryAlloc(structSize)
				RtlFillMemory(result, structSize, 0)
				if hashStructAddress[result, HASH_EXISTS] then
					_setErrorMessage("StructAlloc(): 既に存在するアドレス [0x" + trim(format(result, 8, -1)) + "]")
					_freeMemory(result)
					result = 0
				else
					hashStruct[structName].item(_address) = result
					hashStructAddress[result] = CreateOleObj("Scripting.Dictionary")
					hashStructAddress[result].item(_size) = structSize
					hashStructAddress[result].item(_name) = structName
					hashStructAddress[result].item(_stringPointers) = CreateOleObj("Scripting.Dictionary")
					_getMembersAddresses(structName)
				endif
			else
				_setErrorMessage("StructAlloc(): サイズが0です、DefineMember()でメンバを定義して下さい [" + structName + "]")
				result = 0
			endif
		else
			_setErrorMessage("StructAlloc(): 未定義の構造体名です [" + structName + "]")
			result = 0
		endif
	fend
	
	// 引数:
	//   pStruct   : 構造体のアドレス(ポインタ変数)
	//   structName: DefineStruct()した構造体名
	// 戻り値 :
	//   bool、未定義構造体名を指定するとfalse
	function AttachStruct(pStruct, structName)
		if hashStruct[structName, HASH_EXISTS] then
			structSize = _getSizeOfDefinedStruct(structName)
			if structSize then
				hashStruct[structName].item(_address) = pStruct
				hashStructAddress[pStruct] = CreateOleObj("Scripting.Dictionary")
				hashStructAddress[pStruct].item(_size) = structSize
				hashStructAddress[pStruct].item(_stringPointers) = CreateOleObj("Scripting.Dictionary")
				_getMembersAddresses(structName)
				result = true
			else
				_setErrorMessage("AttachStruct(): サイズが0です、DefineMember()でメンバを定義して下さい [" + structName + "]")
				result = false
			endif
		else
			_setErrorMessage("AttachStruct(): 未定義の構造体名です [" + structName + "]")
			result = false
		endif
	fend
	
	// 構造体名からポインタを得る
	// 引数:
	//   structName: DefineStruct()した構造体名
	// 戻り値 :
	//   構造体のアドレス
	function GetStructPointerByName(structName)
		if hashStruct[structName, HASH_EXISTS] then
			result = hashStruct[structName].item(_address)
		else
			result = 0
			_setErrorMessage("GetStructPointerByName(): 未定義の構造体名です [" + structName + "]")
		endif
	fend
	
	// メンバの型を得る
	// 引数:
	//   structName: DefineStruct()した構造体名
	//   memberName: DefineMember()したメンバ名
	// 戻り値 :
	//   メンバの型(TYPE定数)、失敗時はempty
	function GetMemberType(structName, memberName)
		if hashStruct[structName, HASH_EXISTS] then
			if hashStruct[structName].Exists(memberName)
				sa = hashStruct[structName].item(memberName)
				result = sa[0]
			else
				result = empty
				_setErrorMessage("GetMemberType(): 未定義のメンバ名です [" + memberName + "]")
			endif
		else
			result = empty
			_setErrorMessage("GetMemberType(): 未定義の構造体名です [" + structName + "]")
		endif
	fend
	
	// メンバに値を代入する
	// 引数:
	//   structName: DefineStruct()した構造体名
	//   memberName: DefineMember()したメンバ名
	//   value     : 値
	// 戻り値 :
	//   bool、失敗時はfalse
	function SetMemberValue(structName, memberName, value)
		try
			if hashStruct[structName, HASH_EXISTS] then
				pStruct = hashStruct[structName].item(_address)
				if hashStructAddress[pStruct].Exists(memberName) then
					pMember = hashStructAddress[pStruct].item(memberName)
					sa = hashStruct[structName].item(memberName)
					type = sa[0]
					size = sa[1]
					result = _memCopyToStruct(pMember, type, size, value, pStruct)
					if type = TYPE_PTRSTRING then
						//string型が指定された場合、valueのlengthbをGetMemberValueで受け取る際のバッファサイズにする
						//→DefineMemberで指定したbufferSizeが上書きされる
						sa[1] = lengthb(value)
						hashStruct[structName].item(memberName) = sa
					endif
				else
					result = false
					_setErrorMessage("SetMemberValue(): 未定義のメンバ名 [" + memberName + "]")
				endif
			else
				result = false
				_setErrorMessage("SetMemberValue(): 未定義の構造体名 [" + structName + "]")
			endif
		except
			result = false
			print try_errmsg
			print try_errline
			_setErrorMessage("SetMemberValue(): エラー [" + try_errmsg + "]")
		endtry
	fend
	
	// メンバに値を得る
	// 引数:
	//   structName: DefineStruct()した構造体名
	//   memberName: DefineMember()したメンバ名
	//   value     : 値
	// 戻り値 :
	//   失敗時はnull
	function GetMemberValue(structName, memberName)
		if hashStruct[structName, HASH_EXISTS] then
			pStruct = hashStruct[structName].item(_address)
			if hashStructAddress[pStruct].Exists(memberName) then
				pMember = hashStructAddress[pStruct].item(memberName)
				sa = hashStruct[structName].item(memberName)
				type = sa[0]
				size = sa[1]
				result = _memCopyFromStruct(pMember, type, size)
				if result = null then
					_setErrorMessage("GetMemberValue(): " + GetErrorMessage())
				endif
			else
				_setErrorMessage("GetMemberValue(): 未定義のメンバ名 [" + memberName + "]")
				result = null
			endif
		else
			result = null
			_setErrorMessage("GetMemberValue(): 未定義の構造体名 [" + structName + "]")
		endif
	fend
	
	// StructAlloc()した構造体を開放する
	// Stringのメンバは別途メモリを確保してるのでそれらの開放も行う
	// 引数:
	//   pStructOrStructName: DefineStruct()した構造体名か、構造体のポインタ(StructAlloc()の戻り値)
	// 戻り値 :
	//   bool、失敗時はfalse
	function FreeStruct(pStructOrStructName)
		errmsg = ""
		
		if hashStructAddress[pStructOrStructName, HASH_EXISTS] then
			pStruct = pStructOrStructName
			StructName = hashStructAddress[pStruct].item(_name)
		else
			if hashStruct[pStructOrStructName, HASH_EXISTS] then
				StructName = pStructOrStructName
				pStruct = hashStruct[StructName].item(_address)
			else
				_setErrorMessage("FreeStruct(" + pStructOrStructName + "): 未定義の構造体です")
				result = false
				exit
			endif
		endif
		
		pointers = hashStructAddress[pStruct].item(_stringPointers).items
		keys     = hashStructAddress[pStruct].item(_stringPointers).keys
		for i = 0 to length(pointers) - 1
			if ! _freeMemory(pointers[i]) then
				errmsg = errmsg + "<#CR>" + keys[i] + "の開放に失敗 [" + pointers[i] + "]"
			endif
		next
		if _freeMemory(pStruct) then
			result = hashStructAddress[pStruct, HASH_REMOVE]
			result = result and hashStruct[StructName, HASH_REMOVE]
			if ! result then
				_setErrorMessage("FreeStruct(" + pStructOrStructName + "): 構造体の登録解除に失敗[" + pStruct + "]" + errmsg)
			endif
		else
			errmsg = "構造体の開放に失敗 [" + pStructOrStructName + "]" + errmsg
		endif
		if length(errmsg) then
			_setErrorMessage("FreeStruct(" + pStructOrStructName + "): " + errmsg)
			result = false
		else
			result = true
		endif
	fend
	
	// 構造体のサイズを得る
	// 引数:
	//   pStruct: 構造体のポインタ(StructAlloc()の戻り値)
	// 戻り値 :
	//   サイズ(byte)、失敗時は0
	function GetStructSize(pStruct)
		if hashStructAddress[pStruct, HASH_EXISTS] then
			dicStruct = hashStructAddress[pStruct]
			result = dicStruct.item(_size)
		else
			_setErrorMessage("GetStructSize(" + pStruct + "): SetStructMemberNames()された構造体ではありません")
			result = 0
		endif
	fend
	
	// エラーメッセージを得る、関数失敗時に呼ぶ
	function GetErrorMessage()
		result = errorMessage
		errorMessage = ""
	fend
	
	//-----------------------
	// 内部関数
	//-----------------------

	// 構造体サイズを得る
	// 引数:
	//   structName: DefineStruct()した構造体名
	// 戻り値 :
	//   指定した構造体のサイズ
	function _getSizeOfDefinedStruct(structName)
		result = 0
		items = hashStruct[structName].items
		names = hashStruct[structName].keys
		for i = 0 to length(items) - 1
			if ! (names[i] = _address) then
				sa = items[i]
				type = sa[0]
				size = sa[1]
				if type = TYPE_PTRSTRING then
					result = result + 4
				else
					result = result + size
				endif
			endif
		next
	fend
	
	// メンバのアドレスを配列に格納
	// 引数:
	//   structName: DefineStruct()した構造体名
	procedure _getMembersAddresses(structName)
		pStruct = hashStruct[structName].item(_address)
		names = hashStruct[structName].keys
		type_size = hashStruct[structName].items
		address = pStruct
		for i = 0 to length(names) - 1
			if ! (names[i] = _address) then
				sa = type_size[i]
				type = sa[0]
				size = sa[1]
				hashStructAddress[pStruct].item(names[i]) = address
				if type = TYPE_PTRSTRING then
					address = address + 4
				else
					address = address + size
				endif
			endif
		next
	fend
	
	function _memCopyToStruct(pMember, type, size, value, pStruct)
		result = true
		select type
			case TYPE_INT
				def_dll RtlMoveMemory(dword, var int, dword):kernel32
			case TYPE_LONG
				def_dll RtlMoveMemory(dword, var long, dword):kernel32
			case TYPE_DWORD, TYPE_PTR
				def_dll RtlMoveMemory(dword, var dword, dword):kernel32
			case TYPE_PTRSTRING
				def_dll RtlMoveMemory(dword, var string, dword):kernel32
				str = value
				len = lengthb(str)
				//string型の場合、valueはポインタ
				if len then
					hashStructAddress[pStruct].item(_stringPointers).item(pMember) = _memoryAlloc(len)
					value = hashStructAddress[pStruct].item(_stringPointers).item(pMember)
					RtlMoveMemory(value, str, len)
					def_dll RtlMoveMemory(dword, var dword, dword):kernel32
					size = 4
				else
					exit
				endif
			case TYPE_WORD
				def_dll RtlMoveMemory(dword, var word, dword):kernel32
			case TYPE_BYTE
				def_dll RtlMoveMemory(dword, var byte, dword):kernel32
			case TYPE_CHAR
				def_dll RtlMoveMemory(dword, var string, dword):kernel32
			default
				_setErrorMessage("_memCopyToStruct(): 未対応の型、または不正な値; type = " + type)
				result = false
		selend
		if size then
			RtlMoveMemory(pMember, value, size)
		endif
	fend
	
	function _memCopyFromStruct(pMember, type, size)
		result = empty
		select type
			case TYPE_INT
				def_dll RtlMoveMemory(var int, dword, dword):kernel32
			case TYPE_LONG
				def_dll RtlMoveMemory(var long, dword, dword):kernel32
			case TYPE_DWORD, TYPE_PTR
				def_dll RtlMoveMemory(var dword, dword, dword):kernel32
			case TYPE_PTRSTRING
				def_dll RtlMoveMemory(var dword, dword, dword):kernel32
				dim ppMember = 0
				RtlMoveMemory(ppMember, pMember, 4)
				if ppMember then
					pMember = ppMember
					result = format(chr(0), size)
					def_dll RtlMoveMemory(var string, dword, dword):kernel32
				else
					exit
				endif
			case TYPE_WORD
				def_dll RtlMoveMemory(var word, dword, dword):kernel32
			case TYPE_BYTE
				def_dll RtlMoveMemory(var byte, dword, dword):kernel32
			case TYPE_CHAR
				if false then
					//byte配列をchrb()で変換
					def_dll RtlMoveMemory(var byte[], dword, dword):kernel32
					dim char[size - 1]
					RtlMoveMemory(char, pMember, size)
					for i = 0 to size - 1
						char[i] = chrb(char[i])
					next
					result = join(char, "")
					exit
				else
					//↑こんなんしなくてもstringのポインタにコピーも平気っぽい
					def_dll RtlMoveMemory(var string, dword, dword):kernel32
					result = format(chr(0), size)
				endif
			default
				_setErrorMessage("_memCopyFromStruct(): 未対応の型、または不正な値; type = " + type)
				exit
		selend
		if size then
			RtlMoveMemory(result, pMember, size)
		endif
	fend
	
	function _memoryAlloc(size)
		result = VirtualAlloc(null, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
	fend
	
	function _freeMemory(p)
		result = VirtualFree(p, 0, MEM_RELEASE)
	fend
	
	function _getSize(CONST_TYPE)
		select CONST_TYPE
			case TYPE_PTR, TYPE_INT, TYPE_LONG, TYPE_DWORD, TYPE_PTRSTRING
				result = 4
			case TYPE_WORD
				result = 2
			case TYPE_BYTE
				result = 1
			default
				_setErrorMessage("_getSize(): 未対応の型、または不正な値; CONST_TYPE = " + CONST_TYPE)
				result = 0
		selend
	fend
	
	procedure _setErrorMessage(msg)
		errorMessage = msg
	fend
	


	//-----------------------
	// 構造体管理用連想配列
	//-----------------------

	// hashStruct[構造体の定義名]
	//   メンバリスト及び構造体のポインタを持つ(辞書)
	//     _address   : 構造体のポインタ
	//     (メンバ名) : 長さ2のSafeArray
	//                  SafeArray[0] = 型、SafeArray[1] = サイズ(byte)
	// 
	// hashStructAddress[構造体のポインタ]
	//   構造体情報(辞書)を持つ
	//     _size           : 構造体サイズ
	//     _name           : 構造体名
	//     _stringPointers : String型メンバのポインタリスト(辞書) #Stringの場合はポインタのポインタでやりとりする
	//                       key  : メンバのアドレス
	//                       value: Stringのポインタ
	//     (メンバ名)      : メンバのアドレス
	hashtbl hashStructAddress, hashStruct

	//-----------------------
	// 変数・定数・DLL関数定義
	//-----------------------

	
	dim errorMessage = ""
	dim _size           = "__size__"
	dim _name           = "__name__"
	dim _address        = "__address__"
	dim _stringPointers = "__stringPointers__"
	
	const STRING_BUFFER_SIZE = 1024
	
	const TYPE_PTR       = "TYPE_POINTER"
	const TYPE_INT       = "TYPE_INT"
	const TYPE_LONG      = "TYPE_LONG"
	const TYPE_DWORD     = "TYPE_DWORD"
	const TYPE_PTRSTRING = "TYPE_PTRSTRING"
	const TYPE_WORD      = "TYPE_WORD"
	const TYPE_BYTE      = "TYPE_BYTE"
	const TYPE_CHAR      = "TYPE_CHAR"
	
	const MEM_COMMIT             = $1000
	const PAGE_EXECUTE_READWRITE = $40
	Const MEM_RELEASE            = $8000
	def_dll VirtualAlloc(dword, dword, dword, dword):dword:kernel32
	def_dll VirtualFree(dword, dword, dword):long:kernel32
	def_dll RtlFillMemory(long, dword, byte):kernel32
	
endmodule

続・UWSCで構造体がもうあんまり怖くないmodule」への1件のフィードバック

  1. ピンバック: UWSCで構造体がもうあんまり怖くないmodule | たっぷす庵

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中