微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么不能在Release版本中将char *字符串从C ++返回到C#?

如何解决为什么不能在Release版本中将char *字符串从C ++返回到C#?

| 我正在尝试从C#调用以下简单的C函数
SIMPLEDLL_API const char* ReturnString()
{
    return \"Returning a static string!\";
}
使用以下P / Invoke声明(带有或不带有return属性,这没有什么区别):
[DllImport(\"SimpleDll\")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string ReturnString();
如果DLL是Debug版本,但在Release版本(AccessViolationException)中崩溃,则它可以工作。 我正在调用其他十几个简单的函数,这是唯一失败的函数(其他是:)
[DllImport(\"SimpleDll\")] public static extern int NextInt();
[DllImport(\"SimpleDll\")] public static extern void SetNextInt(int x);
[DllImport(\"SimpleDll\")] public static extern int AddInts(int a,int b);
[DllImport(\"SimpleDll\")] public static extern int AddFourInts(int a,int b,int c,int d);
[DllImport(\"SimpleDll\")] public static extern double AddDoubles(double x,double y);
[DllImport(\"SimpleDll\")] public static extern IntPtr AddDoublesIndirect(ref double x,ref double y);
[DllImport(\"SimpleDll\")] [return: MarshalAs(UnmanagedType.U1)]
public static extern char CharStringArgument([MarshalAs(UnmanagedType.LPStr)]string s);
[DllImport(\"SimpleDll\")] [return: MarshalAs(UnmanagedType.U2)]
public static extern char WCharStringArgument([MarshalAs(UnmanagedType.LPWStr)]string s);
[DllImport(\"SimpleDll\")] [return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string ReturnWString();
[DllImport(\"SimpleDll\")] [return: MarshalAs(UnmanagedType.BStr)]
public static extern string ReturnBstr();
[DllImport(\"SimpleDll\")] public static extern System.Drawing.Point MakePoint(int x,int y);
[DllImport(\"SimpleDll\")] public static extern IntPtr MakePointIndirect(int x,int y);
[DllImport(\"SimpleDll\")] public static extern int GetPointY(System.Drawing.Point p);
[DllImport(\"SimpleDll\")] public static extern int GetPointYIndirect(ref System.Drawing.Point pp);
[DllImport(\"SimpleDll\")] public static extern int SumIntegers(ref int firstElem,int size);
    

解决方法

        或者尝试使用
[DllImport(\"SimpleDll\")]
public static extern IntPtr ReturnString();
然后在您的调用代码中使用元帅课
string ret = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(PInvoke.ReturnString());
    ,        也可以使用自定义的Marshaler来做到这一点:
class ConstCharPtrMarshaler : ICustomMarshaler
{
    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        return Marshal.PtrToStringAnsi(pNativeData);
    }

    public IntPtr MarshalManagedToNative(object ManagedObj)
    {
        return IntPtr.Zero;
    }

    public void CleanUpNativeData(IntPtr pNativeData)
    {
    }

    public void CleanUpManagedData(object ManagedObj)
    {
    }

    public int GetNativeDataSize()
    {
        return IntPtr.Size;
    }

    static readonly ConstCharPtrMarshaler instance = new ConstCharPtrMarshaler();

    public static ICustomMarshaler GetInstance(string cookie)
    {
        return instance;
    }
}
并像这样使用它:
[DllImport(\"SimpleDll\")]
[return: MarshalAs(UnmanagedType.CustomMarshaler,MarshalTypeRef = typeof(ConstCharPtrMarshaler))]
public static extern string ReturnString();
    ,        发布模式下的C ++编译器会将常量放入受保护的数据页;尝试将其交给C#会引起问题。在“调试”模式下,编译器不会在数据页中优化常量,因此没有保护问题。     ,        根据我的P / Invoke经验,您通常有2个参数: 1.预先分配的缓冲区,以及2,缓冲区的长度。 返回值是返回的数据长度(不超过原始长度)。 通常,DEBUG发行版不会移动太多内存。 顺便说一句,您可以传入一个预先分配的StringBuilder,然后设置sb.Lenght = C函数的返回值,然后在字符串的末尾不会有\\ 0空值。     ,        我遇到了类似的问题,并指定了\“ CharSet \”似乎可以解决它。
[DllImport(\"SimpleDll\",CharSet = CharSet.Ansi)]
不知道为什么在调试和发行中会有所不同。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。