使用 C# 互操作性将 char* 编组为字符串的正确方法。收到“堆已损坏”异常

问题描述 投票:0回答:1

没有太多 C++ 经验。尝试使用

char*
将 C 中的
string
编组到 C# 中的
[MarshalAs(UnmanagedType.LPStr)]
,但我得到了
"a heap has been corrupted" exception
。但它确实可以反向工作(C# 中的
string
到 C 中的
char*
)。我在这里做错了什么?

更多详情: 在 C 端,这是结构:

struct STRUCTV
{
    char* _pretext;
    char* _result;
};

这是 C 函数签名:

void add_all_numbers(STRUCTV *structV);

这是C#方面

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCTV
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string _pretext; 
    [MarshalAs(UnmanagedType.LPStr)]
    public string _result;  //<----THIS ISNT WORKING

}

internal partial class NativeMethods
{
    [DllImport(
    "Library.dll",
    EntryPoint = "function1",
    CallingConvention = CallingConvention.Cdecl,
    CharSet = CharSet.Ansi)]
    public static extern void function1(ref STRUCTV structV);
}

这就是我的使用方式:

STRUCTV myStruct = new STRUCTV();
myStruct._pretext = "Pretext";
myStruct._result = null;
NativeMethods.function1(ref myStruct); //<---- ntdll.dll : A heap has been corrupted"
Console.WriteLine(myStruct._result);

如果这很重要,这就是 C 代码内部发生的情况(如果这很重要):

string resultstring = GetResult();
char* result = new char[resultstring.length() + 1];
strcpy_s(result, resultstring.length() + 1, resultstring.c_str());
structV->_result = result;

一些附加信息。如果我不将 char* 编组为 _result 中的字符串,它就会起作用,并且我想了解原因。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCTV
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string _pretext; 
    public IntPtr _result;
}

STRUCTV myStruct = new STRUCTV();
myStruct._pretext = "Pretext";
myStruct._result = IntPtr.Zero;
NativeMethods.function1(ref myStruct);
string resultString = Marshal.PtrToStringAnsi(myStruct._result);
Console.WriteLine(resultString);    
c# c++ interop marshalling wrapper
1个回答
0
投票

C# 代码假设它负责将字符串数据传递给 C++ 代码。但是,C++ 代码实际上是分配字符串数据并将其返回给 C# 代码。因此,您无法按照您尝试的方式用

LPStr
对其进行编组,因为它是输出数据而不是输入数据。

使用

IntPtr
是此处的正确操作。您可以使用
Marshal.PtrToStringAnsi()
IntPtr
转换为 C#
string

但是,还要注意,C++ 代码正在对字符串数据进行

new[]
操作,而 C# 无法释放该内存。因此,您必须从 C++ 导出另一个函数,C# 代码可以调用该函数将
IntPtr
传回 C++,以便它可以正确地
delete[]
内存。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.