Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2349812
  • 博文数量: 527
  • 博客积分: 10343
  • 博客等级: 上将
  • 技术积分: 5565
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-26 23:05
文章分类

全部博文(527)

文章存档

2014年(4)

2012年(13)

2011年(19)

2010年(91)

2009年(136)

2008年(142)

2007年(80)

2006年(29)

2005年(13)

我的朋友

分类: WINDOWS

2008-02-28 09:15:47

UnmanagedType是MarshalAsAttribute的构造函数参数, 或者是其 ArraySubType 这个Property的取值, 典型使用如下:


public struct TestBool
{
  [MarshalAs(UnmanagedType.I1)]
    public bool bool_var;
  [MarshalAs(UnmanagedType.I1)]
    public bool bool_var2;
  [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.I1, SizeConst = 4)]
    public bool[] bool_arr;
};


问题在于: 同一个结构中同时包括bool变量和bool[]成员时, 真实的Marshal行为与指定的并不相符, 而且编译期不会报任何错误, 你只有在运行时发生错误时跟踪出结论.  此文中所有bug表现在.NET 1.1与2.0中都一样, 看来.NET 2.0对此没有做改进.

具体来说: 指定bool[]数组的ArraySubType=UnmanagedType.I1, 顾名思义, Marshal时应该每个数组元素占用一个字节, 正好对应C++中的小写bool变量占用的存储空间, 实际情况是: 不管你指定I1, I2, I4, Bool这些合法取值中的任何一个, Marshal的真正行为都是把每个元素作占用4字节对待.  而普通的bool变量, 则可以根据指定的I1, I2 Marshal成指定的存储空间大小.

结尾处的测试程序用到了 CodeDom, 在程序运行时动态构造出上述结构. 其中
UnmanagedType的取值根据命令行参数而定, 第一个参数指定bool[]的ArraySubType, 第二个参数指定普通bool变量的UnmanagedType.

对于bool合法的取值有I1, I2, I4, Bool. 那么可能的参数组合有16种, 通过bash的命令行扩展机制可以巧妙地得到:
echo {{I1,I2,I4,Bool}-{I1,I2,I4,Bool}}
结果是
I1-I1 I1-I2 I1-I4 I1-Bool I2-I1 I2-I2 I2-I4 I2-Bool I4-I1 I4-I2 I4-I4 I4-Bool Bool-I1 Bool-I2 Bool-I4 Bool-Bool
用vim把上述结果稍加整理形成下面的批处理:
Marshal_Bool_UnmanagedType.exe Bool Bool
Marshal_Bool_UnmanagedType.exe Bool I1
Marshal_Bool_UnmanagedType.exe Bool I2
Marshal_Bool_UnmanagedType.exe Bool I4
Marshal_Bool_UnmanagedType.exe I1 Bool
Marshal_Bool_UnmanagedType.exe I1 I1
Marshal_Bool_UnmanagedType.exe I1 I2
Marshal_Bool_UnmanagedType.exe I1 I4
Marshal_Bool_UnmanagedType.exe I2 Bool
Marshal_Bool_UnmanagedType.exe I2 I1
Marshal_Bool_UnmanagedType.exe I2 I2
Marshal_Bool_UnmanagedType.exe I2 I4
Marshal_Bool_UnmanagedType.exe I4 Bool
Marshal_Bool_UnmanagedType.exe I4 I1
Marshal_Bool_UnmanagedType.exe I4 I2
Marshal_Bool_UnmanagedType.exe I4 I4

调用的结果是: 对于某些组合, 如I4, I4 程序会在调用 Marshal.SizeOf时抛出异常, 这说明此种结构定义无法进行正确的Marshal, 这样的结果无论怎样看都是一个bug, 把同一个结构中的bool数组和bool变量指定为相同的I4竟不允许, 下面是我对测试结果的简单统计: 16种组合中有8种是不允许的:
// arr  var         1.1       2.0
// I2   I2          ×        ×
// I2   I4          ×        ×
// Bool I2          ×        ×
// Bool I4          ×        ×
// I1   I2          ×        ×
// I1   I4          ×        ×
// I4   I2          ×        ×
// I4   I4          ×        ×

我个人的理解, 没有理由不允许上述组合. 尤其是对于同构的I4 I4和I2 I2组合竟不允许, 而从占用空间的角度, Bool也是4个字节, 但Bool Bool的组合却是允许的, 再仔细看, 非法的组合还是非对称的, 比如Bool I2的组合非法, 但I2 Bool却合法, 总之, Marshal对于这种情况的处理给人的直观印象是完全丧失了理智.

异常信息如下:
System.ArgumentException: Type CodeDomWrapper.TestBool can not be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
   at System.Runtime.InteropServices.Marshal.SizeOf(Type t)
   at Slimzhao.Csharp.Test.Marshal_Ptr2Structure.Test.Main(String[] args)

再说一遍, .NET 2.0也
有同样的问题存在
文件:Marshal_Bool_UnmanagedType.zip
大小:1KB
下载:下载


阅读(1606) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~