UWP - Serialize a struct in order to send it with TCP - serialization

My aim with this code is to send a struct to a server which waits for this struct to read the data out of it. So i have to serialize all the references in order to give the server a struct which it can read and understand.
I have got a struct which contains long, ulong, string, enum, long[] and other struct. I've already searched on stackoverflow, but all the solutions serialize my struct to zeros except the strings.
How do I serialize the struct properly, then save it to byte[] and finally send it with tcp ?
My Header-Struct (that's why my struct looks like this):
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 4, Size = size)]
public struct _HEADER
{
[FieldOffset(0)]
public Constants._TYPE Type;
[FieldOffset(4)]
public long Cr;
[FieldOffset(12)]
public Id Id;
[FieldOffset(SIZE+12), MarshalAs(UnmanagedType.ByValArray)]
public long[] array;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 4, Size = SIZE)]
public struct Id
{
[FieldOffset(0)]
public long Protocol;
[FieldOffset(8)]
public long Protocol;
[FieldOffset(16)]
public Constants._TYPE CType;
[FieldOffset(20)]
public Constants._TYPE Cred;
[FieldOffset(24)]
public Constants._TYPE CGred;
}
My CURRENT method to serialize the struct:
IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, pointer, false);
byte[] headerdata = new byte[Marshal.SizeOf(header)];
Marshal.Copy(pointer, headerdata, 0, headerdata.Length);
Marshal.FreeHGlobal(pointer);
My CURRENT method to send the data:
_socket.Send(headerdata);
This is what I get in the tcp-packet, which I send to the server:

Why not to use BinaryFormatter?
https://msdn.microsoft.com/en-us/library/c5sbs8z9(v=vs.110).aspx

Related

Using UnManaged C++ Dll in C#

