FIX: Handle Leak when Passing ADO Objects Between Processes

ID: Q197426


The information in this article applies to:
  • ActiveX Data Objects (ADO), versions 2.0, 2.1 SP2


SYMPTOMS

When marshalling an ActiveX Data Objects (ADO) recordset between processes the handle count incrementally increases for each call made to the out-of- process component. This behavior only occurs if the rowset contains more than 8K of data.


CAUSE

This is a problem in ActiveX Data Objects Version 2.0.


RESOLUTION

A supported fix that corrects this problem is now available from Microsoft, but it has not been fully regression tested and should be applied only to systems experiencing this specific problem. If you are not severely affected by this specific problem, Microsoft recommends that you wait for the next that contains this fix.

To resolve this problem immediately, contact Microsoft Product Support Services to obtain the fix. For a complete list of Microsoft Product Support Services phone numbers and information on support costs, please go to the following address on the World Wide Web:

http://www.microsoft.com/support/supportnet/overview/overview.asp


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.

This problem has been fixed in Microsoft ActiveX Data Objects versions 2.1 and later.

You can install the latest version of Microsoft Data Access Components from the following Web site:

http://www.microsoft.com/data/download.htm


MORE INFORMATION

Steps to Reproduce the Behavior

NOTE: The following steps assume that you are using Visual Basic 5.0 or later.

  1. Build an ActiveX .EXE that creates a disconnected recordset with ADO 2.0.


  2. Use the following SQL statement against the Pubs (SQL Server 6.5) database to produce a recordset that contains more than 8K of data:


  3. 
    (SELECT authors.*, roysched.*, titleauthor.*, titles.*, publishers.*
    FROM titleauthor INNER JOIN authors ON titleauthor.au_id =
    authors.au_id INNER JOIN titles ON titleauthor.title_id =
    titles.title_id INNER JOIN roysched ON titles.title_id =
    roysched.title_id INNER JOIN publishers ON titles.pub_id =
    publishers.pub_id). 
  4. Pass the recordset as the return value of a function in the .exe. Here is sample code for a function that returns an ADODB recordset, using the SQL above:


  5. 
    Public Function GetRs() As ADODB.Recordset
       Dim cn As ADODB.Connection
       Dim Rs As ADODB.Recordset
       Dim strsql As String
    
       Set cn = New ADODB.Connection
       cn.Open "dsn=pubs"
       Set Rs = New ADODB.Recordset
       strsql = "(SELECT authors.*, roysched.*, titleauthor.*, titles.*, " & _
         "publishers.* FROM titleauthor INNER JOIN authors ON " & _
         "titleauthor.au_id = authors.au_id INNER JOIN titles ON " & _ 
         "titleauthor.title_id =  titles.title_id INNER JOIN roysched ON " & _
         "titles.title_id =  roysched.title_id INNER JOIN publishers ON " & _
         "titles.pub_id =  publishers.pub_id)"
    
       Rs.CursorLocation = adUseClient
       Rs.LockType = adLockBatchOptimistic
       Rs.Open strsql, cn
       Set Rs.ActiveConnection = Nothing
       Set GetRs = Rs
    
       cn.Close
       Set cn = Nothing
      
    End Function 
  6. Create a client application that creates an instance of the .exe and calls the recordset returning function from the .exe.


  7. It is important to maintain the scope of the .exe between calls.


  8. Repeat the call process to the .exe several times. Here is sample code that repeatedly calls a function that returns an ADO recordset from an ActiveX EXE named rsEXE, within the scope of a single procedure:


  9. 
    Dim rs1 As ADODB.Recordset
       Dim rs2 As ADODB.Recordset
       Dim rs3 As ADODB.Recordset
    
       Set rs1 = New ADODB.Recordset
       Set rs2 = New ADODB.Recordset
       Set rs3 = New ADODB.Recordset
    
       Dim gs As RsEXE.rs
       Set gs = New RsEXE.rs
     
      'Add rsEXE to Performance Monitor before executing the next line
    
       Set rs1 = gs.GetRs
       Set rs2 = gs.GetRs
       Set rs3 = gs.GetRs
    
       rs1.Close
       rs2.Close
       rs3.Close
    
       Set rs1 = Nothing
       Set rs2 = Nothing
       Set rs3 = Nothing
    
       Set gs = Nothing 
  10. Step through the client application:


    1. After creating the ActiveX EXE object, but before calling the function that returns a recordset, open Windows NT Performance Monitor.


    2. In Performance Monitor, choose Edit, Add to Chart.


    3. For Object, choose Process.


    4. For Counter, choose Handles.


    5. For Instance, choose the now running ActiveX EXE.


    6. Return to stepping through the client application.


    7. While stepping through the client, check the handle count for the ActiveX EXE in Performance Monitor. You will see the handle count increase by 2(+/-1) for each call you make to the component.

Additional query words:

Keywords : kbADO200bug kbADO200fix kbADO210fix kbDatabase kbGrpVBDB kbGrpMDAC kbDSupport kbADO200QFE kbMDAC210fix kbMDAC210SP2
Version : WINDOWS:2.0,2.1 SP2
Platform : WINDOWS
Issue type : kbbug


Last Reviewed: October 21, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.