【问题标题】:List all MSSQL servers in the network VB.NET列出网络 VB.NET 中的所有 MSSQL 服务器
【发布时间】:2017-04-06 14:25:53
【问题描述】:

我正在构建一个项目,它简单地列出了使用 VB.NET 在网络中运行的所有 MSSQL 服务器。我可以使用 'SqlDataSourceEnumerator' 并参考 .NET 3.5 版来获取列表。

我的问题是,'SqlDataSourceEnumerator' 没有给我参考 .NET 4.5 版的列表。因此,为了运行我的项目,我需要将 .NET 3.5 安装到 Windows 8 及更高版本等操作系统。

我在互联网上搜索了它,还得到了codeproject 的链接,它适用于任何 .NET 版本,并使用 ODBC 列出 sql 服务器。但它在 C# 代码中,我无法理解代码。

有没有其他方法可以在 VB.NET 中获取独立于 .NET 版本的 sql server 列表。如果没有其他方法,请帮助理解和转换上述链接中的代码。

更新:

我使用了以下代码

 Dim dt As DataTable = Sql.SqlDataSourceEnumerator.Instance.GetDataSources()
 For Each dr In dt.Rows
     If dr.Item(1).ToString.Trim <> "" Then MsgBox(dr.Item(1).ToString)
 Next

【问题讨论】:

  • 无复制。工作得很好机智4.5+。什么不起作用?为什么您认为 .NET 存在问题?您可能已关闭 SQL Server Browser 服务。如果您无法通过SqlDataSourceEnumerator 获得服务器,您将无法通过更改驱动程序获得它们。发现协议是一样的
  • 您可以浏览 SQL Server 吗?您是否尝试在 SSMS 连接对话框中浏览网络服务器?
  • 是的,我尝试使用 SSMS,我正在那里获取服务器列表。但是当我在没有 .net3.5 的电脑上运行时,我得到了空白列表。

标签: c# .net sql-server vb.net


【解决方案1】:

我的 vb 有点生疏,但只要服务器设置为公开显示他们的信息,这对我有用。

Dim t As DataTable = SqlClient.SqlClientFactory.Instance.CreateDataSourceEnumerator().GetDataSources()

I did find this

【讨论】:

  • @ITresearcher 它确实工作。如果您没有得到任何结果,请检查您的网络、服务器、浏览器服务。
【解决方案2】:

您是否尝试过检索枚举器?

Public NotInheritable Class SqlDataSourceEnumerator _
    Inherits DbDataSourceEnumerator

Dim instance As SqlDataSourceEnumerator   

Dim dataTable As System.Data.DataTable = instance.GetDataSources() 

【讨论】:

  • 是的,试过了,但是没有 dot net 3.5 就不行
  • @ITresearcher 我在答案中添加了一些内容;在.NET3.5 你需要使用继承。 MSDN link
  • @ITresearcher 它确实工作。如果您没有得到任何结果,请检查您的网络、服务器、浏览器服务。
  • 您的更新显示使用Sql.SqlDataSourceEnumerator 的代码;你试过我上面写的吗? (DbDataSourceEnumerator)
【解决方案3】:

有问题的代码项目完美运行,下面是 VB.Net 版本。

formSQLInfoEnumeratorDemo.vb

Imports WindowsApplication2.Moletrator.SQLDocumentor

Public Class formSQLInfoEnumeratorDemo

Private Sub formSQLInfoEnumeratorDemo_Load(sender As Object, e As EventArgs) Handles MyBase.Load

End Sub

Private Sub buttonSQLServerEnumerator_Click(sender As Object, e As EventArgs) Handles buttonSQLServerEnumerator.Click
    GetSQLDetails(Me.listboxSQLServerInstances)
