【问题标题】:How to pass an object pointer from and to a DLL?如何在 DLL 之间传递对象指针?
【发布时间】:2012-02-15 21:09:14
【问题描述】:

我是一位经验丰富的软件工程师,但对 C# 有点陌生。我有一个 DLL,它由具有 C 接口的 C++ 对象组成,如图所示。我使用这个 C 接口是因为我不确定是否有办法从我的 C# 应用程序访问 DLL 中的 C++ 入口点。

   __declspec(dllexport) void *Constructor();
   __declspec(dllexport) void Destructor(void *pObj);
   __declspec(dllexport) int Method(void *pObj, char *pSrcDst, int len);

这是上面接口的C代码。

extern "C" void *Constructor()
{
   return (void *)new Object;
}
extern "C" void Destructor(void *pObj)
{
   delete (Object *)pObj;
}
extern "C" int Method(void *pObj, char *pSrcDst, int len)
{
   if (!pObj) return 0;
   return ((Object *)pObj)->Method(pSrcDst, len);
}

到目前为止一切顺利。现在,我需要能够从 C# 应用程序访问此接口。据我所知,我已经实现了以下 C# 接口。

   unsafe public class Wrapper
   {
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         IntPtr Constructor();
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         void Destructor(IntPtr pObj);
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         int Method(IntPtr pObj, [In,Out] byte[] pSrcDst, int len);

这是使用上述接口的 C# 代码。

  private IntPtr pObject;
  public object()
  {
     pObject = Wrapper.Constructor();
  }
  ~object()
  {
     Wrapper.Destructor(pObject);
  }
  public override byte[] method()
  {
     byte[] bytes = new byte[100];
     int converted = Wrapper.Method(pObject, bytes, bytes.length);
     return bytes;
  }

代码在调用 Wrapper.Method 和 Wrapper.Destructor 时都断言。我假设我没有正确处理指向对象的指针。有什么建议吗?

【问题讨论】:

  • “代码断言”是什么意思?你收到一些错误信息吗?
  • 是的,“检测到 PInvokeStackImbalance”。
  • 请记住,大多数编译器假定 extern "C" 函数不会引发异常(尤其是在 C 代码调用它们的情况下),因此您需要确保包装 new Object() 位在异常块中以防止任何异常(特别是std::bad_alloc)转义。
  • 旁注:您不需要为每个函数重复 extern "C"。您可以将它们全部包装在 extern "C" { /*functions here*/ } 的范围内

标签: c# c++ pointers


【解决方案1】:

最可能的问题是您的代码没有使用正确的calling convention。在 C++ 中默认为__cdecl,但对于DllImport,默认为__stdcall

要解决这个问题,specify the calling convention explicitly:

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]

【讨论】:

  • 如果 OP 不知道,Visual Studio 中的默认调用约定是 compiler setting。可以改为__stdcall,以匹配默认的[DllImport()]约定。
  • @RobertKirnum,如果这个答案解决了你的问题,你应该accept it
【解决方案2】:

我的印象是,做这类事情的最佳方法是使用托管 c++/CLI 包装器。

Creating simple c++.net wrapper. Step-by-step

http://devmaster.net/forums/topic/7357-how-to-build-a-net-wrapper-for-a-c-library/

看起来很有希望。

【讨论】:

  • 如果你只需要调用几个非托管函数,PInvoke 可能更容易。但是,是的,C++/CLI 肯定是一个替代方案。
  • 没错,但那些少数非托管函数甚至存在的唯一原因是缺乏 C++/CLI 知识。如果有办法“做对”,为什么不使用它。你真的愿意使用一个名为“void * Constructor”的函数吗?
  • 只要它没有公开暴露给其余的 C# 代码,我对此没有任何问题。如果您了解 C#,那么学习使用 PInvoke 比学习使用 C++/CLI 容易得多。
猜你喜欢
  • 1970-01-01
  • 2018-09-03
  • 2011-05-11
  • 2016-11-23
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
相关资源
最近更新 更多