Skip to main content
Tweeted twitter.com/#!/StackCodeReview/status/471556410225209344
fixed code block
Source Link
Mathieu Guindon
  • 75.1k
  • 18
  • 191
  • 463
' ***************************************************************************
' * Class: DSN                              *
' * Author: Christopher J. McClellan                                    *
' * Published under Creative Commons Attribution-Share Alike            *
' * http://creativecommons.org/licenses/by-sa/3.0/                      *
' *                                                                         *
' * Allows for easy creation of DSN entries in the ODBC Administrator by    *
' *     leveraging the Registry class.                  *
' * Entries in the ODBC Admin are not created until the                     *
' *         Create() sub is called.                                         *
' ***************************************************************************

Private Const CLASS_NAME As String = "DSN" 'for error handling

Public Enum eDSN_Bitmode
    DSN_64BIT = 0
    DSN_32BIT = 1
End Enum

Private Const REG_KEYNODE_32 As String = "software\wow6432Node\ODBC"
Private Const REG_KEYNODE_64 As String = "software\ODBC"

Public Enum eDSN_type
    DSN_SYSTEM = 0
    DSN_USER = 1
End Enum

Public Enum eDSN_Driver
    DSN_DRIVER_EMPTY = 0
    DSN_DRIVER_SQLSERVER = 1
    DSN_DRIVER_SQLSERVER10 = 2
    DSN_DRIVER_SQLSERVER11 = 3
    DSN_DRIVER_ORA11G = 11
End Enum

Private Const DSN_DRIVER_SQLSERVER_NAME As String = "SQL Server"
Private Const DSN_DRIVER_SQLSERVER10_NAME As String = "SQL Server Native Client 10.0"
Private Const DSN_DRIVER_SQLSERVER11_NAME As String = "SQL Server Native Client 11.0"
Private Const DSN_DRIVER_ORA11G_NAME As String = "Oracle in OraClient11g_home1"

Public Enum eORA_CommitMode
    ORA_COMMIT_IfSuccessful
    ORA_COMMIT_FirstFailure
    ORA_COMMIT_AllSuccessful
End Enum

Private Const ORA_COMMIT_IfSuccessful_Txt As String = "IfAllSuccessful"
Private Const ORA_COMMIT_FirstFailure_Txt As String = "UpToFirstFailure"
Private Const ORA_COMMIT_AllSuccessful_Txt As String = "AllSuccessful"

Public Enum eORA_NumericSetting
    ORA_NUMSET_OracleNLS
    ORA_NUMSET_MSRegional
    ORA_NUMSET_US
End Enum

Private Const ORA_NUMSET_OracleNLS_txt As String = "NLS"
Private Const ORA_NUMSET_MSRegional_txt As String = "MS"
Private Const ORA_NUMSET_US_txt As String = "US"

' shared props
Private mName As String
Private mDriver As eDSN_Driver
Private mDSNType As eDSN_type
Private mBitMode As eDSN_Bitmode
Private mDriverFile As String
Private mDesc As String
' sql server props
Private mServer As String
Private mDatabase As String
Private mTrustedConnection As Boolean
' ora props
Private mAppAttributes As Boolean
Private mReadOnlyConn As Boolean
Private mCommitMode As eORA_CommitMode
Private mBindAsDate As Boolean
Private mBindAsFloat As Boolean
Private mCacheBufferSize As Long
Private mCloseCursor As Boolean
Private mDisableDPM As Boolean
Private mDisableMTS As Boolean
Private mDisableRuleHint As Boolean
Private mExecSchemaOpt As String
Private mExecSyntax As Boolean
Private mFailover As Boolean
Private mFailoverDelay As Long
Private mFailoverRetryCount As Integer
Private mFetchBufferSize As Long
Private mForceWChar As Boolean
Private mLobs As Boolean
Private mMetaDataIdDefault As Boolean
Private mNumericSetting As eORA_NumericSetting
Private mQueryTimeout As Boolean
Private mResultSets As Boolean
Private mStatementCache As Boolean
Private mUserID As String
Private mPwd As String

' defaults
Private Const DSN_DFLT_CacheBufferSize As Long = 20
Private Const DSN_DFLT_FailoverDelay As Long = 10
Private Const DSN_DFLT_FailoverRetryCount As Integer = 10
Private Const DSN_DFLT_FetchBufferSize As Long = 64000
''''''''''''''''''''''''''''BEGIN SHARED PROPERTIES''''''''''''''''''''''''''''''
Property Get NAME() As String
    NAME = mName
End Property

Property Let NAME(str As String)
    mName = str
End Property

Property Get Driver() As eDSN_Driver
' defaults to empty via enum
    Driver = mDriver
End Property

Property Let Driver(eDriver As eDSN_Driver)
    mDriver = eDriver
End Property

Property Get DriverName() As String
' read only property
Select Case mDriver
    Case DSN_DRIVER_EMPTY
        DriverName = ""
    Case DSN_DRIVER_SQLSERVER
        DriverName = DSN_DRIVER_SQLSERVER_NAME
    Case DSN_DRIVER_SQLSERVER10
        DriverName = DSN_DRIVER_SQLSERVER10_NAME
    Case DSN_DRIVER_SQLSERVER11
        DriverName = DSN_DRIVER_SQLSERVER11_NAME
    Case DSN_DRIVER_ORA11G
        DriverName = DSN_DRIVER_ORA11G_NAME
    End Select
End Property

Property Get DSNType() As eDSN_type
    DSNType = mDSNType
End Property

Property Let DSNType(pDSNType As eDSN_type)
    mDSNType = pDSNType
End Property

Property Get BitMode() As eDSN_Bitmode
    BitMode = mBitMode
End Property

Property Let BitMode(pBitMode As eDSN_Bitmode)
    ' defaults to 64 bit via the enum
    mBitMode = pBitMode
End Property

Property Get DriverFile() As String
' read only property
' @ todo - optimize
' save effort by only checking the registry the first time
    'If mDriverFile = "" Then
        mDriverFile = getDriver
        DriverFile = mDriverFile
    'Else
    '    DriverFile = mDriverFile
    'End If
End Property

Public Property Get Description() As String
    Description = mDesc
End Property

Public Property Let Description(desc As String)
    mDesc = desc
End Property

Property Get Server() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Server = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Server = Me.NAME
        Case Else
            Server = mServer
    End Select
End Property

Property Let Server(str As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mServer = str
    Else
        ErrRaise_NotSupported
    End If
End Property

Private Property Get RegNode() As String
' read only property
    Select Case Me.BitMode
        Case DSN_32BIT
            RegNode = REG_KEYNODE_32
        Case DSN_64BIT
            RegNode = REG_KEYNODE_64
        Case Else
            Err.Raise vbObjectError + 25002, CurrentProject.NAME & "." & CLASS_NAME, "Invalid Bitmode"
    End Select
End Property

Private Property Get HKey() As Long
' read only property
' determine which HKEY to use
    Select Case Me.DSNType
        Case DSN_USER
            HKey = HKEY_CURRENT_USER
        Case DSN_SYSTEM
            HKey = HKEY_LOCAL_MACHINE
        Case Else
            Err.Raise vbObjectError + 25001, CurrentProject.NAME & "." & CLASS_NAME, "Invalid DSNType or DSNType not set"
    End Select
End Property
''''''''''''''''''''''''''''''END SHARED PROPERTIES''''''''''''''''''''''''
''''''''''''''''''''''''''''BEGIN ORA PROPERTIES'''''''''''''''''''''''''''
Public Property Get AppAttributes() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            AppAttributes = False
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            AppAttributes = mAppAttributes
        Case Else
            AppAttributes = False
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let AppAttributes(bool As Boolean)
    If Me.Driver = DSN_DRIVER_ORA11G Then
        mAppAttributes = bool
    Else
        mAppAttributes = False
        ErrRaise_NotSupported
    End If
End Property

Public Property Get ReadOnlyConnection() As Boolean
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Attributes                                        '
'   true = "R" (read); false = "W" (write)          '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ReadOnlyConnection = True   'return true as a precaution
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            ReadOnlyConnection = mReadOnlyConn
        Case Else
            ReadOnlyConnection = True
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let ReadOnlyConnection(bool As Boolean)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mReadOnlyConn = bool
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BatchAutoCommitMode() As eORA_CommitMode
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BatchAutoCommitMode = mCommitMode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let BatchAutoCommitMode(mode As eORA_CommitMode)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mCommitMode = mode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BindAsDate() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BindAsDate = mBindAsDate
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

'.... lots of properties with the same logic omitted due to space constraints