End Sub
Private Sub GetSQLDetails(SQLListBox As ListBox)
    Dim sie As New SQLInfoEnumerator()
    Try
        If SQLListBox.Name = "listboxSQLServerDatabaseInstances" Then
            SQLListBox.Items.Clear()
            sie.SQLServer = listboxSQLServerInstances.SelectedItem.ToString()
            sie.Username = textboxUserName.Text
            sie.Password = textboxPassword.Text
            SQLListBox.Items.AddRange(sie.EnumerateSQLServersDatabases())
        Else
            SQLListBox.Items.Clear()
            SQLListBox.Items.AddRange(sie.EnumerateSQLServers())
        End If
    Catch ex As Exception
        MessageBox.Show(ex.ToString())
    End Try
End Sub

End Class

SQLInfoEnumerator.vb

Imports System.Runtime.InteropServices
Imports System.Text

Namespace Moletrator.SQLDocumentor

Public Class SQLInfoEnumerator

    <DllImport("odbc32.dll")> _
    Private Shared Function SQLAllocHandle(handleType As Short, inputHandle As IntPtr, ByRef outputHandlePtr As IntPtr) As Short
    End Function
    <DllImport("odbc32.dll")> _
    Private Shared Function SQLSetEnvAttr(environmentHandle As IntPtr, attribute As Integer, valuePtr As IntPtr, stringLength As Integer) As Short
    End Function
    <DllImport("odbc32.dll")> _
    Private Shared Function SQLFreeHandle(hType As Short, Handle As IntPtr) As Short
    End Function
    <DllImport("odbc32.dll", CharSet:=CharSet.Ansi)> _
    Private Shared Function SQLBrowseConnect(handleConnection As IntPtr, inConnection As StringBuilder, stringLength As Short, outConnection As StringBuilder, bufferLength As Short, ByRef stringLength2Ptr As Short) As Short
    End Function

    Private Const SQL_DRIVER_STR As String = "DRIVER=SQL SERVER"
    Private Const SQL_SUCCESS As Short = 0
    Private Const SQL_HANDLE_ENV As Short = 1
    Private Const SQL_HANDLE_DBC As Short = 2
    Private Const SQL_ATTR_ODBC_VERSION As Integer = 200
    Private Const SQL_OV_ODBC3 As Integer = 3
    Private Const SQL_NEED_DATA As Short = 99
    Private Const DEFAULT_RESULT_SIZE As Short = 1024
    Private Const START_STR As String = "{"
    Private Const END_STR As String = "}"


    ''' <summary>
    ''' A string to hold the selected SQL Server
    ''' </summary>
    Private m_SQLServer As String
    ''' <summary>
    ''' A string to hold the username
    ''' </summary>
    Private m_Username As String
    ''' <summary>
    ''' A string to hold the password
    ''' </summary>
    Private m_Password As String
    ''' <summary>
    ''' Property to set the SQL Server instance
    ''' </summary>
    Public WriteOnly Property SQLServer() As String
        Set(value As String)
            m_SQLServer = value
        End Set
    End Property
    ''' <summary>
    ''' Property to set the Username
    ''' </summary>
    Public WriteOnly Property Username() As String
        Set(value As String)
            m_Username = value
        End Set
    End Property
    ''' <summary>
    ''' Property to set the Password
    ''' </summary>
    Public WriteOnly Property Password() As String
        Set(value As String)
            m_Password = value
        End Set
    End Property

    ''' <summary>
    ''' Enumerate the SQL Servers returning a list (if any exist)
    ''' </summary>
    ''' <returns></returns>
    Public Function EnumerateSQLServers() As String()
        Return RetrieveInformation(SQL_DRIVER_STR)
    End Function
    ''' <summary>
    ''' Enumerate the specified SQL server returning a list of databases (if any exist)
    ''' </summary>
    ''' <returns></returns>
    Public Function EnumerateSQLServersDatabases() As String()
        Return RetrieveInformation(Convert.ToString((Convert.ToString((Convert.ToString(SQL_DRIVER_STR & Convert.ToString(";SERVER=")) & m_SQLServer) + ";UID=") & m_Username) + ";PWD=") & m_Password)
    End Function

    ''' <summary>
    ''' Enumerate for SQLServer/Databases based on the passed information it the string
    ''' The more information provided to SQLBrowseConnect the more granular it gets so
    ''' if only DRIVER=SQL SERVER passed then a list of all SQL Servers is returned
    ''' If DRIVER=SQL SERVER;Server=ServerName is passed then a list of all Databases on the
    ''' servers is returned etc
    ''' </summary>
    ''' <param name="InputParam">A valid string to query for</param>
    ''' <returns></returns>
    Private Function RetrieveInformation(InputParam As String) As String()
        Dim m_environmentHandle As IntPtr = IntPtr.Zero
        Dim m_connectionHandle As IntPtr = IntPtr.Zero
        Dim inConnection As New StringBuilder(InputParam)
        Dim stringLength As Short = CShort(inConnection.Length)
        Dim outConnection As New StringBuilder(DEFAULT_RESULT_SIZE)
        Dim stringLength2Ptr As Short = 0

        Try
            If SQL_SUCCESS = SQLAllocHandle(SQL_HANDLE_ENV, m_environmentHandle, m_environmentHandle) Then
                If SQL_SUCCESS = SQLSetEnvAttr(m_environmentHandle, SQL_ATTR_ODBC_VERSION, New IntPtr(SQL_OV_ODBC3), 0) Then
                    If SQL_SUCCESS = SQLAllocHandle(SQL_HANDLE_DBC, m_environmentHandle, m_connectionHandle) Then
                        If SQL_NEED_DATA = SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, outConnection, DEFAULT_RESULT_SIZE, stringLength2Ptr) Then
                            If SQL_NEED_DATA <> SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, outConnection, DEFAULT_RESULT_SIZE, stringLength2Ptr) Then
                                Throw New ApplicationException("No Data Returned.")
                            End If
                        End If
                    End If
                End If
            End If

        Catch ex As Exception
            Throw New ApplicationException("Cannot Locate SQL Server.")
        Finally
            FreeConnection(m_connectionHandle)
            FreeConnection(m_environmentHandle)
        End Try
        If outConnection.ToString() <> "" Then
            Return ParseSQLOutConnection(outConnection.ToString())
        Else
            Return Nothing
        End If


    End Function
    ''' <summary>
    ''' Parse an outConnection string returned from SQLBrowseConnect
    ''' </summary>
    ''' <param name="outConnection">string to parse</param>
    ''' <returns></returns>
    Private Function ParseSQLOutConnection(outConnection As String) As String()
        Dim m_Start As Integer = outConnection.IndexOf(START_STR) + 1
        Dim m_lenString As Integer = outConnection.IndexOf(END_STR) - m_Start
        If (m_Start > 0) AndAlso (m_lenString > 0) Then
            outConnection = outConnection.Substring(m_Start, m_lenString)
        Else
            outConnection = String.Empty
        End If
        Return outConnection.Split(",".ToCharArray())
    End Function
    Private Sub FreeConnection(handleToFree As IntPtr)
        If handleToFree <> IntPtr.Zero Then
            SQLFreeHandle(SQL_HANDLE_DBC, handleToFree)
        End If
    End Sub

End Class
End Namespace

【讨论】:

    【解决方案4】:

    我发现使用 Item(0) 而不是 Item(1),原始代码在 4.6.1 上运行良好:

    Dim dt As DataTable = Sql.SqlDataSourceEnumerator.Instance.GetDataSources()
    For Each dr In dt.Rows
        If dr.Item(0).ToString.Trim <> "" Then MsgBox(dr.Item(0).ToString)
    Next
    

    【讨论】:

    • @Toni:这不是一个不同的问题。而且,事实上,它非常明确地提出了一个解决方案。它建议将Item(1) 更改为Item(0),并确保有此问题的人至少使用v4.6.1。为什么你认为这是一个新问题?
    猜你喜欢
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    相关资源
    最近更新 更多