学习RCW(RuntimeCallable Wrapper)运行库可调用包装-COM 对象与其基础 RCW 分开后就不能再使用

时间:2022-09-29 13:09:53
学习RCW(RuntimeCallable Wrapper)运行库可调用包装-COM 对象与其基础 RCW 分开后就不能再使用(一)
2011年12月07日 星期三 上午 10:39

学习RCW(RuntimeCallable Wrapper)运行库可调用包装

下面是我遇到的一个错误:

COM 对象与其基础 RCW 分开后就不能再使用。

说明执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息System.Runtime.InteropServices.InvalidComObjectException:COM 对象与其基础 RCW 分开后就不能再使用。

源错误: 

 

行 126:            if (oledbComm != null)

行 127:            {

行 128:                oledbComm.Dispose();

行 129:            }

行 130:        }


源文件e:\code\JXSiteAccess\index.aspx.cs    128 

堆栈跟踪: 

 

[InvalidComObjectException: COM 对象与其基础 RCW 分开后就不能再使用。]

   System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis, IntPtr pThread) +0

   System.Data.Common.IAccessor.ReleaseAccessor(IntPtr hAccessor, Int32& pcRefCount) +0

   System.Data.OleDb.RowBinding.Dispose() +86

   System.Data.OleDb.OleDbCommand.ResetConnection() +56

   System.Data.OleDb.OleDbCommand.Dispose(Boolean disposing) +27

   System.ComponentModel.Component.Dispose() +20

   index.Button2_Click(Object sender, EventArgs e) in e:\code\JXSiteAccess\index.aspx.cs:128

   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +118

   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +112

   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10

   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13

   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36

   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563

 


版本信息: Microsoft .NET Framework 版本:4.0.30319; ASP.NET 版本:4.0.30319.1

源代码是这样的:

  protectedvoid Button2_Click(objectsender, EventArgs e)

    {

        stringconnStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

        OleDbConnectionoledbConn = null;

        OleDbCommandoledbComm = null;

        OleDbDataReaderoledbDR = null;

        OleDbParameter[]oledbParam = { 

         newOleDbParameter("@id",OleDbType.UnsignedInt)

                                      };

        oledbParam[0].Value = 2011000008;

        try

        {

            oledbConn = newOleDbConnection(connStr);

            oledbComm = newOleDbCommand("SP_SelectAdminByID", oledbConn);

            oledbComm.CommandType = CommandType.StoredProcedure;

            if(oledbParam != null)

            {

                foreach(OleDbParameter parameter in oledbParam)

                {

                   oledbComm.Parameters.Add(parameter);

                }

            }

            oledbConn.Open();

            //oledbComm.ExecuteNonQuery();

            oledbDR =oledbComm.ExecuteReader();

            if(oledbDR.HasRows)

            {

                Response.Write("成¨|功|找¨°到ì?数oy据Y了¢?啊ã?!ê?<br />");

                if(oledbDR.Read())

                {

                    Response.Write("获?得ì?账?号?:êo" + oledbDR["AdminID"].ToString()+ ",ê?密¨1码?:êo" + oledbDR["AdminName"].ToString()+ "<br/>");

                }

            }

        }

        catch (Exception ex)

        {

            Response.Write(ex.Message);

        }

        finally

        {

           

            if(oledbConn != null)

            {

                oledbConn.Dispose();

            }

            if(oledbComm != null)

            {

                oledbComm.Dispose();

            }

        }

 

这个错误可能一些人遇到过,我是第一次遇到,就是今天在使用Access数据库的时候,以前都是SQL Server,不知道为什么出现了这个错误。在网站搜了搜,整理整理思考了一下,给大家分享一下哦。

首先要理解下面的哦,从MSDN得来的。

COM 包装

COM 在以下几个重要方面与 .NET Framework 对象模型存在差异:

·        COM 对象的客户端必须管理这些对象的生存期;公共语言运行库管理其环境中各对象的生存期。

·        COM 对象的客户端通过对提供服务的接口发出请求并取回接口指针来发现服务是否可用。.NET 对象的客户端可以使用反射来获取对象功能的说明。

·        .NET 对象驻留在由 .NET Framework 执行环境管理的内存中。为了提高性能,执行环境可以将对象在内存中来回移动,并更新对所移动对象的任何引用。非托管客户端在获取指向对象的指针后,将依赖于该对象来保持其位置不变。这些客户端没有相应的机制来处理位置不固定的对象。

为了克服这些差异,运行库提供了包装类,使托管和非托管客户端认为它们是在其各自的环境中调用对象。每当托管客户端对某个 COM 对象调用方法时,运行库就会创建一个运行库可调用包装 (RCW)。RCW 的功能之一是抽取托管和非托管引用机制之间的差异。运行库还会创建一个 COM可调用包装 (CCW) 来逆转此过程,使 COM 客户端能够对 .NET 对象无缝地调用方法。如下图所示,调用代码的性质将确定运行库所创建的包装类。

COM 包装概览

学习RCW(RuntimeCallable Wrapper)运行库可调用包装-COM 对象与其基础 RCW 分开后就不能再使用

大多数情况下,运行库所生成的标准 RCW 或 CCW 将为跨越 COM 和 .NET Framework 之间边界的调用提供充分的封送处理。利用自定义属性,您可以选择性地调整运行库表示托管和非托管代码的方式。

 

RCW-运行库可调用包装

RCW就是Runtime Callable Wrapper,还有一个就是CCWCom Callable Wrapper)。

公共语言运行库通过名为运行库可调用包装 (RCW) 的代理来公开 COM 对象。虽然 RCW 在 .NET 客户端看来是普通的对象,但它的主要功能是封送在 .NET 客户端和 COM 对象之间传递的调用。

无论一个 COM 对象存在多少个引用,运行库只为每个 COM 对象创建一个 RCW。运行库只为每个对象维护一个每进程的 RCW。如果在一个应用程序域或单元中创建 RCW,然后将引用传递至另外一个应用程序域或单元,则会使用第一个对象的代理。如下图所示,对于公开 INew 和 INewer 接口的 COM 对象,任意数目的托管客户端都可以持有引用。

通过运行库可调用包装来访问 COM 对象

学习RCW(RuntimeCallable Wrapper)运行库可调用包装-COM 对象与其基础 RCW 分开后就不能再使用

 

利用从类型库中导出的元数据,运行库将创建所调用的 COM 对象和该对象的包装。每个 RCW 都会在它所包装的 COM 对象上维护一个接口指针缓存,并且在不再需要 RCW 时释放它对该 COM 对象的引用。运行库将对 RCW 执行垃圾回收。

RCW 的功能之一是代表被包装的对象封送在托管和非托管代码之间传递的数据。具体地说,只要客户端和服务器之间传递了表示形式不同的数据,RCW 就会为方法参数和方法返回值提供封送处理。

标准的包装会强制实施内置的封送处理规则。例如,当 .NET 客户端将一个 String 类型作为参数的一部分传递给非托管对象时,包装就会将该 String 类型转换为 BSTR 类型。如果 COM 对象向其托管调用方返回 BSTR,调用方将接收到 String 类型。客户端和服务器都会收发它们所熟悉的数据。其他类型则不需要进行任何转换。例如,标准的包装将始终在托管和非托管代码之间传递 4 字节的整数,而不会转换其类型。