使用引用类型作为参数从c#调用c ++函数

时间:2013-11-07 14:35:15

标签: c# c++ interop pinvoke

 int Set(CANMsg &CANObj)

我必须从c#调用上面的方法。直到现在我已经定义了一个包装器:

 extern "C" __declspec(dllexport) int SetWrapper(CANMsg CANObj);

CANMsg CANObj ---这个参数是ok还是应该使用CANMsg * CANObj?

在这里我实现了包装器:

 extern "C" __declspec(dllexport) int SetWrapper(CANMsg CANObj)
 { 
      return Set(CANObj);
 }

我正在创建这个包装器,因为这是函数的重载版本,我不得不以某种方式发挥作用。

这是CANMsg类:

 class CANMsg
 {
 public:
 CANMsg();
 ~CANMsg();

 void AddRef() const;
 void Release() const;
 unsigned int MsgId;
 unsigned int DLC;
 unsigned int Handle;
 unsigned int Interval;
 unsigned int TimeStamp;
 unsigned char Data0;
 unsigned char Data1;
 unsigned char Data2;
 unsigned char Data3;
 unsigned char Data4;
 unsigned char Data5;
 unsigned char Data6;
 unsigned char Data7;

  protected:

mutable int refCount;  

};

现在,在C#中我有以下内容:

      [StructLayout(LayoutKind.Sequential)]
      public class CANmsg
   {
      public  int MsgId;
      public int DLC;
      public int Handle;
      public int Interval;
      public int TimeStamp;
      public char Data0;
      public char Data1;
      public char Data2;
      public char Data3;
      public char Data4;
      public char Data5;
      public char Data6;
      public char Data7;
   }

,导入是这样的:

     [DllImport("engine.dll", CallingConvention = CallingConvention.Cdecl)]
  [return: MarshalAs(UnmanagedType.I4)]
  public static extern int SetWrapper(IntPtr canMSGObject);

我对CANMsg对象有点困惑,我是否认为它是正确的IntPtr,是元帅,还是类型?如果我喜欢它,使用IntPtr,我应该在那里执行什么样的实例化?如果我发送一个CANMsg对象,我会收到有关一些无效参数的错误。

如果您需要更多详细信息,请与我们联系。

2 个答案:

答案 0 :(得分:1)

您无法像这样将C#对象传递给本机C ++。 Marshal.StructureToPtr是您所需要的,详细信息和示例是here

答案 1 :(得分:1)

当我看到你的C ++类定义时,我会问自己"在构造函数和析构函数中会发生什么?"和" AddRef()Release()做了什么?"这些都是重要的问题,因为您不能简单地将数据从C#对象投影到IntPtr上,并希望获得最佳效果。相反,你应该考虑制作一个帮助你的助手dll。你可能需要这样的方法:

public ref class MyLibraryHelper {

public:
    IntPtr MakeCANMsg() { return gcnew IntPtr(new CANMsg()); }
    void DestroyCANMsg(IntPtr msgPtr) {
       CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
       if (msg) delete msg;
    }
    void ProjectTo(CSharpCANMsg ^csh, IntPtr msgPtr)
    {
       CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
       if (!msg) return;
       msg->MsgId = csh->get_MsgId();
       // etc
    }
    void ProjectFrom(IntPtr msgPtr, CSharpCANMsg ^csh)
    {
       CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
       if (!msg) return;
       csh->set_MsgId(msg->MsgId);
       // etc
    }
}

我的C ++ / CLI生锈了,所以期待一些问题。如果这看起来像是手工编组,那么,这是因为鉴于你已经暴露过的课程,你似乎需要它。

老实说,你可能不想要这个。实际上,您需要一个C ++ / CLI类来构造一个CANMsg并将其保存为私有成员,然后将.NET属性映射到较低级别的对象上。这种类必须是一次性的,!ClassName()析构函数将负责删除底层对象。