'function.sbp

Const _System_PI = 3.14159265358979323846264
Const _System_SQRT2 = 1.41421356237309504880168872421

'------------- サポート関数の定義 -------------

Function ipow(x As Double, n As Long) As Double
	ipow = ActiveBasic.Math.pow(x, n)
End Function

Function pow(x As Double, y As Double) As Double
	pow = ActiveBasic.Math.pow(x, y)
End Function

Const RAND_MAX = &H7FFFFFFF
Dim _System_RndNext = 1 As DWord

Function rand() As Long
	_System_RndNext = _System_RndNext * 1103515245 + 12345
	rand = (_System_RndNext >> 1) As Long
End Function

Sub srand(dwSeek As DWord)
	_System_RndNext = dwSeek
End Sub

'------------- ここからBasic標準関数の定義 -------------

'------------------
' データ型変換関数
'------------------

Function CDbl(number As Double) As Double
	CDbl=number
End Function

Function _CUDbl(number As QWord) As Double
	_CUDbl=number As Double
End Function

Function CDWord(num As Double) As DWord
	CDWord=num As DWord
End Function

Function CInt(number As Double) As Long
	CInt=number As Long
End Function

Function CSng(number As Double) As Single
	CSng=number As Single
End Function

#ifdef _WIN64
Function Fix(number As Double) As Long
	Fix=number As Long
End Function
#else
'Fix関数はコンパイラに組み込まれている
'Function Fix(number As Double) As Long
#endif

Function Int(number As Double) As Long
	Int = Fix(number)
	If number < 0 Then
		If number < Fix(number) Then Int--
	End If
End Function


'-------------------------------------
' ポインタ関数（コンパイラに組み込み）
'-------------------------------------

'Function GetDouble(p As DWord) As Double
'Function GetSingle(p As DWord) As Single
'Function GetDWord(p As DWord) As DWord
'Function GetWord(p As DWord) As Word
'Function GetByte(p As DWord) As Byte
'Sub SetDouble(p As DWord, dblData As Double)
'Sub SetSingle(p As DWord, fltData As Single)
'Sub SetDWord(p As DWord, dwData As DWord)
'Sub SetWord(p As DWord, wData As Word)
'Sub SetByte(p As DWord, byteData As Byte)


'----------
' 算術関数
'----------

/*
Function Abs(n As Double) As Double
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Abs(n As Single) As Single
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Abs(n As Int64) As Int64
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Abs(n As Long) As Long
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Abs(n As Integer) As Integer
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Abs(n As SByte) As SByte
	Abs = ActiveBasic.Math.Abs(n)
End Function

Function Exp(x As Double) As Double
	Exp = ActiveBasic.Math.Exp(x)
End Function

Function Log(x As Double) As Double
	Log = ActiveBasic.Math.Log(x)
End Function
*/
Function Sgn(n As Double) As Long
'	Sgn = ActiveBasic..Math.Sign(n)
End Function

Function Sqr(x As Double) As Double
	Sqr = ActiveBasic.Math.Sqrt(x)
End Function

Function Atn(x As Double) As Double
	Atn = ActiveBasic.Math.Atan(x)
End Function

Function Atn2(y As Double, x As Double) As Double
	Atn2 = ActiveBasic.Math.Atan2(y, x)
End Function
/*
Function Sin(x As Double) As Double
	Sin = ActiveBasic.Math.Sin(x)
End Function

Function Cos(x As Double) As Double
	Cos = ActiveBasic.Math.Cos(x)
End Function

Function Tan(x As Double) As Double
	Tan = ActiveBasic.Math.Tan(x)
End Function
*/
Const RAND_UNIT = (1.0 / (LONG_MAX + 1.0))
Function Rnd() As Double
	Rnd = RAND_UNIT * rand()
End Function

Const HIDWORD(qw) = (((qw As QWord) >> 32) And &HFFFFFFFF) As DWord
Const LODWORD(qw) = ((qw As QWord) And &HFFFFFFFF) As DWord

Const MAKEDWORD(l, h) = (((l As DWord) And &HFFFF) Or (((h As DWord) And &HFFFF) << 16)) As DWord
Const MAKEQWORD(l, h) = (((l As QWord) And &HFFFFFFFF) Or (((h As QWord) And &HFFFFFFFF) << 32)) As QWord

