I use ADO (specifically for accessing SQL) daily at work. So, I finally decided that I was going to create a class that makes it simple for myself and other programmers on the job to use. Just the other day, I saw @MathieuGuindon's post about creating parameters on the fly, and I really liked his Idea, so I implemented parts of it on top of some of the stuff that I already had.
As for the code itself, I have really struggled with determining if I am using the appropriate level of abstraction for properties and methods, which is why I am here.
ADODBWrapper
Option Explicit
Private Type TADODBWrapper
    ParameterNumericScale As Byte
    ParameterPrecision As Byte
    ADOErrors As ADODB.Errors
    HasADOError As Boolean
End Type
Private this As TADODBWrapper
Public Property Get ParameterNumericScale() As Byte
    ParameterNumericScale = this.ParameterNumericScale
End Property
Public Property Let ParameterNumericScale(ByVal valueIn As Byte)
    this.ParameterNumericScale = valueIn
End Property
Public Property Get ParameterPrecision() As Byte
    ParameterPrecision = this.ParameterPrecision
End Property
Public Property Let ParameterPrecision(ByVal valueIn As Byte)
    this.ParameterPrecision = valueIn
End Property
Public Property Get Errors() As ADODB.Errors
    Set Errors = this.ADOErrors
End Property
Public Property Get HasADOError() As Boolean
    HasADOError = this.HasADOError
End Property
Private Sub Class_Terminate()
    With this
        .ParameterNumericScale = Empty
        .ParameterPrecision = Empty
        .HasADOError = Empty
        Set .ADOErrors = Nothing
    End With
End Sub
Public Function GetRecordSet(ByRef Connection As ADODB.Connection, _
                             ByVal CommandText As String, _
                             ByVal CommandType As ADODB.CommandTypeEnum, _
                             ByVal CursorType As ADODB.CursorTypeEnum, _
                             ByVal LockType As ADODB.LockTypeEnum, _
                             ParamArray ParameterValues() As Variant) As ADODB.Recordset
    Dim Cmnd As ADODB.Command
        ValidateConnection Connection
        On Error GoTo CleanFail
        Set Cmnd = CreateCommand(Connection, CommandText, CommandType, CVar(ParameterValues)) 'must convert paramarray to
                                                                                              'a variant in order to pass
                                                                                              'to another function
        'Note:  When used on a client-side Recordset object,
        '       the CursorType property can be set only to adOpenStatic.
        Set GetRecordSet = New ADODB.Recordset
            GetRecordSet.CursorType = CursorType
            GetRecordSet.LockType = LockType
        Set GetRecordSet = Cmnd.Execute(Options:=ExecuteOptionEnum.adAsyncFetch)
CleanExit:
    Set Cmnd = Nothing
    Exit Function
CleanFail:
    PopulateADOErrorObject Connection
    Resume CleanExit
End Function
Public Function GetDisconnectedRecordSet(ByRef ConnectionString As String, _
                                         ByVal CursorLocation As ADODB.CursorLocationEnum, _
                                         ByVal CommandText As String, _
                                         ByVal CommandType As ADODB.CommandTypeEnum, _
                                         ParamArray ParameterValues() As Variant) As ADODB.Recordset
    Dim Cmnd As ADODB.Command
    Dim CurrentConnection As ADODB.Connection
        On Error GoTo CleanFail
        Set CurrentConnection = CreateConnection(ConnectionString, CursorLocation)
        Set Cmnd = CreateCommand(CurrentConnection, CommandText, CommandType, CVar(ParameterValues)) 'must convert paramarray to
                                                                                                     'a variant in order to pass
                                                                                                     'to another function
        Set GetDisconnectedRecordSet = New ADODB.Recordset
        With GetDisconnectedRecordSet
            .CursorType = adOpenStatic          'Must use this cursortype and this locktype to work with a disconnected recordset
            .LockType = adLockBatchOptimistic
            .Open Cmnd, , , , adAsyncFetch
            'disconnect the recordset
            Set .ActiveConnection = Nothing
        End With
CleanExit:
    Set Cmnd = Nothing
    If Not CurrentConnection Is Nothing Then: If CurrentConnection.State > 0 Then CurrentConnection.Close
    Set CurrentConnection = Nothing
    Exit Function
CleanFail:
    PopulateADOErrorObject CurrentConnection
    Resume CleanExit
