Closed drvic10k closed 2 years ago
I am not fully aware what is your situatino. You are Implementing the MyComplexStruct in the SymbolicServer Sample code? That seems not to be the latest version.
FieldOffset 7 should be correct - because the SymbolServer with its AlignMember Method actually supports an AlignmentMode=Pack1
Trying to use the same from PLC like here:
attribute 'pack_mode' := '1'}
TYPE MyComplexStruct : // Size 7 +7 = 14
STRUCT
a : BOOL; //Offset 0
b : INT; //Offset 1
c : DINT; //Offset 3
d : MYSTRUCT; // Offset 7
END_STRUCT
END_TYPE
{attribute 'pack_mode' := '1'}
TYPE MYSTRUCT : // Size 7
STRUCT
a : BOOL; //Offset 0
b : INT; // Offset 1
c : DINT; // Offset 3
END_STRUCT
END_TYPE
I can upload the following symbolic information (TwinCAT 3.1.4024.29, 64-Bit Windows 10):
PS> $s = new-tcsession -port 851 #local PLC
PS> $s | Get-TcDataType MyComplexStruct,Mystruct | fl
Id : 36
Name : MyComplexStruct
Namespace : 192.168.2.68.1.1:851
Size : 14
Category : Struct
Members : {BOOL, INT, DINT, MYSTRUCT}
Id : 37
Name : MYSTRUCT
Namespace : 192.168.2.68.1.1:851
Size : 7
Category : Struct
Members : {BOOL, INT, DINT}
PS> ($s | Get-TcDataType MyComplexStruct).Members
InstanceName BitOffset TypeName Size Static
------------ --------- -------- ---- ------
a 0 BOOL 1 False
b 8 INT 2 False
c 24 DINT 4 False
d 56 MYSTRUCT 7 False
PS> ($s | Get-TcDataType MyComplexStruct).Members['d'].BitOffset / 8
7
So the FieldOffset is 7 bytes here
PS> ($s | Get-TcDataType MyStruct).Members
InstanceName BitOffset TypeName Size Static
------------ --------- -------- ---- ------
a 0 BOOL 1 False
b 8 INT 2 False
c 24 DINT 4 False
Reading values succeeds also:
PS> $s | Read-TcValue -path Main.mycomplexstruct | fl
a : True
b : 0
c : 0
d : @{a=False; b=0; c=0; PSValue=...}
PSValue : ...
PS> ($s | Read-TcValue -path Main.mycomplexstruct).d | fl
a : False
b : 0
c : 0
PSValue : ...
Double checking now with C# Code (the FieldOffset of 7 is working also):
[StructLayout(LayoutKind.Explicit,Pack =1)]
public struct MyStruct
{
[FieldOffset(0)]
bool a;
[FieldOffset(1)]
short b;
[FieldOffset(3)]
int c;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct MyComplexStruct
{
[FieldOffset(0)]
bool a;
[FieldOffset(1)]
short b;
[FieldOffset(3)]
int c;
[FieldOffset(7)]
MyStruct s;
}
using ConsoleApp1;
using System.Runtime.InteropServices;
Console.WriteLine($"MyComplexStruct Size: {Marshal.SizeOf(typeof(MyComplexStruct))}");
Console.WriteLine($"MyStruct Size: {Marshal.SizeOf(typeof(MyStruct))}");
Console.ReadLine();
Console output is:
MyComplexStruct Size: 14
MyStruct Size: 7
Actually I don't see a problem here - I don't know where the exception is coming from. Probably you should explain more detailed or send a test project.
just to be sure, I updated to 6.0.155 but it did not work, so here is the minimal (not)working example
With the offset of 8 it runs, but then there is the problem with the struct size
could you reproduce the size problem with the offset producing a gap?
sorry, the previous one was not connecting the server, use this one instead
The .NET TypeLoad checker really shows a funny behaviour here. You can simply force the TypeLoadException with the following code:
[StructLayout(LayoutKind.Explicit,Pack =1)]
public class MyStruct
{
[FieldOffset(0)]
bool a;
[FieldOffset(1)]
short b;
[FieldOffset(3)]
int c;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public class MyComplexStruct
{
[FieldOffset(0)]
bool a;
[FieldOffset(1)]
short b;
[FieldOffset(3)]
int c;
[FieldOffset(7)]
MyStruct s;
}
int sizeOf1 = Marshal.SizeOf(typeof(MyComplexStruct));
int sizeOf2 = Marshal.SizeOf(typeof(MyStruct));
If you change your classes MyStruct and MyComplexStruct from 'class' to 'struct' it will work. It will work also if you remove the FieldOffset attributes and state LayoutKind.Sequential instead of LayoutKind.Explicit in combination with Pack=1. Without understood it fully, my opinion is that this is a bug in the .NET TypeLoader.
Actually important is: MyComplexStruct has size 14 and MyStruct has size 7
If you marshal the MyComplexStruct with size of 15 the internal marshaller will fail with invalid size in line 54:
because the SymbolicServer only supports Pack=1 with Sequential Layout (without gaps). We have to extend it to be more flexible in the future and support more PackModes and customizable FieldOffsets in StructType.AddAligned().
Furthermore, I should add an comment in the sample code.
excelent, thank you for clarification
When defining a StructType containing fields that are themselves StructTypes the final size of the type is calculated wrongly
Struct fileds need to be aligned on 8byte boudaries, but the size of the parent struct is calclulated as if the fields were aligned without any gaps
Expanding your example witrh the MyStruct:
the above mentioned exception:
Could not load type 'MyComplexStruct' from assembly because it contains an object field at offset 7 that is incorrectly aligned or overlapped by a non-object field.'
Here you can see, that start of the inner struct is correctly aligned at 100F The size of the complex struct though is 14 bytes, but the last field starts at 8 and has size of 7, so the size should be 15
this results in an error, when requesting the value: