Есть такой вот класс (можно было бы, конечно, структурой, но по ряду причин нужно иметь возможность присвоить экземпляру занчение 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), то все кудряво.
Подскажите, пожалуйста, как поступить в этом случае?
int tOffset = offsetof(Тип2, поле); // получаем смещение поля в структуре данных
Тип1 typeValue = GetTypeValue();
Тип2 tValue = (Тип2*)(void*)((char*)typeValue - tOffset);
Делать это придется, видимо, с помощию маршаллинга. По крайней мере, что-то мне никаких других способов провернуть эту мегаканитель, в голову не приходит.
Заранее благодарю за любые осмысленные комментарии.
Здравствуйте, 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)].
Но нельзя ли вместо этого (маршаллинга) использовать сериализацию?
Здравствуйте, mrozov, Вы писали:
M>Но нельзя ли вместо этого (маршаллинга) использовать сериализацию?
Да, это идея. Что-то я про эту возможность и не вспомнил. Правда, справедливости ради, сериализацию использовал только для сохранения стостояния классов на диск.
А примерчик какой-нить схематичный возможно?
Здравствуйте, 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;
}
}
Оно, конечно, спасибо. Только вот таких примеров и я мог наваять А вообще, это реально сериализовать экземпляр одного класса в поток, а потом считать из этого потока данные в экземпляр другого класса?
И вообще, как в .NET приводятся типы друг к другу? Кроме, конечно, явного пребобразования наподобие
int iValue = 123;
ulong ulValue = (ulong)iValue;
В плюсах это все делалось довольно-таки просто. А тут — вообще непонятно.
Здравствуйте, maxus78, Вы писали:
M>Здравствуйте, mrozov, Вы писали:
M>Оно, конечно, спасибо. Только вот таких примеров и я мог наваять
Ну, эти примеры отвечают описанию задачи.
Хотелось бы понять, зачем может понадобиться лазить в сложную структуру по смещению. Может можно найти и более простые варианты?
M>А вообще, это реально сериализовать экземпляр одного класса в поток, а потом считать из этого потока данные в экземпляр другого класса?
Теоретически — да. Например, используя Xml-сериализацию.
M>И вообще, как в .NET приводятся типы друг к другу? Кроме, конечно, явного пребобразования наподобие
M>
Писал я не "в плюсах делалось просто", а "довольно-таки просто", что в данном контексте означает, что для этого не надо было использовать какие-то библиотеки классов и т.д. и т.п. Все было возможно сделать с помощью встроенных операторов и стандартных функций.
То есть чтобы из экземпляра класса 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-кода и выяснять откуда ноги растут.
Скажи, а тебе действительно необходима кольцевая ссылка при определении класса?
Если да, то я тебе могу только посоветовать копать в сторону MarshalAs(UnmanagedType.CustomMarshaler, но без гарантий.
Здравствуйте, 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. Или я вообще не туда залез?
Здравствуйте, maxus78, Вы писали:
M>А хрен его знает на самом деле. Я же не вникал в суть этого кода. Мне просто тупо надо заменить программу на с на программу на c#. До этого момента весь интим был в переделах нормы. А тут я встал конкретно.
Ну... стремная задача, ежели без переделок.
M>Ну, хорошо, допустим я разобью исходный класс на 3 попроще. Все маршалиться будет. Но как мне это все привести к новому классу по частям — непонятно. Вообще, мне кажется, что в .NET в памяти размещаются не только двоичные данные класса, но еще куча всякой лабуды. Потому, что sizeof показывает какую-то чепуху:
кстати, если работать с .net 2.0, то можно сделать не класс, а все-таки структуру.
А нуллабельная ссылка будет выглядеть как MyTestStruct? _val;
Но все-таки — а зачем непременно переписывать на c#? Ради самого переписывания или есть более значимая цель?
Здравствуйте, mrozov, Вы писали:
M>Ну... стремная задача, ежели без переделок.
Да, задача стремная. Сижу уж второй день как лось над этой фигней
M>Но все-таки — а зачем непременно переписывать на c#? Ради самого переписывания или есть более значимая цель?
Видимо, есть более значимая цель. Иначе зачем бы это делать. Я так понял, что это какая-то программулина под unix. Ее надо перенести под Windows еще и с таким расчетом, чтобы это был .NET-компонент и его можно было прикручивать к готовой программулине на C#. В принципе, эта программулина пишет и читает какие-то навороченные самописные файлы баз данных.
Можно было бы, конечно, сделать COM-библиотеку на С и подкрутить ее к дотнету, но что-то у нас тут никто С настолько не помнит, чтобы на это заморочиться. Было, соответственно, принято волевое решение переписывать все под дотнет. В принципе, 90% работы я сделал за 3 дня. А вот теперь 2-й день сижу с этим приведением типов Так не хочется разбираться что эта программулина в принципе делает — ваще кукан. Реально — это тогда недели на 2-3, чтобы разобраться в чужом сишном коде, состоящем из пары десятков заголовочных, и стольких же c-файлов.
Здравствуйте, 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# — и эта весч работает уже больше двух лет.