Reputation: 223
i have a c++ struct which has char[20] like below, and it is packed.
#pragma pack(push, temp_aion_packed, 1)
struct temp
{
char x[20];
char y[20];
};
#pragma pack(pop, temp_aion_packed)
now how can i write this struct in c# so that both are same. i have written like this in c#
[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public class temp
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string x;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string y;
}
below is the pinvoke declaration in c#
[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
public static extern int OrderRequirement(ref temp tmp);
c++ function that calls this struct as parameter
long __stdcall OrderRequirement(struct temp *tmp)
{
string p="";
string q="";
p=temp->x;
q=temp->y;
char buff[2048];
sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);
}
but when i do like this in c# it is giving me the junk data in c++, when i assign values for them in c#. Can any one please assist.
Thank you all for help on the above one, but now i got a new problem which is an extension of this, i am providing everything in detail below.
My structures in c++
#pragma pack(push, temp_aion_packed, 1)
struct temp
{
long req;
struct type m_type;
short id;
char x[20];
char y[20];
};
#pragma pack(pop, temp_aion_packed)
#pragma pack(push, type_aion_packed, 1)
struct type
{
short i;
};
#pragma pack(pop, type_aion_packed)
i have written equivalent c# structs like this
[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct temp
{
[DataMember]
public long req;
[DataMember]
[MarshalAs(UnmanagedType.Struct)]
public type m_type;
[DataMember]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string x;
[DataMember]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string y;
}
[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct type
{
[DataMember]
public short i;
}
below is my c# pinvoke
[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
public static extern int OrderRequirement(ref temp tmp);
below is my c++ method that calls struct as parameter
long __stdcall OrderRequirement(struct temp *tmp)
{
char buff[2048];
sprintf(buff,"req: %ld \n id: %d \n x: %s\n",tmp->req,tmp->id,tmp->x);
}
now the problem i am getting is as i have structure variable m_type(of struct "type") declared in struct temp, the variables declared before (long req)that are printing fine in my c++ program but the variable declared after that are not giving me any output. So i think the declaration of structures in c# is messing up and i am unable to figure it out so can any one please help.
Upvotes: 1
Views: 4658
Reputation: 612964
You declared the struct as a class in C#. That's fine, but it means that any variable of that type is already a reference. So you don't need to pass by ref
. When you pass a class by ref you end up passing a pointer to a pointer to the object. That's one level of indirection too many.
The P/invoke in the C# code should therefore be like this:
public static extern int OrderRequirement(temp tmp);
The other way to fix it is to leave the ref
in the function declaration, but to declare the temp
type as a struct
rather than a class
. That's because a struct
is a value type. A variable whose type is a struct is a value rather than a reference.
Both solutions work, it's up to you which you choose.
There is another problem in your C++ code.
sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);
You are passing p
and q
, which are of type std::string
to printf
and expecting the %s
format string to print them. That's an error. You need to call c_str()
on the strings. Like this:
sprintf(
buff,
"p: %s\n q: %s\n x: %s\n y: %s\n",
p.c_str(),q.c_str(),temp->x,temp->y
);
The problem with your update is that long is 32 bits in Windows C++ and 64 bits in C#. You need to declare it as int
in C#. And you missed the id
field altogether.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct temp
{
[DataMember]
public int req;
[DataMember]
public type m_type;
[DataMember]
public short id;
[DataMember]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string x;
[DataMember]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string y;
}
Upvotes: 1