Как читать структуру, содержащую массив структур, из TwinCat в C #

Используя TwinCAT 3 ADS.Net для чтения из ПЛК, я пытаюсь прочитать структуру, содержащую массив структур, но при выполнении команды ReadAny происходит сбой с исключением «Unable to marshal type».

Однако прямое чтение массива структур работает нормально.

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

В примечании к заголовку метода ReadAny говорится: «Если тип объекта для чтения является типом массива, количество элементов для каждого измерения должно быть указано в параметре 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);

person Udi Y    schedule 30.07.2019    source источник
comment
Я предполагаю, что это своего рода ошибка памяти, поскольку массивы являются ссылочными типами (поэтому массив структур является ссылкой), а структуры являются типом значения (поэтому структура с массивом структур является значением, а не ссылкой)   -  person MindSwipe    schedule 30.07.2019


Ответы (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];
    }

Код СТ:

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

AdsStruct определяется как stAds в PRG_AIS.

ИЛИ, если у вас есть массив структур, измените код следующим образом:

код 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;
}

Код СТ:

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

TYPE InnerStruct :
STRUCT
    bBoolTest : BOOL;
    nIntTest  : DINT;
END_STRUCT
END_TYPE
person Filippo Boido    schedule 30.07.2019
comment
Ваш код относится к массиву байтов (простой тип), поэтому он работает. Попробуйте это с массивом структур. - person Udi Y; 30.07.2019
comment
Привет, Уди! Чтобы пометить ответ как принятый, нажмите на галочку рядом с ответом, чтобы переключить его с серого на заполненный. https://stackoverflow.com/help/someone-answers - person Filippo Boido; 01.08.2019
comment
Я попытался выяснить, в чем разница между нашими кодами, и увидел, что вы использовали Pack = 1, а не 0. В документации Beckhoff в разделе «Чтение и запись переменных ПЛК любого типа» говорится: «TwinCAT2 Pack = 1 , TwinCAT 3 Pack = 0 ”Поскольку я использую TwinCAT 3, я написал = 0. infosys. beckhoff.com/english.php?content=../content/1033/ - person Udi Y; 01.08.2019
comment
При попытке изменить его на = 1 у меня возникли проблемы со сдвигом / выравниванием памяти. В следующем примере короткое число (2 байта) превратилось в Тарабарщину. [StructLayout (LayoutKind.Sequential, Pack = 1)] открытый класс InnerClass {public EnumTest eEnum; [MarshalAs (UnmanagedType.I1)] public bool bBool; общедоступный короткий sShort; } - person Udi Y; 01.08.2019
comment
У вас должно быть одинаковое выравнивание в ПЛК и в программе C #. В plc вы можете установить пакет структуры со следующим атрибутом: {attribute 'pack_mode': = '‹Value›'} для получения дополнительной информации: infosys.beckhoff.com/index.php?content = .. / content / 1031 / - person Filippo Boido; 01.08.2019
comment
Я считаю, что разница в том, что у вас, вероятно, было что-то вроде class InnerStruct вместо struct. По-видимому, это не сработает, если вы попытаетесь передать типы вложенных классов в ReadAny .. Вы должны использовать структуры, если у вас есть сложные вложенные структуры. - person Filippo Boido; 01.08.2019
comment
Есть ли у тебя другие проблемы? - person Filippo Boido; 02.08.2019
comment
Я изменил свой класс на структуру и вуаля! Теперь все работает нормально. Большое спасибо! - person Udi Y; 04.08.2019