在.net外部组件中使用c++本地dll抛出异常

本文关键字:c++ 本地 dll 抛出异常 net 外部 组件 | 更新日期: 2023-09-27 18:12:27

我试图在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吗?

在.net外部组件中使用c++本地dll抛出异常

试试http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx上的技巧-这已经节省了好几次了:-)

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

我可以猜测问题是,你正在返回一个Ansi字符串,而不是预期的unicode字符串。这会导致默认的pinvoke封送处理程序读取太多内存。

试试这个:[DllImport(@"MyDLL.dll", CharSet = CharSet. auto)][return: MarshalAs(UnmanagedType.LPStr)]public static extern string MyFunction([MarshalAs(UnmanagedType.LPStr)] string input);

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

CharSet = CharSet. auto ??使用的字符集。Ansi

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

你必须改变你的c++函数,你的c++函数必须写入目标缓冲区,这个缓冲区必须被分配,所以它至少包含你需要的字符数加1(对于null终止字符)。

[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。