Convert Visual Basic 6.0 type to VB.NET 'Structure'
Asked Answered
B

2

9

EDIT: Having gotten this to work under 32-bit, I'm now trying to get it to work for 64-bit. I've gotten source code for the DLL and both DLL and application are being compiled for 64-bit. I get an access violation every time. Here is the DLL code (C++ in Visual Studio 2005):

#pragma pack( push, 2 )
// Output Results Structure
typedef struct tagTVA_RESULTS {
    int   iID;             /* Difference ID 1 .. n */
    int   iLeft;           /* Bounding rectangle */
    int   iRight;
    int   iTop;
    int   iBottom;
    double dCx;            /* Center of gravity */
    double dCy;
    double dMajor;         /* Shape information */
    double dMinor;
    double dAngle;         /* Rotational information */
    int    lArea;          /* Number of pixels */
    int    iEdge;          /* Set if difference is at the edge of the image */
    double dNormalDensity;
    int    iNormalCount;
    double dDifferenceDensity;
} TVA_RESULTS, *PTVA_RESULTS;
#pragma pack ( pop )

Note it's setting the pack to 2. I've tried setting it to 2 in the application as well, and it fails. I tried other values, and I even tried values that weren't the same. I've tried explicit using 4 as integer size and 8 as double size. But I would assume (with limited knowledge) that if both pack sizes are the same, it should work.

At this point I'm suspecting how the function is called. Its first parameter is a pointer to an array of these structures. The application passes in the first element of the array ByRef, which I think accomplishes this. But having a bad pointer to the array would explain the symptoms. Here's the function definition in the DLL.

int WINAPI MNtvaAnalyzeVB (TVA_RESULTS *pResults, int iMaxCount)

My boss suggested it could be an big/little endian problem, but that seems unlikely if they're both being compiled in the same environment.

What should I do?

End of edit >>>


I am converting a Visual Basic 6.0 application to VB.NET. I have a couple of structures that get passed to external DLL files. This is not working, and I have a feeling it's due to the structures not being passed correctly.

Here's the original structure:

Public Type TVA_PARAMETERS
    iStandardFilterOnOff As Long
    iSampleFilterOnOff As Long
    iDifferenceFilterOnOff As Long
    iRotationCorrectionOnOff As Long
    iLocalCorrectionOnOff As Long
    iStandardAOIx As Long
    iStandardAOIy As Long
    iStandardAOIdx As Long
    iStandardAOIdy As Long
    iSampleAOIx As Long
    iSampleAOIy As Long
    iSampleAOIdx As Long
    iSampleAOIdy As Long
    iRepeatHorizontal As Long
    iRepeatVertical As Long
    dSensitivity As Double
    iMergeWidth As Long
    iMergeHeight As Long
    iMinimumDifferenceArea As Long
    iMaximumDifferenceArea As Long
End Type

If I do a LenB on a variable of that type in Visual Basic 6.0, I get 84 bytes. (N.B.: I'm not sure if that's a valid way to determine its size.)

I have tried to convert it to VB.NET thusly:

Public Structure TVA_PARAMETERS
    Public iStandardFilterOnOff As Integer
    Public iSampleFilterOnOff As Integer
    Public iDifferenceFilterOnOff As Integer
    Public iRotationCorrectionOnOff As Integer
    Public iLocalCorrectionOnOff As Integer
    Public iStandardAOIx As Integer
    Public iStandardAOIy As Integer
    Public iStandardAOIdx As Integer
    Public iStandardAOIdy As Integer
    Public iSampleAOIx As Integer
    Public iSampleAOIy As Integer
    Public iSampleAOIdx As Integer
    Public iSampleAOIdy As Integer
    Public iRepeatHorizontal As Integer
    Public iRepeatVertical As Integer
    Public dSensitivity As Double
    Public iMergeWidth As Integer
    Public iMergeHeight As Integer
    Public iMinimumDifferenceArea As Integer
    Public iMaximumDifferenceArea As Integer
End Structure

In VB.NET, System.Runtime.InteropServices.Marshal.sizeof() gives 88 bytes. I was hoping since these are just numeric values this would work (I know strings can be a pain). I don't have code for the external function, but it's declared like this:

Declare Function MNtvaParameters Lib "MNTva.dll" (ByRef pParameters As TVA_PARAMETERS) As Integer

I'm guessing this structure is not the same size, so the DLL file call fails, but I get no error, and as I said, I don't have the code to look it. It returns a zero, as is should if it's successful, but it's clearly not actually having an effect.

I've played around a bit with Runtime.InteropServices.StructLayoutAttribute, but if that's the answer, I cannot determine the right parameters.

