0

C++ DLL の C# への implementationint について問題があります。

私のヘッダーファイルコードはこれです:

typedef struct{    
 uchar  Command[4];     
 ushort Lc;    
 uchar  DataIn[512];    
 ushort Le;    
}CON_SEND;



typedef struct{    
 ushort LenOut;     
 uchar  DataOut[512];    
 uchar  outA;    
 uchar  outB;    
}CON_RESP;

SDK_C_DLL_API int   Csdk_Cmd(uchar port, CON_SEND * ConSend,CON_RESP * ConResp);
SDK_C_DLL_API int   Csdk_Open(uchar port);

そして私のC#クラス

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CON_SEND
{
    public byte[] Command;
    public System.UInt16 Lc;
    public byte[] DataIn;
    public System.UInt16 Le;
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CON_RESP
{
    public System.UInt16 LenOut;
    public byte[] DataOut;
    public byte outA;
    public byte outB;
}


[DllImport("SDK_C.dll")]
public static extern System.Int16 Csdk_Cmd(System.Byte port, ref CON_SEND ConSend, ref CON_RESP ConResp);

[DllImport("SDK_C.dll")]
public static extern System.Int16 Csdk_Open(System.Byte port);

今は Csdk_Cmd を使用しています。このコードは問題なく動作しています:

if(SDK_C.Csdk_Open(0x00)== 0)
    lblStatus.Text = "Gate 0 is busy";
else
    lblStatus.Text = "You can use Gate 0";

しかし、このコード Csdk_Cmd を使用しようとすると、「NotSupportedException」が与えられます

CON_SEND SendCon = new CON_SEND(); 
 SendCon.Command = new byte[] { 0xE0, 0xA0, 0xC4, 0x72 };
 SendCon.DataIn = new byte[]{0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xA0};
 SendCon.Lc = 0x0007;
 SendCon.Le = 0x0000;

CON_RESP RespCon = new CON_RESP();
 RespCon.DataOut = new byte[512];

SDK_C.Csdk_Cmd(0, ref SendCon, ref RespCon); // THIS LINE
4

2 に答える 2

2

構造体宣言が正しくありません。C コードにはインライン バイト配列があり、簡単に言えば、デフォルトのマーシャリングと一致しませんbyte[]。それを修正する最も簡単な方法は、を使用することMarshalAs(UnmanagedType.ByValArray)です。このような:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CON_SEND
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] Command;
    public ushort Lc;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
    public byte[] DataIn;
    public ushort Le;
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CON_RESP
{
    public ushort LenOut;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
    public byte[] DataOut;
    public byte outA;
    public byte outB;
}

関数の戻り値も正しくありません。ACintは C# にマップされintます。したがって、宣言は次のようになります。

[DllImport("SDK_C.dll")]
public static extern int Csdk_Cmd(byte port, ref CON_SEND ConSend, 
    ref CON_RESP ConResp);

[DllImport("SDK_C.dll")]
public static extern int Csdk_Open(byte port);

再確認すべきもう 1 つのことは、呼び出し規約です。上記の C# 関数は、デフォルトの を使用しますStdcall。Cコードもそうだと思いますか?戻り値と関数名の間に何も指定されていないので、関数は実際にはCdecl. その場合、次のものが必要です。

[DllImport("SDK_C.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Csdk_Cmd(byte port, ref CON_SEND ConSend, 
    ref CON_RESP ConResp);

[DllImport("SDK_C.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Csdk_Open(byte port);
于 2013-03-28T13:56:49.383 に答える
1

これは実際には推測にすぎませんが、C++ でインライン (固定) 配列を使用して構造体を宣言しているため、c# にもそのように指示する必要があります。Fixed Size Buffersでこれを行うことができます:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CON_SEND
{
   public fixed byte Command[4];
   public System.UInt16 Lc;
   public fixed byte DataIn[512];
   public System.UInt16 Le;
}

警告: このコードは unsafe でコンパイルし、unsafe ブロックに表示する必要があります。

または、構造体のマーシャリング属性をより適切に定義することを検討できます。

http://www.codeproject.com/Articles/66244/Marshaling-with-C-Chapter-2-Marshaling-Simple-Type

(@DavidHeffernanを参照、以下の回答)

于 2013-03-28T13:49:40.920 に答える