如何获得 ADODB 记录集对象的引用计数?

How can I get a reference count to an ADODB recordset object?

我正在调查一些似乎与记录集对象相关的旧 VB6 代码中的内存泄漏,因此我正在尝试获取对象的引用计数。我在网上找到了一些代码,可以计算一个对象的引用数,它适用于自制的 class。但是当我尝试将它应用于 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

这个 returns 以下:

 0
 1492925242 
 1492925242 
 1492925242 
 1492925242 
 1492925242

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

 0 
 1 
 2 
 2 
 1 
 1 

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

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

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

为了从 VB6 做到这一点,find olelib.tlb 在 Internet 上(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

m_dwRefCount ADODB.Recordset 个实例的成员变量出现在偏移量 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

仅供参考,这是一个基于 AddRef/ReleaseGetRefCount 实现,没有额外的类型库

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