我正在实现一个自定义封送器,将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,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
函数中字符串的编码是什么?
是否有更简单的方法来验证字符串是否来自该函数?
发布于 2019-10-15 18:41:44
来自Marshal.PtrToStringAnsi函数的字符串编码是什么?
没有"ANSI“编码。无论您的系统的当前代码页是什么,它都是。它将取决于用户的区域设置。这应该与CharSet
enum相对应
Ansi:Marshal字符串作为多字节字符串:系统默认 (ANSI)代码页在Windows上,UTF-8在Unix上。
请注意Unix上的特殊处理(我猜想,Linux也是如此)。
是否有更简单的方法来验证字符串是否来自该函数?
在我看来,这似乎是一个与主要问题完全不同的问题。特别是:知道函数在从"ANSI“转换到UTF-16 (.NET使用的内部文本编码)时将使用什么编码,在我看来并没有导致一种”验证字符串是否来自该函数“的方法。一旦您有了一个C# string
对象,它已经被编码为UTF-16。它可能起源于几乎所有的编码。
从您的问题中也不清楚您所说的“工作”是什么意思,除非C#字符串来自Marshal.PtrToStringAnsi
函数。也就是说,在这种情况下,它究竟用什么方式不起作用呢?您的编组程序似乎只负责将UTF-8字节传递给或从本机代码中传递。给定一个C# string
对象,应该不会在意如何创建string
。它现在是一个字符串的UTF-16字符,可以可靠地重新编码为UTF-8.如果"ANSI“文本有问题,该问题发生在您的封送员介入之前。你的执法官不应该担心这件事。
最后:为什么不直接使用Encoding.UTF8
而不是在每个封送处理操作上实例化一个新的UTF8Encoding
对象?至少,您应该缓存对象,但是由于GetBytes()
和GetString()
对于任何UTF8Encoding
实例的工作方式都是相同的,所以实际上您应该使用.NET已经为您创建的实例,并让.NET处理缓存对象的问题。
https://stackoverflow.com/questions/58398924
复制相似问题