Маршаллинг класса
От: maxus78  
Дата: 21.02.07 09:34
Оценка:
Добрый день, уважаемые коллеги!

Есть такой вот класс (можно было бы, конечно, структурой, но по ряду причин нужно иметь возможность присвоить экземпляру занчение null)

        [StructLayout(LayoutKind.Sequential)]
        public class TestClass
        {
            public ulong ulNumber;
            [MarshalAs(UnmanagedType.Struct)]
            public SampleClass scInfo;
            [MarshalAs(UnmanagedType.Struct)]
            public TestClass tcNext;
        }


Соответственно, код

TestClass tClass = new TestClass();
int iSize = Marshal.SizeOf(tClass.GetType());


не работает, пишет, что "annot be marshaled as an unmanaged structure; no meaningful size or offset can be computed".
Если убрать третий член класса (tcNext), то все кудряво.

Подскажите, пожалуйста, как поступить в этом случае?
Re: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 09:48
Оценка:
Забыл указать, что используется .NET 2.0

Для чего мне все это в принципе нужно:

Требуется в C# наваять аналог вот такого c-кода


            int tOffset = offsetof(Тип2, поле); // получаем смещение поля в структуре данных
            Тип1 typeValue = GetTypeValue();
            Тип2 tValue = (Тип2*)(void*)((char*)typeValue - tOffset);


Делать это придется, видимо, с помощию маршаллинга. По крайней мере, что-то мне никаких других способов провернуть эту мегаканитель, в голову не приходит.

Заранее благодарю за любые осмысленные комментарии.
Re[2]: Маршаллинг класса
От: mrozov  
Дата: 21.02.07 10:07
Оценка:
Здравствуйте, maxus78, Вы писали:

M>Забыл указать, что используется .NET 2.0


M>Для чего мне все это в принципе нужно:


M>Требуется в C# наваять аналог вот такого c-кода



M>
M>            int tOffset = offsetof(Тип2, поле); // получаем смещение поля в структуре данных
M>            Тип1 typeValue = GetTypeValue();
M>            Тип2 tValue = (Тип2*)(void*)((char*)typeValue - tOffset);
M>


M>Делать это придется, видимо, с помощию маршаллинга. По крайней мере, что-то мне никаких других способов провернуть эту мегаканитель, в голову не приходит.


M>Заранее благодарю за любые осмысленные комментарии.


Ну почему он не дает получить размер — более-менее понятно.
Тебя мог бы (наверное) выручить [MarshalAs(UnmanagedType.CustomMarshaler)].
Но нельзя ли вместо этого (маршаллинга) использовать сериализацию?
Re[3]: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 10:11
Оценка:
Здравствуйте, mrozov, Вы писали:

M>Но нельзя ли вместо этого (маршаллинга) использовать сериализацию?


Да, это идея. Что-то я про эту возможность и не вспомнил. Правда, справедливости ради, сериализацию использовал только для сохранения стостояния классов на диск.
А примерчик какой-нить схематичный возможно?

Заранее, большое человеческое спасибо.
Re[4]: Маршаллинг класса
От: mrozov  
Дата: 21.02.07 10:34
Оценка:
Здравствуйте, maxus78, Вы писали:

M>Здравствуйте, mrozov, Вы писали:


M>>Но нельзя ли вместо этого (маршаллинга) использовать сериализацию?


M>Да, это идея. Что-то я про эту возможность и не вспомнил. Правда, справедливости ради, сериализацию использовал только для сохранения стостояния классов на диск.

M>А примерчик какой-нить схематичный возможно?

M>Заранее, большое человеческое спасибо.


Я не до конца понимаю вашу задачу

Но тупой пример могу и привести:


    [Serializable]
    public class TestClass
    {
        public ulong ulNumber;
        public TestClass tcNext;

        public TestClass(ulong ulNumber, TestClass next)
        {
            this.ulNumber = ulNumber;
            tcNext = next;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            TestClass tClass = new TestClass( 1, new TestClass(2, null));

            MemoryStream stream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();

            formatter.Serialize(stream, tClass);
        }
    }


Теперь у вас в stream-е лежат данные объекта и если вы умеете их читать — честь вам и хвала
Я лично — не умею. Но мне также не вполне понятно, как можно читать из памяти структуру, которая на самом деле является ссылкой на объект


Другой тупой пример:


    public class TestClass
    {
        public ulong ulNumber;
        public TestClass tcNext;

        public TestClass(ulong ulNumber, TestClass next)
        {
            this.ulNumber = ulNumber;
            tcNext = next;
        }

        public TestClass()
        {
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            TestClass tClass = new TestClass( 1, new TestClass(2, null));
            
            XmlSerializer serr = new XmlSerializer(typeof(TestClass), "");

            StringBuilder strData = new StringBuilder();

            serr.Serialize(XmlWriter.Create(strData), tClass);

            XPathDocument xmlDoc = new XPathDocument(new StringReader(strData.ToString()));

            string strValue = xmlDoc.CreateNavigator().SelectSingleNode("TestClass/ulNumber").Value;

        }
    }