'------------
' 文字列関数
'------------

Function Asc(buf As String) As Char
	Asc = buf[0]
End Function

Function Chr$(code As Char) As String
	Chr$ = New String(code, 1)
End Function

#ifdef UNICODE
Function AscW(s As String) As UCSCHAR
	If String.IsNullOrEmpty(s) Then
		AscW = 0
		'ArgumentNullExceptionに変えるかも
	Else
		If _System_IsHighSurrogate(s[0]) Then
			'有効なサロゲートペアになっていない場合には、
			'例外を投げるようにしたほうがよいかもしれない。
			If s.Length > 1 Then
				If _System_IsLowSurrogate(s[0]) Then
					AscW = ((s[0] And &h3FF) As DWord << 10) Or (s[1] And &h3FF)
					AscW += &h10000
					Exit Function
				End If
			End If
		Else
			AscW = s[0]
		End If
	End If
End Function

Function ChrW(c As UCSCHAR) As String
	If c <= &hFFFF Then
		Return New String(c As Char, 1)
	ElseIf c <= &h10FFFF Then
		c -= &h10000
		Dim t[1] As WCHAR
		t[0] = (&hD800 Or (c >> 10)) As WCHAR
		t[1] = (&hDC00 Or (c And &h3FF)) As WCHAR
		Return New String(t, 2)
	Else
		Throw New System.ArgumentOutOfRangeException("ChrW: c is invalid Unicode code point.", "c")
	End If
End Function
#endif

Function Date$() As String
	Dim date = System.DateTime.Now
	Dim buf = New System.Text.StringBuilder(10)

	'year
	buf.Append(date.Year)

	'month
	If date.Month < 10 Then
		buf.Append("/0")
	Else
		buf.Append("/")
	End If
	buf.Append(date.Month)

	'day
	If date.Day < 10 Then
		buf.Append("/0")
	Else
		buf.Append("/")
	End If
	buf.Append(date.Day)

	Date$ = buf.ToString
End Function

Function Hex$(x As DWord) As String
	Imports ActiveBasic.Strings.Detail
	Hex$ = FormatIntegerX(x, 1, 0, None)
End Function

Function Hex$(x As QWord) As String
	Imports ActiveBasic.Strings.Detail
	Hex$ = FormatIntegerLX(x, 1, 0, None)
End Function

Function InStr(StartPos As Long, buf1 As String, buf2 As String) As Long
	Dim i As Long, i2 As Long, i3 As Long

	Dim len1 = 0 As Long
	Dim len2 = 0 As Long
	If Not ActiveBasic.IsNothing(buf1) Then len1 = buf1.Length
	If Not ActiveBasic.IsNothing(buf2) Then len2 = buf2.Length

	If len2 = 0 Then
		InStr = StartPos
		Exit Function
	End If

	StartPos--
	If StartPos < 0 Then
		'error
		InStr = 0
		Exit Function
	End If

	i=StartPos:InStr=0
	While i<=len1-len2
		i2=i:i3=0
		Do
			If i3=len2 Then
				InStr=i+1
				Exit Do
			End If
			If buf1[i2]<>buf2[i3] Then Exit Do

			i2++
			i3++
		Loop
		If InStr Then Exit While
		i++
	Wend
End Function

Function Left$(s As String, length As Long) As String
	If Not ActiveBasic.IsNothing(s) Then
		Left$ = s.Substring(0, System.Math.Min(s.Length, length))
	Else
		Left$ = ""
	End If
End Function

Function Mid$(s As String, startPos As Long) As String
	If Not ActiveBasic.IsNothing(s) Then
		startPos--
		Mid$ = s.Substring(startPos)
	Else
		Mid$ = ""
	End If
End Function

Function Mid$(s As String, startPos As Long, readLength = 0 As Long) As String
	If Not ActiveBasic.IsNothing(s) Then
		startPos--
		Dim length = s.Length
		Mid$ = s.Substring(System.Math.Min(startPos, length), System.Math.Min(readLength, length - startPos))
	Else
		Mid$ = ""
	End If
End Function

Function Oct$(n As QWord) As String
	Imports ActiveBasic.Strings.Detail
	Oct$ = FormatIntegerLO(n, 1, 0, None)
End Function

Function Oct$(n As DWord) As String
	Imports ActiveBasic.Strings.Detail
	Oct$ = FormatIntegerO(n, 1, 0, None)
