473,399 Members | 3,302 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,399 software developers and data experts.

MarshalAs Problems with Arrays

Below is a program that shows a test for marshaling data from a byte
array to a class structure. Unfortunately, there are two annoying
problems (bugs?) that I can't seem to get around.

The first is that if I set the Articulation array to an offset of 22
in the EntityState class instead of 24, I get the following error.
The thing is, it is properly aligned. And the amount of data to be
copied is smaller than the index of 22 anyway.

System.TypeLoadException: Could not load type 'Test.EntityState' from
assembly 'MUSE_Common, Version=7.4.0.25116, Culture=neutral,
PublicKeyToken=null' because it contains an object field at offset 22
that is incorrectly aligned or overlapped by a non-object field.

The next error is that when I set the FieldOffset to 24 for the
articulations array, it runs great ... except that only the first byte
within the "other" array in DeadReckoning is set, they rest of the
bytes are 0 in the array. If I comment out the articulations array,
all the bytes of the "other" array in DeadReckoning are copied
correctly.

Help?

-------------------------------------------------

using System;
using System.Runtime.InteropServices;

namespace MarshalTest
{
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct Articulation
{
[FieldOffset(0)]
public byte parameterTypeDesignator;

[FieldOffset(1)]
public byte change;

[FieldOffset(2)]
public ushort idAttachedTo;

[FieldOffset(4)]
public uint parameterType;

[FieldOffset(8)]
public uint parameterValue1;

[FieldOffset(12)]
public uint parameterValue2;
}

[StructLayout(LayoutKind.Explicit, Size = 20)]
unsafe public struct DeadReckoning
{
[FieldOffset(0)]
public byte header;

[FieldOffset(1)]
public fixed byte other[15];

[FieldOffset(16)]
public uint footer;
}

[StructLayout(LayoutKind.Explicit)]
public class EntityState
{
[FieldOffset(0)]
public byte mySize;

[FieldOffset(1)]
public DeadReckoning deadRecking;

[FieldOffset(21)]
public byte temp1;

// BUG: Cannot set this offset to 22 without a runtime error.
Why?
[FieldOffset(24)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType =
UnmanagedType.Struct)]
public Articulation[] articulations;

public EntityState(byte[] rawData)
{
int thisSize = rawData.Length;

IntPtr pData = Marshal.AllocHGlobal(thisSize);
Marshal.Copy(rawData, 0, pData, thisSize);
Marshal.PtrToStructure(pData, this);
Marshal.FreeHGlobal(pData);

mySize = (byte)thisSize;
}

public byte[] ToRaw()
{
byte[] byteArray = new byte[mySize];
IntPtr pointer = Marshal.AllocHGlobal(mySize);
Marshal.StructureToPtr(this, pointer, false);
Marshal.Copy(pointer, byteArray, 0, mySize);
Marshal.FreeHGlobal(pointer);
return byteArray;
}
}

