Why can't I return a char* string from C++ to C# in a Release build?

后端 未结 5 889
梦如初夏
梦如初夏 2021-01-31 10:07

I\'m attempting to call the following trivial C function from C#:

SIMPLEDLL_API const char* ReturnString()
{
    return \"Returning a static string!\";
}
         


        
相关标签:
5条回答
  • 2021-01-31 10:50

    Or maybe try to use

    [DllImport("SimpleDll")]
    public static extern IntPtr ReturnString();
    

    and in your calling code, use the Marshal Class

    string ret = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(PInvoke.ReturnString());
    
    0 讨论(0)
  • 2021-01-31 10:51

    The C++ compiler in Release mode is putting the constant into the data page, which is protected; attempting to hand this off to C# is causing problems. In Debug mode, the compiler isn't optimizing the constant into the data page, and so there's no protection problem.

    0 讨论(0)
  • 2021-01-31 10:53

    It's also possible to do that with a custom 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;
        }
    }
    

    And use it like this:

    [DllImport("SimpleDll")]
    [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ConstCharPtrMarshaler))]
    public static extern string ReturnString();
    
    0 讨论(0)
  • 2021-01-31 10:57

    In my P/Invoke experience, you usually have 2 parameters: 1. a pre-allocated buffer in, and 2, the length of the buffer. The Return value is the length of data returned (not to exceed the original length).

    Usually the DEBUG releases won't move memory around as much.

    BTW, You can pass in a pre-allocated StringBuilder, then set sb.Lenght = the return value of the C function, then you won't have a bunch of \0 nulls at the end of your string.

    0 讨论(0)
  • 2021-01-31 11:04

    I ran into a similar problem and specifying the "CharSet" seemed to fix it.

    [DllImport("SimpleDll", CharSet = CharSet.Ansi)]
    

    Not sure why this would be different in debug and release.

    0 讨论(0)
提交回复
热议问题