End Function

Function Right$(s As String, length As Long) As String
	If Not ActiveBasic.IsNothing(s) Then
		Right$ = s.Substring(System.Math.Max(0, s.Length - length), s.Length)
	Else
		Right$ = ""
	End If
End Function

Function Space$(length As Long) As String
	Return New String(&h20 As Char, length)
End Function

Sub _ecvt_support(buf As *Char, count As Long, size As Long)
	Dim i As Long
	If buf[count] = 9 Then
		buf[count] = 0
		If count = 0 Then
			For i = size To 1 Step -1
				buf[i] = buf[i-1]
			Next
			buf[0] = 1
		Else
			_ecvt_support(buf, count-1, size)
		End If
	Else
		buf[count]++
	End If
End Sub

Sub _ecvt(buffer As *Char, value As Double, count As Long, ByRef dec As Long, ByRef sign As Boolean)
	Dim i As Long, i2 As Long

	'値が0の場合
	If value = 0 Then
		ActiveBasic.Strings.ChrFill(buffer, count As SIZE_T, &h30 As Char)
		buffer[count] = 0
		dec = 0
		sign = 0
		Exit Function
	End If

	'符号の判断（同時に符号を取り除く）
	If value < 0 Then
		sign = True
		value = -value
	Else
		sign = False
	End If

	'正規化
	dec = 1
	While value < 0.999999999999999 'value<1
		value *= 10
		dec--
	Wend
	While 9.99999999999999 <= value '10<=value
		value /= 10
		dec++
	Wend

	For i = 0 To count - 1
		buffer[i] = Int(value) As Char
		value = (value-CDbl(Int(value))) * 10
	Next

	i--
	If value >= 5 Then
		'切り上げ処理
		_ecvt_support(buffer, i, count)
	End If

	For i = 0 To count - 1
		buffer[i] += &H30
	Next
	buffer[i] = 0
End Sub

Function Str$(dbl As Double) As String
	Imports ActiveBasic.Math
	Imports ActiveBasic.Strings
	If IsNaN(dbl) Then
		Return "NaN"
	ElseIf IsInf(dbl) Then
		If dbl > 0 Then
			Return "Infinity"
		Else
			Return "-Infinity"
		End If
	End If
	Dim dec As Long, sign As Boolean
	Dim buffer[32] As Char, temp[15] As Char
	Dim i = 0 As Long

	'浮動小数点を文字列に変換
	_ecvt(temp, dbl, 15, dec, sign)

	'符号の取り付け
	If sign Then
		buffer[i] = Asc("-")
		i++
	End If

	If dec > 15 Or dec < -3 Then
		'指数表示
		buffer[i] = temp[0]
		i++
		buffer[i] = Asc(".")
		i++
		ChrCopy(VarPtr(buffer[i]), VarPtr(temp[1]), 14 As SIZE_T)
		i += 14
		buffer[i] = 0
		Return MakeStr(buffer) + SPrintf("e%+03d", New System.Int32(dec - 1))
	End If

	'整数部
	Dim i2 = dec
	Dim i3 = 0
	If i2>0 Then
		While i2>0
			buffer[i]=temp[i3]
			i++
			i3++
			i2--
		Wend
		buffer[i]=Asc(".")
		i++
	Else
		buffer[i]=&H30
		i++
		buffer[i]=Asc(".")
		i++

		i2=dec
		While i2<0
			buffer[i]=&H30
			i++
			i2++
		Wend
	End If

	'小数部
	While i3<15
		buffer[i]=temp[i3]
		i++
		i3++
	Wend

	While buffer[i-1]=&H30
		i--
	Wend
	If buffer[i-1]=Asc(".") Then i--

	buffer[i]=0
	Return MakeStr(buffer)
End Function

Function Str$(x As Int64) As String
	Imports ActiveBasic.Strings.Detail
	Return FormatIntegerEx(TraitsIntegerD[1], x As QWord, 1, 0, None)
End Function

Function Str$(x As QWord) As String
	Imports ActiveBasic.Strings.Detail
	Return FormatIntegerEx(TraitsIntegerU[1], x, 1, 0, None)
End Function

Function Str$(x As Long) As String
	Imports ActiveBasic.Strings.Detail
	Return FormatIntegerEx(TraitsIntegerD[0], x, 1, 0, None)
