0

我有一个关于将 C++ DLL 实现为 C# 的问题

我的头文件代码是这样的:

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

要仔细检查的另一件事是调用约定。上面的 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 回答