Marshal类
提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。
命名空间:System.Runtime.InteropServices
Marshal 类中定义的 static 方法对于处理非托管代码至关重要。此类中定义的大多数方法通常由需要在托管和非托管编程模型之间提供桥梁的开发人员使用。
例如,StringToHGlobalAnsi 方法将 ANSI 字符从指定的字符串(在托管堆中)复制到非托管堆中的缓冲区。该方法还分配大小正确的目标堆。
公共方法
方法名称 |
说明 |
递增指定接口上的引用计数。 |
|
从 COM 任务内存分配器分配指定大小的内存块。 |
|
使用 LocalAlloc 分配内存块。 |
|
获取由指定的名字对象标识的接口指针。 |
|
在 COM 可调用包装 (CCW) 句柄包含的对象上更改它的强度。 |
|
将数据从托管数组复制到非托管内存指针,或从非托管内存指针复制到托管数组。 |
|
聚合托管对象和指定的 COM 对象。 |
|
在指定类型的对象中包装指定的 COM 对象。 |
|
释放指定的非托管内存块所指向的所有子结构。 |
|
通过将提供的运行库可调用包装 (RCW) 的引用计数设置为 0,释放对 RCW 的所有引用。 |
|
使用 SysFreeString 释放 BSTR。 |
|
释放由非托管 COM 任务内存分配器使用 Marshal.AllocCoTaskMem 分配的内存块。 |
|
释放以前使用 AllocHGlobal 从进程的非托管内存中分配的内存。 |
|
返回指定类型的全局唯一标识符 (GUID),或使用类型库导出程序 (TlbExp.exe) 所用的算法生成 GUID。 |
|
返回指定类型的编程标识符 (ProgID)。 |
|
从运行对象表 (ROT) 获取指定对象的运行实例。 |
|
返回一个接口指针,该接口指针表示对象的指定接口。 |
|
返回一个接口指针,该指针表示对象的指定接口(如果调用方与对象在同一上下文中)。 |
|
从指定的 COM 对象获取指定键所引用的数据。 |
|
获取指定的 System.Reflection.MemberInfo 在向 COM 公开时的虚函数表 (VTBL) 槽。 |
|
将非托管函数指针转换为委托。 |
|
获取在向 COM 公开时某个类型的虚函数表 (VTBL) 中的最后一个槽。 |
|
检索标识所发生异常的类型的代码。 |
|
。 将 HRESULT 错误代码转换为对应的 Exception 对象。 |
|
检索与计算机无关的异常描述以及有关异常发生时线程的状态信息。 |
|
将委托转换为可从非托管代码调用的函数指针。 |
|
用作特定类型的哈希函数。GetHashCode 适合在哈希算法和数据结构(如哈希表)中使用。 (从 Object 继承。) |
|
返回指定模块的实例句柄 (HINSTANCE)。 |
|
将指定异常转换为 HRESULT。 |
|
返回 HRESULT,它与使用 Marshal 执行的 Win32 代码引起的最后一个错误相对应。 |
|
从托管对象返回一个 IDispatch 接口。 |
|
如果调用方与托管对象在同一上下文中,则从该对象返回一个 IDispatch 接口指针。 |
|
从托管类型返回一个 ITypeInfo 接口。 |
|
从托管对象返回一个 IUnknown 接口。 |
|
如果调用方与托管对象在同一上下文中,则从该对象返回一个 IUnknown 接口。 |
|
返回由上一个非托管函数返回的错误代码,该函数是使用设置了 DllImportAttribute.SetLastError 标志的平台调用来调用的。 |
|
获取指向 thunk 的指针,该 thunk 封送从托管代码到非托管代码的调用。 |
|
检索指定的虚函数表 (VTBL) 槽的 MethodInfo。 |
|
将对象转换为 COM VARIANT。 |
|
返回通过指向 COM 对象的 IUnknown 接口的指针表示该对象的类型实例。 |
|
将 COM VARIANT 转换为对象。 |
|
将 COM VARIANT 数组转换为对象数组。 |
|
获取虚函数表 (VTBL) 中第一个包含用户定义的方法的槽。 |
|
将纤程 Cookie 转换为相应的 System.Threading.Thread 实例。 |
|
返回表示 COM 对象的指定类型的托管对象。 |
|
将 ITypeInfo 转换为托管 Type 对象。 |
|
。 检索由 ITypeInfo 表示的类型的名称。 |
|
。 检索类型库的库标识符 (LIBID)。 |
|
检索从指定程序集导出类型库时分配给该类型库的库标识符 (LIBID)。 |
|
。 检索类型库的 LCID。 |
|
。 检索类型库的名称。 |
|
检索将从指定程序集导出的类型库的版本号。 |
|
为给定的 IUnknown 创建唯一的运行库可调用包装 (RCW) 对象。 |
|
获取指向 thunk 的指针,该 thunk 封送从非托管代码到托管代码的调用。 |
|
指示指定对象是否表示 COM 对象。 |
|
指示类型对 COM 客户端是否可见。 |
|
计算在非托管内存中保存指定方法的参数所需要的字节数。 |
|
返回托管类的非托管形式的字段偏移量。 |
|
在不调用方法的情况下执行一次性方法设置任务。 |
|
对类上的所有方法执行预链接检查。 |
|
分配托管 String 并向其复制所有或部分非托管 ANSI 字符串。 |
|
分配托管 String,并从非托管字符串向其复制指定数目的字符。 |
|
分配托管 String,并向其复制存储在非托管内存中的 BSTR 字符串。 |
|
分配托管 String,并从非托管 Unicode 字符串向其复制指定数目的字符。 |
|
将数据从非托管内存块封送到托管对象。 |
|
从 COM 对象请求指向指定接口的指针。 |
|
从非托管指针读取单个字节。 |
|
从非托管内存中读取一个 16 位有符号整数。 |
|
从非托管内存中读取一个 32 位有符号整数。 |
|
从非托管内存中读取一个 64 位有符号整数。 |
|
从非托管内存中读取处理器本机大小的整数。 |
|
调整以前用 AllocCoTaskMem 分配的内存块的大小。 |
|
调整以前用 AllocHGlobal 分配的内存块的大小。 |
|
确定指定的 Object 实例是否是相同的实例。 (从 Object 继承。) |
|
递减指定接口上的引用计数。 |
|
递减所提供的运行库可调用包装的引用计数。 |
|
释放线程缓存。 |
|
分配 BSTR 并向其复制托管 SecureString 对象的内容。 |
|
将托管 SecureString 对象的内容复制到从非托管 COM 任务分配器分配的内存块。 |
|
将托管 SecureString 对象的内容复制到从非托管 COM 任务分配器分配的内存块。 |
|
将托管 SecureString 中的内容复制到非托管内存,并在复制时转换为 ANSI 格式。 |
|
向非托管内存复制托管 SecureString 的内容。 |
|
设置由指定 COM 对象中的指定键引用的数据。 |
|
使用 Marshal 返回类的非托管大小(以字节为单位)。 |
|
分配 BSTR 并向其复制托管 String 的内容。 |
|
将托管 String 的内容复制到从非托管 COM 任务分配器分配的内存块。 |
|
将托管 String 的内容复制到从非托管 COM 任务分配器分配的内存块。 |
|
将托管 String 的内容复制到从非托管 COM 任务分配器分配的内存块。 |
|
将托管 String 中的内容复制到非托管内存,并在复制时转换为 ANSI 格式。 |
|
向非托管内存复制托管 String 的内容,并在需要时转换为 ANSI 格式。 |
|
向非托管内存复制托管 String 的内容。 |
|
将数据从托管对象封送到非托管内存块。 |
|
用特定的失败 HRESULT 值引发异常。 |
|
返回表示当前 Object 的 String。 (从 Object 继承。) |
|
获取指定数组中指定索引处的元素的地址。 |
|
将单个字节值写入到非托管内存。 |
|
将 16 位有符号整数写入非托管内存。 |
|
将 32 位有符号整数写入非托管内存。 |
|
将 64 位有符号整数写入非托管内存。 |
|
将一个处理器本机大小的整数值写入非托管内存。 |
|
释放 BSTR 指针,该指针是使用 SecureStringToBSTR 方法分配的。 |
|
释放非托管字符串指针,该指针是使用 SecureStringToCoTaskMemAnsi 方法分配的。 |
|
释放非托管字符串指针,该指针是使用 SecureStringToCoTaskMemUnicode 方法分配的。 |
|
释放非托管字符串指针,该指针是使用 SecureStringToGlobalAllocAnsi 方法分配的。 |
|
释放非托管字符串指针,该指针是使用 SecureStringToCoTaskMemUnicode 方法分配的。 |
简介
Marshal 类中有许多成员,但他们大多是公用事业援助COM代码进行互操作。
使用.NET,Visual Basic中有很大的权力,以至于处理在与 Windows 系统较低水平层次,并从外部库的非托管代码的工作。这权力是发现了三个新的工具:IntPtr的,NET的平台相关的内存地址代表性的GCHandle,从而你针和检索的管理内存堆的数据的地址; Marshal类的一站式。您的内存分配,清理,和操作的需要。
如果您决定与VB.NET直接内存操作,你需要了解的第一件事是IntPtr类型。
IntPtr 的是一个结构,它表示两个地址和处理(大多数处理 Windows 的指针的指针)。
IntPtr 的实例也依赖于平台的(或独立,取决于你的观点)。在32位系统,IntPtr 的是32位,而在64位系统 IntPtr 的是64位。这样做的好处是,你不需要更改或重新编译你的代码,或两个平台内的任何.NET Framework的公开的方式与地址和处理工作的功能。
使用 IntPtr 类型,这种功能是封送到非托管代码,仅仅作为内部地址编号,这意味着你可以通过一个 IntPtr 类型的变量的任何非托管代码的预计指针。因此,好消息是,虽然你不能在VB.NET中使用这样的: 如void * Dim MyPointer 这个工程精辟VB.NET:作为 IntPtr 的 DIM MyPointer
请注意,在Beta 1没有IntPtr类型??相反,工作指针和处理使用 Integer 类型。
IntPtr 类型有 ToInt32 方法的地址转换为一个整数,但可以将导致在64位系统的溢出异常。 IntPtr 也有 ToInt64 方法,但你必须保持跟踪的平台,如果你想要做的这些转换。StrPtr()和 VarPtr()NBSP在 VB.NET 这两个无证 VB 的6个功能变量的返回地址。相同的功能,可以在VB.NET的GCHandle类。
让我们来看看如何放到一个 IntPtr 变量的地址。您可以使用的 GCHandle 的类,它有一个 AddrOfPinnedObject 的方法返回一个变量一个IntPtr。
您必须"针"的数据,然后才可以得到这个地址。这可以防止不经意间移动数据的垃圾收集器,而你指的是原来的地址。这代码引脚一个变量,其地址显示在控制台窗口,并释放句柄:"昏暗的管理变量DIM MyString的字符串=阿德南塞缪尔? "针变量和创建"GC的处理实例昏暗的GH(MyString中,GCHandleType.Pinned)的GCHandle = GCHandle.Alloc "得到的变量的地址DIM AddrOfMyString作为IntPtr的= gh.AddrOfPinnedObject() Console.WriteLine(AddrOfMyString.ToString()) "*的处理,并脱离"变量gh.Free()说明AllocHGlobal和AllocCoTaskMem
上的本机堆内部使用GlobalAlloc函数分配内存AllocHGlobal; AllocCoTaskMem,这是类似的,而是使用的COM内存管理器(CoTaskMemAlloc来)。这两个函数有一个参数,分配的字节数。这两个函数返回一个IntPtr,新分配的缓冲区的基地址。释放内存,您使用的FreeHGlobal或FreeCoTaskMem方法,取决于分配方法您使用。这些函数有一个参数,新分配的缓冲区的分配函数返回地址。
使用WriteByte,WriteInt16,WriteInt32,或WriteInt64方法简单的数字数据写入到一个非托管的缓冲区。每个函数作为参数的写操作的目的地址和数值你想要写。这些功能也重载以允许可选的第三个参数指示从抵消所提供的地址,它可以是有用的,如果你试图填充数组元素或结构领域的内存,例如:"分配一些内存,并获得它的地址DIM MyPointer的IntPtr = Marshal.AllocHGlobal(4) "写入到该地址的数量255Marshal.WriteInt32(MyPointer,255) "一些更多的代码(调用"例如的非托管代码) "空闲内存Marshal.FreeHGlobal(MyPointer)
您也可以使用提供的地址,而不是你自己分配的非托管代码:DIM MyPointer作为IntPtr的新的IntPtr([插入整数地址_ 从这里非托管代码)] Marshal.WriteInt32(MyPointer,255)
反过来也有可能。你可以阅读简单的数字数据,从一个IntPtr地址使用的readByte ReadInt16,ReadInt32,并ReadInt64方法:DIM MyInteger为整数= Marshal.ReadInt32(MyPointer)字符串函数
阅读和写作字符串相似,读,写简单的数字数据,有一个小的例外:你不先分配内存,然后写一个字符串。相反,在非托管内存中创建一个字符串的行为分配的空间,并返回字符串的地址。写有七个方法:StringToBSTR,StringToCoTaskMemAnsi,StringToCoTaskMemUni,StringToCoTaskMemAuto,StringToHGlobalAnsi,StringToHGlobalUni和StringToHGlobalAuto。 StringToCoTaskMemxxx功能字符串数据写入到COM分配的内存,而StringToHGlobalxxx功能写入到本地的非托管堆。结束在ANSI的函数写单字节ANSI字符串。结束在统一的函数写双字节的Unicode字符串。功能,自动结束写入ANSI或Unicode字符串,这取决于操作系统:Windows 98和ME,NT为基础的平台(Windows NT 4.0中,2000年,和XP)的Unicode字符串的ANSI字符串。 StringToBSTR写一个自动化BSTR,这是类似于使用SysAllocString函数。这些函数接受一个字符串作为输入参数,并返回一个指针,得到的字符串:DIM MyStrPointer的IntPtr = Marshal.StringToHGlobalAuto(quot;您好Worldquot;)
四个读的方法呢??PtrToStringAnsi,PtrToStringUni,PtrToStringAuto,PtrToStringBSTR??在一个给定的地址读取数据,并创建一个托管String对象,其中包含的字符的副本。 PtrToStringAnsi如果非托管字符串是ANSI,PtrToStringUni如果非托管字符串是Unicode,或PtrToStringBSTR如果非托管字符串是BSTR类型。 PtrToStringAuto假定非托管字符串是一个Windows 98或ME系统的ANSI和Unicode的Windows NT 4.0,2000或XP平台上。 PtrToStringAuto实际上是调用PtrToStringAnsi或PtrToStringUni,取决于操作系统。每个函数重载接受一个可选的数字复制的字符。如果你没有提供的字符数,函数看起来为终止空字符:"复制整个字符串昏暗的MyString的字符串= Marshal.PtrToStringAuto(MyPointer)"复制前5个字符DIM MyString的字符串= Marshal.PtrToStringAuto(MyPointer,5)
拿着一个字符串要释放非托管内存缓冲区,可以调用FreeHGlobal或FreeCoTaskMem成员。要免费StringToBSTR创建一个BSTR,你叫FreeBSTR,这反过来又调用FreeSysString功能。 - ; StructureToPtr和PtrToStructure
你写的非托管内存结构(用户定义类型)使用的StructureToPtr方法。这种方法需要你有时间提前分配的内存缓冲区。它有三个参数:您要编写的结构,内存缓冲区的地址(IntPtr的),和一个删除标志。删除标志设置为True湿巾和释放任何现有的数据从缓冲区。这是非常重要的,因为你可能会导致内存泄漏不删除现有的缓冲空间。例如,如果结构的领域之一,是另一种结构或字符串的引用,数据被外地引用不会被释放,如果该参数设置为False。还要注意的是结构复制到非托管内存,使用特定的格式(你可以控制可选),和非托管的副本可能不像完全的托管表示。使用sizeof的方法来确定缓冲区所需的字节数:DIM MYVARIABLE为点MyVariable.X = 100MyVariable.Y = 250DIM MyPointer作为IntPtr的Marshal.AllocHGlobal(Marshal.SizeOf(MYVARIABLE))Marshal.StructureToPtr(MYVARIABLE,MyPointer,假)
使用PtrToStructure方法扭转的过程和读从非托管内存结构。您可以使用此方法可以作为一个函数返回一个结构的副本类型的基础上,或填补了结构参数作为一个子。请注意,PtrToStructure返回一个Object类型的引用,和Option Strict On时,您必须转换为结构类型(例如,所使用的CType):作为点DIM MyPointMyPoint = CTYPE(Marshal.PtrToStructure(MyPointer的GetType(点)),点)复制方法
读取和写入阵列中的数据,尤其是宝贵的,当你需要二进制数据流。 Copy方法读取和写入,根据您传递给它的参数。如果你想写入数据,你需要先分配一些缓冲区空间,就像你会使用字符串。接下来,您呼叫的复制方法,并通过数组本身,目的地址(IntPtr的分配),你要开始复制的元素的数组的索引,和缓冲区的大小:DIM MyData的(255)作为字节"在这里插入代码,以填补字节数组DIM BufferAddress的IntPtr = Marshal.AllocHGlobal(256)Marshal.Copy(MYDATA,0,BufferAddress,256)
要阅读从非托管内存中的数组,调用复制的方法,并通过缓冲区的地址(IntPtr的),你想从缓冲区中的数据填充数组,数组的索引,你要开始复制到了,你要复制的数据的大小:MyData的DIM(255)以字节 Marshal.Copy(BufferAddress,MYDATA,0,256)
Marshal类中有更多的方法,但他们大多是公用事业援助COM代码进行互操作。结论
这些功能也相当有助于封送处理以及asnbsp管理的数据; CopyMemory如非托管的内存也被称为RtlMoveMomry功能的一个很好的替代。
我总是乐于帮助,因此,如果您有任何疑问,或对我的文章建议,感到*。您还可以在MSN Messenger上达到我的屏幕名称千里马吗??