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

介绍

Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存。然而利用.NET框架中的structures 和 classes,可以做许多类似的事情。它们包括 IntPtr,Marshal 以及 GCHandle。 这些structures 和classes 允许你在托管和非托管环境中进行交互。本文中,我 将向您展示如何使用这些structures 和 classes 去完成指针和内存的操作。尽管是VB.NET的代码,转换成 C# 应该也不会有问题。同时注意,为了简明,我没有提供实际的非托管代码,我的目标是讲解如何让它们应用到每一个独立的需求中。

关于 IntPtr structure

IntPtr structure 的行为像一个整型指针以便能应用到专门的平台。这个 structure 可以应用到支持或不支持指针的语言中。 .NET 文件 IO 类使用这个 structure 扩展操作文件句柄。

关于 Marshal 类

这个 IntPtr structure 形如整型指针的行为,但是它没有写或读相应位置内存的能力。这时你就需要System.Runtime.InteropServices 命名空间中的 Marshal 类。这个类提供了全部分配非托管内存、拷贝非托管内存块,以及转换托管到非托管类型的方法。要保证你的代码导入了 System.Runtime.InteropServices 。

关于 GCHandle structure

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

整数值的读写

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

  1. DimptrAsIntPtr
  2. DimnasInteger=123
  3. ptr=Marshal.AllocHGlobal(4)
  4. Marshal.WriteInt32(ptr,n)

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

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

copy
    DimmyintasInteger=Marshal.ReadInt32(ptr)

字符串的读写

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

copy
    DimstrasString="helloworld"
  1. AsIntPtr=Marshal.StringToHGlobalAuto(str)
  2. DimmystringAsString=Marshal.PtrToStringAuto(ptr)

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

结构的读写

在下一个例子中,我们将看到如何使用Marshal 类和 IntPtr 结构,进行structure的读写。

copy
    PublicStructurePoint
  1. DimxInteger
  2. DimyInteger
  3. EndStructure
  4. Dimmystruct1,mystruct2AsPoint
  5. mystructure.x=100
  6. mystructure.y=200
  7. AsIntPtr=Marshal.AllocHGlobal(Marshal.SizeOf(mystruct))
  8. Marshal.StructureToPtr(mystruct,ptr,True)
  9. mystruct2=Marshal.PtrToStructure(ptr,153); font-weight:bold; background-color:inherit">NewPoint().GetType)

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

对象的读写

现在我们了解了如何用Marshal和IntPtr类读写值类型。托管对象的处理稍微不同。需要使用 GCHandle 来读写这些对象,下面的代码显示如何做:

copy
    ClassEmployee
  1. PublicNameString
  2. PublicSalaryDecimal
  3. Class
  4. DimghAsGCHandle
  5. DimempNewEmployee
  6. emp.Name="John"
  7. emp.Salary=12345.67
  8. gh=GCHandle.Alloc(emp)
  9. Dimemp2AsEmployee=gh.Target
  10. gh.Free()

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

总结

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

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

转载链接:http://www.jb51.cc/article/p-rmxwxwrg-yc.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")