Hi this is my Function in C++ dll.
I am Trying to use it in My C# Application. Have tried so many things but nothing seems to work for me.
xyz_API LONG __stdcall xyz_Login(char *dwIP,unsigned short dwPort,char *dwUseName,char
*dwPassword,MyDetail dwInfo,char *dwInfo);
* Parameter:
[in]
dwIP
dwpPort
dwUseName
dwPassword
[out]
MyDetail (struct)
This is the Struct :
typedef struct
{
int xyz_id;
int xyz_ch;
int xyz_total;
int my_id;
char my_Info[10];
char m_status;
}MyDetail ,*MyDetail ;
I made a Class for this Struct in my code as:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MyDetail
{
public int xyz_id;
public int xyz_ch;
public int xyz_total;
public int my_id;
[MarshalAs(UnmanagedType.ByValArray,
ArraySubType = UnmanagedType.LPStr, SizeConst = 10)]
public char[] my_Info;
public sbyte m_status;
}
I am using following line of code to do use it in C# application:
[DllImport("MYC.dll", EntryPoint = "xyz_Login", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int xyz_Login([MarshalAs(UnmanagedType.LPWStr)]string dwIP, ushort dwPort, [MarshalAs(UnmanagedType.LPWStr)] string dwUseName, [MarshalAs(UnmanagedType.LPWStr)] string dwPassword, MyDetail dwmyInfo, [MarshalAs(UnmanagedType.LPWStr)]string dwInfo);
My Form Calling:
MyDetail obj= new MyDetail();`enter code here`
int result = xyz_Login("192.168.1.10", 9001, "admin", "admin", obj, null);
code works perfectly but there is not output. MyDetail object always return null.
Is There a problem in marshalling. thanks in advance
First, the C++ function:
xyz_API LONG __stdcall xyz_Login(char *dwIP,unsigned short dwPort,char *dwUseName,char
*dwPassword,MyDetail dwInfo,char *dwInfo);
The paramter "dwInfo" is a struct type, not a pointer or a reference type, so the parameter is passed by value, so in the function xyz_Login, you are modifying a local copy of the struct, no changes to the struct in C#. So you should change it: MyDetail* dwInfo
Meanwhile, you should change the dllimport in C# to:
[DllImport("MYC.dll", EntryPoint = "xyz_Login", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int xyz_Login(string dwIP, ushort dwPort, string dwUseName, string dwPassword, ref MyDetail dwmyInfo, string dwInfo);
In a PInvoke call, a ref struct is translated into a pointer to the struct; also, char* is ansi, not unicode.
I got this running using following:
Struct As:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MyDetail
{
public int xyz_id;
public int xyz_ch;
public int xyz_total;
public int my_id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string my_Info;
public sbyte m_status;
}
DLLImport Statement AS:
[DllImport("MYC.dll", EntryPoint = "NET_DVR_Login")]
public static extern Int32 xyz_Login(string dwIP, UInt16 dwPort, string Name,string dwPassword, IntPtr myDetail, char[] info);

How to marshal this nested, and Pointer Used C structure in C#

typedef struct pt_input_bir
{
PT_BYTE byForm;
union {
PT_BIR *pBIR; ///< Used when byForm = PT_FULLBIR_INPUT */
PT_LONG lSlotNr; ///< Used when byForm = PT_SLOT_INPUT */
PT_BYTE abyReserved[20]; /** For future use */
} InputBIR;
} PT_INPUT_BIR
typedef struct pt_bir {
PT_BIR_HEADER Header;
PT_BYTE Data[1];
} PT_BIR
typedef struct pt_bir_header {
PT_DWORD Length;
PT_BYTE HeaderVersion;
PT_BYTE Type;
PT_WORD FormatOwner;
PT_WORD FormatID;
PT_CHAR Quality;
PT_BYTE Purpose;
PT_DWORD FactorsMask;
} PT_BIR_HEADER
and the C function is
PT_STATUS StoreFinger (
IN PT_CONNECTION hConnection,
IN PT_INPUT_BIR *pTemplate,
OUT PT_LONG *plSlotNr
)
Now I need to do the wrapper for the above C function in C#.
How should I marshal the PT_INPUT_BIR* structure and how should I unmarshal it after return of this function?
Please help me to solve this.
/********************** FOR MORE DETAIL ABOUT THIS QUESTION**************************/
C struct and function are defined in above. pls refer there.
C# Struct :
For C# struct declaration i have maintatined two struct for the one C struct. bcz one is for setting the values and another one id for passing to c function.
C# app struct:
[StructLayout(LayoutKind.Sequential)]//for app
public struct FPINPUTBIR
{
public byte byForm;
public InputBIRType InputBIR;
}
[StructLayout(LayoutKind.Sequential)] // here when i use explicit it throws exception so i removed it.
public struct InputBIRType
{
// [FieldOffset(0)]
public FPBIR pBIR;
//[FieldOffset(0)]
public int lSlotNr;
//[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] abyReserved;
}
C# wrapper struct:
[StructLayout(LayoutKind.Sequential)]
public struct FP_INPUTBIR
{
public byte byForm;
public IntPtr mIPBIR;
}
[StructLayout(LayoutKind.Explicit, Size = 20, CharSet = CharSet.Ansi)]
public struct Input_BIRType
{
[FieldOffset(0)]
public IntPtr mBIR;
[FieldOffset(0)]
public int lSlotNr;
//[FieldOffset(8)]
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
//public byte[] abyReserved;
}
finally i will copy the value from the C# app struct to wrapper struct before the call the C fun()
2a) C# App Side Code is :
//here mAppMemory is already known value
FPINPUTBIR lfipdata = new FPINPUTBIR();
FPDATA lfpdata = new FPDATA();
lfipdata.byForm = (byte)eFPVerifyBy.FULLBIR_INPUT;
lfipdata.InputBIR = new InputBIRType();
lfipdata.InputBIR.abyReserved = new byte[20];
lfipdata.InputBIR.pBIR.Data = new byte[mAppMemory[listBox2.SelectedIndex].Header.Length];
Array.Copy(mAppMemory[listBox2.SelectedIndex].Data, lfipdata.InputBIR.pBIR.Data, mAppMemory[listBox2.SelectedIndex].Header.Length);
lfipdata.InputBIR.pBIR.Header = mAppMemory[listBox2.SelectedIndex].Header;
Verify(ref lfipdata); //calling from C# APP side to C# wrapper
C# wrapper side:
public int Verify(ref FPINPUTBIR apStoredTemplate )
{
// i passed the args (apStoredTemplate ) but throws exception struct mismatch with C struct.
//here i don't know what should i do.
CDLL.StoreFinger(..,ref apStoredTemplate,.. ); //pls refer the C function above
}
Questions:
Do i really need two C# structures for this.
what should i do inside the C# wrapper function. please remeber i have two C# struct with diff members.
Thanks.
You just need a little extension on what you used in the previous question for PT_BIR. There we marshalled that variable length struct as byte[]. You can use the same code to generate the byte array, and I won't revisit that.
Next you need the union. That is:
[StructLayout(LayoutKind.Explicit, Size = 20)]
public struct PT_INPUT_BIR_UNION
{
[FieldOffset(0)]
public IntPtr pBIR;
[FieldOffset(0)]
public int lSlotNr; // I'm guessing what PT_LONG is
}
No need to declare the reserved part of the union. The size takes care of that.
Then PT_INPUT_BIR is
[StructLayout(LayoutKind.Sequential)]
public struct PT_INPUT_BIR
{
Byte byForm;
PT_INPUT_BIR_UNION InputBirUnion;
}
Then you need to use GCHandle to pin the PT_BIR byte array. Let's keep to the same naming as used at that question, and assume that the PT_BIR is held in a byte[] variable named data.
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
PT_INPUT_BIR inputBir;
inputBir.byForm := ...;
inputBir.InputBirUnion.pBIR = handle.AddrOfPinnedObject();
// now call StoreFinger passing ref inputBir
}
finally
{
handle.Free();
}
When you declare StoreFinger the PT_BIR* parameter should be declared as ref PT_BIR.

ORCA Api - C# p/invoke issues

I'm trying to work with the Powerbuilder ORCA Api from C#, and I'm having some issues with marshaling. Here is the C header file for the ORCA Api, I'm trying to implement the PBORCA_SccGetConnectProperties function, which requires the pborca_scc struct.
Here are my definitions:
[DllImport(OrcaModule, CharSet = CharSet.Auto)]
internal static extern int PBORCA_SccGetConnectProperties(IntPtr ORCASession,
[MarshalAs(UnmanagedType.LPWStr)] string Workspace,
ref OrcaSccInfo SCCInfo);
public delegate int TextOutDelegate(
[MarshalAs(UnmanagedType.LPWStr)] string data,
int userData);
public delegate void BuildProjectDelegate(
OrcaBuildError BuildError,
IntPtr userData);
[StructLayout(LayoutKind.Sequential)]
public sealed class OrcaSccInfo
{
internal IntPtr Wnd = IntPtr.Zero;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
internal string ProviderName = null;
internal int Capabilities = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
internal string UserID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string Project = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string LocalProjPath = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string AuxPath = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string LogFile = null;
internal TextOutDelegate SccMsgHandler = null;
internal BuildProjectDelegate OrcaMsgHandler = null;
internal int lCommentLen = 0;
internal int lAppend = 0;
internal IntPtr CommBlk = IntPtr.Zero;
internal int DeleteTempFiles = 0;
}
When calling the function like so:
ret = Interop.PBORCA_SccGetConnectProperties(session.Handle,
#"D:\PB11-test\test.pbw",
ref scc);
I receive a FatalExecutionEngineError with a message that it could be due to marshaling errors. I've gone over this again and again and can't seem to find where I'm making a mistake with how I'm marshaling the function, the struct, or the delegates.
For the delegate definition, that second parameter should be a uint rather than an int.
public delegate int TextOutDelegate([MarshalAs(UnmanagedType.LPWStr)] string data, uint userData);
The first parameter in the second delegate could possibly be a ref or a pointer.
public delegate void BuildProjectDelegate(ref OrcaBuildError BuildError, IntPtr userData);
And in the class definition you could try [MarshalAs(UnmanagedType.FunctionPtr)] on the delegate members, and in any methods that take delegates.
Is the size of the OrcaSccInfo class coming out the same size in C# as you'd expect it to be in the C++ code? When I put it into Linqpad and get the size I get 2584 for Auto charset, 1320 with Ansi charset and 1316 when I set Pack=1 on 64-bit and 1300 on 32-bit.
Have you tried replacing the strings with StringBuilders, particularly in the Dllimport declaration itself?
And is it possible that your delegates are being disposed of before they're being used?
Passing a delegate to unmanaged code doesn't create a reference that the garbage collector can see so unless you hold on to a reference to the delegate in your own code it'll be disposed of earlier than you expect.

PInvoke Marshalling Struct and BYTE* as parameter result the Bad Pointer

I had spent 1 day to find out why this problem happen, but the result is still failed.
When I debug in the Native DLL, it show the Bad Pointer for the second parameter. Need the expert in here to advice what is missing in my step that produce this error.
Native Struct
typedef struct
{
BYTE bcdTicketMainType;
BYTE bcdTicketSubType;
BYTE bcdValidityStartDate[4]; // YYYYMMDD
BYTE bcdValidityEndDate[4]; // YYYYMMDD
BYTE bcdPhysicalExpiryDate[4]; // YYYYMMDD
BYTE bFareZone;
SHORT sDepositAmount; // NEW ARGUMENT
LONG lBalance; // NEW ARGUMENT
BYTE bcdStationIDOrigin[2];
BYTE bcdStationIDDestination[2];
BYTE bcdPaymentType;
CHAR strPaymentMediaID[20];
CHAR strAgentID[8];
BYTE bcdShiftID;
} T_TK_KTMB_CSC_SALE_INFO;
Struct in C#
public struct T_TK_KTMB_CSC_SALE_INFO
{
public byte bcdTicketMainType; // 1
public byte bcdTicketSubType; // 1
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] bcdValidityStartDate; // YYYYMMDD
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] bcdValidityEndDate; // YYYYMMDD
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] bcdPhysicalExpiryDate; // YYYYMMDD
public byte bFareZone;
public short sDepositAmount; // NEW ARGUMENT
public long lBalance; // NEW ARGUMENT
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] bcdStationIDOrigin;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] bcdStationIDDestination;
public byte bcdPaymentType;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 20)]
public char[] szPaymentMediaID;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] szAgentID;
public byte bcdShiftID;
}
Native Function
int KTMBBiz_CSCSale( T_TK_KTMB_CSC_SALE_INFO CSCSaleInfo, BYTE*
pbTranxData );
Function in C#
[DllImport("KTMBBizRule.dll")]
public static extern int KTMBBiz_CSTSale([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = >127)] byte[] pbTranxData, T_TK_KTMB_CST_SALE_INFO CSTSaleInfo);
Function called in C#
private void btnCscSale_Click(object sender, EventArgs e)
{
T_TK_KTMB_CSC_SALE_INFO cscSale = new T_TK_KTMB_CSC_SALE_INFO();
byte[] trxData = new byte[2];
BizRule.KTMBBiz_CSCSale(cscSale, trxData);
}
Error founded in Native C++
the SizeParamIndex attribute means that the n-th function parameter (zero-based, counting from the left) contains the actual size of the array.
your function has only 2 parameters, not 127.
what is more, you swapped the pbTranxData and CSTSaleInfo parameters in C++ and C#.
you can use SizeParamIndex to let the C++ function know the size of pbTranxData array:
C++
int KTMBBiz_CSCSale(T_TK_KTMB_CSC_SALE_INFO CSCSaleInfo,
BYTE* pbTranxData, INT iLength);
C#
[DllImport("KTMBBizRule.dll")]
public static extern int KTMBBiz_CSTSale(
T_TK_KTMB_CST_SALE_INFO CSTSaleInfo,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)]
byte[] pbTranxData,
int iLength);
now call it with KTMBBiz_CSTSale(cscSale, trxData, trxData.Length);
you should also add [StructLayout(LayoutKind.Sequential)] before your C# structure.
instead of public char[] szPaymentMediaID; you can say string szPaymentMediaID.
By default strings are marshalled as char*, you can change it to UnmanagedType.ByValTStr with given SizeConst.