' @todo - add sql server support for sql server login
Public Property Get USERID() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            USERID = mUserID
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let USERID(uid As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mUserID = uid
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

' @todo - add sql server support for sql server login
Public Property Get Password() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Password = mPwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let Password(pwd As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mPwd = pwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property
''''''''''''''''''''''''''''''END ORA PROPERTIES'''''''''''''''''''''''''''
''''''''''''''''''''''''BEGIN SQL SERVER PROPERTIES''''''''''''''''''''''''

Property Get Database() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Database = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            'Database = Err_NotSupported
            ErrRaise_NotSupported
        Case Else
            Database = mDatabase
    End Select
End Property

Property Let Database(pDatabase As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mDatabase = pDatabase
    Else
        'mDatabase = Err_NotSupported
        ErrRaise_NotSupported
    End If
End Property

Property Get TrustedConnection() As Boolean
    TrustedConnection = mTrustedConnection
End Property

Property Let TrustedConnection(value As Boolean)
    mTrustedConnection = value
End Property
'''''''''''''''''''''''END SQL SERVER PROPERTIES'''''''''''''''''''''''''''''''''''''
Private Function getDriver() As String
'**********************************************
' returns the file path of the .dll driver file
'**********************************************
Const PROC_NAME As String = "getDriver"
On Error GoTo ErrHandler:
    
    If Me.Driver = DSN_DRIVER_EMPTY Then
        getDriver = ""
    Else
        'determine bitmode
        Dim skey As String
        skey = RegNode
     
        ' find ODBC node
        Dim odbcDriverNode As String
        odbcDriverNode = findSectionKey(HKEY_LOCAL_MACHINE, skey, Me.DriverName)
        If odbcDriverNode <> "" Then
            'create new registry object and find the driver
            Dim reg As New Registry
            With reg
                .ClassKey = HKEY_LOCAL_MACHINE
                .sectionKey = odbcDriverNode
                .ValueKey = "Driver"
                If .value = "" Then
                    Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
                Else
                    'return
                    getDriver = .value
                End If
            End With
        Else
            Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
        End If
    End If
ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function

ErrHandler:
    errBox CLASS_NAME, PROC_NAME
    Resume ExitFunction:
    
End Function

Private Function findSectionKey(regClassKey As ERegistryClassConstants, sectToLookIn As String, sectToFind As String) As String
'******************************************************************
' returns full section key as string
'   if a matching section key is not found, returns an empty string
'******************************************************************
On Error GoTo ErrHandler:
Const PROC_NAME As String = "findSectionKey"

    Dim sSect() As String ' string array of subnodes
    Dim iSectCount As Long ' length of sSect array
    Dim reg As New Registry
    With reg
        .ClassKey = regClassKey
        .sectionKey = sectToLookIn
        .EnumerateSections sSect, iSectCount
        Dim i As Long
        For i = 1 To iSectCount
            'Debug.Print .sectionKey & "\" & sSect(i)
            If findSectionKey = "" Then
                If sSect(i) = sectToFind Then
                    ' found node
                    findSectionKey = .sectionKey & "\" & sSect(i)
                    Exit For
                Else
                    'search subnodes via recursion
                    findSectionKey = findSectionKey(regClassKey, .sectionKey & "\" & sSect(i), sectToFind)
                End If
            Else
                Exit For
            End If
        Next i
    End With

ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function
ErrHandler:
    errBox CLASS_NAME, PROC_NAME
End Function

Public Sub Create(Optional overwrite As Boolean = True)
' ***************************************************************************************************
' Creates a new registry entry defining the DSN (or modifies existing one with matching reg key)
' The actual registry entry (thus the DSN in the odbc admin) is not created until this sub is called.

 ' ***************************************************************************************************
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            createORA overwrite
        Case Else 'some sql server version
            createSQL overwrite
    End Select
        
End Sub

Private Sub createSQL(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            'driver
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            'server
            .ValueKey = "Server"
            .ValueType = REG_SZ
            .value = Me.Server
            'database
            .ValueKey = "Database"
            .ValueType = REG_SZ
            .value = Me.Database
            'trusted connection
            .ValueKey = "Trusted_Connection"
            .ValueType = REG_SZ
            If Me.TrustedConnection = True Then
                .value = "Yes"
            Else
                .value = "No"
            End If
            'last user
            .ValueKey = "LastUser"
            .ValueType = REG_SZ
            .Value = Environ("UserName")
            ' Description
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub createORA(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            .ValueKey = "Application Attributes"
            .ValueType = REG_SZ
            .value = boolAsString(Me.AppAttributes)
            
            .ValueKey = "Attributes"
            .ValueType = REG_SZ
            If Me.ReadOnlyConnection Then
                .value = "R"
            Else
                .value = "W"
            End If
            
            .ValueKey = "BatchAutocommitMode"
            .ValueType = REG_SZ
            Select Case Me.BatchAutoCommitMode
                Case ORA_COMMIT_AllSuccessful
                    .value = ORA_COMMIT_AllSuccessful_Txt
                Case ORA_COMMIT_FirstFailure
                    .value = ORA_COMMIT_FirstFailure_Txt
                Case ORA_COMMIT_IfSuccessful
                    .value = ORA_COMMIT_IfSuccessful_Txt
            End Select
            
            .ValueKey = "BindAsDATE"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsDate)
            
            .ValueKey = "BindAsFLOAT"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsFloat)
            
            .ValueKey = "CacheBufferSize"
            .ValueType = REG_SZ
            .value = Me.CacheBufferSize
            
            .ValueKey = "CloseCursor"
            .ValueType = REG_SZ
            .value = boolAsString(Me.CloseCursor)
            
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
            
            .ValueKey = "DisableDPM"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableDPM)
            
            .ValueKey = "DisableMTS"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableMTS)
            
            .ValueKey = "DisableRULEHint"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableRULEHint)
            
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            
            .ValueKey = "DSN"
            .ValueType = REG_SZ
            .value = Me.NAME
            
            .ValueKey = "EXECSchemaOpt"
            .ValueType = REG_SZ
            .value = Me.EXECSchemaOpt
            
            .ValueKey = "EXECSyntax"
            .ValueType = REG_SZ
            .value = boolAsString(Me.EXECSyntax)
            
            .ValueKey = "Failover"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Failover)
            
            .ValueKey = "FailoverDelay"
            .ValueType = REG_SZ
            .value = Me.FailoverDelay
            
            .ValueKey = "FailoverRetryCount"
            .ValueType = REG_SZ
            .value = Me.FailoverRetryCount
            
            .ValueKey = "FetchBufferSize"
            .ValueType = REG_SZ
            .value = Me.FetchBufferSize
            
            .ValueKey = "ForceWCHAR"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ForceWChar)
            
            .ValueKey = "Lobs"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Lobs)
            
            .ValueKey = "MetadataIdDefault"
            .ValueType = REG_SZ
            .value = boolAsString(Me.MetadataIdDefault)
            
            .ValueKey = "NumericSetting"
            .ValueType = REG_SZ
            Select Case Me.NumericSetting
                Case ORA_NUMSET_OracleNLS
                    .value = ORA_NUMSET_OracleNLS_txt
                Case ORA_NUMSET_MSRegional
                    .value = ORA_NUMSET_MSRegional_txt
                Case ORA_NUMSET_US
                    .value = ORA_NUMSET_US_txt
            End Select
            
            .ValueKey = "Password"
            .ValueType = REG_SZ
            .value = Me.Password
            
            .ValueKey = "QueryTimeout"
            .ValueType = REG_SZ
            .value = boolAsString(Me.QueryTimeout)
            
            .ValueKey = "ResultSets"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ResultSets)
            
            .ValueKey = "ServerName"
            .ValueType = REG_SZ
            .value = Me.Server
            
            .ValueKey = "StatementCache"
            .ValueType = REG_SZ
            .value = boolAsString(Me.StatementCache)
            
            .ValueKey = "UserID"
            .ValueType = REG_SZ
            .value = Me.USERID
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub addDataSourceEntry()
    Dim reg As Registry
    Set reg = New Registry
    With reg
            .ClassKey = HKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .ValueType = REG_SZ
            .value = Me.DriverName
    End With
End Sub

Public Function Exists() As Boolean
' Assumes Name, DSNType, and Bitmode are set
    Dim reg As New Registry
    Dim SCTKEY As String
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        If .KeyExists Then
            Exists = True
        Else
            Exists = False
        End If
    End With
End Function

Public Sub Delete()
    Dim reg As New Registry
    With reg
        .ClassKey = HKey
        'delete registry Section key
        .sectionKey = RegNode & "\odbc.ini\" & Me.NAME
        If Exists Then
            .DeleteKey
            'delete related ODBC Datasource ValueKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .DeleteValue
        End If
    End With
End Sub

Private Function boolAsString(ByVal bool As Boolean) As String
    If bool = True Then
        boolAsString = "T"
    Else
        boolAsString = "F"
    End If
End Function

Private Sub Class_Initialize()
' bypass all setters & getters when initializing

    ' shared props
    'mName =
    mDriver = DSN_DRIVER_EMPTY
    mDSNType = DSN_SYSTEM
    mBitMode = DSN_32BIT
    'mDriverFile =
    'mDesc =
    'mServer =
    
    ' sql server
    'mDatabase =
    mTrustedConnection = True
    
    ' oracle
    mAppAttributes = False
    mReadOnlyConn = True
    mCommitMode = ORA_COMMIT_IfSuccessful
    mBindAsDate = False
    mBindAsFloat = False
    mCacheBufferSize = DSN_DFLT_CacheBufferSize
    mCloseCursor = False
    mDisableDPM = False
    mDisableMTS = True
    mDisableRuleHint = True
    mExecSchemaOpt = ""
    mExecSyntax = False
    mFailover = True
    mFailoverDelay = DSN_DFLT_FailoverDelay
    mFailoverRetryCount = DSN_DFLT_FailoverRetryCount
    mFetchBufferSize = DSN_DFLT_FetchBufferSize
    mForceWChar = False
    mLobs = True
    mMetaDataIdDefault = False
    mNumericSetting = ORA_NUMSET_OracleNLS
    mQueryTimeout = False
    mResultSets = False
    mStatementCache = False
    ' @todo - make sql serv support sql server login; move to shared
    'mUserID =
    'mPwd =

End Sub

Private Sub errBox(ModuleName As String, procName As String, Optional style As VbMsgBoxStyle = vbCritical)
    MsgBox "Module: " & ModuleName & vbCrLf & _
        "Procedure: " & procName & vbCrLf & _
        Err.Description, _
        style, _
        "Runtime Error: " & Err.number
End Sub

Private Sub ErrRaise_NotSupported()
    Err.Raise vbObjectError + 25010, CurrentProject.NAME & "." & CLASS_NAME, "Driver does not support the property."
End Sub

Private Sub ErrRaise_DriverNotSet()
    Err.Raise vbObjectError + 25020, CurrentProject.NAME & "." & CLASS_NAME, "Driver property is not set."
End Sub
' ***************************************************************************
' * Class: DSN                              *
' * Author: Christopher J. McClellan                                    *
' * Published under Creative Commons Attribution-Share Alike            *
' * http://creativecommons.org/licenses/by-sa/3.0/                      *
' *                                                                         *
' * Allows for easy creation of DSN entries in the ODBC Administrator by    *
' *     leveraging the Registry class.                  *
' * Entries in the ODBC Admin are not created until the                     *
' *         Create() sub is called.                                         *
' ***************************************************************************

Private Const CLASS_NAME As String = "DSN" 'for error handling

Public Enum eDSN_Bitmode
    DSN_64BIT = 0
    DSN_32BIT = 1
