Casting explicitly-laid out structures - c#

Let's say I have this structure,
[StructLayout(LayoutKind.Explicit)]
public struct Chapter4Time
{
[FieldOffset(0)]
public UInt16 Unused;
[FieldOffset(2)]
public UInt16 TimeHigh;
[FieldOffset(4)]
public UInt16 TimeLow;
[FieldOffset(6)]
public UInt16 MicroSeconds;
}
and this structure.
[StructLayout(LayoutKind.Explicit)]
public struct IEEE_1588Time
{
[FieldOffset(0)]
public UInt32 NanoSeconds;
[FieldOffset(4)]
public UInt32 Seconds;
}
How would I convert from one structure to the other?

Two options here:
No unsafe code, but explicit structure layout
(Note that although this isn't unsafe as far as the C# compiler is concerned, some frameworks may still disallow it - see Marc Gravell's comment.)
You could use a union type, which is just another struct with two fields, both set explicitly to the same location. Here's a complete example using your structures:
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
public struct Chapter4Time
{
[FieldOffset(0)]
public UInt16 Unused;
[FieldOffset(2)]
public UInt16 TimeHigh;
[FieldOffset(4)]
public UInt16 TimeLow;
[FieldOffset(6)]
public UInt16 MicroSeconds;
}
[StructLayout(LayoutKind.Explicit)]
public struct IEEE_1588Time
{
[FieldOffset(0)]
public UInt32 NanoSeconds;
[FieldOffset(4)]
public UInt32 Seconds;
}
[StructLayout(LayoutKind.Explicit)]
public struct TimeUnion
{
[FieldOffset(0)]
public Chapter4Time Chapter4Time;
[FieldOffset(0)]
public IEEE_1588Time IEEE_1588Time;
}
class Test
{
static void Main()
{
var ch4 = new Chapter4Time { TimeLow = 100, MicroSeconds = 50 };
var union = new TimeUnion { Chapter4Time = ch4 };
Console.WriteLine(union.IEEE_1588Time.Seconds);
}
}
Unsafe code, casting pointers
An alternative to the union type if you can use unsafe code is to cast a pointer of type Chapter4Time* to IEEE_1588Time*:
class Test
{
unsafe static void Main()
{
var ch4 = new Chapter4Time { TimeLow = 100, MicroSeconds = 50 };
var ieee1588 = *((IEEE_1588Time*) &ch4);
Console.WriteLine(ieee1588.Seconds);
}
}
Personally I'd avoid doing any of this if at all possible, but if you *really, really want to do it, these are probably the simplest approaches.

Related

Marshaling c# call to DLL library