I have another structure like this, but it's so similar. I'm guessing if I can fix this one, I'll be able to fix the other.

Boudreaux answered 13/11, 2012 at 1:46 Comment(2)
I have no idea what this question is about, but it looks cool, so +1. :)Godiva
@Neolisk: It is probably the "I have a couple of structures that get passed to external DLLs. This is not working".Sheley
B
8

Well of course the very next thing I tried fixed the problem. Defining the structure like this:

<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential, Pack:=1)> _
Public Structure TVA_PARAMETERS
  Public iStandardFilterOnOff As Integer
  ...
  etc.

fixed the problem.

Boudreaux answered 13/11, 2012 at 1:58 Comment(2)
Does that mean .net aligned the double to an 8-byte boundary (before you fixed it)?Clone
Well that's what I thought, but the other Structure I mentioned had several Long variables and 7 Doubles. Under .NET, changing the Longs to Integers, it was only eight bytes longer. (Again, assuming my length measurements are valid.) So it wasn't padding all the doubles. I'm not sure what was happening exactly. But it looks like with LayoutKind.Sequential and Pack:=1, it just lays each variable out in the listed order with no padding.Boudreaux
I
3

Here are good resources:

Your conversion looks good, a long in Visual Basic 6.0 is 4 bytes which is 32 bits which is an integer in VB.NET. Doubles are 8 bytes both in VB.NET and Visual Basic 6.0 (according to the above articles). I also get 84 bytes in VB.NET.

Option Strict On

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim A As New TVA_PARAMETERS
        MsgBox(A.ByteCount.ToString)
    End Sub

    Public Structure TVA_PARAMETERS
        Public iStandardFilterOnOff As Int32
        Public iSampleFilterOnOff As Int32
        Public iDifferenceFilterOnOff As Int32
        Public iRotationCorrectionOnOff As Int32
        Public iLocalCorrectionOnOff As Int32
        Public iStandardAOIx As Int32
        Public iStandardAOIy As Int32
        Public iStandardAOIdx As Int32
        Public iStandardAOIdy As Int32
        Public iSampleAOIx As Int32
        Public iSampleAOIy As Int32
        Public iSampleAOIdx As Int32
        Public iSampleAOIdy As Int32
        Public iRepeatHorizontal As Int32
        Public iRepeatVertical As Int32
        Public dSensitivity As Double
        Public iMergeWidth As Int32
        Public iMergeHeight As Int32
        Public iMinimumDifferenceArea As Int32
        Public iMaximumDifferenceArea As Int32

        Function ByteCount() As Integer
            Dim Results As New List(Of Byte)
            AddBytesToList(Results, BitConverter.GetBytes(iStandardFilterOnOff))
            AddBytesToList(Results, BitConverter.GetBytes(iSampleFilterOnOff))
            AddBytesToList(Results, BitConverter.GetBytes(iDifferenceFilterOnOff))
            AddBytesToList(Results, BitConverter.GetBytes(iRotationCorrectionOnOff))
            AddBytesToList(Results, BitConverter.GetBytes(iLocalCorrectionOnOff))
            AddBytesToList(Results, BitConverter.GetBytes(iStandardAOIx))
            AddBytesToList(Results, BitConverter.GetBytes(iStandardAOIy))
            AddBytesToList(Results, BitConverter.GetBytes(iStandardAOIdx))
            AddBytesToList(Results, BitConverter.GetBytes(iStandardAOIdy))
            AddBytesToList(Results, BitConverter.GetBytes(iSampleAOIx))
            AddBytesToList(Results, BitConverter.GetBytes(iSampleAOIy))
            AddBytesToList(Results, BitConverter.GetBytes(iSampleAOIdx))
            AddBytesToList(Results, BitConverter.GetBytes(iSampleAOIdy))
            AddBytesToList(Results, BitConverter.GetBytes(iRepeatHorizontal))
            AddBytesToList(Results, BitConverter.GetBytes(iRepeatVertical))
            AddBytesToList(Results, BitConverter.GetBytes(dSensitivity))
            AddBytesToList(Results, BitConverter.GetBytes(iMergeWidth))
            AddBytesToList(Results, BitConverter.GetBytes(iMergeHeight))
            AddBytesToList(Results, BitConverter.GetBytes(iMinimumDifferenceArea))
            AddBytesToList(Results, BitConverter.GetBytes(iMaximumDifferenceArea))
            Return Results.Count
        End Function

        Sub AddBytesToList(ByRef List As List(Of Byte), addBytes As Byte())
            For Each B As Byte In addBytes
                List.Add(B)
            Next

        End Sub
    End Structure

End Class
Immediacy answered 11/12, 2012 at 8:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.