End Enum

Private Const REG_KEYNODE_32 As String = "software\wow6432Node\ODBC"
Private Const REG_KEYNODE_64 As String = "software\ODBC"

Public Enum eDSN_type
    DSN_SYSTEM = 0
    DSN_USER = 1
End Enum

Public Enum eDSN_Driver
    DSN_DRIVER_EMPTY = 0
    DSN_DRIVER_SQLSERVER = 1
    DSN_DRIVER_SQLSERVER10 = 2
    DSN_DRIVER_SQLSERVER11 = 3
    DSN_DRIVER_ORA11G = 11
End Enum

Private Const DSN_DRIVER_SQLSERVER_NAME As String = "SQL Server"
Private Const DSN_DRIVER_SQLSERVER10_NAME As String = "SQL Server Native Client 10.0"
Private Const DSN_DRIVER_SQLSERVER11_NAME As String = "SQL Server Native Client 11.0"
Private Const DSN_DRIVER_ORA11G_NAME As String = "Oracle in OraClient11g_home1"

Public Enum eORA_CommitMode
    ORA_COMMIT_IfSuccessful
    ORA_COMMIT_FirstFailure
    ORA_COMMIT_AllSuccessful
End Enum

Private Const ORA_COMMIT_IfSuccessful_Txt As String = "IfAllSuccessful"
Private Const ORA_COMMIT_FirstFailure_Txt As String = "UpToFirstFailure"
Private Const ORA_COMMIT_AllSuccessful_Txt As String = "AllSuccessful"

Public Enum eORA_NumericSetting
    ORA_NUMSET_OracleNLS
    ORA_NUMSET_MSRegional
    ORA_NUMSET_US
End Enum

Private Const ORA_NUMSET_OracleNLS_txt As String = "NLS"
Private Const ORA_NUMSET_MSRegional_txt As String = "MS"
Private Const ORA_NUMSET_US_txt As String = "US"

' shared props
Private mName As String
Private mDriver As eDSN_Driver
Private mDSNType As eDSN_type
Private mBitMode As eDSN_Bitmode
Private mDriverFile As String
Private mDesc As String
' sql server props
Private mServer As String
Private mDatabase As String
Private mTrustedConnection As Boolean
' ora props
Private mAppAttributes As Boolean
Private mReadOnlyConn As Boolean
Private mCommitMode As eORA_CommitMode
Private mBindAsDate As Boolean
Private mBindAsFloat As Boolean
Private mCacheBufferSize As Long
Private mCloseCursor As Boolean
Private mDisableDPM As Boolean
Private mDisableMTS As Boolean
Private mDisableRuleHint As Boolean
Private mExecSchemaOpt As String
Private mExecSyntax As Boolean
Private mFailover As Boolean
Private mFailoverDelay As Long
Private mFailoverRetryCount As Integer
Private mFetchBufferSize As Long
Private mForceWChar As Boolean
Private mLobs As Boolean
Private mMetaDataIdDefault As Boolean
Private mNumericSetting As eORA_NumericSetting
Private mQueryTimeout As Boolean
Private mResultSets As Boolean
Private mStatementCache As Boolean
Private mUserID As String
Private mPwd As String

' defaults
Private Const DSN_DFLT_CacheBufferSize As Long = 20
Private Const DSN_DFLT_FailoverDelay As Long = 10
Private Const DSN_DFLT_FailoverRetryCount As Integer = 10
Private Const DSN_DFLT_FetchBufferSize As Long = 64000
''''''''''''''''''''''''''''BEGIN SHARED PROPERTIES''''''''''''''''''''''''''''''
Property Get NAME() As String
    NAME = mName
End Property

Property Let NAME(str As String)
    mName = str
End Property

Property Get Driver() As eDSN_Driver
' defaults to empty via enum
    Driver = mDriver
End Property

Property Let Driver(eDriver As eDSN_Driver)
    mDriver = eDriver
End Property

Property Get DriverName() As String
' read only property
Select Case mDriver
    Case DSN_DRIVER_EMPTY
        DriverName = ""
    Case DSN_DRIVER_SQLSERVER
        DriverName = DSN_DRIVER_SQLSERVER_NAME
    Case DSN_DRIVER_SQLSERVER10
        DriverName = DSN_DRIVER_SQLSERVER10_NAME
    Case DSN_DRIVER_SQLSERVER11
        DriverName = DSN_DRIVER_SQLSERVER11_NAME
    Case DSN_DRIVER_ORA11G
        DriverName = DSN_DRIVER_ORA11G_NAME
    End Select
End Property

Property Get DSNType() As eDSN_type
    DSNType = mDSNType
End Property

Property Let DSNType(pDSNType As eDSN_type)
    mDSNType = pDSNType
End Property

Property Get BitMode() As eDSN_Bitmode
    BitMode = mBitMode
End Property

Property Let BitMode(pBitMode As eDSN_Bitmode)
    ' defaults to 64 bit via the enum
    mBitMode = pBitMode
End Property

Property Get DriverFile() As String
' read only property
' @ todo - optimize
' save effort by only checking the registry the first time
    'If mDriverFile = "" Then
        mDriverFile = getDriver
        DriverFile = mDriverFile
    'Else
    '    DriverFile = mDriverFile
    'End If
End Property

Public Property Get Description() As String
    Description = mDesc
End Property

Public Property Let Description(desc As String)
    mDesc = desc
End Property

Property Get Server() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Server = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Server = Me.NAME
        Case Else
            Server = mServer
    End Select
End Property

Property Let Server(str As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mServer = str
    Else
        ErrRaise_NotSupported
    End If
End Property

Private Property Get RegNode() As String
' read only property
    Select Case Me.BitMode
        Case DSN_32BIT
            RegNode = REG_KEYNODE_32
        Case DSN_64BIT
            RegNode = REG_KEYNODE_64
        Case Else
            Err.Raise vbObjectError + 25002, CurrentProject.NAME & "." & CLASS_NAME, "Invalid Bitmode"
    End Select
End Property

Private Property Get HKey() As Long
' read only property
' determine which HKEY to use
    Select Case Me.DSNType
        Case DSN_USER
            HKey = HKEY_CURRENT_USER
        Case DSN_SYSTEM
            HKey = HKEY_LOCAL_MACHINE
        Case Else
            Err.Raise vbObjectError + 25001, CurrentProject.NAME & "." & CLASS_NAME, "Invalid DSNType or DSNType not set"
    End Select
End Property
''''''''''''''''''''''''''''''END SHARED PROPERTIES''''''''''''''''''''''''
''''''''''''''''''''''''''''BEGIN ORA PROPERTIES'''''''''''''''''''''''''''
Public Property Get AppAttributes() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            AppAttributes = False
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            AppAttributes = mAppAttributes
        Case Else
            AppAttributes = False
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let AppAttributes(bool As Boolean)
    If Me.Driver = DSN_DRIVER_ORA11G Then
        mAppAttributes = bool
    Else
        mAppAttributes = False
        ErrRaise_NotSupported
    End If
End Property

Public Property Get ReadOnlyConnection() As Boolean
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Attributes                                        '
'   true = "R" (read); false = "W" (write)          '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ReadOnlyConnection = True   'return true as a precaution
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            ReadOnlyConnection = mReadOnlyConn
        Case Else
            ReadOnlyConnection = True
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let ReadOnlyConnection(bool As Boolean)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mReadOnlyConn = bool
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BatchAutoCommitMode() As eORA_CommitMode
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BatchAutoCommitMode = mCommitMode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let BatchAutoCommitMode(mode As eORA_CommitMode)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mCommitMode = mode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BindAsDate() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BindAsDate = mBindAsDate
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

'.... lots of properties with the same logic omitted due to space constraints

