AccessViolationException on API Call

Alexamex

New member
Joined
Oct 21, 2012
Messages
4
Programming Experience
5-10
Hi,
I migrated a VB6 ActiveX to Vb.Net and I am having an issue on API Calls.
The ActiveX consist of making API calls to read or write data from flat files.
It works pretty well in VB6, but throws an exception in Vb.Net : AccessViolationException
Let me know if you want me to post the working VB6 Code

Also, I apologize for my english skills. =)

Here is the VB.Net Code:

VB.NET:
Module nif_types
'Define structure for RGETDAT_BITS procedure call
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Public Structure rgetdat_bits_data_str
        Dim type As Short 'data type (set internally)
        Dim file As Short 'file in database
        Dim rec As Short 'record in file
        Dim word As Short 'word offset in record
        Dim start_bit As Short 'start bit in word
        Dim length As Short 'number of bits
        Dim flags As Short 'flags
        Dim padding As Short
        Dim value As Short 'database value
        <VBFixedArray(2)> Dim padV() As Short
        Dim status As Short 'return status
        <VBFixedArray(2)> Dim padA() As Short
        Public Sub Initialize()
            ReDim padV(2)
            ReDim padA(2)
        End Sub
    End Structure
End Module


Module HSCNAPI


Public Declare Function rgetdat_bits Lib "hscnetapi.dll" Alias "rgetdat_bits_vb" (ByVal Server As String, ByVal num_points As Short, ByRef getdat_bits_data() As rgetdat_bits_data_str) As Short


End Module


Class MyControl


<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=255)> Dim ServerName As String ' For fixed length compatibility


 Public Sub GetServerName()
                ServerName = RegQuery("Honeywell", "Experion PKS Server", "Server", "ConnectedServerName")
 End Sub


 Public Function HSC_get_bits_data(ByVal iFile As Short, ByVal iRec As Short, ByVal iWord As Short, ByVal iStart As Short, Optional ByVal DataNumber As Integer = 1) As Array
            Dim ArrData(0) As rgetdat_bits_data_str
            Dim ArrReturn(0 To 100) As String
            Dim iWordCount As Integer = 0
            Dim iBitCount As Integer = 0
            Try
                For i As Integer = 0 To DataNumber - 1
                    ArrData(0).file = (iFile)
                    ArrData(0).rec = Convert.ToInt16(iRec)
                    ArrData(0).word = Convert.ToInt16(iWord + iWordCount)
                    ArrData(0).start_bit = Convert.ToInt16(iStart + iBitCount)
                    ArrData(0).length = Convert.ToInt16(1)
                    ArrData(0).flags = Convert.ToInt16(0)
                    rgetdat_bits(ServerName, Convert.ToInt16(1), ArrData) ' <------------------- Stacktrace shows this Exception happens on this line, which is the API Call
                    ArrReturn(i) = CStr(ArrData(0).value)
                    iBitCount += 1 ' Counter to increment the StartBit by 1: 1 bit = 1 bit. 
                    If iBitCount = 16 Then ' 0 to 15 represent 16 bits. When 16 bit count is reached, increment word and reset bit counter
                        iWordCount += 1
                        iBitCount = 0
                    End If
                Next
                Return ArrReturn
            Catch Ex1 As AccessViolationException
                'mylogWriter.WriteLine("Record Time: " & time.ToString(timeformat) & " :: " & "HSC_get_bits_data: " & Ex1.Message, Ex1.InnerException.ToString)
            Catch Ex As Exception
                'mylogWriter.WriteLine("Record Time: " & time.ToString(timeformat) & " :: " & "HSC_get_bits_data: " & Ex.Message, Ex.InnerException.ToString)
            End Try
            Return Nothing
        End Function
End Class
Thanks
Alex
 

Alexamex

New member
Joined
Oct 21, 2012
Messages
4
Programming Experience
5-10
You're using Short an awful lot there, which is unusual for PInvoke. What do the original unmanaged declarations look like and what did the VB6 code look like?

The reason why I used Short is to have the Integer 16-Bit compatibility that the API requires. I believe I could use int16 intead or try to pass 32-Bit Integer and see what happens.

Here is the VB6 code as per your request:

VB.NET:
HSCNAPI.bas :

Public Declare Function rgetdat_bits Lib "hscnetapi.dll" _
    Alias "rgetdat_bits_vb" _
    (ByVal Server As String, ByVal num_points As Integer, _
    getdat_bits_data() As rgetdat_bits_data_str) As Integer

nif_types.bas :

