码迷,mamicode.com
首页 > Web开发 > 详细

VB.NET 内存指针和非托管内存的应用

时间:2015-11-03 10:24:35      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:

 

介绍

Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存。然而利用.NET框架中的structures 和 classes,可以做许多类似的事情。它们包括 IntPtr,   Marshal 以及 GCHandle。 这些structures(结构) 和classes(类) 允许你在托管和非托管环境中进行交互。本文中将向您展示如何使用这些structures 和 classes 去完成指针和内存的操作。

关于 IntPtr 结构

IntPtr  结构的行为像一个整型指针以便能应用到专门的平台。这个结构可以应用到支持或不支持指针的语言中。 .NET 文件 IO 类使用这个 结构扩展操作文件句柄。这个 IntPtr 结构形如整型指针的行为,但是它没有写或读相应位置内存的能力。这时你就需要System.Runtime.InteropServices 命名空间中的 Marshal 类。

关于 Marshal 类

这个类提供了全部分配非托管内存、拷贝非托管内存块,以及转换托管到非托管类型的方法。要保证你的代码导入了   System.Runtime.InteropServices

关于 GCHandle 结构

GCHandle 结构提供了从非托管内存中处理托管对象的方法。在非托管代码使用它时,可以控制垃圾碎片收集。

整数值的(读) 与 (写)

在我们的第一个例子中,使用 Marshal 类在内存中储存一个整数,得到一个内存指针去指向它在内存中的位置,并存到一个 IntPtr 结构中。最终我们将使用 Marshal  类读回这个值。

这里我们声明一个IntPtr类型,并且使用Marshal类中的AllocHGlobal   共享方法从全局堆中分配一个4字节的内存,并返回它的地址,存储在 IntPtr   变量中。接下来我们使用Marshal类中的WriteInt32 方法将整数值写到内存中。

               Dim ptr As IntPtr : Dim n As Integer = 123

               tr = Marshal.AllocHGlobal(4)    ‘在进程的非托管内存中划分 4 字节大小的内存空间

               Marshal.WriteInt32(ptr, n)    ‘将32位有符号的整数写入划分的内存空间中

Marshal.AllocHGlobal 方法的返回值为:指向新分配的内存的指针。用完后必须使用 Marshal.FreeHGlobal 方法释放划分的内存

用下面的方法,你可以读指定位置的内存中的数。

               Dim myInt As Integer = Marshal.ReadInt32(ptr)   ‘参数 ptr 为内存空间指针

        Marshal.AllocHGlobal 方法的返回值为:内存空间中的数据值

字符串的(读) 与 (写)

在这个例子中,我们写一个托管字符串到堆中,并且随后读出来。

        Dim str As String = "hello world"  ‘字符串为引用类型,所以存储在托管堆上
        Dim ptr As IntPtr = Marshal.StringToHGlobalAuto(str) ‘向非托管内存中复制托管内容,并转换为ANSI格式
        Dim mystring As String = Marshal.PtrToStringAuto(ptr) ‘从存储在非托管内存中的字符串复制等数量的字符到托管内存中

这里,我们使用了Marshal类中的StringToHGlobalAuto()方法拷贝托管字符串到非托管内存中。我们将内存地址保存在 IntPtr 结构中。为了从指定内存位置读回字符串,我们使用Marshal类中的PtrToStringAuto()方法 。

结构的读写

在下一个例子中,我们将看到如何使用Marshal 类和 IntPtr 结构,进行structure的读写。 Public Structure Point     Dim x As Integer     Dim y As Integer End Structure Dim mystruct1,mystruct2 As Point   mystructure.x=100   mystructure.y=200   Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(mystruct))   Marshal.StructureToPtr(mystruct, ptr, True)   mystruct2 = Marshal.PtrToStructure(ptr, New Point().GetType)  

这里我们使用一个名为Point的结构。这个代码和例子1中的相似,但要注意,我们使用了Marshal类中SizeOf method方法返回结构变量的尺寸。 方法StructureToPtr 接收要被写的结构变量,一个IntPtr 实例将被返回,同时标明是否Marshal类应该调用   DestroyStructure 方法,建议标记为   True,如果标记为 false 可能导致内存泄漏。最后我们使用Marshal累得PtrToStructure方法对会结构的值。

对象的读写

现在我们了解了如何用Marshal和IntPtr类读写值类型。托管对象的处理稍微不同。需要使用 GCHandle 来读写这些对象,下面的代码显示如何做: Public Class Employee      Public Name As String      Public Salary As Decimal   End Class     Dim gh As GCHandle   Dim emp As New Employee   emp.Name = "John"   emp.Salary = 12345.67   gh = GCHandle.Alloc(emp)   Dim emp2 As Employee = gh.Target   gh.Free()   

这里,对于employee类我们使用GCHandle (碎片手机句柄) 类进行分配和释放内存。共享(静态)的 Alloc 方法接受对象并存储在内存中并一个 GCHandle 类的实例。我们可以使用这个对象的Target属性指向对象的引用。我们可以使用GCHandle实例的Free方法来销毁相应的内存。

总结

在VB.NET中使用指针和非托管操作并不是易事,然而 IntPtr ,GCHandle 结构 和 Marshal 类可以让你完成类似的事情。

作者
Bipin   Joshi
Bipin   Joshi  BinaryIntellect Consulting  的所有者,在那里他提供了许多关于 .NET 技术的训练程序。

VB.NET 内存指针和非托管内存的应用

标签:

原文地址:http://www.cnblogs.com/lfls128/p/4932185.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!