' @todo - add sql server support for sql server login
Public Property Get USERID() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            USERID = mUserID
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let USERID(uid As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mUserID = uid
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

' @todo - add sql server support for sql server login
Public Property Get Password() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Password = mPwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let Password(pwd As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mPwd = pwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property
''''''''''''''''''''''''''''''END ORA PROPERTIES'''''''''''''''''''''''''''
''''''''''''''''''''''''BEGIN SQL SERVER PROPERTIES''''''''''''''''''''''''

Property Get Database() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Database = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            'Database = Err_NotSupported
            ErrRaise_NotSupported
        Case Else
            Database = mDatabase
    End Select
End Property

Property Let Database(pDatabase As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mDatabase = pDatabase
    Else
        'mDatabase = Err_NotSupported
        ErrRaise_NotSupported
    End If
End Property

Property Get TrustedConnection() As Boolean
    TrustedConnection = mTrustedConnection
End Property

Property Let TrustedConnection(value As Boolean)
    mTrustedConnection = value
End Property
'''''''''''''''''''''''END SQL SERVER PROPERTIES'''''''''''''''''''''''''''''''''''''
Private Function getDriver() As String
'**********************************************
' returns the file path of the .dll driver file
'**********************************************
Const PROC_NAME As String = "getDriver"
On Error GoTo ErrHandler:
    
    If Me.Driver = DSN_DRIVER_EMPTY Then
        getDriver = ""
    Else
        'determine bitmode
        Dim skey As String
        skey = RegNode
     
        ' find ODBC node
        Dim odbcDriverNode As String
        odbcDriverNode = findSectionKey(HKEY_LOCAL_MACHINE, skey, Me.DriverName)
        If odbcDriverNode <> "" Then
            'create new registry object and find the driver
            Dim reg As New Registry
            With reg
                .ClassKey = HKEY_LOCAL_MACHINE
                .sectionKey = odbcDriverNode
                .ValueKey = "Driver"
                If .value = "" Then
                    Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
                Else
                    'return
                    getDriver = .value
                End If
            End With
        Else
            Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
        End If
    End If
ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function

ErrHandler:
    errBox CLASS_NAME, PROC_NAME
    Resume ExitFunction:
    
End Function

Private Function findSectionKey(regClassKey As ERegistryClassConstants, sectToLookIn As String, sectToFind As String) As String
'******************************************************************
' returns full section key as string
'   if a matching section key is not found, returns an empty string
'******************************************************************
On Error GoTo ErrHandler:
Const PROC_NAME As String = "findSectionKey"

    Dim sSect() As String ' string array of subnodes
    Dim iSectCount As Long ' length of sSect array
    Dim reg As New Registry
    With reg
        .ClassKey = regClassKey
        .sectionKey = sectToLookIn
        .EnumerateSections sSect, iSectCount
        Dim i As Long
        For i = 1 To iSectCount
            'Debug.Print .sectionKey & "\" & sSect(i)
            If findSectionKey = "" Then
                If sSect(i) = sectToFind Then
                    ' found node
                    findSectionKey = .sectionKey & "\" & sSect(i)
                    Exit For
                Else
                    'search subnodes via recursion
                    findSectionKey = findSectionKey(regClassKey, .sectionKey & "\" & sSect(i), sectToFind)
                End If
            Else
                Exit For
            End If
        Next i
    End With

ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function
ErrHandler:
    errBox CLASS_NAME, PROC_NAME
End Function

Public Sub Create(Optional overwrite As Boolean = True)
' ***************************************************************************************************
' Creates a new registry entry defining the DSN (or modifies existing one with matching reg key)
' The actual registry entry (thus the DSN in the odbc admin) is not created until this sub is called.

     Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            createORA overwrite
        Case Else 'some sql server version
            createSQL overwrite
    End Select
        
End Sub

Private Sub createSQL(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            'driver
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            'server
            .ValueKey = "Server"
            .ValueType = REG_SZ
            .value = Me.Server
            'database
            .ValueKey = "Database"
            .ValueType = REG_SZ
            .value = Me.Database
            'trusted connection
            .ValueKey = "Trusted_Connection"
            .ValueType = REG_SZ
            If Me.TrustedConnection = True Then
                .value = "Yes"
            Else
                .value = "No"
            End If
            'last user
            .ValueKey = "LastUser"
            .ValueType = REG_SZ
            .Value = Environ("UserName")
            ' Description
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub createORA(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            .ValueKey = "Application Attributes"
            .ValueType = REG_SZ
            .value = boolAsString(Me.AppAttributes)
            
            .ValueKey = "Attributes"
            .ValueType = REG_SZ
            If Me.ReadOnlyConnection Then
                .value = "R"
            Else
                .value = "W"
            End If
            
            .ValueKey = "BatchAutocommitMode"
            .ValueType = REG_SZ
            Select Case Me.BatchAutoCommitMode
                Case ORA_COMMIT_AllSuccessful
                    .value = ORA_COMMIT_AllSuccessful_Txt
                Case ORA_COMMIT_FirstFailure
                    .value = ORA_COMMIT_FirstFailure_Txt
                Case ORA_COMMIT_IfSuccessful
                    .value = ORA_COMMIT_IfSuccessful_Txt
            End Select
            
            .ValueKey = "BindAsDATE"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsDate)
            
            .ValueKey = "BindAsFLOAT"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsFloat)
            
            .ValueKey = "CacheBufferSize"
            .ValueType = REG_SZ
            .value = Me.CacheBufferSize
            
            .ValueKey = "CloseCursor"
            .ValueType = REG_SZ
            .value = boolAsString(Me.CloseCursor)
            
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
            
            .ValueKey = "DisableDPM"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableDPM)
            
            .ValueKey = "DisableMTS"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableMTS)
            
            .ValueKey = "DisableRULEHint"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableRULEHint)
            
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            
            .ValueKey = "DSN"
            .ValueType = REG_SZ
            .value = Me.NAME
            
            .ValueKey = "EXECSchemaOpt"
            .ValueType = REG_SZ
            .value = Me.EXECSchemaOpt
            
            .ValueKey = "EXECSyntax"
            .ValueType = REG_SZ
            .value = boolAsString(Me.EXECSyntax)
            
            .ValueKey = "Failover"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Failover)
            
            .ValueKey = "FailoverDelay"
            .ValueType = REG_SZ
            .value = Me.FailoverDelay
            
            .ValueKey = "FailoverRetryCount"
            .ValueType = REG_SZ
            .value = Me.FailoverRetryCount
            
            .ValueKey = "FetchBufferSize"
            .ValueType = REG_SZ
            .value = Me.FetchBufferSize
            
            .ValueKey = "ForceWCHAR"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ForceWChar)
            
            .ValueKey = "Lobs"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Lobs)
            
            .ValueKey = "MetadataIdDefault"
            .ValueType = REG_SZ
            .value = boolAsString(Me.MetadataIdDefault)
            
            .ValueKey = "NumericSetting"
            .ValueType = REG_SZ
            Select Case Me.NumericSetting
                Case ORA_NUMSET_OracleNLS
                    .value = ORA_NUMSET_OracleNLS_txt
                Case ORA_NUMSET_MSRegional
                    .value = ORA_NUMSET_MSRegional_txt
                Case ORA_NUMSET_US
                    .value = ORA_NUMSET_US_txt
            End Select
            
            .ValueKey = "Password"
            .ValueType = REG_SZ
            .value = Me.Password
            
            .ValueKey = "QueryTimeout"
            .ValueType = REG_SZ
            .value = boolAsString(Me.QueryTimeout)
            
            .ValueKey = "ResultSets"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ResultSets)
            
            .ValueKey = "ServerName"
            .ValueType = REG_SZ
            .value = Me.Server
            
            .ValueKey = "StatementCache"
            .ValueType = REG_SZ
            .value = boolAsString(Me.StatementCache)
            
            .ValueKey = "UserID"
            .ValueType = REG_SZ
            .value = Me.USERID
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub addDataSourceEntry()
    Dim reg As Registry
    Set reg = New Registry
    With reg
            .ClassKey = HKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .ValueType = REG_SZ
            .value = Me.DriverName
    End With
End Sub

Public Function Exists() As Boolean
' Assumes Name, DSNType, and Bitmode are set
    Dim reg As New Registry
    Dim SCTKEY As String
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        If .KeyExists Then
            Exists = True
        Else
            Exists = False
        End If
    End With
End Function

Public Sub Delete()
    Dim reg As New Registry
    With reg
        .ClassKey = HKey
        'delete registry Section key
        .sectionKey = RegNode & "\odbc.ini\" & Me.NAME
        If Exists Then
            .DeleteKey
            'delete related ODBC Datasource ValueKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .DeleteValue
        End If
    End With
End Sub

Private Function boolAsString(ByVal bool As Boolean) As String
    If bool = True Then
        boolAsString = "T"
    Else
        boolAsString = "F"
    End If
End Function

Private Sub Class_Initialize()
' bypass all setters & getters when initializing

    ' shared props
    'mName =
    mDriver = DSN_DRIVER_EMPTY
    mDSNType = DSN_SYSTEM
    mBitMode = DSN_32BIT
    'mDriverFile =
    'mDesc =
    'mServer =
    
    ' sql server
    'mDatabase =
    mTrustedConnection = True
    
    ' oracle
    mAppAttributes = False
    mReadOnlyConn = True
    mCommitMode = ORA_COMMIT_IfSuccessful
    mBindAsDate = False
    mBindAsFloat = False
    mCacheBufferSize = DSN_DFLT_CacheBufferSize
    mCloseCursor = False
    mDisableDPM = False
    mDisableMTS = True
    mDisableRuleHint = True
    mExecSchemaOpt = ""
    mExecSyntax = False
    mFailover = True
    mFailoverDelay = DSN_DFLT_FailoverDelay
    mFailoverRetryCount = DSN_DFLT_FailoverRetryCount
    mFetchBufferSize = DSN_DFLT_FetchBufferSize
    mForceWChar = False
    mLobs = True
    mMetaDataIdDefault = False
    mNumericSetting = ORA_NUMSET_OracleNLS
    mQueryTimeout = False
    mResultSets = False
    mStatementCache = False
    ' @todo - make sql serv support sql server login; move to shared
    'mUserID =
    'mPwd =

End Sub

Private Sub errBox(ModuleName As String, procName As String, Optional style As VbMsgBoxStyle = vbCritical)
    MsgBox "Module: " & ModuleName & vbCrLf & _
        "Procedure: " & procName & vbCrLf & _
        Err.Description, _
        style, _
        "Runtime Error: " & Err.number
End Sub

Private Sub ErrRaise_NotSupported()
    Err.Raise vbObjectError + 25010, CurrentProject.NAME & "." & CLASS_NAME, "Driver does not support the property."
End Sub

Private Sub ErrRaise_DriverNotSet()
    Err.Raise vbObjectError + 25020, CurrentProject.NAME & "." & CLASS_NAME, "Driver property is not set."
End Sub
' ***************************************************************************
' * Class: DSN                              *
' * Author: Christopher J. McClellan                                    *
' * Published under Creative Commons Attribution-Share Alike            *
' * http://creativecommons.org/licenses/by-sa/3.0/                      *
' *                                                                         *
' * Allows for easy creation of DSN entries in the ODBC Administrator by    *
' *     leveraging the Registry class.                  *
' * Entries in the ODBC Admin are not created until the                     *
' *         Create() sub is called.                                         *
' ***************************************************************************

Private Const CLASS_NAME As String = "DSN" 'for error handling

Public Enum eDSN_Bitmode
    DSN_64BIT = 0
    DSN_32BIT = 1
End Enum

Private Const REG_KEYNODE_32 As String = "software\wow6432Node\ODBC"
Private Const REG_KEYNODE_64 As String = "software\ODBC"

Public Enum eDSN_type
    DSN_SYSTEM = 0
    DSN_USER = 1
End Enum

Public Enum eDSN_Driver
    DSN_DRIVER_EMPTY = 0
    DSN_DRIVER_SQLSERVER = 1
    DSN_DRIVER_SQLSERVER10 = 2
    DSN_DRIVER_SQLSERVER11 = 3
    DSN_DRIVER_ORA11G = 11
End Enum

Private Const DSN_DRIVER_SQLSERVER_NAME As String = "SQL Server"
Private Const DSN_DRIVER_SQLSERVER10_NAME As String = "SQL Server Native Client 10.0"
Private Const DSN_DRIVER_SQLSERVER11_NAME As String = "SQL Server Native Client 11.0"
Private Const DSN_DRIVER_ORA11G_NAME As String = "Oracle in OraClient11g_home1"