End Function
Public Function QuickExecuteNonQuery(ByVal ConnectionString As String, _
                                     ByVal CommandText As String, _
                                     ByVal CommandType As ADODB.CommandTypeEnum, _
                                     ByRef RecordsAffectedReturnVal As Long, _
                                     ParamArray ParameterValues() As Variant) As Boolean
    Dim Cmnd As ADODB.Command
    Dim CurrentConnection As ADODB.Connection
        On Error GoTo CleanFail
        Set CurrentConnection = CreateConnection(ConnectionString, adUseServer)
        Set Cmnd = CreateCommand(CurrentConnection, CommandText, CommandType, CVar(ParameterValues))    'must convert paramarray to
                                                                                                        'a variant in order to pass
                                                                                                        'to another function
        Cmnd.Execute RecordsAffected:=RecordsAffectedReturnVal, Options:=ExecuteOptionEnum.adExecuteNoRecords
        QuickExecuteNonQuery = True
CleanExit:
    Set Cmnd = Nothing
    If Not CurrentConnection Is Nothing Then: If CurrentConnection.State > 0 Then CurrentConnection.Close
    Set CurrentConnection = Nothing
    Exit Function
CleanFail:
    PopulateADOErrorObject CurrentConnection
    Resume CleanExit
End Function
Public Function ExecuteNonQuery(ByRef Connection As ADODB.Connection, _
                                ByVal CommandText As String, _
                                ByVal CommandType As ADODB.CommandTypeEnum, _
                                ByRef RecordsAffectedReturnVal As Long, _
                                ParamArray ParameterValues() As Variant) As Boolean
    Dim Cmnd As ADODB.Command
        ValidateConnection Connection
        On Error GoTo CleanFail
        Set Cmnd = CreateCommand(Connection, CommandText, CommandType, CVar(ParameterValues))    'must convert paramarray to
                                                                                                 'a variant in order to pass
                                                                                                 'to another function
        Cmnd.Execute RecordsAffected:=RecordsAffectedReturnVal, Options:=ExecuteOptionEnum.adExecuteNoRecords
        ExecuteNonQuery = True
CleanExit:
    Set Cmnd = Nothing
    Exit Function
CleanFail:
    PopulateADOErrorObject Connection
    Resume CleanExit
End Function
Public Function CreateConnection(ByRef ConnectionString As String, ByVal CursorLocation As ADODB.CursorLocationEnum) As ADODB.Connection
        On Error GoTo CleanFail
        Set CreateConnection = New ADODB.Connection
            CreateConnection.CursorLocation = CursorLocation
            CreateConnection.Open ConnectionString
CleanExit:
    Exit Function
CleanFail:
    PopulateADOErrorObject CreateConnection
    Resume CleanExit
End Function
Private Function CreateCommand(ByRef Connection As ADODB.Connection, _
                               ByVal CommandText As String, _
                               ByVal CommandType As ADODB.CommandTypeEnum, _
                               ByRef ParameterValues As Variant) As ADODB.Command
        Set CreateCommand = New ADODB.Command
        With CreateCommand
            .ActiveConnection = Connection
            .CommandText = CommandText
            .Prepared = True
            .CommandTimeout = 0
            AppendParameters CreateCommand, ParameterValues
            .CommandType = CommandType
        End With
End Function
Private Sub AppendParameters(ByRef Command As ADODB.Command, ByRef ParameterValues As Variant)
    Dim i As Long
    Dim ParamVal As Variant
        If UBound(ParameterValues) = -1 Then Exit Sub 'not allocated
        For i = LBound(ParameterValues) To UBound(ParameterValues)
            ParamVal = ParameterValues(i)
            Command.Parameters.Append ToADOInputParameter(ParamVal)
        Next i
End Sub
Private Function ToADOInputParameter(ByVal ParameterValue As Variant) As ADODB.Parameter
    Dim ResultParameter As New ADODB.Parameter
    If Me.ParameterNumericScale = 0 Then Me.ParameterNumericScale = 10
    If Me.ParameterPrecision = 0 Then Me.ParameterPrecision = 2
        With ResultParameter
            Select Case VarType(ParameterValue)
                Case vbInteger
                    .Type = adInteger
                Case vbLong
                    .Type = adInteger
                Case vbSingle
                    .Type = adSingle
                    .Precision = Me.ParameterPrecision
                    .NumericScale = Me.ParameterNumericScale
                Case vbDouble
                    .Type = adDouble
                    .Precision = Me.ParameterPrecision
                    .NumericScale = Me.ParameterNumericScale
                Case vbDate
                    .Type = adDate
                Case vbCurrency
                    .Type = adCurrency
                    .Precision = Me.ParameterPrecision
                    .NumericScale = Me.ParameterNumericScale
                Case vbString
                    .Type = adVarChar
                    .Size = Len(ParameterValue)
                Case vbBoolean
                    .Type = adBoolean
            End Select
            .Direction = ADODB.ParameterDirectionEnum.adParamInput
            .value = ParameterValue
        End With
    Set ToADOInputParameter = ResultParameter
