C# 字符串编组的问题

C# 字符串编组的问题,c#,.net-core,pinvoke,C#,.net Core,Pinvoke,我正在编写一些代码,调用本机库进行一些计算。从下面的代码片段可以看出,我正在调用一个返回std::string的方法。我的目的是将该结果转换为char*,并将其封送回我的托管C#应用程序。这里的问题是,有时执行结果将包含UTF-8字符 代码: extern“C”\uuuuu declspec(dllexport)int\uuuu stdcall执行\u负载(示例::本机代码*实例、字符*负载、字符**结果){ std::string execution\u result=instance->ex

我正在编写一些代码,调用本机库进行一些计算。从下面的代码片段可以看出,我正在调用一个返回
std::string
的方法。我的目的是将该结果转换为
char*
,并将其封送回我的托管C#应用程序。这里的问题是,有时执行结果将包含UTF-8字符

代码:

extern“C”\uuuuu declspec(dllexport)int\uuuu stdcall执行\u负载(示例::本机代码*实例、字符*负载、字符**结果){
std::string execution\u result=instance->execute(有效负载);
char*result\u数组=新字符[execution\u result.size()+1];
strcpy(result_数组,execution_result.c_str());
*结果=结果_数组;
返回执行结果.length();
}
下面是C#的一个片段,可以产生预期的结果

代码:

private HandleRef NativeInstance;
公共包装器()
{
NativeInstance=newHandleref(这是NativeCode.CreateNew());
}
公共字符串执行代码(字符串有效负载)
{
IntPtr resultPointer=Marshal.AllocHGlobal(sizeof(int));
var resultLength=NativeCode.Execute(NativeInstance、payload、ref resultPointer);
var resultBytes=新字节[resultLength-1];
Marshal.Copy(resultPointer,resultBytes,0,resultLength-1);
var resultString=Encoding.UTF8.GetString(resultBytes);
FreeHGlobal元帅(结果点);
返回结果字符串;
}
预期结果:

123,45 €
123,45 €
实际结果:

123,45 €
㈱ⰳ㔴ꃂ苢¬缀\0ᴹ襴翻\0
下面是一些代码的示例,我试图“简单地”封送字符串结果。但它并没有真正起作用

代码:

private HandleRef NativeInstance;
公共包装器()
{
NativeInstance=newHandleref(这是NativeCode.CreateNew());
}
公共字符串执行代码(字符串有效负载)
{
IntPtr resultPointer=Marshal.AllocHGlobal(sizeof(int));
var resultLength=NativeCode.Execute(NativeInstance、payload、ref resultPointer);
var resultString=Marshal.PtrToStringUni(resultPointer,resultLength);
FreeHGlobal元帅(结果点);
返回结果字符串;
}
预期结果:

123,45 €
123,45 €
实际结果:

123,45 €
㈱ⰳ㔴ꃂ苢¬缀\0ᴹ襴翻\0
我有两个问题

  • 为什么第二个片段不起作用

  • 不管第二个代码段为什么不起作用,我还能做得更好吗


  • 谢谢

    marshall.AllocHGlobal(sizeof(int))
    看起来可疑。它似乎正在接收指针(
    *result=result\u array;
    ),但您只分配了4个字节。在64位体系结构上,缓冲区会溢出。也许您想分配
    IntPtr.Size
    ?两者都分配了4个字节,所以第一个实现可能掩盖了这个问题。。。
    new char[execution\u result.size()+1]
    的结果永远不会被释放。我们没有完整的代码,如何定义C也非常重要。如果你能调整你的C++侧,你可以像一些Windows API一样对它进行建模,例如:GETWINDOWTING:那么正确的互操作就是这样:如果我错了,请纠正我,但是考虑到你已经做了C++助手函数,为什么不做一个C++/CLI包装器,然后简单地将CLR类型返回到.NET代码。这是一种更简单的方法,
    消除了任何封送的需要
    如果第一个版本有效,请坚持使用,但也要导出一个函数,
    删除
    正在分配的数组,并在
    封送之前调用它
    处理内存泄漏。
    Marshal.AllocHGlobal(sizeof(int))
    看起来可疑。它似乎正在接收指针(
    *result=result\u array;
    ),但您只分配了4个字节。在64位体系结构上,缓冲区会溢出。也许您想分配
    IntPtr.Size
    ?两者都分配了4个字节,所以第一个实现可能掩盖了这个问题。。。
    new char[execution\u result.size()+1]
    的结果永远不会被释放。我们没有完整的代码,如何定义C也非常重要。如果你能调整你的C++侧,你可以像一些Windows API一样对它进行建模,例如:GETWINDOWTING:那么正确的互操作就是这样:如果我错了,请纠正我,但是考虑到你已经做了C++助手函数,为什么不做一个C++/CLI包装器,然后简单地将CLR类型返回到.NET代码。这是一种更简单的方法,
    消除了任何封送的需要
    如果第一个版本有效,请坚持使用,但也要导出一个函数,
    删除
    正在分配的数组,并在
    封送之前调用它
    来处理内存泄漏。