Public Enum eORA_CommitMode
    ORA_COMMIT_IfSuccessful
    ORA_COMMIT_FirstFailure
    ORA_COMMIT_AllSuccessful
End Enum

Private Const ORA_COMMIT_IfSuccessful_Txt As String = "IfAllSuccessful"
Private Const ORA_COMMIT_FirstFailure_Txt As String = "UpToFirstFailure"
Private Const ORA_COMMIT_AllSuccessful_Txt As String = "AllSuccessful"

Public Enum eORA_NumericSetting
    ORA_NUMSET_OracleNLS
    ORA_NUMSET_MSRegional
    ORA_NUMSET_US
End Enum

Private Const ORA_NUMSET_OracleNLS_txt As String = "NLS"
Private Const ORA_NUMSET_MSRegional_txt As String = "MS"
Private Const ORA_NUMSET_US_txt As String = "US"

' shared props
Private mName As String
Private mDriver As eDSN_Driver
Private mDSNType As eDSN_type
Private mBitMode As eDSN_Bitmode
Private mDriverFile As String
Private mDesc As String
' sql server props
Private mServer As String
Private mDatabase As String
Private mTrustedConnection As Boolean
' ora props
Private mAppAttributes As Boolean
Private mReadOnlyConn As Boolean
Private mCommitMode As eORA_CommitMode
Private mBindAsDate As Boolean
Private mBindAsFloat As Boolean
Private mCacheBufferSize As Long
Private mCloseCursor As Boolean
Private mDisableDPM As Boolean
Private mDisableMTS As Boolean
Private mDisableRuleHint As Boolean
Private mExecSchemaOpt As String
Private mExecSyntax As Boolean
Private mFailover As Boolean
Private mFailoverDelay As Long
Private mFailoverRetryCount As Integer
Private mFetchBufferSize As Long
Private mForceWChar As Boolean
Private mLobs As Boolean
Private mMetaDataIdDefault As Boolean
Private mNumericSetting As eORA_NumericSetting
Private mQueryTimeout As Boolean
Private mResultSets As Boolean
Private mStatementCache As Boolean
Private mUserID As String
Private mPwd As String

' defaults
Private Const DSN_DFLT_CacheBufferSize As Long = 20
Private Const DSN_DFLT_FailoverDelay As Long = 10
Private Const DSN_DFLT_FailoverRetryCount As Integer = 10
Private Const DSN_DFLT_FetchBufferSize As Long = 64000
''''''''''''''''''''''''''''BEGIN SHARED PROPERTIES''''''''''''''''''''''''''''''
Property Get NAME() As String
    NAME = mName
End Property

Property Let NAME(str As String)
    mName = str
End Property

Property Get Driver() As eDSN_Driver
' defaults to empty via enum
    Driver = mDriver
End Property

Property Let Driver(eDriver As eDSN_Driver)
    mDriver = eDriver
End Property

Property Get DriverName() As String
' read only property
Select Case mDriver
    Case DSN_DRIVER_EMPTY
        DriverName = ""
    Case DSN_DRIVER_SQLSERVER
        DriverName = DSN_DRIVER_SQLSERVER_NAME
    Case DSN_DRIVER_SQLSERVER10
        DriverName = DSN_DRIVER_SQLSERVER10_NAME
    Case DSN_DRIVER_SQLSERVER11
        DriverName = DSN_DRIVER_SQLSERVER11_NAME
    Case DSN_DRIVER_ORA11G
        DriverName = DSN_DRIVER_ORA11G_NAME
    End Select
End Property

Property Get DSNType() As eDSN_type
    DSNType = mDSNType
End Property

Property Let DSNType(pDSNType As eDSN_type)
    mDSNType = pDSNType
End Property

Property Get BitMode() As eDSN_Bitmode
    BitMode = mBitMode
End Property

Property Let BitMode(pBitMode As eDSN_Bitmode)
    ' defaults to 64 bit via the enum
    mBitMode = pBitMode
End Property

Property Get DriverFile() As String
' read only property
' @ todo - optimize
' save effort by only checking the registry the first time
    'If mDriverFile = "" Then
        mDriverFile = getDriver
        DriverFile = mDriverFile
    'Else
    '    DriverFile = mDriverFile
    'End If
End Property

Public Property Get Description() As String
    Description = mDesc
End Property

Public Property Let Description(desc As String)
    mDesc = desc
End Property

Property Get Server() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Server = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Server = Me.NAME
        Case Else
            Server = mServer
    End Select
End Property

Property Let Server(str As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mServer = str
    Else
        ErrRaise_NotSupported
    End If
End Property

Private Property Get RegNode() As String
' read only property
    Select Case Me.BitMode
        Case DSN_32BIT
            RegNode = REG_KEYNODE_32
        Case DSN_64BIT
            RegNode = REG_KEYNODE_64
        Case Else
            Err.Raise vbObjectError + 25002, CurrentProject.NAME & "." & CLASS_NAME, "Invalid Bitmode"
    End Select
End Property

Private Property Get HKey() As Long
' read only property
' determine which HKEY to use
    Select Case Me.DSNType
        Case DSN_USER
            HKey = HKEY_CURRENT_USER
        Case DSN_SYSTEM
            HKey = HKEY_LOCAL_MACHINE
        Case Else
            Err.Raise vbObjectError + 25001, CurrentProject.NAME & "." & CLASS_NAME, "Invalid DSNType or DSNType not set"
    End Select
End Property
''''''''''''''''''''''''''''''END SHARED PROPERTIES''''''''''''''''''''''''
''''''''''''''''''''''''''''BEGIN ORA PROPERTIES'''''''''''''''''''''''''''
Public Property Get AppAttributes() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            AppAttributes = False
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            AppAttributes = mAppAttributes
        Case Else
            AppAttributes = False
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let AppAttributes(bool As Boolean)
    If Me.Driver = DSN_DRIVER_ORA11G Then
        mAppAttributes = bool
    Else
        mAppAttributes = False
        ErrRaise_NotSupported
    End If
End Property

Public Property Get ReadOnlyConnection() As Boolean
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Attributes                                        '
'   true = "R" (read); false = "W" (write)          '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ReadOnlyConnection = True   'return true as a precaution
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            ReadOnlyConnection = mReadOnlyConn
        Case Else
            ReadOnlyConnection = True
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let ReadOnlyConnection(bool As Boolean)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mReadOnlyConn = bool
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BatchAutoCommitMode() As eORA_CommitMode
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BatchAutoCommitMode = mCommitMode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let BatchAutoCommitMode(mode As eORA_CommitMode)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mCommitMode = mode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BindAsDate() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BindAsDate = mBindAsDate
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

'.... lots of properties with the same logic omitted due to space constraints