Re[5]: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 11:02
Оценка:
Здравствуйте, mrozov, Вы писали:

Оно, конечно, спасибо. Только вот таких примеров и я мог наваять А вообще, это реально сериализовать экземпляр одного класса в поток, а потом считать из этого потока данные в экземпляр другого класса?

И вообще, как в .NET приводятся типы друг к другу? Кроме, конечно, явного пребобразования наподобие

int iValue = 123;
ulong ulValue = (ulong)iValue;


В плюсах это все делалось довольно-таки просто. А тут — вообще непонятно.

Заранее, большое человеческое спасибо.
Re[6]: Маршаллинг класса
От: mrozov  
Дата: 21.02.07 11:18
Оценка:
Здравствуйте, maxus78, Вы писали:

M>Здравствуйте, mrozov, Вы писали:


M>Оно, конечно, спасибо. Только вот таких примеров и я мог наваять

Ну, эти примеры отвечают описанию задачи.
Хотелось бы понять, зачем может понадобиться лазить в сложную структуру по смещению. Может можно найти и более простые варианты?

M>А вообще, это реально сериализовать экземпляр одного класса в поток, а потом считать из этого потока данные в экземпляр другого класса?

Теоретически — да. Например, используя Xml-сериализацию.

M>И вообще, как в .NET приводятся типы друг к другу? Кроме, конечно, явного пребобразования наподобие


M>
M>int iValue = 123;
M>ulong ulValue = (ulong)iValue;
M>


M>В плюсах это все делалось довольно-таки просто. А тут — вообще непонятно.


M>Заранее, большое человеческое спасибо.


Ну.... я вот про "в плюсах делалось просто" первый раз слышу. Если имеются ввиду перегруженные операторы приведения типов, то тут есть аналог.

static public implicit operator RomanNumeral(BinaryNumeral binary);


Есть прекрасный тип Convert и т.п.
Re[7]: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 12:11
Оценка:
Здравствуйте, mrozov, Вы писали:

Что-то мы отвлеклись.

Писал я не "в плюсах делалось просто", а "довольно-таки просто", что в данном контексте означает, что для этого не надо было использовать какие-то библиотеки классов и т.д. и т.п. Все было возможно сделать с помощью встроенных операторов и стандартных функций.
То есть чтобы из экземпляра класса Class1 сделать экземпляр класса Class2 достаточно было 3-4х строчек. См. работу со стеком и кучей.

Что касается Convert, то насколько я понмню, он преобразовывает простые встроенные типы, наподобие bool, int, byte и т.д.
Меня же по сути интересует возможность взять участок памяти, занимаемый экземпляром Class1 и запихнуть эти данные в экземпляр Class2. Причем, в двоичном виде т.к. структура классов абсолютно разная.
Как это делается в .NET я не знаю, точнее с простыми структурами это можно было бы сделать с помощью Marshal.StructToPtr и PtrToStruct, поковырявшись какое-то время с MarshalAs Это, к сожалению, не мой случай. У меня объекты какие-то навороченные .

Что касается задачи, то конкретнее по-моему просто некуда (я, конечно, могу ошибаться).

Требуется в C# наваять аналог вот такого c-кода


            int tOffset = offsetof(Тип2, поле); // получаем смещение поля в структуре данных
            Тип2 *tValue = (Тип2*)(void*)((char*)typeValue - tOffset);


Причем, первую строку я мог бы сделать в виде

int tOffset = Marshal.ReadInt32(Marshal.OffsetOf(Тип2.GetType(), "поле"));


если бы работал маршаллинг А он не работает, как я и писал в начале темы. Ни Marshal.SizeOf, ни, естественно, Marshal.OffsetOf не работают.

Почему и зачем это надо делать — разбираться реально нет возможности. Придется поднимать кучу c-кода и выяснять откуда ноги растут.

Так что вот такая вот у меня беда.

Заранее, большое человеческое спасибо.
Re[8]: Маршаллинг класса
От: mrozov  
Дата: 21.02.07 13:12
Оценка:
Здравствуйте, maxus78, Вы писали:

Скажи, а тебе действительно необходима кольцевая ссылка при определении класса?
Если да, то я тебе могу только посоветовать копать в сторону MarshalAs(UnmanagedType.CustomMarshaler, но без гарантий.
Re[9]: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 13:30
Оценка:
Здравствуйте, mrozov, Вы писали:

M>Здравствуйте, maxus78, Вы писали:


M>Скажи, а тебе действительно необходима кольцевая ссылка при определении класса?

M>Если да, то я тебе могу только посоветовать копать в сторону MarshalAs(UnmanagedType.CustomMarshaler, но без гарантий.

А хрен его знает на самом деле. Я же не вникал в суть этого кода. Мне просто тупо надо заменить программу на с на программу на c#. До этого момента весь интим был в переделах нормы. А тут я встал конкретно.

Ну, хорошо, допустим я разобью исходный класс на 3 попроще. Все маршалиться будет. Но как мне это все привести к новому классу по частям — непонятно. Вообще, мне кажется, что в .NET в памяти размещаются не только двоичные данные класса, но еще куча всякой лабуды. Потому, что sizeof показывает какую-то чепуху:

класс

        [StructLayout(LayoutKind.Sequential)]
        public class TestClass
        {
            public int pValue; 
            public bool bValue; 
            public ulong ulValue; 
            public bool bValue2; 
            public bool bValue3;
            public int iValue;
        }


двоичный размер экземпляра этого класса по логике вещей не более 11 байтов.
А SizeOf показывает 32. Или я вообще не туда залез?

Заранее, большое человеческое спасибо.
Re[10]: Маршаллинг класса
От: mrozov  
Дата: 21.02.07 13:43
Оценка:
Здравствуйте, maxus78, Вы писали:

M>А хрен его знает на самом деле. Я же не вникал в суть этого кода. Мне просто тупо надо заменить программу на с на программу на c#. До этого момента весь интим был в переделах нормы. А тут я встал конкретно.


Ну... стремная задача, ежели без переделок.

M>Ну, хорошо, допустим я разобью исходный класс на 3 попроще. Все маршалиться будет. Но как мне это все привести к новому классу по частям — непонятно. Вообще, мне кажется, что в .NET в памяти размещаются не только двоичные данные класса, но еще куча всякой лабуды. Потому, что sizeof показывает какую-то чепуху:


кстати, если работать с .net 2.0, то можно сделать не класс, а все-таки структуру.
А нуллабельная ссылка будет выглядеть как MyTestStruct? _val;

Но все-таки — а зачем непременно переписывать на c#? Ради самого переписывания или есть более значимая цель?
Re[11]: Маршаллинг класса
От: maxus78  
Дата: 21.02.07 18:01
Оценка:
Здравствуйте, mrozov, Вы писали:

M>Ну... стремная задача, ежели без переделок.


Да, задача стремная. Сижу уж второй день как лось над этой фигней

M>Но все-таки — а зачем непременно переписывать на c#? Ради самого переписывания или есть более значимая цель?


Видимо, есть более значимая цель. Иначе зачем бы это делать. Я так понял, что это какая-то программулина под unix. Ее надо перенести под Windows еще и с таким расчетом, чтобы это был .NET-компонент и его можно было прикручивать к готовой программулине на C#. В принципе, эта программулина пишет и читает какие-то навороченные самописные файлы баз данных.
Можно было бы, конечно, сделать COM-библиотеку на С и подкрутить ее к дотнету, но что-то у нас тут никто С настолько не помнит, чтобы на это заморочиться. Было, соответственно, принято волевое решение переписывать все под дотнет. В принципе, 90% работы я сделал за 3 дня. А вот теперь 2-й день сижу с этим приведением типов Так не хочется разбираться что эта программулина в принципе делает — ваще кукан. Реально — это тогда недели на 2-3, чтобы разобраться в чужом сишном коде, состоящем из пары десятков заголовочных, и стольких же c-файлов.
Re: Маршаллинг класса
От: maxus78  
Дата: 22.02.07 14:28
Оценка:
Здравствуйте, господа!

Ну так может кто-нить что-нить подскажет? Или это глухо?
Re[12]: Маршаллинг класса
От: mrozov  
Дата: 22.02.07 14:37
Оценка:
Здравствуйте, maxus78, Вы писали:

M>Здравствуйте, mrozov, Вы писали:


M>>Ну... стремная задача, ежели без переделок.


M>Да, задача стремная. Сижу уж второй день как лось над этой фигней


M>>Но все-таки — а зачем непременно переписывать на c#? Ради самого переписывания или есть более значимая цель?


M>Видимо, есть более значимая цель. Иначе зачем бы это делать. Я так понял, что это какая-то программулина под unix. Ее надо перенести под Windows еще и с таким расчетом, чтобы это был .NET-компонент и его можно было прикручивать к готовой программулине на C#. В принципе, эта программулина пишет и читает какие-то навороченные самописные файлы баз данных.

M>Можно было бы, конечно, сделать COM-библиотеку на С и подкрутить ее к дотнету, но что-то у нас тут никто С настолько не помнит, чтобы на это заморочиться. Было, соответственно, принято волевое решение переписывать все под дотнет. В принципе, 90% работы я сделал за 3 дня. А вот теперь 2-й день сижу с этим приведением типов Так не хочется разбираться что эта программулина в принципе делает — ваще кукан. Реально — это тогда недели на 2-3, чтобы разобраться в чужом сишном коде, состоящем из пары десятков заголовочных, и стольких же c-файлов.

Ага, ну вот тут ситуевина проясняется.
У меня была схожая (но гораздо более запутанная) ситуация.
Решилась она следующим образом — я подключил весь c++ код к проекту на managed c++. Для начала — просто подключил и заставил компилиться .
Потом — написал очень простой класс на managed c++ (работая с ним в первый и последний пока раз), который использовал unmanaged код и переводил результаты его работы в managed классы (adapter).
Потом — подключил результирующую сборку к проекту на c# — и эта весч работает уже больше двух лет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.