'Define structure for RGETDAT_BITS procedure call
Type rgetdat_bits_data_str
    type As Integer                                     'data type (set internally)
    file As Integer                                     'file in database
    rec As Integer                                      'record in file
    word As Integer                                     'word offset in record
    start_bit As Integer                                'start bit in word
    Length As Integer                                   'number of bits
    flags As Integer                                    'flags
    padding As Integer
    Value As Integer                                    'database value
    padV(0 To 2) As Integer
    status As Integer                                   'return status
    padA(0 To 2) As Integer
End Type

MyControl.cls :

Public Sub GetServerName()


            RegKey.Company = "XXX"
            RegKey.AppName = "XXXX"
            ServerName = RegKey.GetSetting("Server", "ConnectedServerName")

End Sub

'Read bit in User File
        Public Function HSC_get_bits_data(ByVal iFile As Integer, ByVal iRec As Integer, ByVal iWord As Integer, ByVal iStart As Integer, ByVal iWidth As Integer) As Integer
            Dim ArrData(0) As rgetdat_bits_data_str
            On Error GoTo errHandler
            
            ArrData(0).file = iFile
            ArrData(0).rec = iRec
            ArrData(0).word = iWord
            ArrData(0).start_bit = iStart
            ArrData(0).Length = iWidth
            ArrData(0).flags = 0


            rgetdat_bits ServerName, 1, ArrData
            HSC_get_bits_data = ArrData(0).Value
            
            Exit Function
errHandler:
        ErrorIn "MyControl.HSC_get_bits_data"
        End Function


        'Write bit in User File
        Public Sub HSC_put_bits_data(ByVal iFile As Integer, ByVal iRec As Integer, ByVal iWord As Integer, ByVal iStart As Integer, ByVal iWidth As Integer, ByVal iBit As Integer)
            Dim ArrData(0) As rgetdat_bits_data_str
            On Error GoTo errHandler
            
            ArrData(0).file = iFile
            ArrData(0).rec = iRec
            ArrData(0).word = iWord
            ArrData(0).start_bit = iStart
            ArrData(0).Length = iWidth
            ArrData(0).flags = 0
            ArrData(0).Value = iBit


            rputdat_bits ServerName, 1, ArrData


            Exit Sub
errHandler:
        ErrorIn "MyControl.HSC_put_bits_data"
          End Sub

Thanks for your help.
Alex
 

Alexamex

New member
Joined
Oct 21, 2012
Messages
4
Programming Experience
5-10
You're using Short an awful lot there, which is unusual for PInvoke. What do the original unmanaged declarations look like and what did the VB6 code look like?

The only 2 things that I have added to the unmanage declarations is :

- "
Convert.ToInt16" for 16-Bit Integer compatibility, which do not seems to solve this issue.
- Marshalled the ServerName to fixed length 255 characters
, which do not seems to solve this issue.

Just so you know, a lot of forums says to disable "JIT Debugger", which I did. Did not solve this issue.

 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,609
Location
Norway
Programming Experience
10+
I would say you should declare the array parameter ByVal, and not ByRef. Arrays are objects (reference), though when marshalled they are only passed as input, you have to apply marshalling attributes to make them to also marshal as output, see examples of these attribute usage here: Marshaling Different Types of Arrays
 

Alexamex

New member
Joined
Oct 21, 2012
Messages
4
Programming Experience
5-10
I would say you should declare the array parameter ByVal, and not ByRef. Arrays are objects (reference), though when marshalled they are only passed as input, you have to apply marshalling attributes to make them to also marshal as output, see examples of these attribute usage here: Marshaling Different Types of Arrays

Hi,
Just a quick update.
I have tried what you pointed out by changing the following:

VB.NET:
Public Declare Function rgetdat_bits Lib "hscnetapi.dll" Alias "rgetdat_bits_vb" (ByVal Server As String, ByVal num_points As Short, [COLOR=#ff0000][B]<[In](), [Out]()> ByVal getdat_bits_data()[/B][/COLOR] As rgetdat_bits_data_str) As Short

Still does not work.

New strange Fact: I have the same kind of function for querying string (rgetdat_str) and calling this function does not give exception like this one does, but return "" instead of the proper value.

Thanks.
Alex
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,609
Location
Norway
Programming Experience
10+
VBFixedArray is not used by interop marshaling, you can describe behaviour for parameters and fields in structure using the MarshalAs attribute. For example you can marshal the array parameter as LPArray, and the structure arrays as ByValArray with SizeConst set. See Default Marshaling for Arrays
 
Top Bottom