' @todo - add sql server support for sql server login
Public Property Get USERID() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            USERID = mUserID
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let USERID(uid As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mUserID = uid
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

' @todo - add sql server support for sql server login
Public Property Get Password() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Password = mPwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let Password(pwd As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mPwd = pwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property
''''''''''''''''''''''''''''''END ORA PROPERTIES'''''''''''''''''''''''''''
''''''''''''''''''''''''BEGIN SQL SERVER PROPERTIES''''''''''''''''''''''''

Property Get Database() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Database = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            'Database = Err_NotSupported
            ErrRaise_NotSupported
        Case Else
            Database = mDatabase
    End Select
End Property

Property Let Database(pDatabase As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mDatabase = pDatabase
    Else
        'mDatabase = Err_NotSupported
        ErrRaise_NotSupported
    End If
End Property

Property Get TrustedConnection() As Boolean
    TrustedConnection = mTrustedConnection
End Property

Property Let TrustedConnection(value As Boolean)
    mTrustedConnection = value
End Property
'''''''''''''''''''''''END SQL SERVER PROPERTIES'''''''''''''''''''''''''''''''''''''
Private Function getDriver() As String
'**********************************************
' returns the file path of the .dll driver file
'**********************************************
Const PROC_NAME As String = "getDriver"
On Error GoTo ErrHandler:
    
    If Me.Driver = DSN_DRIVER_EMPTY Then
        getDriver = ""
    Else
        'determine bitmode
        Dim skey As String
        skey = RegNode
     
        ' find ODBC node
        Dim odbcDriverNode As String
        odbcDriverNode = findSectionKey(HKEY_LOCAL_MACHINE, skey, Me.DriverName)
        If odbcDriverNode <> "" Then
            'create new registry object and find the driver
            Dim reg As New Registry
            With reg
                .ClassKey = HKEY_LOCAL_MACHINE
                .sectionKey = odbcDriverNode
                .ValueKey = "Driver"
                If .value = "" Then
                    Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
                Else
                    'return
                    getDriver = .value
                End If
            End With
        Else
            Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
        End If
    End If
ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function

ErrHandler:
    errBox CLASS_NAME, PROC_NAME
    Resume ExitFunction:
    
End Function

Private Function findSectionKey(regClassKey As ERegistryClassConstants, sectToLookIn As String, sectToFind As String) As String
'******************************************************************
' returns full section key as string
'   if a matching section key is not found, returns an empty string
'******************************************************************
On Error GoTo ErrHandler:
Const PROC_NAME As String = "findSectionKey"

    Dim sSect() As String ' string array of subnodes
    Dim iSectCount As Long ' length of sSect array
    Dim reg As New Registry
    With reg
        .ClassKey = regClassKey
        .sectionKey = sectToLookIn
        .EnumerateSections sSect, iSectCount
        Dim i As Long
        For i = 1 To iSectCount
            'Debug.Print .sectionKey & "\" & sSect(i)
            If findSectionKey = "" Then
                If sSect(i) = sectToFind Then
                    ' found node
                    findSectionKey = .sectionKey & "\" & sSect(i)
                    Exit For
                Else
                    'search subnodes via recursion
                    findSectionKey = findSectionKey(regClassKey, .sectionKey & "\" & sSect(i), sectToFind)
                End If
            Else
                Exit For
            End If
        Next i
    End With

ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function
ErrHandler:
    errBox CLASS_NAME, PROC_NAME
End Function

Public Sub Create(Optional overwrite As Boolean = True)
' ***************************************************************************************************
' Creates a new registry entry defining the DSN (or modifies existing one with matching reg key)
' The actual registry entry (thus the DSN in the odbc admin) is not created until this sub is called.
' ***************************************************************************************************
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            createORA overwrite
        Case Else 'some sql server version
            createSQL overwrite
    End Select
        
End Sub

Private Sub createSQL(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            'driver
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            'server
            .ValueKey = "Server"
            .ValueType = REG_SZ
            .value = Me.Server
            'database
            .ValueKey = "Database"
            .ValueType = REG_SZ
            .value = Me.Database
            'trusted connection
            .ValueKey = "Trusted_Connection"
            .ValueType = REG_SZ
            If Me.TrustedConnection = True Then
                .value = "Yes"
            Else
                .value = "No"
            End If
            'last user
            .ValueKey = "LastUser"
            .ValueType = REG_SZ
            .Value = Environ("UserName")
            ' Description
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub createORA(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            .ValueKey = "Application Attributes"
            .ValueType = REG_SZ
            .value = boolAsString(Me.AppAttributes)
            
            .ValueKey = "Attributes"
            .ValueType = REG_SZ
            If Me.ReadOnlyConnection Then
                .value = "R"
            Else
                .value = "W"
            End If
            
            .ValueKey = "BatchAutocommitMode"
            .ValueType = REG_SZ
            Select Case Me.BatchAutoCommitMode
                Case ORA_COMMIT_AllSuccessful
                    .value = ORA_COMMIT_AllSuccessful_Txt
                Case ORA_COMMIT_FirstFailure
                    .value = ORA_COMMIT_FirstFailure_Txt
                Case ORA_COMMIT_IfSuccessful
                    .value = ORA_COMMIT_IfSuccessful_Txt
            End Select
            
            .ValueKey = "BindAsDATE"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsDate)
            
            .ValueKey = "BindAsFLOAT"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsFloat)
            
            .ValueKey = "CacheBufferSize"
            .ValueType = REG_SZ
            .value = Me.CacheBufferSize
            
            .ValueKey = "CloseCursor"
            .ValueType = REG_SZ
            .value = boolAsString(Me.CloseCursor)
            
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
            
            .ValueKey = "DisableDPM"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableDPM)
            
            .ValueKey = "DisableMTS"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableMTS)
            
            .ValueKey = "DisableRULEHint"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableRULEHint)
            
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            
            .ValueKey = "DSN"
            .ValueType = REG_SZ
            .value = Me.NAME
            
            .ValueKey = "EXECSchemaOpt"
            .ValueType = REG_SZ
            .value = Me.EXECSchemaOpt
            
            .ValueKey = "EXECSyntax"
            .ValueType = REG_SZ
            .value = boolAsString(Me.EXECSyntax)
            
            .ValueKey = "Failover"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Failover)
            
            .ValueKey = "FailoverDelay"
            .ValueType = REG_SZ
            .value = Me.FailoverDelay
            
            .ValueKey = "FailoverRetryCount"
            .ValueType = REG_SZ
            .value = Me.FailoverRetryCount
            
            .ValueKey = "FetchBufferSize"
            .ValueType = REG_SZ
            .value = Me.FetchBufferSize
            
            .ValueKey = "ForceWCHAR"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ForceWChar)
            
            .ValueKey = "Lobs"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Lobs)
            
            .ValueKey = "MetadataIdDefault"
            .ValueType = REG_SZ
            .value = boolAsString(Me.MetadataIdDefault)
            
            .ValueKey = "NumericSetting"
            .ValueType = REG_SZ
            Select Case Me.NumericSetting
                Case ORA_NUMSET_OracleNLS
                    .value = ORA_NUMSET_OracleNLS_txt
                Case ORA_NUMSET_MSRegional
                    .value = ORA_NUMSET_MSRegional_txt
                Case ORA_NUMSET_US
                    .value = ORA_NUMSET_US_txt
            End Select
            
            .ValueKey = "Password"
            .ValueType = REG_SZ
            .value = Me.Password
            
            .ValueKey = "QueryTimeout"
            .ValueType = REG_SZ
            .value = boolAsString(Me.QueryTimeout)
            
            .ValueKey = "ResultSets"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ResultSets)
            
            .ValueKey = "ServerName"
            .ValueType = REG_SZ
            .value = Me.Server
            
            .ValueKey = "StatementCache"
            .ValueType = REG_SZ
            .value = boolAsString(Me.StatementCache)
            
            .ValueKey = "UserID"
            .ValueType = REG_SZ
            .value = Me.USERID
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub addDataSourceEntry()
    Dim reg As Registry
    Set reg = New Registry
    With reg
            .ClassKey = HKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .ValueType = REG_SZ
            .value = Me.DriverName
    End With
End Sub

Public Function Exists() As Boolean
' Assumes Name, DSNType, and Bitmode are set
    Dim reg As New Registry
    Dim SCTKEY As String
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        If .KeyExists Then
            Exists = True
        Else
            Exists = False
        End If
    End With
End Function

Public Sub Delete()
    Dim reg As New Registry
    With reg
        .ClassKey = HKey
        'delete registry Section key
        .sectionKey = RegNode & "\odbc.ini\" & Me.NAME
        If Exists Then
            .DeleteKey
            'delete related ODBC Datasource ValueKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .DeleteValue
        End If
    End With
End Sub

Private Function boolAsString(ByVal bool As Boolean) As String
    If bool = True Then
        boolAsString = "T"
    Else
        boolAsString = "F"
    End If
End Function

Private Sub Class_Initialize()
' bypass all setters & getters when initializing

    ' shared props
    'mName =
    mDriver = DSN_DRIVER_EMPTY
    mDSNType = DSN_SYSTEM
    mBitMode = DSN_32BIT
    'mDriverFile =
    'mDesc =
    'mServer =
    
    ' sql server
    'mDatabase =
    mTrustedConnection = True
    
    ' oracle
    mAppAttributes = False
    mReadOnlyConn = True
    mCommitMode = ORA_COMMIT_IfSuccessful
    mBindAsDate = False
    mBindAsFloat = False
    mCacheBufferSize = DSN_DFLT_CacheBufferSize
    mCloseCursor = False
    mDisableDPM = False
    mDisableMTS = True
    mDisableRuleHint = True
    mExecSchemaOpt = ""
    mExecSyntax = False
    mFailover = True
    mFailoverDelay = DSN_DFLT_FailoverDelay
    mFailoverRetryCount = DSN_DFLT_FailoverRetryCount
    mFetchBufferSize = DSN_DFLT_FetchBufferSize
    mForceWChar = False
    mLobs = True
    mMetaDataIdDefault = False
    mNumericSetting = ORA_NUMSET_OracleNLS
    mQueryTimeout = False
    mResultSets = False
    mStatementCache = False
    ' @todo - make sql serv support sql server login; move to shared
    'mUserID =
    'mPwd =

End Sub

Private Sub errBox(ModuleName As String, procName As String, Optional style As VbMsgBoxStyle = vbCritical)
    MsgBox "Module: " & ModuleName & vbCrLf & _
        "Procedure: " & procName & vbCrLf & _
        Err.Description, _
        style, _
        "Runtime Error: " & Err.number
End Sub

Private Sub ErrRaise_NotSupported()
    Err.Raise vbObjectError + 25010, CurrentProject.NAME & "." & CLASS_NAME, "Driver does not support the property."
End Sub

Private Sub ErrRaise_DriverNotSet()
    Err.Raise vbObjectError + 25020, CurrentProject.NAME & "." & CLASS_NAME, "Driver property is not set."
End Sub
deleted 8 characters in body; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Domain Name Service Class - Preparing for Refactor

So, I am concerned with Issue #2 first and foremost, but all feedback is welcome. Thanks.

Domain Name Service Class - Preparing for Refactor

So, I am concerned with Issue #2 first and foremost, but all feedback is welcome. Thanks.

Domain Name Service Class

So, I am concerned with Issue #2 first and foremost, but all feedback is welcome.

Source Link
RubberDuck
  • 30.9k
  • 6
  • 71
  • 174

Domain Name Service Class - Preparing for Refactor

I recently wrote a DSN class for use with the Access flavor of VBA. I'm preparing to refactor and would appreciate feedback.

I am aware of two issues.

  1. I added the findSectionKey() function to the Registry class (which is separate and out of scope for this question) that I call, but never went back to remove the duplicate logic from my DSN class. I am aware of this and will correct it during my refactor.
  2. I am completely unsatisfied with the way I implemented the Driver property. I use an Enum to specify the DriverType and then a select statement to return a string from the aforementioned Driver property. It's works well in practice, but is kind of clunky to work with (particularly when adding support for a new driver). I'm thinking I could use a Dictionary to do this better, but I've never used one and I'm unsure if that's the best approach.

So, I am concerned with Issue #2 first and foremost, but all feedback is welcome. Thanks.

' ***************************************************************************
' * Class: DSN                              *
' * Author: Christopher J. McClellan                                    *
' * Published under Creative Commons Attribution-Share Alike            *
' * http://creativecommons.org/licenses/by-sa/3.0/                      *
' *                                                                         *
' * Allows for easy creation of DSN entries in the ODBC Administrator by    *
' *     leveraging the Registry class.                  *
' * Entries in the ODBC Admin are not created until the                     *
' *         Create() sub is called.                                         *
' ***************************************************************************

Private Const CLASS_NAME As String = "DSN" 'for error handling

Public Enum eDSN_Bitmode
    DSN_64BIT = 0
    DSN_32BIT = 1
End Enum

Private Const REG_KEYNODE_32 As String = "software\wow6432Node\ODBC"
Private Const REG_KEYNODE_64 As String = "software\ODBC"

Public Enum eDSN_type
    DSN_SYSTEM = 0
    DSN_USER = 1
End Enum

