最近在将CTP的调用从 .net 转到.net core,在windows下能正常运行后,在linux下则无法运行,会直接中断后退出。经过多方测试,最后,发现是在登录完成后,返回的登录信息时,导致的。
数据返回的结构为
[StructLayout(LayoutKind.Sequential)]
public struct struct_error_ret
{
public int ErrorId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
public string ErrorMsg;
}
从c++回调c#后,输出ErrorMsg得到的是一个乱码返回。
在退出托管的回调代码后,会诱发异常,你没看错,不是在转换时触发异常,而是回调完成后,应该是在释放托管资源时触发,很蛋疼的情况:《
通过两天的bing.com搜索,最后得到的结论是
- 系统默认的字符串转换,在windows下,会按照系统的编码进行转换(这就是windows下没错误的情况)
- 在macos和linux下,默认,也只能按照utf8的格式对字符串进行转换。而且,还不支持手动修改,因为硬编码了。看这篇就够了
- 上文提到的 UnmanagedType.CustomMarshaler 和 ICustomMarshaler 接口的自定义序列化,只支持函数参数传递时的处理,不支持结构体里成员变量的自定义转化。
- 最后只能暴力的将结构体,从字符串转为byte[]
- 目前已经是9102年了,距离.net core 3.0发布还有1个月,已经下过最新的corclr代码看,这部分的代码估计会留到.net core 4.0 吧。
/// <summary>
/// 响应信息
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct CThostFtdcRspInfoField
{
/// <summary>
/// 错误代码
/// </summary>
public int ErrorID;
/// <summary>
/// 错误信息
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 81)]
public byte[] ErrorMsg;
public unsafe string GetErrorMsg()
{
return ErrorMsg.GetGB2312String();
}
}
public static class AssemblyExtend
{
public static unsafe string GetGB2312String(this byte[] array)
{
int len = 0;
for (var i = 0; i < array.Length; i++)
{
if (array[i] == 0)
{
len = i;
break;
}
}
fixed (byte* p = array)
{
var s = encoding.GetString(p, len);
return s;
}
}
static Encoding encoding = CodePagesEncodingProvider.Instance.GetEncoding("GB2312");
}