在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1. 功能及位置 将数据从托管对象封送到非托管内存块,属于.NET Framework 类库 命名空间:System.Runtime.InteropServices 程序集:mscorlib(在 mscorlib.dll 中) 2. 语法 C#: [ComVisibleAttribute(true)] public static void StructureToPtr (Object structure,IntPtr ptr,bool fDeleteOld); C++: [ComVisibleAttribute(true)]public: static void StructureToPtr (Object^ structure, IntPtr ptr, bool fDeleteOld); 3. 参数说明 structure:托管对象,包含要封送的数据。该对象必须是格式化类的实例。 ptr:指向非托管内存块的指针,必须在调用此方法之前分配该指针。 fDeleteOld:设置为 true 可在执行Marshal.DestroyStructure方法前对 ptr 参数调用此方法。请注意,传递 false 可导致内存泄漏。 4. 异常 异常类型:ArgumentException 条件:structrue参数是泛型类型 5. 备注 StructureToPtr将结构的内容复制到 ptr 参数指向的预分配内存块。如果 fDeleteOld 参数为 true,则使用嵌入指 针上适当的删除 API 来删除最初由 ptr 指向的缓冲区,但该缓冲区必须包含有效数据。此方法为在镜像托管类中指 定的每个引用字段执行清理工作。 假设 ptr 指向非托管内存块。此内存块的布局由相应的托管类 structure 描述。StructureToPtr将字段值从结构封 送到指针。假设 ptr 块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到 ptr 块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。最后,您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。如果将 fDeleteOld 参数设置为真,则 StructureToPtr 在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。 6. 举例 定义PERSON结构,并将该结构的一个变量拷贝到非托管内存,再将该内存中的PERSON还原为PERSON对象,观察其内容的变化。 源代码如下: using System; using System.Text; using System.Runtime.InteropServices; namespace testStructureToPtr { public static class define //define some constant { public const int MAX_LENGTH_OF_IDENTICARDID = 20; //maximum length of identicardid public const int MAX_LENGTH_OF_NAME = 50; //maximum length of name public const int MAX_LENGTH_OF_COUNTRY = 50; //maximum length of country public const int MAX_LENGTH_OF_NATION = 50; //maximum length of nation public const int MAX_LENGTH_OF_BIRTHDAY = 8; //maximum length of birthday public const int MAX_LENGTH_OF_ADDRESS = 200; //maximum length of address } public struct PERSON //person structure { //MarshalAs:指示如何在托管代码和非托管代码之间封送数据 //UnmanagedType:指定如何将参数或字段封送到非托管内存块 [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)] public byte[] identicardid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)] public byte[] name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)] public byte[] country; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)] public byte[] nation; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)] public byte[] birthday; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)] public byte[] address; } class testProgram { private static byte _fillChar = 0; //the fill character //convert string to byte array in Ascii with length is len public static byte[] CodeBytes(string str, int len) { if (string.IsNullOrEmpty(str)) { str = string.Empty; } byte[] result = new byte[len]; byte[] strBytes = Encoding.Default.GetBytes(str); //copy the array converted into result, and fill the remaining bytes with 0 for (int i = 0; i < len; i++) result[i] = ((i < strBytes.Length) ? strBytes[i] : _fillChar); return result; } //show the person information public static void ShowPerson(PERSON person) { Console.WriteLine("cardid :" + Encoding.ASCII.GetString(person.identicardid)); Console.WriteLine("name :" + Encoding.ASCII.GetString(person.name)); Console.WriteLine("country :" + Encoding.ASCII.GetString(person.country)); Console.WriteLine("nation :" + Encoding.ASCII.GetString(person.nation)); Console.WriteLine("birthday :" + Encoding.ASCII.GetString(person.birthday)); Console.WriteLine("address :" + Encoding.ASCII.GetString(person.address)); } static void Main(string[] args) { PERSON person; person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID); person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME); person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY); person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION); person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY); person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS); int nSizeOfPerson = Marshal.SizeOf(person); IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfPerson); Console.WriteLine("The person infomation is as follows:"); ShowPerson(person); try { //将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr Marshal.StructureToPtr(person, intPtr, true); //将数据从非托管内存块封送到新分配的指定类型的托管对象anotherPerson PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON)); Console.WriteLine("The person after copied is as follows:"); ShowPerson(anotherPerson); } catch (ArgumentException) { throw; } finally { Marshal.FreeHGlobal(intPtr); //free tha memory } } } } 7. 分析及扩展 结构体: public struct PERSON //person structure { //MarshalAs:指示如何在托管代码和非托管代码之间封送数据 //UnmanagedType:指定如何将参数或字段封送到非托管内存块 [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)] public byte[] identicardid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)] public byte[] name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)] public byte[] country; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)] public byte[] nation; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)] public byte[] birthday; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)] public byte[] address; } A. 通过获取Person信息的函数返回的指针,再将该指针转换为结构体,并显示结构体中的内容 a. 获取Person信息的函数 //获取 Person信息 [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr GetPerson(IntPtr pEngine); b. 使用指针定义一个变量,来获取一个返回值为该指针的函数 IntPtr Person = GetPerson(pEngine); c. 将指针变量装换为结构体,操作如下: PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON)); d. 通过ShowPerson(PERSON person)函数,用来打印输出信息 Console.WriteLine("cardid :" + Encoding.ASCII.GetString(anotherPerson.identicardid)); B. 通过定义结构体,并赋值结构体中的数据,再将结构体转为指针数据,并将指针传入到SetPerson信息的函数中 a. 设置Person信息的函数 //获取 Person信息 [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int SetPerson(IntPtr pEngine); b. 定义结构体,并赋值结构体中的数据 PERSON person = new PERSON(); person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID); person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME); person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY); person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION); person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY); person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS); c. 将结构体转为指针数据 int nSizeOfPerson = Marshal.SizeOf(person); //定义指针长度 IntPtr personX = Marshal.AllocHGlobal(nSizeOfPerson); //定义指针 Marshal.StructureToPtr(person, personX, true); //将结构体person转为personX指针 d. 将指针传入到SetPerson函数中 SetPerson(personX);
|
请发表评论