End Function
Private Sub ValidateConnection(ByRef Connection As ADODB.Connection)
    If Connection.Errors.Count = 0 Then Exit Sub
        If Not this.HasADOError Then PopulateADOErrorObject Connection
        Dim ADOError As ADODB.Error
        Set ADOError = GetError(Connection.Errors, Connection.Errors.Count - 1) 'Note: 0 based collection
        Err.Raise ADOError.Number, ADOError.Source, ADOError.Description, ADOError.HelpFile, ADOError.HelpContext
End Sub
Private Sub PopulateADOErrorObject(ByRef Connection As ADODB.Connection)
        If Connection.Errors.Count = 0 Then Exit Sub
        this.HasADOError = True
        Set this.ADOErrors = Connection.Errors
End Sub
Public Function ErrorsToString() As String
    Dim ADOError As ADODB.Error
    Dim i As Long
    Dim ErrorMsg As String
        For Each ADOError In this.ADOErrors
            i = i + 1
            With ADOError
                ErrorMsg = ErrorMsg & "Count: " & vbTab & i & vbNewLine
                ErrorMsg = ErrorMsg & "ADO Error Number: " & vbTab & CStr(.Number) & vbNewLine
                ErrorMsg = ErrorMsg & "Description: " & vbTab & .Description & vbNewLine
                ErrorMsg = ErrorMsg & "Source: " & vbTab & .Source & vbNewLine
                ErrorMsg = ErrorMsg & "NativeError: " & vbTab & CStr(.NativeError) & vbNewLine
                ErrorMsg = ErrorMsg & "HelpFile: " & vbTab & .HelpFile & vbNewLine
                ErrorMsg = ErrorMsg & "HelpContext: " & vbTab & CStr(.HelpContext) & vbNewLine
                ErrorMsg = ErrorMsg & "SQLState: " & vbTab & .SqlState & vbNewLine
            End With
        Next
    ErrorsToString = ErrorMsg
End Function
Public Function GetError(ByRef ADOErrors As ADODB.Errors, ByVal Index As Variant) As ADODB.Error
    Set GetError = ADOErrors.Item(Index)
End Function
I provide two methods for returning a recordset:
- GetRecordSet: The client code owns the- Connectionobject so cleanup should be managed by them.
- GetDisconnectedRecordset: this method owns and manages the- Connectionobject itself.
And Two Methods for Executing a Command that does not return an records:
- ExecuteNonQuery: Just as in- GetRecordSet, the client owns and manages the connection.
- QuickExecuteNonQuery: Just as was done in this post, I used the "Quick" prefix to refer to an "overload" method that owns its own connection.
The Properties ParameterNumericScale and ParameterPrecision are used for setting the total number of digits and number of digits to the right of the decimal point in a number respectively. I opted to make these Properties instead of passing them as function parameters to either of GetRecordSet, GetDisconnectedRecordset, ExecuteNonQuery, or QuickExecuteNonQuery, because I felt that it was far too cluttered otherwise. 
The Errors property exposes the ADODB.Errors collection which is available only through the Connection object, without actually exposing the connection itself. The reason for this is that depending on the method used in the client code, the Connection may or may not be available to the client...also, it would just be a bad idea all around to have a globally available Connection object. Saying that, if an error occurs that does not populate VBA runtime's native Err object, then I am populating the the Error property in the class with any the errors found in the Connnection.Errors collection, so that I can use return useful error information to the client code. 
CreateCommand creates an AADODB.Command object and uses ApendParameters with ToADOInputParameter to create ADODB.Parameter objects on the fly by interpreting the datatype passed in to the ParameterValues array and generating the equivalent ADODB datatype to pass to the database.   
Usage:
Sub TestingSQLQueryText()
    Dim SQLDataAdapter As ADODBWrapper
    Dim Conn As ADODB.Connection
    Dim rsConnected As ADODB.Recordset
        Set SQLDataAdapter = New ADODBWrapper
        On Error GoTo CleanFail
        Set Conn = SQLDataAdapter.CreateConnection(CONN_STRING, adUseClient)
        Set rsConnected = SQLDataAdapter.GetRecordSet(Conn, "Select * From SOME_TABLE Where SOME_FIELD=?", _
                                                       adCmdText, adOpenStatic, adLockReadOnly, "1361")
        FieldNamesToRange rsConnected, Sheet1.Range("A1")
        rsConnected.Filter = "[SOME_FIELD]='215485'"
        Debug.Print rsConnected.RecordCount
        Sheet1.Range("A2").CopyFromRecordset rsConnected
        Conn.Close
        Set Conn = Nothing
    '***********************************************************************************************
    Dim rsDisConnected As ADODB.Recordset
        Set rsDisConnected = SQLDataAdapter.GetDisconnectedRecordSet(CONN_STRING, adUseClient, _
                                                                     "Select * From SOME_TABLE Where SOME_FIELD=?", _
                                                                     adCmdText, "1361")
        FieldNamesToRange rsDisConnected, Sheet2.Range("A1")
        rsDisConnected.Filter = "[SOME_FIELD]='215485'"
        Debug.Print rsDisConnected.RecordCount
        Sheet2.Range("A2").CopyFromRecordset rsDisConnected
