Listing SQL Server instances

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

I wish to create a small .NET app that will help an end user to create my
applications database. I wanted to provide them with a list of all SQLServers
on a network and then all databases on a chosen server. What is the best way
of getting these lists? Is it best to use ADO or something like WMI?

Thanks for your help
 
Thanks for the links.

However, ideally I want to avoid interop (COM or otherwise). Does anyone
know if this makes it impossible?
 
Gravy:

If I may ask, is there a particular reason that you need to avoid using COM
Interop? The framework is far from fully mature and there's a lot of stuff
that hasn't been wrapped yet - so if you need the functionality you're going
to have to use the Interop libs to get there or P/Invoke yourself. I can't
tell you with 100% certainty that you can't enumerate them another way, but
I don't know of any .NET features that provide this outside of what I
posted. You can write your own classes and either use SQL DMO or P/Invoke
or both, store it in a library and use it just like you would any other
function. I'm not sure what your reasons are for wanting to avoid them, and
in no way do I mean any disrespect- the only reason I ask is that I know
there's a lot of misinformation out there about using interop/P/Invoke and
if that's what's giving you your misgivings then I wouldn't want you
avoiding it for those reasons. I've seen a bunch of posts where people
tell others to avoid P/Invoke because it's not 'managed' or because they
should keep everythign 100% .NET. The truth is Microsoft didn't rewrite
everythign referenced in .NET in 'pure' .NET code. Much of the framework is
simply existing COM stuff in a managed wrapper.

HTH,

Bill
 
Bill,

the truth of it was I wanted to keep things pure .NET but you are right in
what you say and perhaps I was being a little naive.

Infact, using SQLDMO it is really as easy as :

SQLDMO.Application myapp = new SQLDMO.ApplicationClass();
if(myapp != null)
{
SQLDMO.NameList list = myapp.ListAvailableSQLServers();

int listCounter = list.Count;

for(int index = 1; index <= listCounter; index++)
{
Console.WriteLine(list.Item(index));
}
}

Thanks for your help.
 
Good to hear. The reason I mention it is because I had heard the same
things you did when I first started and fortunately I read Dan Appleman's
piece on this subject pretty early on which dispelled many of these very
popular myths. As the framework matures you'll have to use interop less and
less but to be honest, a portion of it may well just be wrappers again.
John Paul Mueller has a book .NET Framework Solutions - In Search of the
Lost Win32 API that has a look of cool api manipulation - it was definitely
a great read.

Good Luck,

Bill
 
Bill:

I, too, am a bit leery about COM Interop. Certainly, there are times, but I
approach the subject warily. There is, of course, no way around SQL DMO (or
is that "no easy way"), so it is the option.

When crossing into Interop, IDisposable is your friend.

---

Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

***************************
Think Outside the Box!
***************************
 
Here is an Example Using the API

Public Class clsNetAPI32
Private Const SV_TYPE_SQLSERVER = &H4S
' NetServerEnum Return Values
Private Const ERR_SUCCESS = 0
Private Const ERROR_MORE_DATA As Int32 = 234
Private Const ERROR_NO_BROWSER_SERVERS_FOUND As Int32 = 6118I

Private Structure SERVER_INFO_100
Dim sv100_platform_id As Integer
Dim sv100_name As Integer
End Structure
'
' level : Specifies the information level of the data
' bufptr : Pointer to the buffer that receives the data
' prefmaxlen : Specifies the preferred maximum length of returned data,
in bytes
' entriesread : Pointer to a value that receives the count of elements
actually enumerated
' totalentries : Pointer to a value that receives the total number of
visible servers and workstations on the network
' servertype : Specifies a value that filters the server entries to
return from the enumeration
' domain : Pointer to a constant string that specifies the name of the
domain for which a list of servers is to be returned
' resume_handle : Reserved; must be set to zero
Private Declare Unicode Function NetServerEnum Lib "netapi32" _
(ByVal servername As IntPtr _
, ByVal level As Integer _
, ByRef bufptr As IntPtr _
, ByVal prefmaxlen As Integer _
, ByRef entriesread As Integer _
, ByRef totalentries As Integer _
, ByVal servertype As Integer _
, ByVal domain As IntPtr _
, ByVal resume_handle As Integer _
) As Integer

Private Declare Function NetApiBufferFree Lib "netapi32" _
(ByVal BufPtr As IntPtr) As Integer

Public Function GetListOfServers(ByRef colSQLServers As Collection) As
Boolean

Dim sServerName As IntPtr = IntPtr.Zero
Dim iLevel As Integer = 100
Dim lBufPtr As IntPtr
Dim iprefMaxLen As Integer = -1
Dim iEntriesRead As Integer
Dim iTotalEntries As Integer
Dim sDomain As IntPtr = IntPtr.Zero
Dim iResumeHandle As Integer = 0
Dim iReturnValue As Integer

Dim sctSrvList As SERVER_INFO_100
Dim nStructSize As Integer = Marshal.SizeOf(sctSrvList)
Dim scSQLServers As New Specialized.StringCollection
Dim iIndex As Integer

colSQLServers = New Collection
iReturnValue = NetServerEnum(sServerName _
, iLevel _
, lBufPtr _
, iprefMaxLen _
, iEntriesRead _
, iTotalEntries _
, SV_TYPE_SQLSERVER _
, sDomain _
, iResumeHandle _
)
If iReturnValue = ERR_SUCCESS Then
' Loop through each SQL Server returned by the NetServerEnum call
For iIndex = 0 To iEntriesRead - 1
' Convert each SQL Server entry into a SERVER_INFO_100
structure
sctSrvList = DirectCast(Marshal.PtrToStructure(New
IntPtr(lBufPtr.ToInt32 + (nStructSize * iIndex)) _
,
GetType(SERVER_INFO_100) _
) _
, SERVER_INFO_100 _
)
' Add each SQL Server SERVER_INFO_100 structure entry into
the StringCollection
scSQLServers.Add(Marshal.PtrToStringUni(New
IntPtr(sctSrvList.sv100_name)))
Next

End If

' Clean up regardless of iReturnValue
Call NetApiBufferFree(lBufPtr)

' Move from String Collection to Array To Collection
' I only return the list as a collection because
' collections are what I am used to
Dim sSQLServers(scSQLServers.Count - 1) As String
scSQLServers.CopyTo(sSQLServers, 0)
For iIndex = 0 To sSQLServers.GetUpperBound(0)
colSQLServers.Add(sSQLServers(iIndex))
Next
Return True

End Function

End Class
 
Glenn,

Does et return SQL Server named instances as well? In our company, we have
servers running 3-4 SQL Servers with different instance names.

Best regards,

Benny Tordrup
 
Have not tested but it should

Benny Tordrup said:
Glenn,

Does et return SQL Server named instances as well? In our company, we have
servers running 3-4 SQL Servers with different instance names.

Best regards,

Benny Tordrup
 
Back
Top