Shared pointer polymorphic object's reference not being passed properly

I have a program whose main calls Simulation class object in the following manner.
int number_of_sims = std::stoi(num_sims)/MAX_THREADS_SIM_THREADS;
for (int inst=0; inst<Instruments.size(); inst++)
{
Simulation Simulations(Instruments[inst], Symbols[inst], number_of_sims);
SimVector.push_back(Simulations);
}
The simulation class in turn makes call to class Analysis and class Strategy and has the following skeleton.
class Simulation
{
public:
Simulation();
Simulation(Instrument& instrument, String& Symbol, int runs);
virtual ~Simulation();
boost::shared_ptr<Strategy> getStrategyName(String& StratName);
bool constructTimeSeries();
bool InitializeStrategy();
bool getMeanMTM();
bool printStrategyTrades(int run);
bool printAggregateMTM();
bool Run();
private:
String Symbol_;
double Mean_;
int runs_;
Instrument instrument_;
std::map<String, DoubleVector> AggregateMTM_;
boost::shared_ptr<Analysis> analysis_;
boost::shared_ptr<Strategy> strategy_;
};
The constructor looks something like this.
Simulation::Simulation(Instrument& instrument, String& Symbol, int runs)
: instrument_(instrument), Symbol_(Symbol), analysis_(new Analysis(instrument)), runs_(runs)
{
String filelocation = "/else/abc/xyz/klmn/file.config";
ConfigReader Config(filelocation, "=", false);
Config.parseFile();
String StrategyName = Config.getValue("strategyname");
Logger::getLogger().log(DEBUG, "The Strategy name is: " + StrategyName);
strategy_ = getStrategyName(StrategyName);
}
Now i make a polymorphic call to the XYZ strategy in the config file as below.
boost::shared_ptr<Strategy> Simulation::getStrategyName(String& StratName)
{
if (StratName.compare("XYZ") == 0)
return (boost::shared_ptr<Strategy>(new XYZ(instrument_, Symbol_)));
}
My XYZ strategy class inherits the strategy base and populates the TS_(LongStruct vector) member variable which is a protected member of class Strategy and uses it to perform certain funtions, one of which is getting the size of the vector.
The skeleton of these two classes looks something like below.
class Strategy
{
public:
Strategy(Instrument& instrument, String& Symbol);
virtual ~Strategy();
virtual bool Initialize();
virtual bool printData(std::ofstream& outputfile);
virtual double getMeanMTM();
protected:
virtual int CalculateTradeSignal(double& lower_limit, double& upper_limit, double& tau, double& meanTau, bool trade);
virtual double CalculateMTM(double& EntryPrice, double& ExitPrice);
std::map<int, String> Side_;
std::vector<String> TradeVector_;
Instrument instrument_;
LongToSymbolInfoPairVector TS_;
String Symbol_, start_, end_, tradeend_;
int numticks_, tradeticks_, tickinterval_;
double MeanMTM_;
};
XYZ:
class XYZ : public Strategy
{
public:
XYZ(Instrument& instrument, String& Symbol);
virtual ~XYZ();
bool Calculate();
bool CalculateTau();
bool Initialize();
bool updateNetPosition(int SigVal, int i, double& tau);
double getMeanMTM();
bool printData(std::ofstream& outputfile);
private:
// Initializers
bool entry_, trade_;
int netposition_;
long unsigned int tauMA_, lokBK_;
long entryT_, exitT_;
// TODO: Move the temporary variables, entryP, exitP, MTM to local variables
double entryP_, exitP_, MTM_, stoploss_, takeprofit_;
double lowtau_, hightau_;
LongVector entrytimeVector_, exittimeVector_;
IntVector posVector_;
DoubleVector entryPriceVector_, exitPriceVector_, MTMVector_, tauVector_;
};
In the CalculateTau function i try to get the size of the TS_ vector which has been initialized in the following manner.
bool XYZ::CalculateTau()
{
Logger::getLogger().log(DEBUG, "Calculating Tau .. ");
Logger::getLogger().log(DEBUG, "The size of the TS is: " + std::to_string(TS_.size()));
return true;
}
Strategy::Strategy(Instrument& instrument, String& Symbol)
: instrument_(instrument)
{
}
bool Strategy::Initialize()
{
TS_ = instrument_.GetTS();
return true;
}
Here get TS does the following:
class Instrument
{
public:
Instrument();
virtual ~Instrument();
LongToSymbolInfoPairVector GetTS() { return newTS_; }
private:
LongToSymbolInfoPairVector TS_, newTS_;
};
Now the problem is that i am getting the value of this size as 0.
Kindly assist in letting me know, where am i going wrong here.
I have been able to get around this problem by reducing the indirection from Simulation->Analysis->Instrument to Instrument->Simulation->Analysis then Analysis->Strategy