Struct trouble Visual Basic.net

G

Guest

Hi there !!!

I browsed around the Internet in search for a solution of a little difficult
problem i have in VB.NET....

However, i cannot find a suitable anwser anywhere, so i thought i'll give it
a try here...

Okay, here's the deal:
I am trying to read from unmanaged memory with a class type struct, this
works fine as i can read the data from the unmanaged memory. The trouble
starts when i try to fill an array of structs within a struct, all the array
members get filled with the last read values from the unmanaged memory:

The structs i build for managing the unmanaged memory;
<code>
Imports System.Runtime.InteropServices

'Beckhoff TwinCat Struct

'TYPE ST_TeleMeBool :
'STRUCT
' ID:STRING;
' Value:BOOL;
' Qualify:STRING;
' TypeB:STRING;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TeleMeBool
'-- enum unmanagedtype ByValStr = a fixed size string of 80 chars
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public ID As String = ""
<MarshalAs(UnmanagedType.I1)> _
Public Value As Boolean
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public Qualify As String = ""
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeB As String = ""

End Class


'Beckhoff TwinCat Struct

'TYPE ST_TelemeReal :
'STRUCT
' ID:STRING;
' Value:REAL;
' Qualify:STRING;
' TypeB:STRING;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TeleMeReal

<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public ID As String = ""
'-- enum unmanagedtype r4 = a 4 byte Real (aka Single / system.float)
<MarshalAs(UnmanagedType.R4)> _
Public Value As Single
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public Qualify As String = ""
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeB As String = ""

End Class


'Beckhoff TwinCat Struct

'TYPE ST_TelemeOut :
'STRUCT
' CountBool:INT;
' CountReal:INT;
' bArray: ARRAY[0..999] OF ST_TelemeBool;
' rArray: ARRAY[0..999] OF ST_TelemeReal;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TelemeOut

'-- enum unmanagedtype I2 = a 2 byte signed integer (aka short /
system.int16)
<MarshalAs(UnmanagedType.I2)> _
Public CountBool As Integer
<MarshalAs(UnmanagedType.I2)> _
Public CountReal As Integer
'-- enum unmanagedtype ByValArray = an array of which the maximum
elementsize MUST be specified (sizeconst)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=999)> _
Public bArray(1000) As ST_TeleMeBool
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=999)> _
Public rArray(1000) As ST_TeleMeReal

End Class
</code>


Now the code to read the unmanaged code and fill my struct:

<code>

Public stTelemeOut As ST_TelemeOut = New ST_TelemeOut '--
declares a VB side St_TelemeOut struct to fill from PLC TelemeOut struct

Public stTelemeBool As ST_TeleMeBool = New ST_TeleMeBool '-- vb
sided instance of a single .bArray() struct element within St_TelemeOut, may
be useful

Public stTelemeReal As ST_TeleMeReal = New ST_TeleMeReal

For i = 0 To .CountBool - 1
stTelemeBool.ID = ADSClient.ReadAny(hbID(i),
GetType(String), New Integer() {80}) '--
WATCH SYNTAX TO ASK STRINGS!!!!
stTelemeBool.Value = ADSClient.ReadAny(hbValue(i),
GetType(Boolean))
stTelemeBool.Qualify = ADSClient.ReadAny(hbQualify(i),
GetType(String), New Integer() {80})
stTelemeBool.TypeB = ADSClient.ReadAny(hbTypeB(i),
GetType(String), New Integer() {80})
.bArray(i) = stTelemeBool
Next i


For i = 0 To .CountReal - 1
stTelemeReal.ID = ADSClient.ReadAny(hrID(i),
GetType(String), New Integer() {80})
stTelemeReal.Value = ADSClient.ReadAny(hrValue(i),
GetType(Single))
stTelemeReal.Qualify = ADSClient.ReadAny(hrQualify(i),
GetType(String), New Integer() {80})
stTelemeReal.TypeB = ADSClient.ReadAny(hrTypeB(i),
GetType(String), New Integer() {80})
.rArray(i) = stTelemeReal
Next i
</code>

The problem i encounter resides in the statement:
bArray(i) = stTelemeBool

and (equally so):

rArray(i) = stTelemeReal

ALL the array members get filled with the last read data values from the
unmanaged memory, this instead of filling each array member with the
corresponding unamanaged memory data.

I am at a loss... can anybody help me out??
 
C

Chris Calzaretta

Couple of questions here
when i = 0 and you check the value of hbID is it the same when i=ubound(i)
if that is the case then your hb object is not getting declared or populated
correct
if they are not the same then take a look at
since your not rediming your arrays then that could be reason.. All though
never seen that to be a problem but
redim array(ubound(.countreal))
before you start looping to fill your array

you do not show us how hb is getting filled
If the other component is filling hb.. When you get hb back make sure it is
more then array of 1





DaHool said:
Hi there !!!

I browsed around the Internet in search for a solution of a little
difficult
problem i have in VB.NET....

However, i cannot find a suitable anwser anywhere, so i thought i'll give
it
a try here...

Okay, here's the deal:
I am trying to read from unmanaged memory with a class type struct, this
works fine as i can read the data from the unmanaged memory. The trouble
starts when i try to fill an array of structs within a struct, all the
array
members get filled with the last read values from the unmanaged memory:

The structs i build for managing the unmanaged memory;
<code>
Imports System.Runtime.InteropServices

