天天看點

不同平台中(.NET Compact Framework2.0和.NET Framework2.0)定義的結構體預設屬性之差異...

      前一段时间用Socket做了一个可用于Windows Mobile 6.1的dll,用于在网络上传输各种文件,支持断点续传;其服务器是在Windows XP上做的;开发语言是C#。在最后的测试阶段出了问题,经过一天的跟踪和调试,终于找到问题所在:客户端和服务器在交互的时候,用于信息交换的结构体在两端解析出错了。这个Bug真是没有想到,因为我的代码的这个模块在Windows XP平台都测试是正确的,而且系统提示的出错信息都是网络连接上面的问题,导致调试的大部分精力都放在无线网络上。

      好了,言归正传,现在说问题和解决方法。我在程序中定义了一个结构体:

        [StructLayoutAttribute(LayoutKind.Sequential)]

        public struct filemessage

        {

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

            public string myid;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]

            public string filename;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]

            public string filepath;

            public System.Int32 tmpseek;    

            public System.Int32 filesize;   

            public System.Int32 sysmark;

        };

      StructLayoutAttribute 类使用户可以控制类或结构的数据字段的物理布局;值 Sequential 用于强制将成员按其出现的顺序进行顺序布局;在这个Struct里面,定义了每个string 成员的大小,那么想当然的认为这个Struct的大小为172Bytes。的确,我在Windows XP中用Marshal.SizeOf( )测试得到其大小也是这么多,但到了Windows Mobile 6.1中,其大小还是这么多吗?用同样的测试方法,发现了问题,测试得到其大小为332bytes!两端对这个Struct的默认结构不一样,于是出现了对该结构体的解析问题。

      为了发现问题,继续作了一系列的测试:设置StructLayoutAttribute 类成员CharSet的值为Auto,Unicode,Ansi(XP独有),在Windows XP和Windows Mobile 6.1中测试,其大小分别为:332bytes,332bytes,172bytes和332bytes,332bytes。所以问题出在两个平台对CharSet字段的默认值的不同造成的。

      再来看MSDN,对于CharSet有如下描述:如果 CharSet 字段设置为 CharSet.Unicode,则所有字符串参数在传递到非托管实现之前都转换成 Unicode 字符 (LPWSTR)。如果该字段设置为 CharSet.Ansi,则字符串将转换成 ANSI 字符串 (LPSTR)。如果 CharSet 字段设置为 CharSet.Auto,则转换与平台相关(在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上为 Unicode;在 Windows 98 和 Windows Me 上为 ANSI)。

      于是问题就可以解决了,只要设置StructLayoutAttribute 类成员CharSet的值为Auto或Unicode即可。

      最后我的解决方法是:重新对该Struct进行定义,如下

        [StructLayoutAttribute(LayoutKind.Explicit, CharSet = CharSet.Unicode)]

        public struct filemessage

        {

            [FieldOffset(0)]

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

            public string myid;

            [FieldOffset(32)]

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]

            public string filename;

            [FieldOffset(96)]

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]

            public string filepath;

            [FieldOffset(160)]

            public System.Int32 tmpseek;   

            [FieldOffset(164)]

            public System.Int32 filesize;   

            [FieldOffset(168)]

            public System.Int32 sysmark;

        };

      Explicit 控制每个数据成员的精确位置。最后该struct的大小为224bytes;在Windows XP中,若不设置CharSet的值,则大小为172bytes,而WM6.1中为332bytes。另外改变机构体成员的位置,如将filename放到最后,结构体的大小也会变,上面这种成员排列使结构体的大小最小。

      但问题还没完,一个开始认为大小只有172Bytes的结构体怎么现在变成了332bytes的,多余的字节到哪里去了?这里涉及到了一个内存对齐(+其他?)的问题,诸位看官可以搜索一下,我在这里先就不多说了,因为我自己也还没有完全搞明白,待理解过来后再补上,或哪位高手指教一下,不胜感激!!

      附:在C#/Socket编程中结构体和byte[]之间的相互转换方法。

         byte[] StructToBytes(object structObj)

        {

            int size = Marshal.SizeOf(structObj);

            IntPtr buffer = Marshal.AllocHGlobal(size);

            try

            {

                Marshal.StructureToPtr(structObj, buffer, false);

                byte[] bytes = new byte[size];

                Marshal.Copy(buffer, bytes, 0, size);

                return bytes;

            }

            finally

            {

                Marshal.FreeHGlobal(buffer);

            }

        }

        object BytesToStruct(byte[] bytes, Type strcutType)

        {

            int size = Marshal.SizeOf(strcutType);

            if (size > bytes.Length)

            {

                return null;

            }

            IntPtr buffer = Marshal.AllocHGlobal(size);

            try

            {

                Marshal.Copy(bytes, 0, buffer, size);

                return Marshal.PtrToStructure(buffer, strcutType);

            }

            finally

            {

                Marshal.FreeHGlobal(buffer);

            }

        }

 

 

 

 

 

转载于:https://www.cnblogs.com/carrey/archive/2009/04/07/Carrey.html