从非托管的C++ DLL返回字符串到C#

4
我正在尝试从C#调用未托管的C++代码,但是收到有关返回值的异常。
异常信息如下:
System.Runtime.InteropServices.MarshalDirectiveException:“无法编组'返回值': 无效的托管/未托管类型组合(数组只能作为LPArray、ByValArray或SafeArray进行编组)。”
我有一个类似的函数,它没有返回值(void),可以正常工作而没有任何问题。
我将c++项目的平台(编译器)设置为v100 (Visual Studio 2010),并在c#项目中使用.net 4.5。
c++项目创建了一个lib+dll文件,我将它们都放在可执行文件夹中。
当我尝试将返回值替换为“String”时,在c#代码中,异常变成了:
System.AccessViolationException:“企图读取或写入受保护的内存。这通常表明其他内存已损坏。”
当我删除返回值函数属性([return: MarshalAs(UnmanagedType.BStr)])时,我会收到以下异常:
System.Runtime.InteropServices.MarshalDirectiveException:“无法编组'返回值': 无效的托管/未托管类型组合。”
当我同时删除返回值函数属性并将返回类型转换为字符串时,应用程序会自动关闭而不捕获任何异常。
以下是C++代码:
extern "C"
{
    ExternalDll_API char* FuncA(char* projectId);
}

ExternalDll_API char* FuncA(char* projectId)
{
    return "abc";
}

C# 代码

[DllImport("ExternalDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern char[] FuncA(string projectId);

var key = FuncA(projectId.ToString());

https://dev59.com/GGgv5IYBdhLWcg3wKtvj - Artemy Vysotsky
这不是完全重复的,建议的答案基于以下两点:1-知道返回字符串的大小,2-传递一个StringBuilder并从C++代码中填充它,而不是直接返回char指针。 - Gusman
1个回答

10

要从C++ dll中接收以null结尾的字符串,你可以这样做:

1-将返回类型更改为IntPtr

[DllImport("ExternalDll.dll")]
public static extern IntPtr FuncA(string projectId);

2-使用Marshal从指针中检索字符串:

var result = FuncA(someString);
var strResult = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(result);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接