问题描述
我正在尝试将libpng-dev
的内容直接复制到非托管内存中。
Microsoft建议使用securestring
,Marshal.securestringToBstr()
,Marshal.securestringToGlobalAllocAnsi()
和相应的COM使用方法。
我有一个Marshal.securestringToGlobalAllocUnicode()
,其字符为“ 127”和“ 128”。因为ANSI使用8位编码,所以我希望将以下转换成非托管字符串是可行的:
securestring
但是'128'结果为'63'。
我可以使用 var securestring = new securestring();
securestring.AppendChar((char)127);
securestring.AppendChar((char)128);
IntPtr unmanagedString = Marshal.securestringToGlobalAllocAnsi(securestring);
var b1 = Marshal.ReadByte(unmanagedString,0); // 127
var b2 = Marshal.ReadByte(unmanagedString,1); // 63
或securestringToBstr()
并忽略其他所有字节。这会起作用。但是我想理解为什么ANSI方法返回的是“ 63”而不是“ 128”。
我在.Net Framework 4.8中使用C#。
解决方法
字符串是char
的序列,而不是字节。 (char)128
代表Unicode codepoint U+0080,它在计算机的ANSI代码页的任何代码页中都没有表示,因此您会得到一个问号(ANSI 63)。
这与SecureString
无关。通过Encoding.GetBytes
/ Encoding.GetString
您将获得相同的结果。
在继续操作之前,请确保您已访问this。
如果您确定安全字符串仅包含256以下的代码点,并且希望在ANSI中对这些代码点进行往返表示,则可以安排using codepage 28591:
public static byte[] SecureStringToRoundtripAnsiByteArray(SecureString secureString)
{
var buffer_ptr = Marshal.SecureStringToCoTaskMemUnicode(secureString);
try
{
byte[] buffer = new byte[secureString.Length * sizeof(char)];
Marshal.Copy(buffer_ptr,buffer,buffer.Length);
try
{
return System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.GetEncoding(28591),buffer);
}
finally
{
Array.Clear(buffer,buffer.Length);
}
}
finally
{
Marshal.ZeroFreeCoTaskMemUnicode(buffer_ptr);
}
}
using (var secureString = new SecureString())
{
for (int i = 0; i < 256; i++)
secureString.AppendChar((char)i);
secureString.MakeReadOnly();
byte[] b = SecureStringToRoundtripAnsiByteArray(secureString);
for (int i = 0; i < 256; i++)
Console.WriteLine(b[i]);
}