【问题标题】:How can I get a reference count to an ADODB recordset object?如何获得对 ADODB 记录集对象的引用计数?
【发布时间】:2021-01-27 05:39:12
【问题描述】:

我正在调查一些似乎与记录集对象相关的旧 VB6 代码中的内存泄漏,因此我正在尝试获取对象的引用计数。我在网上找到了一些代码,可以计算对对象的引用,它适用于本土类。但是当我尝试将它应用于 ADODB 记录集对象时,计数始终为 1492925242。我在现有应用程序中尝试过,然后在虚拟应用程序中尝试过 - 总是返回相同的数字(除非没有引用,那么它是0).

获取引用计数的代码如下:

    Private Declare Sub RtlMoveMemory Lib "kernel32" (dest As Any, src As Any, ByVal nbytes As Long)

Function objRefCnt(obj As IUnknown) As Long 
    If Not obj Is Nothing Then
       RtlMoveMemory objRefCnt, ByVal ObjPtr(obj) + 4, 4
       objRefCnt = objRefCnt - 2
    Else
       objRefCnt = 0
    End If
End Function

这是在 ADODB 记录集上调用它的代码:

    Sub main()
    Dim obj_1 As ADODB.Recordset
    Dim obj_2 As ADODB.Recordset

    Debug.Print objRefCnt(obj_1) ' 0

    Set obj_1 = New ADODB.Recordset
    Debug.Print objRefCnt(obj_1) ' 1

    Set obj_2 = obj_1
    Debug.Print objRefCnt(obj_1) ' 2
    Debug.Print objRefCnt(obj_2) ' 2

    Set obj_2 = New ADODB.Recordset
    Debug.Print objRefCnt(obj_1) ' 1
    Debug.Print objRefCnt(obj_2) ' 1
    End Sub

这将返回以下内容:

 0
 1492925242 
 1492925242 
 1492925242 
 1492925242 
 1492925242

但是当我添加一个名为 Class1 的虚拟类,它有一个属性(一个整数),并创建 obj_1obj_2 作为 Class1 对象时,我得到了这个:

 0 
 1 
 2 
 2 
 1 
 1 

关于如何获得 ADODB 记录集的引用计数的任何想法? 提前致谢。

【问题讨论】:

    标签: vb6 adodb reference-counting


    【解决方案1】:

    您找到的代码假定引用计数存储在对象内的偏移量 4 处。没有这样的要求。 IUnknown 定义方法,而不是必须存储私有变量的位置(并且引用计数是对象的私有变量)。

    获取引用计数的方法(仅用于测试目的)是call IUnknown.Release

    为了从VB6中做到这一点,互联网上的findolelib.tlb(Edanmo的OLE接口和功能),参考它,并拥有

    Public Function GetRefCount(ByVal obj As olelib.IUnknown) As Long
      obj.AddRef
      GetRefCount = obj.Release - 2
    End Function
    
    Dim r1 As ADODB.Recordset
    Dim r2 As ADODB.Recordset
      
    Set r1 = New ADODB.Recordset
    Set r2 = r1
      
    MsgBox GetRefCount(r1)  ' 2
    

    【讨论】:

      【解决方案2】:

      看来ADODB.Recordset 实例的m_dwRefCount 成员变量位于偏移量16。

      试试这个objRefCnt 替换:

      Private Declare Sub RtlMoveMemory Lib "kernel32" (dest As Any, src As Any, ByVal nbytes As Long)
      
      Function RecordsetRefCnt(rs As Recordset) As Long
          If Not rs Is Nothing Then
             RtlMoveMemory RecordsetRefCnt, ByVal ObjPtr(rs) + 16, 4
             RecordsetRefCnt = RecordsetRefCnt - 1
          Else
             RecordsetRefCnt = 0
          End If
      End Function
      

      JFYI,这是基于 GetRefCountAddRef/Release impl,没有额外的类型库

      Private Declare Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
      
      Public Function GetRefCount(pUnk As IUnknown) As Long
          Const CC_STDCALL    As Long = 4
          Dim vResult         As Variant
          
          Call DispCallFunc(ObjPtr(pUnk), 1 * 4, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, 0)
          Call DispCallFunc(ObjPtr(pUnk), 2 * 4, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, vResult)
          GetRefCount = vResult - 2
      End Function
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多