从Marshal.PtrToStringAnsi返回的字符串的编码是什么?

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

我正在实现自定义的Marshaler,以便将utf8字符串从本机发送到本机,或从本机发送到本机。

{
    [ComVisible(true)]
    public class UTF8StringMarshaler : ICustomMarshaler
    {
        private static ICustomMarshaler marshalerInstance = new UTF8StringMarshaler();

        public static ICustomMarshaler GetInstance(string optionalCookie)
        {
            return marshalerInstance;
        }
        public void CleanUpManagedData(object ManagedObj)
        {
            //Managed Data will be deleted by the garbage collector
        }

        public void CleanUpNativeData(IntPtr pNativeData)
        {
            Marshal.FreeCoTaskMem(pNativeData);
        }

        public int GetNativeDataSize()
        {
            //Not used in our case
            return -1;
        }

        public IntPtr MarshalManagedToNative(object ManagedObj)
        {
            if (ManagedObj == null || ManagedObj as string == null)
                return IntPtr.Zero;

            if (!(ManagedObj is string))
                throw new MarshalDirectiveException("UTF8StringMarshaler can only be used on String.");

            UTF8Encoding utf8Encoder = new UTF8Encoding();
            string utf8string = ManagedObj as string;
            byte[] stringBuffer = utf8Encoder.GetBytes(utf8string);
            IntPtr buffer = Marshal.AllocCoTaskMem(stringBuffer.Length + 1);
            Marshal.Copy(stringBuffer, 0, buffer, stringBuffer.Length);
            Marshal.WriteByte(buffer + stringBuffer.Length, 0);
            return buffer;
        }

        public unsafe object MarshalNativeToManaged(IntPtr pNativeData)
        {
            if (pNativeData == IntPtr.Zero)
                return null;
            string temp = null;
            UTF8Encoding utf8Encoder = new UTF8Encoding(true, true);
            byte* buffer = (byte*)pNativeData;
            while (*buffer != 0)
            {
                buffer++;
            }
            int length = (int)(buffer - (byte*)pNativeData);

            byte[] stringbuffer = new byte[length];

            Marshal.Copy(pNativeData, stringbuffer, 0, length);
            try
            {
                temp = utf8Encoder.GetString(stringbuffer);
            }
            catch (EncoderFallbackException e)
            {
                Console.WriteLine("Encoding Exception type {0}, Error {1}", e.GetType().Name, e.Message);
            }
            return temp;
        }
    }

此实现有效,除非C#字符串来自Marshal.PtrToStringAnsi函数。

因此,在MarshalNativeToManaged函数中,我需要验证字符串是否是从Marshal.PtrToStringAnsi开始的正确编码

从Microsoft Doc,Marshal.PtrToStringAnsi将每个ANSI字符扩展为Unicode:

Copies all characters up to the first null character from an unmanaged ANSI string to a managed String, and widens each ANSI character to Unicode.

所以问题是,Marshal.PtrToStringAnsi函数中的字符串的编码是什么?

是否有更简单的方法来验证字符串是否来自该函数?

c# encoding marshalling
1个回答
1
投票

Marshal.PtrToStringAnsi函数的字符串的编码是什么?

没有一种“ ANSI”编码。无论系统当前的代码页是什么。这将取决于用户的区域设置。这应该对应于CharSet enum

Ansi:将字符串编组为多字节字符串:Windows上的系统默认Windows(ANSI)代码页,Unix上的UTF-8。

但是请注意,在Unix(以及我认为是Linux)上的特殊处理。

是否有更简单的方法来验证字符串是否来自该函数?

在我看来,这和似乎是主要问题是一个完全不同的问题。特别是:在我看来,了解从“ ANSI”转换为UTF-16(.NET使用的内部文本编码)时函数将使用哪种编码似乎并不导致一种“验证字符串是否为通过该功能”。一旦有了C#CharSet对象,它就已经被编码为UTF-16。它实际上可能源自any编码。

从您的问题中也不清楚“的含义,除了C#字符串来自string函数时,”是有效的“。也就是说,在这种情况下precisely不能以什么方式工作?您的封送处理程序似乎只负责向本地代码传递UTF-8字节或从本地代码传递UTF-8字节。给定一个C#Marshal.PtrToStringAnsi对象,该string的创建方式无关紧要。现在它是一串UTF-16字符,可以可靠地将其重新编码为UTF-8。如果“ ANSI”文本存在问题,则在您的封送处理程序介入之前就发生了该问题。您的封送整理者不必为此担心。

最后:为什么不只使用string而不是在每个封送处理操作上实例化一个新的Encoding.UTF8对象?至少,您应该缓存该对象,但是由于UTF8EncodingGetBytes()对于GetString()的任何实例都可以工作,因此实际上,您只应使用.NET已经为您创建的对象,并让.NET处理对象的缓存。

© www.soinside.com 2019 - 2024. All rights reserved.