in a previous post I asked "how to send a Struct from C# (Win10) to C (Unix-like OS) via socket".
The suggested solution was Marshalling.
Now I have no problem sending Integers, Enums or Strings. Unfortunately I have problems sending or receiving (I don't know if I'm wrong the Send of C # or the Read of C) the Double and Long data.
C Structure declared in Unix-like OS (vxWorks):
enum TYPE_OP
{
START_INITIALIZE = 0,
STOP_INITIALIZE = 1,
IDENTIFY = 2,
GET_VALUE = 3,
SET_VALUE = 4,
SET_RSE_MODE = 5,
GET_VALUE_DOUBLE = 6,
SET_VALUE_DOUBLE = 7,
SET_STRING = 8,
GET_VALUE_FLOAT = 9,
SET_VALUE_FLOAT = 10,
SET_TARGET = 11,
GET_TARGET = 12,
GET_TASK_STATUS = 13
};
typedef struct
{
long addr; //address of an element in GPIB chain (ex. 1, 13, etc.)
long value; //number (ex. enumerative position)
double dvalue; //a double number
} DESCR_DATA;
struct VAR_DATA
{
int len ;
enum TYPE_OP type;
char name[100]; //Name of the element in GPIB chain
DESCR_DATA data;
};
then after the "accept" in C:
bytes_read = read(client_sock, &vardata, sizeof(vardata));
printf("ENUM VALUE = %d\n", vardata.type);
printf("DOUBLE VALUE = %.2f\n", vardata.data.value);
but result is always 0.00
C# structure declared in Windows:
public enum TYPE_OP
{
START_INITIALIZE = 0,
STOP_INITIALIZE = 1,
IDENTIFY = 2,
GET_VALUE = 3,
SET_VALUE = 4,
SET_RSE_MODE = 5,
GET_VALUE_DOUBLE = 6,
SET_VALUE_DOUBLE = 7,
SET_STRING = 8,
GET_VALUE_FLOAT = 9,
SET_VALUE_FLOAT = 10,
SET_TARGET = 11,
GET_TARGET = 12,
GET_TASK_STATUS = 13
}
public struct DESCR_DATA
{
public long addr;
public long value;
public double dvalue;
}
public struct VAR_DATA
{
public int len;
public TYPE_OP type;
public string name;
public DESCR_DATA data;
}
VAR_DATA vardata = new VAR_DATA();
Code in C# to send structure "vardata" to C server:
public byte[] Struct2Bytes(CommonStructures.VAR_DATA vdata_struct)
{
byte[] b_arr = new byte[Marshal.SizeOf(vdata_struct)];
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(vdata_struct));
Marshal.StructureToPtr(vdata_struct, ptr, true);
Marshal.Copy(ptr, b_arr, 0, Marshal.SizeOf(vdata_struct));
return b_arr;
}
public void Identify(Socket Socket2Server, CommonStructures.VAR_DATA vardata, IPEndPoint remoteEP)
{
Socket2Server.Connect(remoteEP);
Socket2Server.RemoteEndPoint.ToString();
vardata.name = "Device Name"; // new char[100];
vardata.len = 105;
vardata.data.dvalue = 16.6;
vardata.data.addr = 11;
vardata.data.value = 666;
vardata.type = CommonStructures.TYPE_OP.IDENTIFY;
int bytesSent = Socket2Server.Send(Struct2Bytes(vardata));
Socket2Server.Shutdown(SocketShutdown.Both);
Socket2Server.Close();
}
CodePudding user response:
You have quite a few mistakes in your struct
definitions:
long
in C is 32-bit, which isint
in C#name
ischar[100]
, which is a fixed-size array of ANSI characters. So it should haveByValTStr
applied to it, andVAR_DATA
needsCharSet.Ansi
public struct DESCR_DATA
{
public int addr;
public int value;
public double dvalue;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct VAR_DATA
{
public int len;
public TYPE_OP type;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string name;
public DESCR_DATA data;
}
You don't need to marshal the struct yourself (your marshalling code is leaking HGlobals anyway). Instead just pass it as a ref
parameter
public void Identify(Socket Socket2Server, CommonStructures.VAR_DATA vardata, IPEndPoint remoteEP)
{
Socket2Server.Connect(remoteEP);
Socket2Server.RemoteEndPoint.ToString();
vardata.name = "Device Name";
vardata.len = 105;
vardata.data.dvalue = 16.6;
vardata.data.addr = 11;
vardata.data.value = 666;
vardata.type = CommonStructures.TYPE_OP.IDENTIFY;
int bytesSent = Socket2Server.Send(ref vardata);
Socket2Server.Shutdown(SocketShutdown.Both);
Socket2Server.Close();
}
If you really need to use a byte[]
array, you must make sure to release the HGlobal in a finally
public byte[] Struct2Bytes(CommonStructures.VAR_DATA vdata_struct)
{
byte[] b_arr = new byte[Marshal.SizeOf(vdata_struct)];
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(vdata_struct));
Marshal.StructureToPtr(vdata_struct, ptr, true);
Marshal.Copy(ptr, b_arr, 0, Marshal.SizeOf(vdata_struct));
}
finally
{
Marshal.FreeHGlobal(ptr);
}
return b_arr;
}
I must say, I don't understand why you are using C code here anyway. C# has a full complement of library classes for sockets.