End Function

Function Str$(x As DWord) As String
	Imports ActiveBasic.Strings.Detail
	Return FormatIntegerEx(TraitsIntegerU[0], x, 1, 0, None)
End Function

Function Str$(x As Word) As String
	Return Str$(x As DWord)
End Function

Function Str$(x As Integer) As String
	Return Str$(x As Long)
End Function

Function Str$(x As Byte) As String
	Return Str$(x As DWord)
End Function

Function Str$(x As SByte) As String
	Return Str$(x As Long)
End Function

Function Str$(x As Single) As String
	Return Str$(x As Double)
End Function

Function Str$(b As Boolean) As String
	If b Then
		Return "True"
	Else
		Return "False"
	End If
End Function

Function Str$(s As String) As String
	Str$ = s
End Function

Function String$(n As Long, s As Char) As String
	Return New String(s, n)
End Function

#ifdef _AB4_COMPATIBILITY_STRING$_
Function String$(n As Long, s As String) As String
	If n < 0 Then
		'Throw ArgumentOutOfRangeException
	End If
	Dim buf = New System.Text.StringBuilder(s.Length * n)
	Dim i As Long
	For i = 1 To n
		buf.Append(s)
	Next
End Function
#else
Function String$(n As Long, s As String) As String
	Dim c As Char
	If String.IsNullOrEmpty(s) Then
		c = 0
	Else
		c = s[0]
	End If
	String$ = New String(c, n)
End Function
#endif

Function Time$() As String
	Dim time = System.DateTime.Now
	Dim buf = New System.Text.StringBuilder(8)
	'hour
	If time.Hour < 10 Then
		buf.Append("0")
	End If
	buf.Append(time.Hour)

	'minute
	If time.Minute < 10 Then
		buf.Append(":0")
	Else
		buf.Append(":")
	End If
	buf.Append(time.Minute)

	'second
	If time.Second < 10 Then
		buf.Append(":0")
	Else
		buf.Append(":")
	End If
	buf.Append(time.Second)
	Time$ = buf.ToString
End Function

Function Val(buf As *Char) As Double
	If buf = 0 Then
		Exit Function
	End If

	Dim i As Long, i2 As Long, i3 As Long, i4 As Long
	Dim temporary As String
	Dim TempPtr As *Char
	Dim dbl As Double
	Dim i64data As Int64

	Val=0

	While ActiveBasic.CType.IsSpace(buf[0])
		buf = VarPtr(buf[1])
	Wend

	If buf[0]=Asc("&") Then
		temporary = New String( buf )
		temporary = temporary.ToUpper()
		TempPtr = StrPtr(temporary)
		If TempPtr(1) = Asc("O") Then
			'8進数
			i=2
			While 1
				'数字以外の文字の場合は抜け出す
				i3=TempPtr[i]-&H30
				If Not (0<=i3 And i3<=7) Then Exit While

				TempPtr[i]=i3 As Char
				i++
			Wend
			i--

			i64data=1
			While i>=2
				Val += ( i64data * TempPtr[i] ) As Double

				i64data *= &O10
				i--
			Wend
		ElseIf TempPtr(1)=Asc("H") Then
			'16進数
			i=2
			While 1
				'数字以外の文字の場合は抜け出す
				i3=TempPtr[i]-&H30
				If Not(0<=i3 and i3<=9) Then
					i3=TempPtr[i]-&H41+10
					If Not(&HA<=i3 and i3<=&HF) Then Exit While
				End If

				TempPtr[i]=i3 As Char
				i++
			Wend
			i--

			i64data=1
			While i>=2
				Val += (i64data*TempPtr[i]) As Double

				i64data *= &H10
				i--
			Wend
		End If
	Else
		'10進数
#ifdef UNICODE
		swscanf(buf,"%lf",VarPtr(Val))
#else
		sscanf(buf,"%lf",VarPtr(Val))
#endif
	End If
End Function


'--------------
' ファイル関数
'--------------

Function Eof(FileNum As Long) As Long
	FileNum--
	Dim dwCurrent = SetFilePointer(_System_hFile(FileNum), 0,NULL, FILE_CURRENT)
	Dim dwEnd = SetFilePointer(_System_hFile(FileNum), 0, NULL, FILE_END)
	SetFilePointer(_System_hFile(FileNum), dwCurrent, NULL, FILE_BEGIN)

	If dwCurrent>=dwEnd Then
		Eof=-1
	Else
		Eof=0
	End If
