SonghaySystem(::)

Developing a Customized COM Object for ADO

The motivation behind building a COM object for ADO (which is already a COM object) is to generalize and package all of the routines and objects involving ADO that are useful in my solutions. In Chapter One of the ADO Programmer’s Guide, Microsoft writes, “ADO is designed to provide developers with a powerful, logical object model for programmatically accessing, editing and updating a wide variety of data sources through OLE DB system interfaces.” Where we see “wide variety” suggesting that ADO is extremely general. My solutions require a finite number of generic routines that are a subset of the total number of features ADO provides. The routines are:

The remainder of this document will list and describe the properties and methods of this object, explore a few real world cases where this object is implemented, and look toward future enhancements.

ADO Services

The file name is rasxADO.dll, containing the Class ADOServices.

Public Properties of ADOServices
ConnectionGet an ADODB.Connection object. This property is read only.
ErrorTextGet both the VBA error and the Collection of ADO error numbers and descriptions. This property is read only.
RecordsAffectedGet the number of data records affected by procedures/SQL executed by this Object. Usually this value is -1 since it is poorly supported by the OLE DB providers used by this Class. (See StoredProcCmd() below.) This property is read only.
SessionLogGet verbose descriptions of ADO connection/disconnection attempts, procedure/SQL execution and Class initialization/termination. Recommended for debugging purposes. This property is read only.
Public Methods of ADOServices
ClientRst()Returns a disconnected, ADO Recordset (CursorType:=adOpenStatic and LockType:=adLockBatchOptimistic), optimized for “fat-client” grid controls like those for VB 6 x forms. This method is also used to access ADO Recordset methods like MoveFirst() and MovePrevious(), and properties like Recordcount.
CloseRecordset()Closes the specified Recordset object and sets the object to Nothing.
CnnCmd()Executes dynamic SQL commands against the ADODB.Connection object.
CnnRst()Executes dynamic SQL projections against the ADODB.Connection object and returns a read-only, forward-only ADO Recordset.
Connect()Returns a Boolean value indicating success/failure while attempting to set the Connection property of this Class. This method must be used before any other methods in this Class.
Disconnect()Closes the ADO connection object.
StoredProcCmd()Executes a stored procedure against the ADODB.Command object.
StoredProcRst()Executes a stored procedure against the ADODB.Command object and returns a read-only, forward-only ADO Recordset.

Remarks

The arguments forClientRst(),CnnCmd(), andCnnRst() are identical. The following table summarizes:

Arguments of ClientRst(), CnnCmd(), and CnnRst()
SourceRequired. String literal. By value. Valid SQL for the DBMS. SQL strings with parameters contain question marks (?).
OptionsRequired. ADODB.CommandTypeEnum. By value. As of this writing, adCmdStoredProc is not supported by these methods: ClientRst(), CnnCmd(), and CnnRst(). Only adCmdText has been extensively tested.
SQLPrmsOptional. Variant. By value. This value can be an array or delimited string literal corresponding to the parameters required by Source. The string literal must be delimited by vbNullChar characters.

Two of the arguments for Connect() has its own Enumerated Constants. The following table summarizes:

Arguments of Connect()
DataSrcRequired. String literal. By value. When DataSrcType is not set to adUDL then this contains the server name of the data source. When DataSrcType:=adUDL then this contains the path to the Microsoft Data Link file.
DataSrcType

Required. rasxADO.EnumDataSrcType. By value. Specifies the types of data sources recognized by the Class. The Class contains the appropriate ADO connection string for each type.

The Enumerated Constants for this class are:

adJetOLEDB = 0&
adJet4OLEDB = 1&
adODBCOLEDB = 2&
adOracleOLEDB = 3&
adSQL7OLEDB = 4&
adSybaseOLEDB = 5&
adUDL = 6&

When this class is used in ASP-based solutions these constants should be specified in an Include File.

ConnectType

Required. rasxADO.EnumConnectOption. By value. Specifies the connection behavior of the ADO connection object.

The Enumerated Constants for this class are:

adConnectAsynchronous = 16&
adConnectSynchronous = -1&

The value adConnectAsynchronous is frequently used in “fat” or “rich” client Solutions where Controls can report on the status of ADO connecting in real time (via SessionLog and ErrorText properties). When this class is used in ASP-based solutions these constants should be specified in an Include File.