'Beckhoff TwinCat Struct

'TYPE ST_TeleMeBool :
'STRUCT
' ID:STRING;
' Value:BOOL;
' Qualify:STRING;
' TypeB:STRING;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TeleMeBool
'-- enum unmanagedtype ByValStr = a fixed size string of 80 chars
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public ID As String = ""
<MarshalAs(UnmanagedType.I1)> _
Public Value As Boolean
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public Qualify As String = ""
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeB As String = ""

End Class


'Beckhoff TwinCat Struct

'TYPE ST_TelemeReal :
'STRUCT
' ID:STRING;
' Value:REAL;
' Qualify:STRING;
' TypeB:STRING;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TeleMeReal

<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public ID As String = ""
'-- enum unmanagedtype r4 = a 4 byte Real (aka Single / system.float)
<MarshalAs(UnmanagedType.R4)> _
Public Value As Single
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public Qualify As String = ""
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeB As String = ""

End Class


'Beckhoff TwinCat Struct

'TYPE ST_TelemeOut :
'STRUCT
' CountBool:INT;
' CountReal:INT;
' bArray: ARRAY[0..999] OF ST_TelemeBool;
' rArray: ARRAY[0..999] OF ST_TelemeReal;
'END_STRUCT
'END_TYPE

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Public Class ST_TelemeOut

'-- enum unmanagedtype I2 = a 2 byte signed integer (aka short /
system.int16)
<MarshalAs(UnmanagedType.I2)> _
Public CountBool As Integer
<MarshalAs(UnmanagedType.I2)> _
Public CountReal As Integer
'-- enum unmanagedtype ByValArray = an array of which the maximum
elementsize MUST be specified (sizeconst)
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=999)> _
Public bArray(1000) As ST_TeleMeBool
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=999)> _
Public rArray(1000) As ST_TeleMeReal

End Class
</code>


Now the code to read the unmanaged code and fill my struct:

<code>

Public stTelemeOut As ST_TelemeOut = New ST_TelemeOut '--
declares a VB side St_TelemeOut struct to fill from PLC TelemeOut struct

Public stTelemeBool As ST_TeleMeBool = New ST_TeleMeBool '-- vb
sided instance of a single .bArray() struct element within St_TelemeOut,
may
be useful

Public stTelemeReal As ST_TeleMeReal = New ST_TeleMeReal

For i = 0 To .CountBool - 1
stTelemeBool.ID = ADSClient.ReadAny(hbID(i),
GetType(String), New Integer() {80}) '--
WATCH SYNTAX TO ASK STRINGS!!!!
stTelemeBool.Value = ADSClient.ReadAny(hbValue(i),
GetType(Boolean))
stTelemeBool.Qualify = ADSClient.ReadAny(hbQualify(i),
GetType(String), New Integer() {80})
stTelemeBool.TypeB = ADSClient.ReadAny(hbTypeB(i),
GetType(String), New Integer() {80})
.bArray(i) = stTelemeBool
Next i


For i = 0 To .CountReal - 1
stTelemeReal.ID = ADSClient.ReadAny(hrID(i),
GetType(String), New Integer() {80})
stTelemeReal.Value = ADSClient.ReadAny(hrValue(i),
GetType(Single))
stTelemeReal.Qualify = ADSClient.ReadAny(hrQualify(i),
GetType(String), New Integer() {80})
stTelemeReal.TypeB = ADSClient.ReadAny(hrTypeB(i),
GetType(String), New Integer() {80})
.rArray(i) = stTelemeReal
Next i
</code>

The problem i encounter resides in the statement:
bArray(i) = stTelemeBool

and (equally so):

rArray(i) = stTelemeReal

ALL the array members get filled with the last read data values from the
unmanaged memory, this instead of filling each array member with the
corresponding unamanaged memory data.

I am at a loss... can anybody help me out??
 
C

Chris Dunaway

starts when i try to fill an array of structs within a struct, all
the array
members get filled with the last read values from the unmanaged
memory:

The problem is that you reuse the same instance of the object every
time through the loop. Your rArray was filled with references to the
*SAME* object. You need to create a NEW object each time inside the
for loops, like this:
Public stTelemeBool As ST_TeleMeBool
Public stTelemeReal As ST_TeleMeReal

For i = 0 To .CountBool - 1
stTelemeBool = New ST_TelemeOut 'CREATE A NEW OBJECT
HERE

'Code to set stTelemeBool properties
.bArray(i) = stTelemeBool
Next i


For i = 0 To .CountReal - 1
stTelemeReal = New ST_TeleMeReal 'CREATE A NEW OBJECT
HERE

'Code to set stTelemeReal properties
.rArray(i) = stTelemeReal
Next i
</code>

Once you create the objects inside the for loops you should be ok
 
C

Chris Calzaretta

that is not the problem if you look at the code below he
makes stTelemeReal = the array at the end of the loop
So does not matter if he resues the stTelemeReal
over and over in his loops
 
C

Chris Dunaway

It does matter, when he assigns the object reference to the array in
this line
.rArray(i) = stTelemeReal

He now has two refereneces *to the same object*. At the end of the
loop, *all* the array elements point to the same object. And since
there is only one object, they all reflect the values of the most
recent changes.

Had he defined his "structs" as Structures instead of classes it may be
different, since he would then be working with value types and not
reference types.

Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top