CleanExit:
    If Not Conn Is Nothing Then: If Conn.State > 0 Then Conn.Close
    Set Conn = Nothing
    Exit Sub
CleanFail:
    If SQLDataAdapter.HasADOError Then Debug.Print SQLDataAdapter.ErrorsToString()
    Resume CleanExit
End Sub
Sub TestingStoredProcedures()
    Dim SQLDataAdapter As ADODBWrapper
    Dim Conn As ADODB.Connection
    Dim rsConnected As ADODB.Recordset
        Set SQLDataAdapter = New ADODBWrapper
        On Error GoTo CleanFail
        Set Conn = SQLDataAdapter.CreateConnection(CONN_STRING, adUseClient)
        Set rsConnected = SQLDataAdapter.GetRecordSet(Conn, "SOME_STORED_PROC", _
                                                       adCmdStoredProc, adOpenStatic, adLockReadOnly, "1361,476")
        FieldNamesToRange rsConnected, Sheet1.Range("A1")
        rsConnected.Filter = "[SOME_FIELD]='1361'"
        Debug.Print rsConnected.RecordCount
        Sheet1.Range("A2").CopyFromRecordset rsConnected
        Conn.Close
        Set Conn = Nothing
    '***********************************************************************************************
    Dim rsDisConnected As ADODB.Recordset
        Set rsDisConnected = SQLDataAdapter.GetDisconnectedRecordSet(CONN_STRING, adUseClient, _
                                                                     "SOME_STORED_PROC", _
                                                                     adCmdStoredProc, "1361,476")
        FieldNamesToRange rsDisConnected, Sheet2.Range("A1")
        rsDisConnected.Filter = "[SOME_FIELD]='1361'"
        Debug.Print rsDisConnected.RecordCount
        Sheet2.Range("A2").CopyFromRecordset rsDisConnected
CleanExit:
    If Not Conn Is Nothing Then: If Conn.State > 0 Then Conn.Close
    Set Conn = Nothing
    Exit Sub
CleanFail:
    If SQLDataAdapter.HasADOError Then Debug.Print SQLDataAdapter.ErrorsToString()
    Resume CleanExit
End Sub
Sub TestingNonQuery()
    Dim SQLDataAdapter As ADODBWrapper
    Dim Conn As ADODB.Connection
    Dim RecordsUpdated1 As Long
        Set SQLDataAdapter = New ADODBWrapper
        On Error GoTo CleanFail
        Set Conn = SQLDataAdapter.CreateConnection(CONN_STRING, adUseClient)
        If SQLDataAdapter.ExecuteNonQuery(Conn, "Update SOME_TABLE Where SOME_FIELD = ?", _
                                          adCmdText, RecordsUpdated, "2") Then Debug.Print RecordsUpdated
    '***********************************************************************************************
    Dim RecordsUpdated2 As Long
        If SQLDataAdapter.QuickExecuteNonQuery(CONN_STRING, "SOME_STORED_PROC", _ 
                                                adCmdStoredProc, "1361, 476") Then Debug.Print RecordsUpdated2
CleanExit:
    If Not Conn Is Nothing Then: If Conn.State > 0 Then Conn.Close
    Set Conn = Nothing
    Exit Sub
CleanFail:
    If SQLDataAdapter.HasADOError Then Debug.Print SQLDataAdapter.ErrorsToString()
    Resume CleanExit
End Sub