CatalogOptional. String literal. By value. Usually specifies the name of the database.
UserNameOptional. String literal. By value. Usually specifies the name of the database user with permission to access the data.*
PasswordOptional. String literal. By value. Usually specifies the password of the database user with permission to access the data.*

*By omitting the UserName and Password when calling Connect() for SQL Server 7.x (or MSDE 1.x) on Windows NT/2000, ADOServices will use the NT/2000 login credentials to attempt to connect to the database server.

The arguments forStoredProcCmd(), andStoredProcRst() are identical. The following table summarizes:

Arguments of StoredProcCmd(), and StoredProcRst()
StoredProcNameRequired. String literal. By value. Contains the name of the stored procedure of the DBMS supported by this Class.
Params

Optional. String literal. By reference. This value can be an array or delimited string literal corresponding to the parameters required by StoredProcName. The string literal must be delimited by vbNullChar characters.

When Has2DparamArray:=True parameters passed as a two-dimensional parameter array can be updated after execution. For example, in Microsoft remote data management systems parameters modified by the OUTPUT keyword will be updated.

The 2D parameter array has the following form:

, 
, 
, 
, 

etc.

Has2DparamArrayOptional. Boolean. By value. Indicates if Params contains a two-dimensional array. See Params.
TimeOutOptional. Number. By value. The number of seconds to set the CommandTimeout property of the ADO Command object. By default it is set to 30 seconds.

Example Implementations

The function basGetKeyString() is used to retrieve string literals from a remote database. These miscellaneous strings are stored in a single table with columns name, caption and string. This function attempts to eliminate the need to “hard-code” strings into a code Module that is “globally” accessible. This function calls the stored procedure GetKeyString:

Private Function basGetKeyString(ByVal KeyName As String, _
    Optional ByVal ColumnName = "string") As String

    Dim objADO As rasxADO.ADOServices
    Dim objRst As ADODB.Recordset
    
    On Error GoTo basGetKeyString_Err
    
    basGetKeyString = vbNullString
    
    Set objADO = VBA.CreateObject("rasxADO.ADOServices")
    
    If objADO.Connect(dbSERVER, adSQL7OLEDB, _
        adConnectSynchronous, dbCATALOG, dbUSER) Then _
        Set objRst = objADO.StoredProcRst("GetKeyString", KeyName)
        If objRst.BOF And objRst.EOF Then
            'Recordset with 0 rows.
            Call Me.basAppInfoMsg("KeyName """ _
            & KeyName & """ returns no records.")
        Else
            basGetKeyString = objRst.Fields(ColumnName) & vbNullString
        End If
    Else
        GoTo basGetKeyString_Err
    End If

basGetKeyString_Exit:
    Call objADO.CloseRecordset(objRst)
    objADO.Disconnect
    Set objADO = Nothing
    Exit Function

basGetKeyString_Err:
    If (VBA.Err.Number <> 0) Or (objADO.Connection.Errors.Count > 0) Then
        Call Me.basDataErrMsg(objADO, "basGetKeyString()")
        If (VBA.Err.Number <> 0) Then
            Resume basGetKeyString_Exit
        Else
            GoTo basGetKeyString_Exit
        End If
    End If
End Function

The subroutine basFavoritesScan() is one of three functions used to generate an HTML page out the Internet Explorer Favorites stored on a local machine. This function illustrates the use of two-dimensional parameter passed to the stored procedure NewFavorite:

Private Sub basFavoritesScan(ByRef objADO As rasxADO.ADOServices, _
    Optional ByVal Directory = "\")

    Dim objFolders As Scripting.Folders
    Dim objFolder As Scripting.Folder
    Dim objFiles As Scripting.Files
    Dim objFile As Scripting.File
    
    Dim lngFolderCount As Long

    Dim varParameters(0 To 1, 0 To 1) As Variant
    'To be a two-dimensional array of form:
    '   , 
    '   , 
    '   , 
    '   , 
    'etc.
    
    'For readability:
    varParameters(0, 0) = "@path"
    varParameters(1, 0) = vbNullString
    
    varParameters(0, 1) = "@url"
    varParameters(1, 1) = vbNullString
    
    On Error GoTo basFavoritesScan_Err
    
    p_strInFile = basGetKeyString("path_root_favorites") & Directory
    Set objFolders = p_objFileSys.GetFolder(p_strInFile).SubFolders
    
    'Initialize Progress Bar.
    Call basProgress(0, 0, objFolders.Count): p_lngStatusCount = 0
    
    For Each objFolder In objFolders
    
        varParameters(1, 0) = Directory & objFolder.Name
        varParameters(1, 1) = "Directory"
        If Not(objADO.StoredProcCmd("NewFavorite", varParameters, True)) _
        Then GoTo basFavoritesScan_Err
        
        Set objFiles = objFolder.Files
        For Each objFile In objFiles
            varParameters(1, 0) = Directory _
                & objFolder.Name & "\" & objFile.Name
            varParameters(1, 1) = "File"
            If Not(objADO.StoredProcCmd("NewFavorite", _
                varParameters, True)) _
            Then GoTo basFavoritesScan_Err
        Next
        
        'Mark progress.
        p_lngStatusCount = p_lngStatusCount + 1
        Call basProgress(p_lngStatusCount)
    
    Next
    
    'Terminate Progress Bar.
    Call basProgress(0): p_lngStatusCount = 0

basFavoritesScan_Exit:
    Exit Sub

basFavoritesScan_Err:
    If (VBA.Err.Number <> 0) Or (p_objADO.Connection.Errors.Count > 0) Then
        Call Me.basDataErrMsg(p_objADO, "basFavorites()")
        If (VBA.Err.Number <> 0) Then
            Resume basFavoritesScan_Exit
        Else
            GoTo basFavoritesScan_Exit
        End If
    End If
End Sub

Future Enhancements and Free Samples

The functionality of this COM object is directly related to the needs of the Solutions that inspired its creation. It follows that these proposed future enhancements primarily anticipate future demands that may be. What “may be” could be:

Recognizing ADOX. The Microsoft Access 2000 Project File (.ADP) is certainly using ADOX to support the UI. It is possible that one can “outgrow” what Microsoft is already offering through its use of ADOX in Access 2000. It may be prudent to prepare for that day. Chapter 15 of the ADO Programmer’s Guide, “ADOX Fundamentals” is a good start.

Recognizing ADO MD. Support for multidimensional data providers via ADO appears to be limited to OLE DB providers to Microsoft systems. However, exploring the issue for a few minutes can’t hurt. Mike Gunderloy’s Advanced Data Shaping article for Smart Access get right into the thick of it.

Recognizing XML. Paul Enfield’s Using Server-Side XSL for Early Rendering: Generating Frequently Accessed Data-Driven Web Pages in Advance seems to take ADO out of picture when he shows us an XML world. However, ADO 2.6 can be used to open XML files into an ADO Recordset and can even remind me of a really clunky in-memory database. The most compelling treatment of this subject comes from Don Box, his Using ADO to Create XML-based Recordsets, which had me seriously considering using the ADO schema.1

Recognizing ADO.NET. Having seen the simplified object model in ADO.NET it is possible that my class will not be needed in .NET projects. This remains to be seen.

DownloadDescription
rasxADO.zipCompiled DLL and associated library files.

Endnotes

1 The main thing that stopped me in my tracks was the amount of security permissions I would have to give the anonymous access account of IIS in order to persist ADO XML files. The problem is that the file can’t be saved twice: my code would have to delete the file first before saving a new one from memory. Not good. Curiously, the “save method” of the MSXML 4.x DOM object does not have this problem.

 
This document was last reviewed on Tuesday, April 26, 2005 at 06:37 PM PDT.
Copyright© 2008 by Bryan D. Wilhite All rights reserved. No part of this material may be used or reproduced in any form or by any means, or stored in a database or retrieval system, without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this material for any purpose other than your own personal use is a violation of United States copyright laws.

The information provided by Bryan D. Wilhite at kintespace.com is provided “as is” without warranty of any kind. In no event shall Bryan D. Wilhite or any of his affiliates be liable for any damages whatsoever including, but not limited to, direct, indirect, incidental, consequential, loss of business profits or special damages due to material published by Bryan D. Wilhite or any of his affiliates.