Took me a while, but I got around the ODBC.NET limitations around
getting a list of available DSN Sources and getting a list of tables
in the database. I had to call the ODBC API SQLDataSources for the
DSN list and reference ADO to get the Tables list. Below is my
class. I would really like to use the ODBC API SQLTables to get the
list of tables, but no matter what I tried it didn't work - I just got
back SQL_NO_DATA_FOUND. If someone solves this I would really
appreciate seeing how they did it. Because I am using unmanaged code
here, do I need to provide a Dispose method? I didn't think so since
I am calling everything local to Sub's and they get cleaned up in the
Sub by either me, or by going out of scope...
Anyway, I thought I'd share this since I{*filter*}d so much code off of
google groups in the past! This is the best programmers resource
around!
***********************
THE CLASS - You must reference ODBC.NET and ADO 2.5 in your project
It returns a DataTable object back through the properties -
also below that... how to call it...
***********************
Imports ADODB
Imports Microsoft.Data.Odbc
Public Class CRODBCHelper
Inherits Object
Private Const SQL_BUFFER_SIZE As Short = 1024
Private Const SQL_FETCH_FIRST As Short = 1
Private Const SQL_SUCCESS As Short = 0
Private Const SQL_SUCCESS_WITH_INFO As Short = 1
Private Const SQL_NO_DATA As Short = 100
Private Const SQL_HANDLE_ENV As Integer = 1
Private Const SQL_HANDLE_DBC As Integer = 2
Private Const SQL_HANDLE_STMT As Integer = 3
Private Const SQL_HANDLE_DESC As Short = 4
Private Const SQL_NULL_HANDLE As Short = 0
Private Declare Function SQLAllocEnv Lib "ODBC32.DLL" (ByRef
env As Integer) As Short
Private Declare Function SQLFreeHandle Lib "odbc32.dll" (ByVal
handleType As Short, ByVal Handle As Integer) As Short
Private Declare Function SQLDataSources Lib "ODBC32.DLL" _
(ByVal WindowHandle As
Integer, _
ByVal Direction As
Short, _
ByVal DSNBuffer As
String, _
ByVal DSNBufferLength As
Short, _
ByRef DSNLength As
Short, _
ByVal DESCBuffer As
String, _
ByVal DESCBufferLength
As Short, _
ByRef DESCLength As
Short) As Short
Declare Function SQLGetDiagRec Lib "odbc32.dll" (ByVal iHType
As Short, _
ByVal lHInput As Integer, _
ByVal iRecNumber As Short, _
ByVal szSQLState As String, _
ByRef iNativeError As Integer, _
ByVal strMessageText As String, _
ByVal iBufferLength As Short, _
ByRef iTextLength As Short) As Short
Private m_ConnectString As String
Private m_DSNDataTable As DataTable
Private m_TablesDataTable As DataTable
Private m_ODBCNativeError As Integer
Private m_ODBCMessage As String
Public Sub New(ByVal ConnectStr As String)
MyBase.New()
m_ConnectString = ConnectStr
InitializeTables()
End Sub
Public Sub New()
MyBase.New()
InitializeTables()
End Sub
Public Property ConnectString() As String
Get
Return m_ConnectString
End Get
Set(ByVal Value As String)
m_ConnectString = Value
End Set
End Property
Public ReadOnly Property DSNDataTable() As DataTable
Get
Return m_DSNDataTable
End Get
End Property
Public ReadOnly Property TablesDataTable() As DataTable
Get
Return m_TablesDataTable
End Get
End Property
Public ReadOnly Property ErrorCode() As Integer
Get
Return m_ODBCNativeError
End Get
End Property
Public ReadOnly Property ErrorMessage() As String
Get
Return m_ODBCMessage
End Get
End Property
Private Sub InitializeTables()
m_DSNDataTable = New DataTable("DSNList")
m_TablesDataTable = New DataTable("TableList")
m_DSNDataTable.Columns.Add(New
System.Data.DataColumn("DSN_NAME"))
m_DSNDataTable.Columns.Add(New
System.Data.DataColumn("DSN_DESCRIPTION"))
m_TablesDataTable.Columns.Add(New
System.Data.DataColumn("TABLE_CATALOG"))
m_TablesDataTable.Columns.Add(New
System.Data.DataColumn("TABLE_SCHEMA"))
m_TablesDataTable.Columns.Add(New
System.Data.DataColumn("TABLE_NAME"))
m_TablesDataTable.Columns.Add(New
System.Data.DataColumn("TABLE_TYPE"))
End Sub
Public Function BuildDSNDataTable() As Boolean
Dim EnvHandle As IntPtr
Dim env As Integer
Dim hDbc As IntPtr
Dim ODBCRC As Integer
Dim ret As Short
Dim DSNBuffer As String
Dim DSNBufferLength As Short
Dim ReturnedDSNLength As Short
Dim DESCBuffer As String
Dim DESCBufferLength As Short
Dim ReturnedDESCLength As Short
Dim DSNName As String
Dim DSNDescription As String
'Initialize the string buffer lengths
DSNBufferLength = SQL_BUFFER_SIZE
DESCBufferLength = SQL_BUFFER_SIZE
ODBCRC = SQLAllocEnv(env)
If ProcessODBCError(env, ODBCRC) = True Then
SQLFreeHandle(SQL_HANDLE_ENV, env)
env = Nothing
Return False
End If
ret = SQL_SUCCESS
'Get the DSN names & descriptions
While (ret = SQL_SUCCESS) Or (ret = SQL_SUCCESS_WITH_INFO)
DSNBuffer = Space(DSNBufferLength)
DESCBuffer = Space(DESCBufferLength)
ret = SQLDataSources(env, SQL_FETCH_FIRST, DSNBuffer,
_
DSNBufferLength, ReturnedDSNLength, DESCBuffer,
DESCBufferLength, _
ReturnedDESCLength)
If ProcessODBCError(env, ret) = True Then
SQLFreeHandle(SQL_HANDLE_ENV, env)
env = Nothing
Return False
End If
DSNName = DSNBuffer.Substring(0, ReturnedDSNLength)
DSNDescription = DESCBuffer.Substring(0,
ReturnedDESCLength)
Dim nr As System.Data.DataRow =
m_DSNDataTable.NewRow()
nr("DSN_NAME") = DSNName
nr("DSN_DESCRIPTION") = DSNDescription
m_DSNDataTable.Rows.Add(nr)
End While
SQLFreeHandle(SQL_HANDLE_ENV, env)
env = Nothing
Return True
End Function
Public Function BuildTablesDataTable(ByVal ConnectStr As
String) As Boolean
Dim ret As Boolean
m_ConnectString = ConnectStr
Return BuildTablesDataTable()
End Function
Public Function BuildTablesDataTable() As Boolean
Dim mConnect As New Connection()
Dim rstSchema As New ADODB.Recordset()
Dim Buffer As String
Dim Ret As Boolean
Ret = True
mConnect.ConnectionString = m_ConnectString
Try
mConnect.Open()
Catch Ex As Exception
m_ODBCNativeError = -1
m_ODBCMessage = Ex.Message
Try
mConnect.Close()
Catch Ex2 As Exception
'Do Nothing
Finally
mConnect = Nothing
End Try
Return False
End Try
'Get the database schema.
Try
rstSchema =
mConnect.OpenSchema(SchemaEnum.adSchemaTables)
Catch Ex As Exception
m_ODBCNativeError = -1
m_ODBCMessage = Ex.Message
Try
mConnect.Close()
Catch Ex2 As Exception
'Do Nothing
Finally
mConnect = Nothing
rstSchema = Nothing
End Try
Return False
End Try
With rstSchema
'Make sure something is found.
If Not .BOF And Not .EOF Then
'Add the tables to the collection.
Do While Not rstSchema.EOF
Dim nr As System.Data.DataRow =
m_TablesDataTable.NewRow()
nr("TABLE_CATALOG") =
rstSchema.Fields("TABLE_CATALOG").Value
nr("TABLE_SCHEMA") =
rstSchema.Fields("TABLE_SCHEMA").Value
nr("TABLE_NAME") =
rstSchema.Fields("TABLE_NAME").Value
nr("TABLE_TYPE") =
rstSchema.Fields("TABLE_TYPE").Value
m_TablesDataTable.Rows.Add(nr)
rstSchema.MoveNext()
Loop
Ret = True
Else 'No tables found.
Ret = False
End If
End With
mConnect.Close()
mConnect = Nothing
rstSchema = Nothing
Return Ret
End Function
Private Function ProcessODBCError(ByVal env As Integer, ByVal
retval As Short) As Boolean
Dim ODBCRC As Short
Dim State As String, Message As String
Dim NativeError As Long, Length As Integer
Dim strErrMsg As String
strErrMsg = Space(128)
ODBCRC = retval
If (ODBCRC <> SQL_SUCCESS) And (ODBCRC <>
SQL_SUCCESS_WITH_INFO) Then
ODBCRC = SQLGetDiagRec(SQL_HANDLE_ENV, env, 1, State,
NativeError, strErrMsg, strErrMsg.Length, Length)
If ODBCRC = SQL_SUCCESS Then
m_ODBCNativeError = NativeError
m_ODBCMessage = strErrMsg
env = Nothing
Return True
End If
ElseIf (ODBCRC = SQL_SUCCESS_WITH_INFO) Then
ODBCRC = SQLGetDiagRec(SQL_HANDLE_ENV, env, 1, State,
NativeError, strErrMsg, strErrMsg.Length, Length)
If ODBCRC = SQL_SUCCESS Then
m_ODBCNativeError = NativeError
m_ODBCMessage = strErrMsg
Return False
End If
End If
Return False
End Function
End Class
******************************
How to call it
******************************
Private ODBCHelper As New CRODBCHelper()
Private mDSNTable As DataTable
Private mTablesList As DataTable
--------------------------
'GET THE DSN LIST
Dim ret As Boolean
ret = ODBCHelper.BuildDSNDataTable()
If ret = True Then
mDSNTable = ODBCHelper.DSNDataTable
' Use the Datatable to show in a grid or loop through it to get the
data...
DataGrid2.DataSource = mDSNTable
Else
MsgBox("(" + Str(ODBCHelper.ErrorCode) + ")" +
ODBCHelper.ErrorMessage)
End If
-----------------------
' Get the tables list
Dim ret As Boolean
ODBCHelper.ConnectString =
"DSN=MySQLServerDsn;uid=sa;pwd=manager;database=Northwind"
ret = ODBCHelper.BuildTablesDataTable()
If ret = True Then
mTablesList = ODBCHelper.TablesDataTable
' Use the Datatable to show in a grid or loop through it to get the
data...
DataGrid1.DataSource = mTablesList
Else
MsgBox("(" + Str(ODBCHelper.ErrorCode) + ")" +
ODBCHelper.ErrorMessage)
End If