Public Enum eDSN_Driver
    DSN_DRIVER_EMPTY = 0
    DSN_DRIVER_SQLSERVER = 1
    DSN_DRIVER_SQLSERVER10 = 2
    DSN_DRIVER_SQLSERVER11 = 3
    DSN_DRIVER_ORA11G = 11
End Enum

Private Const DSN_DRIVER_SQLSERVER_NAME As String = "SQL Server"
Private Const DSN_DRIVER_SQLSERVER10_NAME As String = "SQL Server Native Client 10.0"
Private Const DSN_DRIVER_SQLSERVER11_NAME As String = "SQL Server Native Client 11.0"
Private Const DSN_DRIVER_ORA11G_NAME As String = "Oracle in OraClient11g_home1"

Public Enum eORA_CommitMode
    ORA_COMMIT_IfSuccessful
    ORA_COMMIT_FirstFailure
    ORA_COMMIT_AllSuccessful
End Enum

Private Const ORA_COMMIT_IfSuccessful_Txt As String = "IfAllSuccessful"
Private Const ORA_COMMIT_FirstFailure_Txt As String = "UpToFirstFailure"
Private Const ORA_COMMIT_AllSuccessful_Txt As String = "AllSuccessful"

Public Enum eORA_NumericSetting
    ORA_NUMSET_OracleNLS
    ORA_NUMSET_MSRegional
    ORA_NUMSET_US
End Enum

Private Const ORA_NUMSET_OracleNLS_txt As String = "NLS"
Private Const ORA_NUMSET_MSRegional_txt As String = "MS"
Private Const ORA_NUMSET_US_txt As String = "US"

' shared props
Private mName As String
Private mDriver As eDSN_Driver
Private mDSNType As eDSN_type
Private mBitMode As eDSN_Bitmode
Private mDriverFile As String
Private mDesc As String
' sql server props
Private mServer As String
Private mDatabase As String
Private mTrustedConnection As Boolean
' ora props
Private mAppAttributes As Boolean
Private mReadOnlyConn As Boolean
Private mCommitMode As eORA_CommitMode
Private mBindAsDate As Boolean
Private mBindAsFloat As Boolean
Private mCacheBufferSize As Long
Private mCloseCursor As Boolean
Private mDisableDPM As Boolean
Private mDisableMTS As Boolean
Private mDisableRuleHint As Boolean
Private mExecSchemaOpt As String
Private mExecSyntax As Boolean
Private mFailover As Boolean
Private mFailoverDelay As Long
Private mFailoverRetryCount As Integer
Private mFetchBufferSize As Long
Private mForceWChar As Boolean
Private mLobs As Boolean
Private mMetaDataIdDefault As Boolean
Private mNumericSetting As eORA_NumericSetting
Private mQueryTimeout As Boolean
Private mResultSets As Boolean
Private mStatementCache As Boolean
Private mUserID As String
Private mPwd As String

' defaults
Private Const DSN_DFLT_CacheBufferSize As Long = 20
Private Const DSN_DFLT_FailoverDelay As Long = 10
Private Const DSN_DFLT_FailoverRetryCount As Integer = 10
Private Const DSN_DFLT_FetchBufferSize As Long = 64000
''''''''''''''''''''''''''''BEGIN SHARED PROPERTIES''''''''''''''''''''''''''''''
Property Get NAME() As String
    NAME = mName
End Property

Property Let NAME(str As String)
    mName = str
End Property

Property Get Driver() As eDSN_Driver
' defaults to empty via enum
    Driver = mDriver
End Property

Property Let Driver(eDriver As eDSN_Driver)
    mDriver = eDriver
End Property

Property Get DriverName() As String
' read only property
Select Case mDriver
    Case DSN_DRIVER_EMPTY
        DriverName = ""
    Case DSN_DRIVER_SQLSERVER
        DriverName = DSN_DRIVER_SQLSERVER_NAME
    Case DSN_DRIVER_SQLSERVER10
        DriverName = DSN_DRIVER_SQLSERVER10_NAME
    Case DSN_DRIVER_SQLSERVER11
        DriverName = DSN_DRIVER_SQLSERVER11_NAME
    Case DSN_DRIVER_ORA11G
        DriverName = DSN_DRIVER_ORA11G_NAME
    End Select
End Property

Property Get DSNType() As eDSN_type
    DSNType = mDSNType
End Property

Property Let DSNType(pDSNType As eDSN_type)
    mDSNType = pDSNType
End Property

Property Get BitMode() As eDSN_Bitmode
    BitMode = mBitMode
End Property

Property Let BitMode(pBitMode As eDSN_Bitmode)
    ' defaults to 64 bit via the enum
    mBitMode = pBitMode
End Property

Property Get DriverFile() As String
' read only property
' @ todo - optimize
' save effort by only checking the registry the first time
    'If mDriverFile = "" Then
        mDriverFile = getDriver
        DriverFile = mDriverFile
    'Else
    '    DriverFile = mDriverFile
    'End If
End Property

Public Property Get Description() As String
    Description = mDesc
End Property

Public Property Let Description(desc As String)
    mDesc = desc
End Property

Property Get Server() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Server = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Server = Me.NAME
        Case Else
            Server = mServer
    End Select
End Property

Property Let Server(str As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mServer = str
    Else
        ErrRaise_NotSupported
    End If
End Property

Private Property Get RegNode() As String
' read only property
    Select Case Me.BitMode
        Case DSN_32BIT
            RegNode = REG_KEYNODE_32
        Case DSN_64BIT
            RegNode = REG_KEYNODE_64
        Case Else
            Err.Raise vbObjectError + 25002, CurrentProject.NAME & "." & CLASS_NAME, "Invalid Bitmode"
    End Select
End Property

Private Property Get HKey() As Long
' read only property
' determine which HKEY to use
    Select Case Me.DSNType
        Case DSN_USER
            HKey = HKEY_CURRENT_USER
        Case DSN_SYSTEM
            HKey = HKEY_LOCAL_MACHINE
        Case Else
            Err.Raise vbObjectError + 25001, CurrentProject.NAME & "." & CLASS_NAME, "Invalid DSNType or DSNType not set"
    End Select
End Property
''''''''''''''''''''''''''''''END SHARED PROPERTIES''''''''''''''''''''''''
''''''''''''''''''''''''''''BEGIN ORA PROPERTIES'''''''''''''''''''''''''''
Public Property Get AppAttributes() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            AppAttributes = False
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            AppAttributes = mAppAttributes
        Case Else
            AppAttributes = False
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let AppAttributes(bool As Boolean)
    If Me.Driver = DSN_DRIVER_ORA11G Then
        mAppAttributes = bool
    Else
        mAppAttributes = False
        ErrRaise_NotSupported
    End If
End Property

Public Property Get ReadOnlyConnection() As Boolean
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' Attributes                                        '
'   true = "R" (read); false = "W" (write)          '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ReadOnlyConnection = True   'return true as a precaution
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            ReadOnlyConnection = mReadOnlyConn
        Case Else
            ReadOnlyConnection = True
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let ReadOnlyConnection(bool As Boolean)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mReadOnlyConn = bool
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BatchAutoCommitMode() As eORA_CommitMode
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BatchAutoCommitMode = mCommitMode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let BatchAutoCommitMode(mode As eORA_CommitMode)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mCommitMode = mode
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Get BindAsDate() As Boolean
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            BindAsDate = mBindAsDate
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

'.... lots of properties with the same logic omitted due to space constraints

