i want to migrate code from vb6 to vb.net. the project is very basic ( not use dll or component reference) just module

in compress function, it has been successfully. i'm very happy. but when decompress sub not success. the program was hang. i tried fix it, i found that the problem is do.. exit do..loop statement.

note: the code run successfully in vb6.

this is my code for decompress

Public Sub Decompress(ByteArray() As Byte)
Dim InpPos As Long
Dim InBitPos As Integer
Dim LowValue As Long
Dim HighValue As Long
Dim RangValue As Long
Dim MidValue As Long
Dim Value As Long
Dim mChar As Byte
Dim i As Integer
Dim Index As Integer
Dim EOF_State As Boolean
Dim TopBit As Long
Dim One(256) As Long
Dim Zero(256) As Long
Call Initiate
LowValue = 0
HighValue = (2 ^ MaxBits) - 1
TopBit = 2 ^ (MaxBits - 1)
InpPos = 0
Value = ReadBitsFromArray(ByteArray, InpPos, InBitPos, MaxBits)
Index = -1
For i = 0 To 256
    One(i) = 1
    Zero(i) = 1
Next
Do
    mChar = 0
    For i = 0 To 7
        Index = (1 * (2 ^ i)) - 1 + mChar
        RangValue = HighValue - LowValue
        MidValue = LowValue + (RangValue * (Zero(Index) / (One(Index) + Zero(Index))))
        If MidValue = LowValue Then MidValue = MidValue + 1
        If MidValue = HighValue - 1 Then MidValue = MidValue - 1
        If Value >= MidValue Then
            mChar = (2 * mChar) + 1
            LowValue = MidValue
            One(Index) = One(Index) + 1
        Else
            mChar = 2 * mChar
            HighValue = MidValue
            Zero(Index) = Zero(Index) + 1
        End If

        Do While (HighValue And TopBit) = (LowValue And TopBit) Or LowValue > HighValue - 255
            If InpPos <= UBound(ByteArray) Then
                Value = (Value And (TopBit - 1)) * 2 + ReadBitsFromArray(ByteArray, InpPos, InBitPos, 1)
                HighValue = (HighValue And (TopBit - 1)) * 2 + 1
                LowValue = (LowValue And (TopBit - 1)) * 2
                If LowValue >= HighValue Then HighValue = (2 ^ MaxBits) - 1
            Else
                EOF_State = True
                Exit Do
            End If
        Loop
        If EOF_State = True Then Exit Do
    Next
    Call AddmCharToArray(OutStream, OutPos, mChar)
Loop
ReDim Preserve OutStream(OutPos - 1)
End Sub

Private Sub Initiate()
ReDim OutStream(500)
OutPos = 0
OutBitCount = 0
OutByteBuf = 0
End Sub

Private Sub AddBitsToOutStream(Number As Integer)
OutByteBuf = OutByteBuf * 2 + Number
OutBitCount = OutBitCount + 1
If OutBitCount = 8 Then
    OutStream(OutPos) = OutByteBuf
    OutBitCount = 0
    OutByteBuf = 0
    OutPos = OutPos + 1
    If OutPos > UBound(OutStream) Then
        ReDim Preserve OutStream(OutPos + 500)
    End If
End If
End Sub

Private Function ReadBitsFromArray(FromArray() As Byte, FromPos As Long, FromBit As Integer, NumBits As Integer) As Long
Dim i As Integer
Dim Temp As Long
For i = 1 To NumBits
    Temp = Temp * 2 + (-1 * ((FromArray(FromPos) And 2 ^ (7 - FromBit)) > 0))
    FromBit = FromBit + 1
    If FromBit = 8 Then
        If FromPos + 1 > UBound(FromArray) Then
            Do While i < NumBits
                Temp = Temp * 2
                i = i + 1
            Loop
            FromPos = FromPos + 1
            Exit For
        End If
        FromPos = FromPos + 1
    FromBit = 0
    End If
Next
ReadBitsFromArray = Temp
End Function

Private Sub AddmCharToArray(ToArray() As Byte, ToPos As Long, mChar As Byte)
If ToPos > UBound(ToArray) Then ReDim Preserve ToArray(ToPos + 500)
ToArray(ToPos) = mChar
ToPos = ToPos + 1
End Sub

do..exit do..

Do
    mChar = 0
    For i = 0 To 7
        Index = (1 * (2 ^ i)) - 1 + mChar
        RangValue = HighValue - LowValue
        MidValue = LowValue + (RangValue * (Zero(Index) / (One(Index) + Zero(Index))))
        If MidValue = LowValue Then MidValue = MidValue + 1
        If MidValue = HighValue - 1 Then MidValue = MidValue - 1
        If Value >= MidValue Then
            mChar = (2 * mChar) + 1
            LowValue = MidValue
            One(Index) = One(Index) + 1
        Else
            mChar = 2 * mChar
            HighValue = MidValue
            Zero(Index) = Zero(Index) + 1
        End If

        Do While (HighValue And TopBit) = (LowValue And TopBit) Or LowValue > HighValue - 255
            If InpPos <= UBound(ByteArray) Then
                Value = (Value And (TopBit - 1)) * 2 + ReadBitsFromArray(ByteArray, InpPos, InBitPos, 1)
                HighValue = (HighValue And (TopBit - 1)) * 2 + 1
                LowValue = (LowValue And (TopBit - 1)) * 2
                If LowValue >= HighValue Then HighValue = (2 ^ MaxBits) - 1
            Else
                EOF_State = True
                Exit Do
            End If
        Loop
        If EOF_State = True Then Exit Do
    Next
    Call AddmCharToArray(OutStream, OutPos, mChar)
Loop

sorry i cannot write english well.

有帮助吗?

解决方案

  Private Function ReadBitsFromArray(FromArray() As Byte, FromPos As Long, ...)

The bug is located in this function declaration. Your loop can only exit when InpPos increments beyond the upper bound of the array, setting the EOF_State variable to True. The loop itself doesn't increment InpPos at all. Back in VB6, it got incremented by the ReadBitsFromArray() function, FromBit = FromBit + 1 statement. But that is no longer the case in VB.NET.

An important change in VB.NET is the way arguments are passed. Old Visual Basic versions defaulted to ByRef. A somewhat strange choice whose reasons are lost in the mist of time. It is a very expensive way to pass arguments, passing ByRef requires passing a pointer to the value instead of the value itself. And every access to the variable requires a pointer dereference. It is at least 3 times slower than passing by value on modern machines, .NET is heavily optimized to pass argument values through CPU registers instead of the stack, that can't work if the argument is passed by reference.

So VB.NET made ByVal the default. Since you didn't declare it explicitly, the default applies and InpPos is passed by value. Never to increment, something that's easy to see in the debugger. Fix:

Private Function ReadBitsFromArray(ByVal FromArray() As Byte, _
                                   ByRef FromPos As Integer, _
                                   ByVal FromBit As Integer, _
                                   ByVal NumBits As Integer) As Integer

Note that the choice between Long and Integer is something else you will have to fret about. A VB6 Long is a VB.NET Integer. I guessed that Integer was appropriate here. Do consider the .NET GZipStream class as an alternative, it doesn't sound like you remember enough about the way it works to still be able to maintain this code.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top