如何从 TwinCat 读取包含结构数组的结构到 C#

Posted

技术标签:

【中文标题】如何从 TwinCat 读取包含结构数组的结构到 C#【英文标题】:How to read a struct containing array of structs from TwinCat to C# 【发布时间】:2019-07-30 09:42:39 【问题描述】:

使用 TwinCAT 3 ADS.Net 从 PLC 读取,我试图读取包含结构数组的结构,但 ReadAny 命令因“无法编组类型”异常而崩溃。

不过,直接读取结构数组也可以。

public object ReadAny(long indexGroup, long indexOffset, Type type, int[] args);

ReadAny 方法的标头注释说: “如果要读取的对象的Type是数组类型,则必须在参数args中指定每个维度的元素个数。”

但是对于包含结构数组的结构,args 应该是什么? (没有 'args' 它也会失败。)

我目前使用 .NET 4.7,VS 2013。

有办法吗?

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class WholeData

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Station[] StationArray;
    // Potentially more fields...


[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class Station

    [MarshalAs(UnmanagedType.I1)]
    public bool isPass;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
    public string name;
    // More fields...


// -- Main --
int[] args =  5 ;

// Works fine:
Station[] stationArray = (Station[])m_AdsClient.ReadAny(indexGroup, indexOffset, typeof(Station[]), args);

// Fail:
WholeData wholeData = (WholeData)m_AdsClient.ReadAny(indexGroup, indexOffset, typeof(WholeData), args);
// - OR -
WholeData wholeData = (WholeData)m_AdsClient.ReadAny(m_VarHandle, typeof(WholeData), args);

【问题讨论】:

我猜这是某种内存错误,因为数组是引用类型(所以结构数组是引用)而结构是值类型(所以结构和结构数组是值而不是参考) 【参考方案1】:

我通过以下代码测试成功:

c#代码:

    class Program
    
        public static TcAdsClient client;
        static void Main(string[] args)
        


            // Create the ADS Client
            using (client = new TcAdsClient())
            
                // Establish Connection
                client.Connect(new AmsAddress("10.1.2.95.1.1", 851));
                int handle = client.CreateVariableHandle("PRG_AIS.stAds");

                AdsClass ads = (AdsClass)client.ReadAny(handle, typeof(AdsClass));
                ads.boolArr[0] = 1;
                client.WriteAny(handle, ads);
                Console.ReadLine();

            
        
    

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    class AdsClass
    

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public byte[] boolArr = new byte[10];
    

ST代码:

TYPE AdsStruct :
STRUCT
    bTestArray : ARRAY[0..9] OF BOOL;
END_STRUCT
END_TYPE

AdsStruct 在 PRG_AIS 中被定义为 stAds。

或者,如果您有一个结构数组,请按以下方式修改代码:

c#代码:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
class AdsClass


    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public InnerStruct[] strArr = new InnerStruct[10];


struct InnerStruct

    public byte bBoolTest;
    public int nIntTest;

ST代码:

TYPE AdsStruct  :
STRUCT
    stTestArray : ARRAY[0..9] OF InnerStruct;
END_STRUCT
END_TYPE

TYPE InnerStruct :
STRUCT
    bBoolTest : BOOL;
    nIntTest  : DINT;
END_STRUCT
END_TYPE

【讨论】:

您的代码引用了一个字节数组(一种简单类型),因此它可以工作。尝试使用结构数组。 Hey Udi,“要将答案标记为已接受,请单击答案旁边的复选标记以将其从灰色切换为已填充。” ***.com/help/someone-answers 我试图找出我们的代码之间有什么不同,发现您使用“Pack = 1”而不是 0。在 Beckhoff 文档中,在“读取和写入任何类型的 PLC 变量”部分下”,他们说:“TwinCAT2 Pack = 1,TwinCAT 3 Pack = 0” 因为我使用的是 TwinCAT 3,所以我写了 =0。 infosys.beckhoff.com/english.php?content=../content/1033/… 你必须在plc和c#程序中对齐。在 plc 中,您可以使用以下属性设置结构的包:attribute 'pack_mode' := '' 了解更多信息:infosys.beckhoff.com/index.php?content=../content/1031/… 我相信不同之处在于你可能有类似“class” InnerStruct 而不是“struct”。如果您尝试将嵌套类类型传递给 ReadAny,显然它不起作用。如果您有复杂的嵌套结构,则必须使用结构。

以上是关于如何从 TwinCat 读取包含结构数组的结构到 C#的主要内容,如果未能解决你的问题,请参考以下文章

twincat是啥软件

通过 ADS.Net 将数组从 C# 发送到 TwinCat 3

如何将 char 数组转换为结构?

JNR-FFI如何从指针读取结构数组

Pyads 读取通知值:当 TwinCat 循环发生时

c语言中如何修改储存在文件的结构体内容中。小文件