' @todo - add sql server support for sql server login
Public Property Get USERID() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            USERID = mUserID
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let USERID(uid As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mUserID = uid
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

' @todo - add sql server support for sql server login
Public Property Get Password() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            Password = mPwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property

Public Property Let Password(pwd As String)
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            mPwd = pwd
        Case Else
            ErrRaise_NotSupported
    End Select
End Property
''''''''''''''''''''''''''''''END ORA PROPERTIES'''''''''''''''''''''''''''
''''''''''''''''''''''''BEGIN SQL SERVER PROPERTIES''''''''''''''''''''''''

Property Get Database() As String
    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            'Database = Err_DriverNotSet
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            'Database = Err_NotSupported
            ErrRaise_NotSupported
        Case Else
            Database = mDatabase
    End Select
End Property

Property Let Database(pDatabase As String)
    If Me.Driver <> DSN_DRIVER_ORA11G Then
        mDatabase = pDatabase
    Else
        'mDatabase = Err_NotSupported
        ErrRaise_NotSupported
    End If
End Property

Property Get TrustedConnection() As Boolean
    TrustedConnection = mTrustedConnection
End Property

Property Let TrustedConnection(value As Boolean)
    mTrustedConnection = value
End Property
'''''''''''''''''''''''END SQL SERVER PROPERTIES'''''''''''''''''''''''''''''''''''''
Private Function getDriver() As String
'**********************************************
' returns the file path of the .dll driver file
'**********************************************
Const PROC_NAME As String = "getDriver"
On Error GoTo ErrHandler:
    
    If Me.Driver = DSN_DRIVER_EMPTY Then
        getDriver = ""
    Else
        'determine bitmode
        Dim skey As String
        skey = RegNode
     
        ' find ODBC node
        Dim odbcDriverNode As String
        odbcDriverNode = findSectionKey(HKEY_LOCAL_MACHINE, skey, Me.DriverName)
        If odbcDriverNode <> "" Then
            'create new registry object and find the driver
            Dim reg As New Registry
            With reg
                .ClassKey = HKEY_LOCAL_MACHINE
                .sectionKey = odbcDriverNode
                .ValueKey = "Driver"
                If .value = "" Then
                    Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
                Else
                    'return
                    getDriver = .value
                End If
            End With
        Else
            Err.Raise vbObjectError + 25003, CurrentProject.NAME & "." & CLASS_NAME, "Driver Not Found"
        End If
    End If
ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function

ErrHandler:
    errBox CLASS_NAME, PROC_NAME
    Resume ExitFunction:
    
End Function

Private Function findSectionKey(regClassKey As ERegistryClassConstants, sectToLookIn As String, sectToFind As String) As String
'******************************************************************
' returns full section key as string
'   if a matching section key is not found, returns an empty string
'******************************************************************
On Error GoTo ErrHandler:
Const PROC_NAME As String = "findSectionKey"

    Dim sSect() As String ' string array of subnodes
    Dim iSectCount As Long ' length of sSect array
    Dim reg As New Registry
    With reg
        .ClassKey = regClassKey
        .sectionKey = sectToLookIn
        .EnumerateSections sSect, iSectCount
        Dim i As Long
        For i = 1 To iSectCount
            'Debug.Print .sectionKey & "\" & sSect(i)
            If findSectionKey = "" Then
                If sSect(i) = sectToFind Then
                    ' found node
                    findSectionKey = .sectionKey & "\" & sSect(i)
                    Exit For
                Else
                    'search subnodes via recursion
                    findSectionKey = findSectionKey(regClassKey, .sectionKey & "\" & sSect(i), sectToFind)
                End If
            Else
                Exit For
            End If
        Next i
    End With

ExitFunction:
    If Not (reg Is Nothing) Then
        Set reg = Nothing
    End If
    Exit Function
ErrHandler:
    errBox CLASS_NAME, PROC_NAME
End Function

Public Sub Create(Optional overwrite As Boolean = True)
' ***************************************************************************************************
' Creates a new registry entry defining the DSN (or modifies existing one with matching reg key)
' The actual registry entry (thus the DSN in the odbc admin) is not created until this sub is called.

    Select Case Me.Driver
        Case DSN_DRIVER_EMPTY
            ErrRaise_DriverNotSet
        Case DSN_DRIVER_ORA11G
            createORA overwrite
        Case Else 'some sql server version
            createSQL overwrite
    End Select
        
End Sub

Private Sub createSQL(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            'driver
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            'server
            .ValueKey = "Server"
            .ValueType = REG_SZ
            .value = Me.Server
            'database
            .ValueKey = "Database"
            .ValueType = REG_SZ
            .value = Me.Database
            'trusted connection
            .ValueKey = "Trusted_Connection"
            .ValueType = REG_SZ
            If Me.TrustedConnection = True Then
                .value = "Yes"
            Else
                .value = "No"
            End If
            'last user
            .ValueKey = "LastUser"
            .ValueType = REG_SZ
            .Value = Environ("UserName")
            ' Description
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub createORA(ByVal overwrite As Boolean)
    Dim reg As New Registry
    Dim SCTKEY As String
    Dim isRegKey As Boolean
    
    ' Registry Section Key
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    ' Create New Key and set values
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        ' Check existance and overwrite value
        isRegKey = .KeyExists
        If overwrite = True Or (overwrite = False And isRegKey = False) Then
            .ValueKey = "Application Attributes"
            .ValueType = REG_SZ
            .value = boolAsString(Me.AppAttributes)
            
            .ValueKey = "Attributes"
            .ValueType = REG_SZ
            If Me.ReadOnlyConnection Then
                .value = "R"
            Else
                .value = "W"
            End If
            
            .ValueKey = "BatchAutocommitMode"
            .ValueType = REG_SZ
            Select Case Me.BatchAutoCommitMode
                Case ORA_COMMIT_AllSuccessful
                    .value = ORA_COMMIT_AllSuccessful_Txt
                Case ORA_COMMIT_FirstFailure
                    .value = ORA_COMMIT_FirstFailure_Txt
                Case ORA_COMMIT_IfSuccessful
                    .value = ORA_COMMIT_IfSuccessful_Txt
            End Select
            
            .ValueKey = "BindAsDATE"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsDate)
            
            .ValueKey = "BindAsFLOAT"
            .ValueType = REG_SZ
            .value = boolAsString(Me.BindAsFloat)
            
            .ValueKey = "CacheBufferSize"
            .ValueType = REG_SZ
            .value = Me.CacheBufferSize
            
            .ValueKey = "CloseCursor"
            .ValueType = REG_SZ
            .value = boolAsString(Me.CloseCursor)
            
            .ValueKey = "Description"
            .ValueType = REG_SZ
            .value = Me.Description
            
            .ValueKey = "DisableDPM"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableDPM)
            
            .ValueKey = "DisableMTS"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableMTS)
            
            .ValueKey = "DisableRULEHint"
            .ValueType = REG_SZ
            .value = boolAsString(Me.DisableRULEHint)
            
            .ValueKey = "Driver"
            .ValueType = REG_SZ
            .value = Me.DriverFile
            
            .ValueKey = "DSN"
            .ValueType = REG_SZ
            .value = Me.NAME
            
            .ValueKey = "EXECSchemaOpt"
            .ValueType = REG_SZ
            .value = Me.EXECSchemaOpt
            
            .ValueKey = "EXECSyntax"
            .ValueType = REG_SZ
            .value = boolAsString(Me.EXECSyntax)
            
            .ValueKey = "Failover"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Failover)
            
            .ValueKey = "FailoverDelay"
            .ValueType = REG_SZ
            .value = Me.FailoverDelay
            
            .ValueKey = "FailoverRetryCount"
            .ValueType = REG_SZ
            .value = Me.FailoverRetryCount
            
            .ValueKey = "FetchBufferSize"
            .ValueType = REG_SZ
            .value = Me.FetchBufferSize
            
            .ValueKey = "ForceWCHAR"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ForceWChar)
            
            .ValueKey = "Lobs"
            .ValueType = REG_SZ
            .value = boolAsString(Me.Lobs)
            
            .ValueKey = "MetadataIdDefault"
            .ValueType = REG_SZ
            .value = boolAsString(Me.MetadataIdDefault)
            
            .ValueKey = "NumericSetting"
            .ValueType = REG_SZ
            Select Case Me.NumericSetting
                Case ORA_NUMSET_OracleNLS
                    .value = ORA_NUMSET_OracleNLS_txt
                Case ORA_NUMSET_MSRegional
                    .value = ORA_NUMSET_MSRegional_txt
                Case ORA_NUMSET_US
                    .value = ORA_NUMSET_US_txt
            End Select
            
            .ValueKey = "Password"
            .ValueType = REG_SZ
            .value = Me.Password
            
            .ValueKey = "QueryTimeout"
            .ValueType = REG_SZ
            .value = boolAsString(Me.QueryTimeout)
            
            .ValueKey = "ResultSets"
            .ValueType = REG_SZ
            .value = boolAsString(Me.ResultSets)
            
            .ValueKey = "ServerName"
            .ValueType = REG_SZ
            .value = Me.Server
            
            .ValueKey = "StatementCache"
            .ValueType = REG_SZ
            .value = boolAsString(Me.StatementCache)
            
            .ValueKey = "UserID"
            .ValueType = REG_SZ
            .value = Me.USERID
        End If
    End With
    
    ' add a registry key to make the newly added DSN visible
    If overwrite = True Or (overwrite = False And isRegKey = False) Then
        addDataSourceEntry
    End If
End Sub

Private Sub addDataSourceEntry()
    Dim reg As Registry
    Set reg = New Registry
    With reg
            .ClassKey = HKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .ValueType = REG_SZ
            .value = Me.DriverName
    End With
End Sub

Public Function Exists() As Boolean
' Assumes Name, DSNType, and Bitmode are set
    Dim reg As New Registry
    Dim SCTKEY As String
    SCTKEY = RegNode & "\odbc.ini\" & Me.NAME
    With reg
        .ClassKey = HKey
        .sectionKey = SCTKEY
        If .KeyExists Then
            Exists = True
        Else
            Exists = False
        End If
    End With
End Function

Public Sub Delete()
    Dim reg As New Registry
    With reg
        .ClassKey = HKey
        'delete registry Section key
        .sectionKey = RegNode & "\odbc.ini\" & Me.NAME
        If Exists Then
            .DeleteKey
            'delete related ODBC Datasource ValueKey
            .sectionKey = RegNode & "\odbc.ini\odbc data sources"
            .ValueKey = Me.NAME
            .DeleteValue
        End If
    End With
End Sub

Private Function boolAsString(ByVal bool As Boolean) As String
    If bool = True Then
        boolAsString = "T"
    Else
        boolAsString = "F"
    End If
End Function

Private Sub Class_Initialize()
' bypass all setters & getters when initializing

    ' shared props
    'mName =
    mDriver = DSN_DRIVER_EMPTY
    mDSNType = DSN_SYSTEM
    mBitMode = DSN_32BIT
    'mDriverFile =
    'mDesc =
    'mServer =
    
    ' sql server
    'mDatabase =
    mTrustedConnection = True
    
    ' oracle
    mAppAttributes = False
    mReadOnlyConn = True
    mCommitMode = ORA_COMMIT_IfSuccessful
    mBindAsDate = False
    mBindAsFloat = False
    mCacheBufferSize = DSN_DFLT_CacheBufferSize
    mCloseCursor = False
    mDisableDPM = False
    mDisableMTS = True
    mDisableRuleHint = True
    mExecSchemaOpt = ""
    mExecSyntax = False
    mFailover = True
    mFailoverDelay = DSN_DFLT_FailoverDelay
    mFailoverRetryCount = DSN_DFLT_FailoverRetryCount
    mFetchBufferSize = DSN_DFLT_FetchBufferSize
    mForceWChar = False
    mLobs = True
    mMetaDataIdDefault = False
    mNumericSetting = ORA_NUMSET_OracleNLS
    mQueryTimeout = False
    mResultSets = False
    mStatementCache = False
    ' @todo - make sql serv support sql server login; move to shared
    'mUserID =
    'mPwd =

End Sub

Private Sub errBox(ModuleName As String, procName As String, Optional style As VbMsgBoxStyle = vbCritical)
    MsgBox "Module: " & ModuleName & vbCrLf & _
        "Procedure: " & procName & vbCrLf & _
        Err.Description, _
        style, _
        "Runtime Error: " & Err.number
End Sub

Private Sub ErrRaise_NotSupported()
    Err.Raise vbObjectError + 25010, CurrentProject.NAME & "." & CLASS_NAME, "Driver does not support the property."
End Sub

Private Sub ErrRaise_DriverNotSet()
    Err.Raise vbObjectError + 25020, CurrentProject.NAME & "." & CLASS_NAME, "Driver property is not set."
End Sub