1

以下のようなchar[20]を持つc++構造体があり、パックされています。

#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#ピンボークです

[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
    public static extern int OrderRequirement(ref temp tmp);

以下は、パラメーターとしてstructを呼び出す私のc++メソッドです。

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);
}

今私が得ている問題は、構造体変数m_type(struct "type"の)がstruct tempで宣言されているため、c ++プログラムで正常に出力される前に宣言された変数(long req)ですが、その後に宣言された変数は私にどんな出力でも。ですから、c#での構造体の宣言がめちゃくちゃになっていて、それを理解できないので、誰か助けてください。

4

1 に答える 1

1

構造体をC#のクラスとして宣言しました。それは問題ありませんが、そのタイプの変数はすでに参照になっていることを意味します。したがって、通過する必要はありませんref。refでクラスを渡すと、オブジェクトへのポインタへのポインタを渡すことになります。これは、間接参照の1つのレベルが多すぎます。

したがって、C#コードのP/invokeは次のようになります。

public static extern int OrderRequirement(temp tmp);

refこれを修正するもう1つの方法は、関数宣言にを残すことですが、temp型をではstructなくとして宣言しclassます。これstructは、aが値型であるためです。タイプが構造体である変数は、参照ではなく値です。

どちらのソリューションも機能します。どちらを選択するかはあなた次第です。


C++コードに別の問題があります。

sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);

とを渡してpおり、これらはtoq型であり、フォーマット文字列がそれらを出力することを期待しています。それはエラーです。文字列を呼び出す必要があります。このような:std::stringprintf%sc_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
);

アップデートの問題は、longがWindows C ++では32ビット、C#では64ビットであるということです。intC#のように宣言する必要があります。そして、あなたは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;
}
于 2012-05-24T16:11:39.963 に答える