【问题标题】:Using C++ native dll in .Net External component has thrown an exception在 .Net 外部组件中使用 C++ 本机 dll 引发异常
【发布时间】:2011-10-25 16:46:36
【问题描述】:

我正在尝试在 C# 中使用本机 C++ dll,并且收到“外部组件已引发异常”,错误代码为 -2147467259。

C#:

[DllImport(@"MyDLL.dll", CharSet = CharSet.Auto)]
public static extern string MyFunction([MarshalAs(UnmanagedType.LPStr)] StringBuilder input);

C++:

__declspec(dllexport) char * __stdcall MyFunction(const char* inputPtr);

该函数在 C++ 中运行良好。如何追踪此错误? 我尝试使用字符串和字符串生成器作为参数。

更新

我发现这篇文章http://tom-shelton.net/index.php/2008/12/11/creating-a-managed-wrapper-for-a-lib-file/

它详细介绍了一种使用托管 C++ 在 C++ 中包装非托管静态库的方法,然后可以在托管语言中使用该库。这是解决这个问题的好方法吗? lib可以是非托管dll吗?

【问题讨论】:

    标签: c# c++ dllimport


    【解决方案1】:

    尝试http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx 的技术 - 这已经多次节省时间:-)

    【讨论】:

    • 然后点击链接...它显示了处理此问题的不同方法
    • 我在您更改答案之前发表了评论。
    • 其实我昨天也看到了这篇文章。一旦我通读它并尝试这种技术,我会回帖。
    【解决方案2】:

    如果参数是 in-only(而不是 out),则不需要 stringbuilder。如果它是一个 out 参数(或 ref),您应该使用 stringbuilder 并使用 stringbuilder 构造函数预分配缓冲区。

    我猜问题是您返回的是 Ansi 字符串,而不是预期的 unicode 字符串。这会导致默认的 pinvoke marshaler 读取过多的内存。

    试试这个: [DllImport(@"MyDLL.dll", CharSet = CharSet.Auto)] [返回:MarshalAs(UnmanagedType.LPStr)] 公共静态外部字符串 MyFunction([MarshalAs(UnmanagedType.LPStr)] 字符串输入);

    无论如何,在绝大多数情况下,编写 Ansi C++ 代码没有任何意义。我建议将 C++ 代码仅转换为 unicode(不是 tchar,而是 wchar_t)。

    【讨论】:

      【解决方案3】:

      CharSet = CharSet.Auto??使用 CharSet.Ansi

      不能使用 char 数组作为返回值,用 c++ 分配的内存块不能被 C# 使用!在您的情况下,您可能需要将其复制到 C# 托管内存中。 使用 StringBuilder 或 MarshalAs 属性,它将为您将缓冲区复制到 C# 托管内存中。

      您必须更改您的 C++ 函数,您的 C++ 函数必须写入必须分配的目标缓冲区,以便它至少包含您需要的字符数加一(对于空终止字符)。

      [DllImport(@"MyDLL.dll", CharSet = CharSet.Ansi)]
      private static extern void MyFunction([MarshalAs(UnmanagedType.LPStr)] string input, StringBuilder result);
      
      public static string MyFunctionPublic(string input)
      {
          StringBuilder sb = new StringBuilder(input.Length + 1);
          MyFunction(input, sb);
          return sb.ToString();
      }
      

      我希望你的 C 函数能做这样的事情:

      void __stdcall MyFunction(const char* input, char* result)
      {
          strcpy(result, input); // this is a dummy stupid code to show how it works.
      }
      

      您可能需要一个函数,让您了解在 C# 中必须分配多少字节。这个函数可以是这样的:

      int __stdcall ComputeMyFunctionBytes(const char* input)
      {
          return strlen(input); // this is a dummy stupid code to show how it works.
      }
      

      永远不要将一块分配的内存返回给 C#,它不能做任何事情,也不能解除分配,也不能读取和写入,除非你使用不安全的代码,但这不是你想要做的。

      这里好像有一篇好文章:http://www.devx.com/dotnet/Article/6990/1954

      还要注意 C# 使用 unicode,每个字符 16 位,所以它会从 ansi 转换为 unicode。

      【讨论】:

      • 我的 C++ 函数不应该返回一个字符指针吗?我将如何为此目的使用 StringBuilder?
      • 我认为你的 strcpy 应该是 strcpy(result, input)。
      • 我用一个非常简单的函数(如上面的 strcpy)让它工作,但我不能让它和我的 c++ 函数一起工作。
      • 也许你必须发布你的函数,我们不知道它是做什么的。
      • 我应该修改一下,这个简单的例子只有在它不属于我的 dll 中的类时才有效。当我从课堂上调用时,我得到一个堆栈不平衡错误。
      猜你喜欢
      • 2013-04-19
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2015-12-05
      • 2021-03-28
      • 2011-05-26
      • 2010-09-21
      • 2015-06-14
      相关资源
      最近更新 更多