class Program
{
static void Main(string[] args)
{
// Simulate raw data read from hardware
int dataSize = 22;
byte[] rawData = new byte[dataSize];
rawData[0] = (byte)dataSize;
for (int i = 0; i < dataSize; i++)
{
rawData[i] = (byte)(i + 1);
}

// Convert raw data to class
EntityState entity = new EntityState(rawData);

// Compare original data with data stored in class
byte[] rawData2 = entity.ToRaw();

if (rawData.Length != rawData2.Length)
{
Console.WriteLine("**** ERROR *****: Data not the same
length.");
return;
}
bool dataIdentical = true;

// BUG: Offsets 3 - 16 are not identical
for (int i = 1; i < rawData.Length; i++)
{
if (rawData[i] != rawData2[i])
{
Console.WriteLine(i + ":\t" + rawData[i] +
" != " + rawData2[i] + "
*****");
dataIdentical = false;
}
else
{
Console.WriteLine(i + ":\t" + rawData[i] + " == "
+ rawData2[i]);
}
}
if (!dataIdentical)
{
Console.WriteLine("**** ERROR *****: Data not the
same.");
}
}
}
}
Jul 13 '08 #1
3 5295
O.B. wrote:
Below is a program that shows a test for marshaling data from a byte
array to a class structure. Unfortunately, there are two annoying
problems (bugs?) that I can't seem to get around.

The first is that if I set the Articulation array to an offset of 22
in the EntityState class instead of 24, I get the following error.
The thing is, it is properly aligned.
I'm afraid not. Under default packing the framework requires reference
fields to be aligned to a word boundary, that's 4 bytes in this case. So 24
bytes is OK, 22 is not. You can get around this by using SequentialLayout
and specifying a pack size of 1 (that is, no alignment padding). Using
ExplicitLayout won't work because the packing size is ignored if you do
that. I don't know why; it doesn't seem to be an entirely logical restriction.
The next error is that when I set the FieldOffset to 24 for the
articulations array, it runs great ... except that only the first byte
within the "other" array in DeadReckoning is set, they rest of the
bytes are 0 in the array. If I comment out the articulations array,
all the bytes of the "other" array in DeadReckoning are copied
correctly.
<snip>
>
// BUG: Cannot set this offset to 22 without a runtime error.
Why?
[FieldOffset(24)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType =
UnmanagedType.Struct)]
public Articulation[] articulations;
This isn't going to work. Marshalling as .ByValArray requires that you
specify the size of the array in the SizeConst parameter. If you don't know
the size in advance, you can't use .ByValArray. So you'll have to make clear
what you're going for, here. Is "articulations" a variable-sized array or a
fixed-size array? If it's variable-sized, what indicates the number of
elements and how?

OK, snipping the rest of the code. These declarations work:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Articulation {
public byte parameterTypeDesignator;
public byte change;
public ushort idAttachedTo;
public uint parameterType;
public uint parameterValue1;
public uint parameterValue2;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeadReckoning {
public byte header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] other;
public uint footer;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class EntityState {
public byte mySize;
public DeadReckoning deadRecking;
public byte temp1;

// This is probably wrong. You'll have to marshal this array manually
if it's variable-sized.
[MarshalAs(UnmanagedType.ByValArray, ArraySubType =
UnmanagedType.Struct, SizeConst = 1)]
public Articulation[] articulations;
}

It appears fixed arrays in substructures aren't marshalled correctly, or
else I just haven't found the right way to tickle the marshaller. Using a
regular array and marshalling it as .ByValArray works, though.

--
J.
Jul 13 '08 #2
On Jul 13, 4:16 pm, Jeroen Mostert <jmost...@xs4all.nlwrote:
O.B. wrote:
Below is a program that shows a test for marshaling data from a byte
array to a class structure. Unfortunately, there are two annoying
problems (bugs?) that I can't seem to get around.
The first is that if I set the Articulation array to an offset of 22
in the EntityState class instead of 24, I get the following error.
The thing is, it is properly aligned.

I'm afraid not. Under default packing the framework requires reference
fields to be aligned to a word boundary, that's 4 bytes in this case. So 24
bytes is OK, 22 is not. You can get around this by using SequentialLayout
and specifying a pack size of 1 (that is, no alignment padding). Using
ExplicitLayout won't work because the packing size is ignored if you do
that. I don't know why; it doesn't seem to be an entirely logical restriction.
Thanks. You are a blessing! In my real code, the offsets are not
sequential, but I can insert some "dummy" offsets to get the
sequential behavior to work.
The next error is that when I set the FieldOffset to 24 for the
articulations array, it runs great ... except that only the first byte
within the "other" array in DeadReckoning is set, they rest of the
bytes are 0 in the array. If I comment out the articulations array,
all the bytes of the "other" array in DeadReckoning are copied
correctly.

<snip>
// BUG: Cannot set this offset to 22 without a runtime error.
Why?
[FieldOffset(24)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType =
UnmanagedType.Struct)]
public Articulation[] articulations;

This isn't going to work. Marshalling as .ByValArray requires that you
specify the size of the array in the SizeConst parameter. If you don't know
the size in advance, you can't use .ByValArray. So you'll have to make clear
what you're going for, here. Is "articulations" a variable-sized array or a
fixed-size array? If it's variable-sized, what indicates the number of
elements and how?
It is actually variable sized. There is another attribute in the
EntityState class that specifies the number of articulations. I have
modified the test program (below) to include this attribute and how
I'm manually marshaling the data (see the ctor of EntityState). What
is odd is that the Marshal.SizeOf operation is returning a size
smaller than the actual array size returned by ToRaw(). Am I safe to
assume that the data returned by ToRaw is legit and Marshal's SizeOf
operation cannot handle dynamic arrays? Or is the SizeOf operation
correct and I am overwriting memory I shouldn't be?

using System;
using System.Runtime.InteropServices;

namespace MarshalTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Articulation
{
public byte parameterTypeDesignator;
public byte change;
public ushort idAttachedTo;
public uint parameterType;
public uint parameterValue1;
public uint parameterValue2;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeadReckoning
{
public byte header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] other;
public uint footer;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class EntityState
{
public byte mySize; // Offset 0
public DeadReckoning deadRecking; // Offset 1
public byte numArticulations; // Offset 21
[MarshalAs(UnmanagedType.ByValArray, ArraySubType =
UnmanagedType.Struct)]
public Articulation[] articulations;

public EntityState(byte[] rawData)
{
// Marshal the fixed data
int fixedSize = rawData.Length 22 ? 22 : rawData.Length;

IntPtr pData = Marshal.AllocHGlobal(fixedSize);
Marshal.Copy(rawData, 0, pData, fixedSize);
Marshal.PtrToStructure(pData, this);
Marshal.FreeHGlobal(pData);

// Manually marshal values for each articulation
if (numArticulations 0)
{
articulations = new Articulation[numArticulations];
byte[] tempArray = new byte[16];
for (int i = 0; i < numArticulations; i++)
{
Array.Copy(rawData, 22 + i * 16, tempArray, 0,
16);
unsafe
{
fixed (byte* pData2 = tempArray)
{
articulations[i] =

(Articulation)Marshal.PtrToStructure((IntPtr)pData 2,
typeof(Articulation));
}
}
}
}
}

public byte[] ToRaw()
{
byte[] byteArray = new byte[mySize];
IntPtr pointer = Marshal.AllocHGlobal(mySize);
Marshal.StructureToPtr(this, pointer, false);
Marshal.Copy(pointer, byteArray, 0, mySize);
Marshal.FreeHGlobal(pointer);
return byteArray;
}
}

class Program
{
static void Main(string[] args)
{
// Simulate raw data read from hardware
int dataSize = 54;
byte[] rawData = new byte[dataSize];
rawData[0] = (byte)dataSize;
for (int i = 1; i < dataSize; i++)
{
rawData[i] = (byte)(i + 1);
}
rawData[21] = 2; // 2 articulations

// Convert raw data to class
EntityState entity = new EntityState(rawData);

// Why is size of resulting structure smaller than 54?
if (Marshal.SizeOf(entity) != dataSize)
{
Console.WriteLine("Marshal says entity size is " +
Marshal.SizeOf(entity));
}

// Compare original data with data stored in class
byte[] rawData2 = entity.ToRaw();

if (rawData.Length != rawData2.Length)
{
Console.WriteLine("**** ERROR *****: Data not the same
length.");
return;
}
bool dataIdentical = true;

for (int i = 1; i < rawData.Length; i++)
{
if (rawData[i] != rawData2[i])
{
Console.WriteLine(i + ":\t" + rawData[i] + " != "
+ rawData2[i] + " *****");
dataIdentical = false;
}
else
{
Console.WriteLine(i + ":\t" + rawData[i] + " == "
+ rawData2[i]);
}
}
if (!dataIdentical)
{
Console.WriteLine("**** ERROR *****: Data not the
same.");
}
}
}
}

Jul 14 '08 #3
O.B. wrote:
It is actually variable sized. There is another attribute in the
EntityState class that specifies the number of articulations. I have
modified the test program (below) to include this attribute and how
I'm manually marshaling the data (see the ctor of EntityState). What
is odd is that the Marshal.SizeOf operation is returning a size
smaller than the actual array size returned by ToRaw(). Am I safe to
assume that the data returned by ToRaw is legit and Marshal's SizeOf
operation cannot handle dynamic arrays? Or is the SizeOf operation
correct and I am overwriting memory I shouldn't be?
Marshal.SizeOf will only return the amount of memory the marshaller thinks
is necessary (and also what it will use to marshal data back). The
marshaller can't handle variable-sized arrays, so it will always return the
size as if the array contained one element.

I have no idea why .ToRaw() works, actually. It shouldn't. :-) Apparently
the marshaller is clever enough to marshal the array fully, but not clever
enough to adjust its size measurements for it. You are not overwriting
memory that's not yours, so it shouldn't be a problem.

--
J.
Jul 14 '08 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Shane Mergy | last post by:
i have a program that reads through an ini file and does stuff so far the only thing i am having trouble with is the writing to the ini file. if the section is alreadey there i want to do a search...
33
by: Peter Seaman | last post by:
I understand that structures are value types and arrays and classes are reference types. But what about arrays as members of structures i.e. as in C struct x { int n; int a; }
2
by: Thomas Kent | last post by:
I have a dll that is expecting a 3x3 array which I'm am using DllImport to access. In addition, this array is located in a struct that is getting passed. I'm having problems that I think are...
2
by: Robin Tucker | last post by:
I'm having problems with the IPersistFile interface. We have in house objects that support IPersistFile (and have done for years). I would like to load an object using this interface with VB.NET...
0
by: jg | last post by:
just for those who have to deal with legacy application that supports COM, OCX, and WINAPI(_stadcall) - c-style?, I worked out the COM interface for function out array parameters. For example...
10
by: David Fort | last post by:
Hi, I'm upgrading a VB6 app to VB.net and I'm having a problem with a call to a function provided in a DLL. The function takes the address of a structure which it will fill in with values. I...
1
by: jsshah | last post by:
Hi I want to marshal following Win32 struct into .NEt class or struct as I want to call a native dll function from a Csharp code. The win32 struct ----------------------- typedef struct...
4
by: Bjarne Nielsen | last post by:
Hi all From a C# program, I need to call an unmanaged (C++) dll. The dll fills an array with variables and returns that to the C# program. When I have a fixed sized array, this works fine by...
8
webroten
by: webroten | last post by:
I've been working through trying to access a C DLL from VB.NET. I've read many online postings, but I'm still having problems. Now, my error is the "Attempted to read or write protected memory"...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.