从 Marshal.PtrToStringAnsi 返回的字符串的编码是什么?
What is the encoding of the string returned from Marshal.PtrToStringAnsi?
我正在实施自定义封送拆收器,以发送 utf8 字符串 from/to 本机 from/to 托管。
{
[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
函数的字符串编码是什么?
是否有更简单的方法来验证字符串是否来自该函数?
what is the Encoding of the string from Marshal.PtrToStringAnsi function?
没有"ANSI"编码。它是您系统的当前代码页。这将取决于用户的区域设置。这应该对应于 CharSet
enum:
Ansi: Marshal strings as multiple-byte character strings: the system default Windows (ANSI) code page on Windows, and UTF-8 on Unix.
注意 Unix 上的特殊处理(我想,Linux)。
Is there a simpler way to verify if the string is from that function?
在我看来,这似乎是一个与主要问题完全不同的问题。特别是:在我看来,知道从 "ANSI" 转换为 UTF-16(.NET 使用的内部文本编码)时函数将使用什么编码并不会导致 "verify if the string is from that function"。一旦你有了 C# string
对象,它就已经被编码为 UTF-16。它实际上可能源自 any 编码。
从你的问题中也不清楚你所说的 "works except when the C# string is from Marshal.PtrToStringAnsi
function" 是什么意思。也就是说,精确地在那种情况下它以什么方式不起作用?您的封送拆收器似乎只负责将 UTF-8 字节传入或传出本机代码。给定一个 C# string
对象,该 string
的创建方式应该无关紧要。它现在是一串 UTF-16 字符,可以可靠地重新编码为 UTF-8。如果 "ANSI" 文本有问题,则该问题在您的封送拆收器介入之前就已发生。您的封送拆收器不必为此担心。
最后:为什么不直接使用 Encoding.UTF8
而不是在每个封送处理操作中实例化一个新的 UTF8Encoding
对象?至少,您应该缓存该对象,但是由于 GetBytes()
和 GetString()
对于 UTF8Encoding
的任何实例都一样工作,实际上您应该只使用 .NET 已有的对象为您创建,并让 .NET 处理缓存对象。
我正在实施自定义封送拆收器,以发送 utf8 字符串 from/to 本机 from/to 托管。
{
[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
函数的字符串编码是什么?
是否有更简单的方法来验证字符串是否来自该函数?
what is the Encoding of the string from Marshal.PtrToStringAnsi function?
没有"ANSI"编码。它是您系统的当前代码页。这将取决于用户的区域设置。这应该对应于 CharSet
enum:
Ansi: Marshal strings as multiple-byte character strings: the system default Windows (ANSI) code page on Windows, and UTF-8 on Unix.
注意 Unix 上的特殊处理(我想,Linux)。
Is there a simpler way to verify if the string is from that function?
在我看来,这似乎是一个与主要问题完全不同的问题。特别是:在我看来,知道从 "ANSI" 转换为 UTF-16(.NET 使用的内部文本编码)时函数将使用什么编码并不会导致 "verify if the string is from that function"。一旦你有了 C# string
对象,它就已经被编码为 UTF-16。它实际上可能源自 any 编码。
从你的问题中也不清楚你所说的 "works except when the C# string is from Marshal.PtrToStringAnsi
function" 是什么意思。也就是说,精确地在那种情况下它以什么方式不起作用?您的封送拆收器似乎只负责将 UTF-8 字节传入或传出本机代码。给定一个 C# string
对象,该 string
的创建方式应该无关紧要。它现在是一串 UTF-16 字符,可以可靠地重新编码为 UTF-8。如果 "ANSI" 文本有问题,则该问题在您的封送拆收器介入之前就已发生。您的封送拆收器不必为此担心。
最后:为什么不直接使用 Encoding.UTF8
而不是在每个封送处理操作中实例化一个新的 UTF8Encoding
对象?至少,您应该缓存该对象,但是由于 GetBytes()
和 GetString()
对于 UTF8Encoding
的任何实例都一样工作,实际上您应该只使用 .NET 已有的对象为您创建,并让 .NET 处理缓存对象。