What are the C# equivalent of these C++ structs
typedef union _Value {
signed char c;
unsigned char b;
signed short s;
unsigned short w;
signed long l;
unsigned long u;
float f;
double *d;
char *p;
} Value;
typedef struct _Field {
WORD nFieldId;
BYTE bValueType;
Va开发者_运维问答lue Value;
} Field;
typedef struct _Packet {
WORD nMessageType;
WORD nSecurityType;
BYTE bExchangeId;
BYTE bMarketCenter;
int iFieldCount;
char cSymbol[20];
Field FieldArr[1];
} Packet;
What are the C# equivalent of these C++ structs?
I am migrating some code from C++ to C# and having problems to migrate these structures. I had tried a few things but I always ended up having marshalling problems.
I'm assuming the 'char' is being used as an 8 bit number, if so, then here are you're mappings:
signed char c; -> SByte c;
unsigned char b; -> Byte b;
signed short s; -> Int16 s;
unsigned short w; -> UInt16 w;
signed long l; -> Int32 l;
unsigned long u; -> UInt32 u;
float f; -> Single f; (though 'float' still works)
double *d; -> Double d; (was this meant to be a pointer???)
char *p; -> String s; (assuming its a string here, in the marshaling you can tell it whether it is ASCII or wide char format)
With this info it should be relatively easy to translate those strucutres (just make sure you keep them as a struct and give it the attribute "[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", which will make sure that the marshaller keeps all the data in the same order.
Also, I recommend looking through both the classes and attributes in System.Runtime.InteropServices as they do provide quite a few methods for automating marshaling of data to c/c++ code (and it doesn't require "unsafe" c# code either).
Some of the other posts already have great information, I thought I would share a quick tip. I had to go through this kind of issue recently. It may be obvious but if you own the code to both sides of the interface I found that commenting out all but the one fields and making sure that works and then adding them back slowly one by one was a much safer way to get this working.
See this MSDN article on marshaling structs with PInvoke.
The key is using the StructLayout
attribute to ensure that the struct is treated properly by PInvoke, and the MarshalAs
attribute for types that don't line up exactly.
Back in .Net 2.0 days i also had a network socket and to convert the byte stream into a meaningful structure. At this time there was the only solution to do it by hand with BitConverter and Buffer class.
Unfortunately i couldn't find the example on the web again. So i stripped down my old class (gosh, this looks so old and ugly...). Maybe due to strip down, there are some small typo errors within it, but it should give you a good idea on how to accomplish the problem.
using System;
using System.Collections.Generic;
using System.Text;
namespace VehicleSpeedTracer
{
public class Datagram
{
//Offsets im ByteArray
private const int SizeOffset = 0;
private const int TimeOffset = SizeOffset + sizeof(uint);
private const int SpeedOffset = TimeOffset + sizeof(double);
private const int UnitOffset = SpeedOffset + sizeof(char);
private const int UnitMaxSize = (int)MaxSize - UnitOffset;
//Daten Current
public const uint MaxSize = 128;
public TimeSpan CurrentTime;
public double CurrentSpeed;
public string Unit;
public uint Size
{
get { return MaxSize - (uint)UnitMaxSize + (uint)Unit.Length; }
}
public Datagram()
{
}
public Datagram(Datagram Data)
{
CurrentTime = Data.CurrentTime;
CurrentSpeed = Data.CurrentSpeed;
Unit = Data.Unit;
}
public Datagram(byte[] RawData)
{
CurrentTime = TimeSpan.FromSeconds(GetDouble(RawData, TimeOffset));
CurrentSpeed = GetDouble(RawData, SpeedOffset);
Unit = GetString(RawData, UnitOffset, (int)(GetUInt(RawData, SizeOffset) - UnitOffset));
}
public override string ToString()
{
return this.CurrentTime.Hours.ToString().PadLeft(2, '0') + ":" +
this.CurrentTime.Minutes.ToString().PadLeft(2, '0') + ":" +
this.CurrentTime.Seconds.ToString().PadLeft(2, '0') + "." +
this.CurrentTime.Milliseconds.ToString().PadLeft(3, '0') + " " +
this.Unit;
}
public static implicit operator byte[](Datagram Data)
{
byte[] RawData;
RawData = new byte[Data.Size];
SetUInt(RawData, SizeOffset, Data.Size);
SetDouble(RawData, TimeOffset, Data.CurrentTime.TotalDays);
SetDouble(RawData, SpeedOffset, Data.CurrentSpeed);
SetString(RawData, UnitOffset, Data.Unit);
return RawData;
}
#region Utility Functions
// utility: get a uint from the byte array
private static uint GetUInt(byte[] aData, int Offset)
{
return BitConverter.ToUInt32(aData, Offset);
}
// utility: set a uint into the byte array
private static void SetUInt(byte[] aData, int Offset, uint Value)
{
byte[] buint = BitConverter.GetBytes(Value);
Buffer.BlockCopy(buint, 0, aData, Offset, buint.Length);
}
// utility: get a ushort from the byte array
private static ushort GetUShort(byte[] aData, int Offset)
{
return BitConverter.ToUInt16(aData, Offset);
}
// utility: set a ushort into the byte array
private static void SetUShort(byte[] aData, int Offset, int Value)
{
byte[] bushort = BitConverter.GetBytes((short)Value);
Buffer.BlockCopy(bushort, 0, aData, Offset, bushort.Length);
}
// utility: get a double from the byte array
private static double GetDouble(byte[] aData, int Offset)
{
return BitConverter.ToDouble(aData, Offset);
}
// utility: set a double into the byte array
private static void SetDouble(byte[] aData, int Offset, double Value)
{
byte[] bushort = BitConverter.GetBytes(Value);
Buffer.BlockCopy(bushort, 0, aData, Offset, bushort.Length);
}
// utility: get a unicode string from the byte array
private static string GetString(byte[] aData, int Offset, int Length)
{
String sReturn = Encoding.ASCII.GetString(aData, Offset, Length);
return sReturn;
}
// utility: set a unicode string in the byte array
private static void SetString(byte[] aData, int Offset, string Value)
{
byte[] arr = Encoding.ASCII.GetBytes(Value);
Buffer.BlockCopy(arr, 0, aData, Offset, arr.Length);
}
#endregion
}
public delegate void DatagramEventHandler(object sender, DatagramEventArgs e);
public class DatagramEventArgs : EventArgs
{
public Datagram Data;
public DatagramEventArgs(Datagram Data)
{
this.Data = Data;
}
}
}
精彩评论