End Function

Function Lof(FileNum As Long) As Long
	Lof = GetFileSize(_System_hFile(FileNum-1), 0)
End Function

Function Loc(FileNum As Long) As Long
	FileNum--

	Dim NowPos = SetFilePointer(_System_hFile(FileNum), 0, 0, FILE_CURRENT)
	Dim BeginPos = SetFilePointer(_System_hFile(FileNum), 0, 0, FILE_BEGIN)
	SetFilePointer(_System_hFile(FileNum), NowPos - BeginPos, 0, FILE_BEGIN)

	Loc = NowPos - BeginPos
End Function


'------------------
' メモリ関連の関数
'------------------

Function malloc(stSize As SIZE_T) As VoidPtr
	Return _System_pGC->__malloc(stSize,_System_GC_FLAG_NEEDFREE or _System_GC_FLAG_ATOMIC)
End Function

Function calloc(stSize As SIZE_T) As VoidPtr
	Return _System_pGC->__malloc(stSize,_System_GC_FLAG_NEEDFREE or _System_GC_FLAG_ATOMIC or _System_GC_FLAG_INITZERO)
End Function

Function realloc(lpMem As VoidPtr, stSize As SIZE_T) As VoidPtr
	If lpMem = 0 Then
		Return malloc(stSize)
	Else
		Return _System_pGC->__realloc(lpMem,stSize)
	End If
End Function

Sub free(lpMem As VoidPtr)
	_System_pGC->__free(lpMem)
End Sub

Function _System_malloc(stSize As SIZE_T) As VoidPtr
	Return HeapAlloc(_System_hProcessHeap, 0, stSize)
End Function

Function _System_calloc(stSize As SIZE_T) As VoidPtr
	Return HeapAlloc(_System_hProcessHeap, HEAP_ZERO_MEMORY, stSize)
End Function

Function _System_realloc(lpMem As VoidPtr, stSize As SIZE_T) As VoidPtr
	If lpMem = 0 Then
		Return HeapAlloc(_System_hProcessHeap, 0, stSize)
	Else
		Return HeapReAlloc(_System_hProcessHeap, 0, lpMem, stSize)
	End If
End Function

Sub _System_free(lpMem As VoidPtr)
	HeapFree(_System_hProcessHeap, 0, lpMem)
End Sub


'--------
' その他
'--------

Sub _splitpath(path As PCSTR, drive As PSTR, dir As PSTR, fname As PSTR, ext As PSTR)
	Dim i As Long, i2 As Long, i3 As Long, length As Long
	Dim buffer[MAX_PATH] As SByte

	'":\"をチェック
	If not(path[1]=&H3A and path[2]=&H5C) Then Exit Sub

	'ドライブ名をコピー
	If drive Then
		drive[0]=path[0]
		drive[1]=path[1]
		drive[2]=0
	End If

	'ディレクトリ名をコピー
	i=2
	i2=0
	Do
		If IsDBCSLeadByte(path[i]) <> FALSE and path[i + 1] <> 0 Then
			If dir Then
				dir[i2]=path[i]
				dir[i2+1]=path[i+1]
			End If

			i += 2
			i2 += 2
			Continue
		End If

		If path[i]=0 Then Exit Do

		If path[i]=&H5C Then '"\"記号であるかどうか
			i3=i2+1
		End If

		If dir Then dir[i2]=path[i]

		i++
		i2++
	Loop
	If dir Then dir[i3]=0
	i3 += i-i2

	'ファイル名をコピー
	i=i3
	i2=0
	i3=-1
	Do
'#ifdef UNICODE
'		If _System_IsSurrogatePair(path[i], path[i + 1]) Then
'#else
		If IsDBCSLeadByte(path[i]) <> FALSE and path[i + 1] <> 0 Then
'#endif
			If fname Then
				fname[i2]=path[i]
				fname[i2+1]=path[i+1]
			End If

			i += 2
			i2 += 2
			Continue
		End If

		If path[i]=0 Then Exit Do

		If path[i]=&H2E Then	'.'記号であるかどうか
			i3=i2
		End If

		If fname Then fname[i2]=path[i]

		i++
		i2++
	Loop
	If i3=-1 Then i3=i2
	If fname Then fname[i3]=0
	i3 += i-i2

	'拡張子名をコピー
	If ext Then
		If i3 Then
			ActiveBasic.Strings.StrCpy(ext,path+i3)
		End If
		else ext[0]=0
	End If
