我有一个c ++结构,它的char [20]如下所示,它是打包的。
#pragma pack(push, temp_aion_packed, 1)
struct temp
{
char x[20];
char y[20];
};
#pragma pack(pop, temp_aion_packed)
现在我如何在c#中编写这个结构,以便两者都相同。我在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;
}
下面的是c#
中的pinvoke声明[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
public static extern int OrderRequirement(ref temp tmp);
c ++函数,将此结构称为参数
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);
}
但是当我在c#中这样做的时候,它给了我c ++中的垃圾数据,当我在c#中为它们赋值时。请任何人协助。
谢谢大家对上述方面的帮助,但现在我遇到了一个新问题,这是一个新的问题,我将在下面详细介绍。
我在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)
我写过像这样的等效c#结构
[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;
}
下面是我的c#pinvoke
[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
public static extern int OrderRequirement(ref temp tmp);
下面是我的c ++方法,它将struct作为参数
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);
}
现在我遇到的问题是因为我在struct temp中声明了结构变量m_type(结构“type”),在我的c ++程序中打印的变量(long req)之前声明的变量,但是之后声明的变量没有给我任何输出。所以我认为c#中的结构声明搞砸了,我无法弄清楚,所以任何人都可以帮忙。
答案 0 :(得分:1)
您在C#中将结构声明为一个类。这很好,但这意味着该类型的任何变量都已经是一个参考。所以你不需要经过ref
。当你通过ref传递一个类时,你最终会传递一个指向该对象的指针。这是间接的一个层次太多了。
C#代码中的P / invoke应该是这样的:
public static extern int OrderRequirement(temp tmp);
另一种解决方法是将ref
保留在函数声明中,但要将temp
类型声明为struct
而不是class
。这是因为struct
是值类型。类型为结构的变量是值而不是引用。
两种解决方案都有效,取决于您的选择。
您的C ++代码中还有另一个问题。
sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);
您正在将p
和q
std::string
传递给printf
,并希望%s
格式字符串可以打印它们。那是一个错误。您需要在字符串上调用c_str()
。像这样:
sprintf(
buff,
"p: %s\n q: %s\n x: %s\n y: %s\n",
p.c_str(),q.c_str(),temp->x,temp->y
);
更新的问题是Windows C ++中的长度为32位,C#中为64位。您需要在C#中将其声明为int
。你完全错过了id
字段。
[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;
}