krishna555
krishna555

Reputation: 223

char[] array equivalent in c#

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

Answers (1)

David Heffernan
David Heffernan

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

Related Questions