微软Marshal.ReleaseComObject--微软Marshal.ReleaseComObject 方法的来龙去脉
Posted on 2009-09-26 11:22 懒人ABC 阅读(712) 评论(0) 编辑 收藏 举报微软Marshal.ReleaseComObject 方法的来龙去脉
目的:研究了很多微软调用COM 对象或者ActiveX控件的范例,都很少有用到Marshal.ReleaseComObject 方法。因此,对超图范例频繁使用该方法的原因产生了好奇。所以花2天时间集中研究了一下。
定义:递减所提供的运行库可调用包装的引用计数。
但实际上因为无论调用包装 COM 对象的托管客户端有多少,.net运行库可调用包装仅保留对该对象的一次引用。所以这个方法将导致.net运行库释放非托管 COM 对象上的所有引用。
(白话解释下:COM对象与.NET环境处理内存的机制不同,所以要让老的COM东东能够在新的.NET环境运行,必须给COM对象包装一下,让她打扮成.NET对象的样子。但有的东西是COM特有的,比如引用计数,这是COM对象处理内存的方法,有人调用我就+1,这样6个人在用我,引用计数=6;当计数=0的时候,表示没人用我啦,于是羞愧而自杀,从内存中消失。但.NET环境不是这样处理,所有事情都由自动啦。新老东西打交道的时候,.NET说,COM老弟,你还是自己管你自己吧。于是,在.NET环境调用COM对象,比如Layer,就必须让superMap控件自己在没人用的时候识相的走人。当然我们编程人员希望能够控制拉,这时候就是显式控制。微软提供的Marshal.ReleaseComObject 方法,就是让我们显示控制COM对象的生存。你调用这个方法,就是通过.NET环境,告诉COM对象,不用你了,马上消失。)
用途:此方法用于显式控制从托管代码使用的 COM 对象的生存期。应及时(或者在对象按指定的顺序必须释放时)使用此方法,来释放引用某些资源的基础 COM 对象。
还有隐式控制,在代码嵌套结束时自动释放。就像for循环中的int i = 0;变量一样,出了循环代码段,int i自动消失。如果你在循环中调用一个COM对象,那就不用显示控制释放。系统自动解决。在其它代码段的嵌套情况下一样。我想我看到的很多微软的范例,都是这种隐式控制的方法吧。例如很多朋友用SuperMap时会遇到时有时无的故障。在不知不觉间用了隐式控制感觉没有问题;有时候恰好调用COM的代码没有隐式处理,所以出现故障。
COM对象与.NET的交互是牵扯到多方面的知识,是一个复杂的庞大话题。有兴趣的话可以MSDN研究下。在与COM对象打交道的时候,最好把更多的精力投入到体会其体系结构方面。
文章出处:DIY部落(http://www.diybl.com/course/4_webprogram/asp.net/netjs/20090311/160442.html)
Marshal类:
Marshal类支持从托管内存空间复制数据到非托管内存空间或是从非托管内存空间到托管内存空间。如果你研究在线的MSDN文档库,你会看到在桌面.NET框架下这个类支持的分配非托管内存空间的方法和其他一些与COM对象共同工作的方法。没有任何内存空间管理和COM支持方法在.NET精简框架的Marshal实现中出现。表4.5总结了Marshal类的被.NET精简框架支持的成员:13方法名(有一个或多个重载版本)和1个只读域。
表4.5 Marshal类中.NET精简框架支持的成员
Marshal 成员 |
描 述 |
在托管和非托管间复制 |
|
Copy |
在托管和非托管内存空间之间复制值类型数组。支持CLI整型,包括64位整型。支持单精度和双精度浮点数。有14个重载的方法(7个用来复制到托管内存空间;7个用来复制到非托管内存空间) |
复制到非托管内存空间 |
|
StructureToPtr |
复制托管对象到非托管内存空间 |
续表
Marshal 成员 |
描 述 |
WriteByte |
写入一个字节(byte)到非托管内存空间 |
WriteInt16 |
写入两个字节到非托管内存空间 |
WriteInt32 |
写入4个字节到非托管内存空间 |
复制到托管内存空间 |
|
PtrToStringUni |
在非托管内存空间中创建一个托管的字符串 |
PtrToStructure |
在非托管内存空间中创建一个对象 |
ReadByte |
从非托管内存空间中读取一个字节 |
ReadInt16 |
从非托管内存空间中读取两个字节 |
ReadInt32 |
从非托管内存空间中读取四个字节 |
信息的 |
|
IsComObject |
如果是硬编码返回False |
SizeOf |
查询一个对象实体的非托管大小。用来设置一些Win32函数调用的结构体大小的域值 |
GetLastWin32Error |
调用GetLastError函数来取回Win32错误码 |
SystemDefaultCharSize |
在默认的字符集中,字符大小的只读的域。(在.NET精简框架中返回2)为了可移植性 |
Marshal类的一些方法允许改写非托管的缓存,于是你就能够将它们作为参数传递到非托管函数中。这个类的另外一些方法可以让你从非托管缓存中读取值并写入托管数据对象中。从缓存中改写和读取都是重要的,因此Win32 API(连同许多其他的基于C的API)为从一个调用者到一个被调函数的通信提供了使用缓存的扩展。
这个表不包括许多用来分配非托管内存的函数。下面的内存分配函数在MSDN库中有所说明,并且内建在桌面.NET框架中,但是他们不被.NET精简框架所支持。
ü AllocHGlobal
ü FreeHGlobal
ü AllocCoTaskMem
ü FreeCoTaskMem
在你从托管内存中读取或写入之前,你需要获得一些非托管内存空间。在深入到Marshal类的内存复制方法之前,我们需要看一看一个.NET精简框架程序员如何处理内存分配。