I am having trouble calling a DLL library with a specific signature. This is on the xamarin platform and running on iOS. I am trying to get a list of DNS servers. I can call other functions without an issue, but the one I really need is not working. I am sure its becuase my struct is not correct. I believe the issue is the "union" type. I just dont know what my struct should look like to appease that parameter. Here are the relevant c++ types:
1: The DLL singature
`int res_getservers __P((res_state, union res_sockaddr_union * , int));`
2: The c++ structs
union res_sockaddr_union {
struct sockaddr_in sin;
#ifdef IN6ADDR_ANY_INIT
struct sockaddr_in6 sin6;
#endif
#ifdef ISC_ALIGN64
int64_t __align64; /* 64bit alignment */
#else
int32_t __align32; /* 32bit alignment */
#endif
char __space[128]; /* max size */
};
struct sockaddr_in6 {
__uint8_t sin6_len; /* length of this struct(sa_family_t) */
sa_family_t sin6_family; /* AF_INET6 (sa_family_t) */
in_port_t sin6_port; /* Transport layer port # (in_port_t) */
__uint32_t sin6_flowinfo; /* IP6 flow information */
struct in6_addr sin6_addr; /* IP6 address */
__uint32_t sin6_scope_id; /* scope zone index */
};
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Any help on generating the proper c# structs would be greatly appreciated! Thank you.
Disclaimer: I don't have C++ installed on my machine any more but I believe this will either work, or at least give you a good shove in the right direction.
Based on: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738571(v=vs.85).aspx
And: https://learn.microsoft.com/en-us/cpp/mfc/reference/sockaddr-in-structure
And: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute(v=vs.110).aspx
And numerous other Google searches for the types in question.
using System;
using System.Runtime.InteropServices;
namespace SockStructTest
{
class Program
{
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct struct_sin_zero
{
[FieldOffset(0)]
public byte s_b1;
[FieldOffset(1)]
public byte s_b2;
[FieldOffset(2)]
public byte s_b3;
[FieldOffset(3)]
public byte s_b4;
[FieldOffset(4)]
public byte s_b5;
[FieldOffset(5)]
public byte s_b6;
[FieldOffset(6)]
public byte s_b7;
[FieldOffset(7)]
public byte s_b8;
[FieldOffset(0)]
public UInt64 s_ui64;
};
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct in_addr
{
[FieldOffset(0)]
public byte s_b1;
[FieldOffset(1)]
public byte s_b2;
[FieldOffset(2)]
public byte s_b3;
[FieldOffset(3)]
public byte s_b4;
[FieldOffset(0)]
public UInt16 s_w1;
[FieldOffset(2)]
public UInt16 s_w2;
[FieldOffset(0)]
public UInt32 S_addr;
};
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct sockaddr_in
{
[FieldOffset(0)]
public Int16 sin_family;
[FieldOffset(2)]
public UInt16 sin_port;
[FieldOffset(4)]
public in_addr sin_addr;
[FieldOffset(8)]
public struct_sin_zero sin_zero;
};
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct in6_addr_u
{
[FieldOffset(0)]
public byte Byte0;
[FieldOffset(1)]
public byte Byte1;
[FieldOffset(2)]
public byte Byte2;
[FieldOffset(3)]
public byte Byte3;
[FieldOffset(4)]
public byte Byte4;
[FieldOffset(5)]
public byte Byte5;
[FieldOffset(6)]
public byte Byte6;
[FieldOffset(7)]
public byte Byte7;
[FieldOffset(8)]
public byte Byte8;
[FieldOffset(9)]
public byte Byte9;
[FieldOffset(10)]
public byte ByteA;
[FieldOffset(11)]
public byte ByteB;
[FieldOffset(12)]
public byte ByteC;
[FieldOffset(13)]
public byte ByteD;
[FieldOffset(14)]
public byte ByteE;
[FieldOffset(15)]
public byte ByteF;
[FieldOffset(0)]
public UInt16 Word0;
[FieldOffset(2)]
public UInt16 Word1;
[FieldOffset(4)]
public UInt16 Word2;
[FieldOffset(6)]
public UInt16 Word3;
[FieldOffset(8)]
public UInt16 Word4;
[FieldOffset(10)]
public UInt16 Word5;
[FieldOffset(12)]
public UInt16 Word6;
[FieldOffset(14)]
public UInt16 Word7;
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct in6_addr
{
[FieldOffset(0)]
public in6_addr_u u;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct sockaddr_in6
{
public UInt64 sin6_len; // length of this struct(sa_family_t)
public UInt32 sin6_family; // AF_INET6 (sa_family_t)
public UInt16 sin6_port; // Transport layer port # (in_port_t)
public UInt32 sin6_flowinfo; // IP6 flow information
public in6_addr sin6_addr; // IP6 address
public UInt32 sin6_scope_id; // scope zone index
};
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct res_sockaddr_union
{
[FieldOffset(0)]
public sockaddr_in sin;
[FieldOffset(0)]
public sockaddr_in6 sin6;
[FieldOffset(0)]
public Int64 __align64;
[FieldOffset(0)]
public Int32 __align32;
// This is the char __space[128] bit.
// I've cheated and used 16 8 byte values.
[FieldOffset(0)]
public UInt64 __space0;
[FieldOffset(8)]
public UInt64 __space1;
[FieldOffset(16)]
public UInt64 __space2;
[FieldOffset(24)]
public UInt64 __space3;
[FieldOffset(32)]
public UInt64 __space4;
[FieldOffset(40)]
public UInt64 __space5;
[FieldOffset(48)]
public UInt64 __space6;
[FieldOffset(56)]
public UInt64 __space7;
[FieldOffset(64)]
public UInt64 __space8;
[FieldOffset(72)]
public UInt64 __space9;
[FieldOffset(80)]
public UInt64 __spaceA;
[FieldOffset(88)]
public UInt64 __spaceB;
[FieldOffset(96)]
public UInt64 __spaceC;
[FieldOffset(104)]
public UInt64 __spaceD;
[FieldOffset(112)]
public UInt64 __spaceE;
[FieldOffset(120)]
public UInt64 __spaceF;
}
static void Main(string[] args)
{
sockaddr_in ad;
ad.sin_zero.s_ui64 = 0;
ad.sin_family = 0; // or whatever
ad.sin_port = 1234;
// Address as b bit values
ad.sin_addr.s_b1 = 0;
ad.sin_addr.s_b2 = 1;
ad.sin_addr.s_b3 = 2;
ad.sin_addr.s_b4 = 3;
// Address as 16 bits
ad.sin_addr.s_w1 = 0;
ad.sin_addr.s_w2 = 0;
}
}
}
Best I can do - don't feel under pressure to accept the answer if it doesn't solve your issue but please do take some time to try to understand what's going on in the example I've given you.
I haven't had chance to test it - but it does build.
Good luck!
Regards,
Adam.

How to implicitly cast this?

I'm trying to create some wrapper classes around some native DLL structs. Here's what I've got:
public class Event // <-- managed class
{
internal SDL_Event _event;
public EventType Type
{
get { return (EventType) _event.type; }
}
public KeyboardEvent Key
{
get
{
return new KeyboardEvent(_event.key); // <-- I want to avoid making a copy of the struct here
}
}
}
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct SDL_Event // <-- a union holding ~15 different event types
{
[FieldOffset(0)] public UInt32 type;
[FieldOffset(0)] public SDL_KeyboardEvent key;
[FieldOffset(0)] private fixed byte _padding[56];
}
public class KeyboardEvent
{
private SDL_KeyboardEvent _event;
internal KeyboardEvent(SDL_KeyboardEvent e)
{
_event = e;
}
// some properties that deal specifically with SDL_KeyboardEvent
}
[StructLayout(LayoutKind.Sequential)]
internal struct SDL_KeyboardEvent
{
public UInt32 type; // <-- sits in the same memory location as SDL_Event.type
public UInt32 timestamp;
public UInt32 windowID;
public byte state;
public byte repeat;
private byte _padding2;
private byte _padding3;
public SDL_Keysym keysym;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SDL_Keysym
{
public UInt32 scancode;
public Int32 sym;
public UInt16 mod;
private UInt32 _unused;
}
Event is supposed to wrap SDL_Event and KeyboardEvent should wrap SDL_KeyboardEvent. I would essentially like to "cast" Event to KeyboardEvent when Event.Key is accessed, without copying any data around. Ideally, Event would be directly castable to KeyboardEvent too.
unsafe static SDL_KeyboardEvent ToSDL_KeyboardEvent (SDL_Event event)
{
return *((SDL_KeyboardEvent*) &event);
}
That's the best I can do with the structs. For the classes, you'll have to write some explicit casts in the usual way, but this should help with those.

I'd like to use union as C# with byte array

I had idea about message parsing in serial communication, there are many kind of packets which have different form. but they're all sent by byte array.
so I thought using union to parse each message.
but it's not working well.
following code is the sample code which I'm In Error
[StructLayout(LayoutKind.Explicit, Size=12)]
public struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
public byte[] data;
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
if this were possible, it would be very happy, but it isn't. This code occurs TypeLoadException "... because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field."
So I changed some code like this
[StructLayout(LayoutKind.Explicit, Size= 12)]
public struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
[FieldOffset(0)]
public byte[] data;
//[FieldOffset(0)]
//public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
for test, i just disabled Time field which offset is 0, and this didn't occur Exception. but, if i change other fields, it doesn't change byte array. i think that byte array's real memory location is allocated in other heap, so it cannot be done.
Is there any way to solve this problem in C#? only C++ or C can solve this?
and if i use this with inheritance, is it possible?
P.S. Sorry about my poor english
I'm not 100% sure what you are trying to do, but:
first approach, with array stored inside of a structure is possible, if you use it with fixed/unsafe keywords. I don't know if this is possible for you. So having code like this should work:
[StructLayout(LayoutKind.Explicit, Size = 12)]
public unsafe struct UnionPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
[FieldOffset(0)]
public fixed byte data[12];
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
Of course, then you have to enable unsafe code blocks in VS and use wrap your structure around with it:
unsafe
{
var u = new UnionPacket();
for (byte i = 0; i < 12; i++)
{
u.data[i] = i;
}
Console.WriteLine(u.Time);
Console.WriteLine(u.CoordX);
Console.WriteLine(u.CoordY);
Console.WriteLine(u.Red);
Console.WriteLine(u.Green);
Console.WriteLine(u.Blue);
Console.WriteLine(u.Alpha);
}
Other approach would be - just forgetting about this array inside struct, and handle parsing using Marshal.Copy:
[StructLayout(LayoutKind.Explicit, Size = 12)]
public struct UnionPacket2
{
[FieldOffset(0)]
public float Time;
[FieldOffset(4)]
public Int16 CoordX;
[FieldOffset(6)]
public Int16 CoordY;
[FieldOffset(8)]
public byte Red;
[FieldOffset(9)]
public byte Green;
[FieldOffset(10)]
public byte Blue;
[FieldOffset(11)]
public byte Alpha;
}
static void Main(string[] args)
{
var len = Marshal.SizeOf(typeof(UnionPacket2));
var buffer = new byte[len];
for (byte i = 0; i < len; i++)
{
buffer[i] = i;
}
var ptr = Marshal.AllocHGlobal(len);
Marshal.Copy(buffer, 0, ptr, len);
var u = (UnionPacket2)Marshal.PtrToStructure(ptr, typeof(UnionPacket2));
Marshal.FreeHGlobal(ptr);
Console.WriteLine(u.Time);
Console.WriteLine(u.CoordX);
Console.WriteLine(u.CoordY);
Console.WriteLine(u.Red);
Console.WriteLine(u.Green);
Console.WriteLine(u.Blue);
Console.WriteLine(u.Alpha);
}

How use struct with union in c#

Hi I writing a wrapper in c# and i have some problem. I have this struct in c++.
typedef struct pjmedia_format
{
pj_uint32_t id;
pjmedia_type type;
pjmedia_format_detail_type detail_type;
union
{
pjmedia_audio_format_detail aud;
pjmedia_video_format_detail vid;
char user[PJMEDIA_FORMAT_DETAIL_USER_SIZE];
} det;
} pjmedia_format;
This is link to this struct pjmedia_format
in c# I have this:
[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_format
{
public uint id;
public pjmedia_type type;
public pjmedia_format_detail_type detail_type;
public det_t det;
}
[StructLayout(LayoutKind.Explicit)]
public struct det_t
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public pjmedia_audio_format_detail aud;
[FieldOffset(36)]
[MarshalAs(UnmanagedType.Struct)]
public pjmedia_video_format_detail vid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
[FieldOffset(60)]
public char[] user;
}
[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_audio_format_detail
{
public uint clock_rate;
public uint channel_count;
public uint frame_time_usec;
public uint bits_per_sample;
public int avg_bps;
public int max_bps;
}
[StructLayout(LayoutKind.Sequential)]
public struct pjmedia_video_format_detail
{
public pjmedia_rect_size size;
public pjmedia_ratio fps;
public int avg_bps;
public int max_bps;
}
and when i want to use this struct i get this error
System.Runtime.InteropServices.MarshalDirectiveException was unhandled.
Message="A method signature is not PInvoke compatible with the element."
I try to use some attributes like size or pack but it doesn't help (probably i use it wrong). I tested singly other struct e.g. pjmedia_video_format_detail and they works well. Any advice?
Best regards
Andrzej
As this is a union, shouldn't that be:
[StructLayout(LayoutKind.Explicit)]
public struct det_t
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public pjmedia_audio_format_detail aud;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public pjmedia_video_format_detail vid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
[FieldOffset(0)]
public char[] user;
}
i.e. overlapping? Also, you might need user to be a fixed buffer rather than an array.
In the C++ code, det is a union. That means that all the fields have zero offset, they are overlayed. Simply change your C# declaration to match by using [FieldOffset(0)] for all fields in det_t.

Without using "fixed", how do I access values of an array within a struct?

I'm doing C++ --> C# interop stuff and I have a bunch of structs that contain each other like Matryoshka dolls. The problem is that one of these 'nestings' takes the form of a fixed length array:
typedef struct tagBIRDREADING
{
BIRDPOSITION position;
BIRDANGLES angles;
BIRDMATRIX matrix;
BIRDQUATERNION quaternion;
WORD wButtons;
}
BIRDREADING;
typedef struct tagBIRDFRAME
{
DWORD dwTime;
BIRDREADING reading[BIRD_MAX_DEVICE_NUM + 1];
}
BIRDFRAME;
Following the hallowed teachings of Eric Gunnerson, I did the following in C#:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BIRDREADING
{
public BIRDPOSITION position;
public BIRDANGLES angles;
public BIRDMATRIX matrix;
public BIRDQUATERNION quaternion;
public ushort wButtons;
}
[StructLayout(LayoutKind.Sequential, Size = 127)]
public struct BIRDREADINGa
{
public BIRDREADING reading;
}
public struct BIRDFRAME
{
public uint dwTime;
public BIRDREADINGa readings;
}
My question is, how do I access each of the 127 instances of BIRDREADING contained within BIRDREADINGa and therefore BIRDFRAME? Or have I gone terrible wrong?
I think you just want this:
[StructLayout(LayoutKind.Sequential)]
public struct BIRDFRAME
{
public uint dwTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=127)]
public BIRDREADING[] readings;
}
To access all those instances without using an array you need to use an unsafe block to grab the address of the "fake array" you set up, and then use pointer arithmetic. It's going to get ugly:
public struct BIRDREADINGa
{
public BIRDREADING reading;
public BIRDREADING GetReading(int index)
{
unsafe
{
fixed(BIRDREADING* r = &reading)
{
return *(r + index);
}
}
}
}

Categories

Resources