End Sub

Function GetBasicColor(ColorCode As Long) As Long
	Select Case ColorCode
		Case 0
			GetBasicColor=RGB(0,0,0)
		Case 1
			GetBasicColor=RGB(0,0,255)
		Case 2
			GetBasicColor=RGB(255,0,0)
		Case 3
			GetBasicColor=RGB(255,0,255)
		Case 4
			GetBasicColor=RGB(0,255,0)
		Case 5
			GetBasicColor=RGB(0,255,255)
		Case 6
			GetBasicColor=RGB(255,255,0)
		Case 7
			GetBasicColor=RGB(255,255,255)
	End Select
End Function

Function _System_BSwap(x As Word) As Word
	Dim src = VarPtr(x) As *Byte
	Dim dst = VarPtr(_System_BSwap) As *Byte
	dst[0] = src[1]
	dst[1] = src[0]
End Function

Function _System_BSwap(x As DWord) As DWord
	Dim src = VarPtr(x) As *Byte
	Dim dst = VarPtr(_System_BSwap) As *Byte
	dst[0] = src[3]
	dst[1] = src[2]
	dst[2] = src[1]
	dst[3] = src[0]
End Function

Function _System_BSwap(x As QWord) As QWord
	Dim src = VarPtr(x) As *Byte
	Dim dst = VarPtr(_System_BSwap) As *Byte
	dst[0] = src[7]
	dst[1] = src[6]
	dst[2] = src[5]
	dst[3] = src[4]
	dst[4] = src[3]
	dst[5] = src[2]
	dst[6] = src[1]
	dst[7] = src[0]
End Function

Function _System_HashFromUInt(x As QWord) As Long
	Return (HIDWORD(x) Xor LODWORD(x)) As Long
End Function

Function _System_HashFromUInt(x As DWord) As Long
	Return x As Long
End Function

Function _System_HashFromPtr(p As VoidPtr) As Long
	Return _System_HashFromUInt(p As ULONG_PTR)
End Function

/*!
@brief	ObjPtrの逆。ABオブジェクトを指すポインタをObject型へ変換。
@author	Egtra
@date	2007/08/24
@param[in]	p	オブジェクトを指すポインタ
@return Object参照型
*/
Function _System_PtrObj(p As VoidPtr) As Object
	SetPointer(VarPtr(_System_PtrObj), p)
End Function

/*!
@brief	IUnknownその他COMインタフェースを指すポインタをIUnknown参照型へ変換。
@author	Egtra
@date	2007/09/24
@param[in]	p	COMインタフェースを指すポインタ
@return IUnknown参照型
*/
Function _System_PtrUnknown(p As VoidPtr) As IUnknown
	SetPointer(VarPtr(_System_PtrUnknown), p)
End Function

'--------
' 文字列関数その2
'--------
Function _System_IsSurrogatePair(wcHigh As WCHAR, wcLow As WCHAR) As Boolean
	If _System_IsHighSurrogate(wcHigh) Then
		If _System_IsLowSurrogate(wcLow) Then
			Return True
		End If
	End If
	Return False
End Function

Function _System_IsHighSurrogate(c As WCHAR) As Boolean
	Return &hD800 <= c And c < &hDC00
End Function

Function _System_IsLowSurrogate(c As WCHAR) As Boolean
	Return &hDC00 <= c And c < &hE000
End Function

Function _System_IsDoubleUnitChar(lead As WCHAR, trail As WCHAR) As Boolean
	Return _System_IsSurrogatePair(lead, trail)
End Function

Function _System_IsDoubleUnitChar(lead As SByte, trail As SByte) As Boolean
	Return IsDBCSLeadByte(lead) <> FALSE
End Function

Function _System_GetHashFromWordArray(p As *Word, n As SIZE_T) As Long
	Dim hash = 0 As DWord
	Dim i As Long
	For i = 0 To ELM(n)
		hash = ((hash << 16) + p[i]) Mod &h7fffffff
	Next
	_System_GetHashFromWordArray = hash As Long
End Function
