Click here to Skip to main content
Click here to Skip to main content

Finding SQL Servers on the Network

By , 22 Dec 2003
 

Sample Image - DBGrep.jpg

Introduction

I am a TSQL fanatic. The programs I code are highly dependent upon MS SQL stored procedures. I pay for this love of TSQL when a major overhaul of the system is necessary. Sometimes my code needs to be updated heavily in two places; client and server. To facilitate these updates, I created a database searching program I call DB Grep. It uses Regex to search out every reference to words or phrases in an entire database. The program has saved many hours of research and gives me the warm fuzzy "I didn’t miss anything" feeling.

When developing DB Grep, I ran into an interesting problem. How do I find the SQL Servers on my network?

Options

After many hours of web research, I came up with the following alternatives:

Option Pro Con
No Location Services. No code to write. Typing in SQL server names by memory is a pain.
Use Windows OS Services. Using NetServerEnum is very fast. Does not always return the desired results. It returns Windows server names, not SQL Server names, and they are not always the same. It also does not work well on a non-domain based network. Couldn't find my local MSDE server.
Use the SQLDMO objects. Returns the desired results. Installation headaches. Installing COM objects is always problematic, not to mention possible license issues.
Use ODBC Returns the desired results. Should already be installed. Haven't found any yet.

Needless to say, I picked the ODBC solution. This required a bit of research with a lot of PInvoke trial and error.

I should state up front that this has not been tested on Windows 95/98/ME. I have decided that these operating systems are no longer necessary for my new development. The code has been tested on Windows 2000 and XP using Framework 1.1.

The Process

In order to acquire the names of the available SQL servers from ODBC, we have to allocate an environment, set the ODBC style and connect to the ODBC service. SQLAllocHandle() is used to get the environment and connection handles. In between the calls, it is necessary to specify what version of ODBC is to be used, by calling SQLSetEnvAttr(). I choose ODBC 3.0 using a system constant. Of course, you must always play nice with the ODBC resources by releasing both the environment and connection handles with matching calls to SQLFreeHandle().

I wrapped the allocation calls in a try block and the free calls in the finally section to ensure the release of the ODBC resources. The necessary PInvoke declarations to setup and tear down the ODBC environment are as follows:

private const short SQL_HANDLE_ENV = 1;
private const short SQL_HANDLE_DBC = 2;
private const int SQL_ATTR_ODBC_VERSION = 200;
private const int SQL_OV_ODBC3 = 3;
private const short SQL_SUCCESS = 0;


[DllImport("odbc32.dll")]
private static extern short SQLAllocHandle(
    short hType, 
    IntPtr inputHandle, 
    out IntPtr outputHandle);
[DllImport("odbc32.dll")]
private static extern short SQLSetEnvAttr(
    IntPtr henv, 
    int attribute, 
    IntPtr valuePtr, 
    int strLength);
[DllImport("odbc32.dll")]
private static extern short SQLFreeHandle(
    short hType, 
    IntPtr handle);

Once the connection has been established, we can use a trick of the SQL ODBC driver to locate the advertising MS SQL servers. I attempt to open a MS SQL database connection using SQLBrowseConnect() by specifying only the SQL driver. The driver accommodates my request by building a connection string with the required parameters filled in with the possible values it can derive (like the available MS SQL Servers). It then returns a value stating that it needs more information. The server names can be easily parsed out of this connection string.

For speed, I pre-allocate a StringBuilder with a capacity of 1024 characters. In case of an extra large list of available servers, I test an out parameter to see if a larger string is necessary. I recall the SQLBrowseConnect() function with the newly resized string if necessary. The PInvoke for SQLBrowseConnect() call follows:

private const short SQL_NEED_DATA = 99;
private const string SQL_DRIVER_STR = "DRIVER=SQL SERVER";
 
[DllImport("odbc32.dll",CharSet=CharSet.Ansi)]
private static extern short SQLBrowseConnect(
    IntPtr hconn, 
    StringBuilder inString, 
    short inStringLength, 
    StringBuilder outString, 
    short outStringLength, 
    out short outLengthNeeded);

For example, I pass "DRIVER=SQL SERVER" into SQLBrowseConnect() and get something like "SERVER:Server={(local),SQL_SERVER1,SQL_BKSVR};UID:Login ID=?; PWD:Password=?; *APP:AppName=?; *WSID:WorkStation ID=?" returned. It is a simplistic task to pull out the comma delimited substring between the two curly braces. To simplify the use of the server list, I call the Split() method on the substring to return a string array that can be used in a foreach statement.

For reuse, I encapsulated the PInvoke declarations and the static method within a class. Since this is just a helper method, I took precautions to hide any failures from release code and return a null string[] value in that case. A null return value indicates that no servers were found. Here is an example of calling the resultant code:

string[] theAvailableSqlServers = SqlLocator.GetServers();
if (theAvailableSqlServers != null)
{
    myListBox.DataSource = theAvailableSqlServers;
} 
else
{
    MessageBox.Show("No SQL servers found.");
}

Summary

This code is more research than skill derived. Hopefully, I am able to save you a few hours of trudging through MSDN on a future project. If you do a lot of MS SQL work, you may be interested in my DB Grep program, which is freely available (with source) on GotDotNet. It currently works very well in my environment but, I am sure it could use a good workout elsewhere.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

About the Author

Michael Potter
Chief Technology Officer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralLink for DB Grep ToolmemberMember 142514920 Jan '11 - 1:51 
Hi
 
Thanks for your code, it is very useful for me.
 
given link is broken
 
Could you please tell me new link for Grep Source Code?
 
Thanks,
Karl
QuestionCan you send me the form related to this program?memberlathavarma29 Sep '10 - 22:24 
Your code suits my need, but not able to use as the form is not attached. Can you please provide the form?
GeneralSuggested improvement using Regexmemberkjhduyudmhmxc31 Jul '10 - 17:42 
I'm not sure if the string returned from SQLBrowseConnect will always be the same, but I'm going to use regex to locate the server names.
 
Regex regex = new Regex("Server={(.+)}", RegexOptions.IgnoreCase);
Match match = regex.Match(outString.ToString());
 
if (match.Groups.Count != 2)
throw new ApplicationException("Cannot locate formatted SQL Server names.");
 
text = match.Groups[1].Value;
 
which will replace
 
txt = outString.ToString();
int start = txt.IndexOf("{") + 1;
int len = txt.IndexOf("}") - start;
 
if ((start > 0) && (len > 0))
txt = txt.Substring(start, len);
else
txt = string.Empty;
GeneralLink for DB GrepmemberMember 39203771 Oct '09 - 17:34 
link broken Frown | :(
 
where can get the DB Grep Source Code?
QuestionLicensememberSparkley Doodads14 Jul '08 - 7:37 
Hey, Great class!
 
I was curious as to what license you've released this under. If you could let me know, that'd be great!
 
Thanks!
AnswerRe: LicensememberMichael Potter14 Jul '08 - 7:59 
This is very old code written when .Net 1.0 was king. I believe there are better ways of doing this now.
 
That said: This code (and any other code I have released on this site) can be used anyway you want. I consider it all public domain.
GeneralVery BadmemberDevelopmentTech6 Jul '08 - 4:49 
Very Bad
GeneralThanksmemberGeethanga Amarasinghe9 Oct '07 - 18:19 
Thanks buddy,
this is cool, keep up the good work.Smile | :)
Questionconnect to database in sql?memberlildiapaz5 Jul '07 - 4:11 
Hi, I'm a newbie to c# programming. Can someone please explain to me how to connect to a database from another pc when the server name is provided by the user in a text box. What I want to happen is the user provides the server name, and then I want to connect to a database by using the appropriate login Also is there a way to require the user to provide a user name and password using sql authentication.
 
here's what I tried but it didn't seem to work
 
SqlConnection myConnection =new SqlConnection();
System.Data.SqlClient.SqlConnection conn=new System.Data.SqlClient.SqlConnection();
myConnection.ConnectionString="Persist Security Info=False; Server=myServer; Data Source=remote_machine; UID=*****; PWD=*****; Database=your-database";
 

Any help would be greatly appreciatedConfused | :confused:
 
try
{
myConnection.Open()
textbox1.Text="Connected!";
}
catch(Exception ex)
{
MessageBox.Show("Failed");
}
finally
{
myConnection.Close();
}
Generalusing your GetSqlClassmemberRepliCrux19 Jun '07 - 15:12 
Hi Michael,
 
I am using your GetSqlClass to browse servers in my project. If complete I will give your referecne in the class before I display in code project.
 
Thanks
GeneralUse with Sybase 9memberChris_McGrath6 Apr '06 - 15:06 
I need a class similar to this only it looks up Sybase 9 databases. I tried changing the SQL_DRIVER_STR to "DRIVER=Adaptive Server Anywhere 9.0" but it still doesn't work. Any ideas?
 
Cheers,
Chris
QuestionCannot see local sql server (MSDE) when .NET Framework 2.0 is installedmemberCaJuDo23 Jan '06 - 0:03 
When i install the .net framework 1.1 and .net framework 2.0 I cannot see my local msde db.
When i deinstall framework 1.1 everything works fine.
What can I do? Is it possible to have both frameworks installed and use SQLBrowseConnect?
 
Thanks a lot!
 

AnswerRe: Cannot see local sql server (MSDE) when .NET Framework 2.0 is installedmemberTommi G25 Oct '06 - 15:13 
.NET 2.0 supports direct finding of SQL Server instances by a class under System.Data (which name I just can't remember).
GeneralApp Failed to Initializememberdna199012 Jan '06 - 6:28 
Running DBGrep.exe, I get the above message.
 
What did I miss? Is there a .NET, COM, etc type of install needed?
GeneralRe: App Failed to InitializememberMichael Potter12 Jan '06 - 8:04 
No idea - I think I wrote in Framework 1.1 (that is all it should require). It has been awhile. You are welcome to the source if you would like it.
GeneralHelp me,please.memberSinbaQL29 Dec '05 - 17:07 
I can't understand SQLBrowseConnect() very clearly.
For example, If I pass "Driver=SQL Server;SERVER=OTHER;UID=; PWD=" or "Driver=SQL Server" into SQLBrowseConncetion() will get the same result.
Of course, I can't use uid named null to connect the server named OTHER, but how can I get the error information.D'Oh! | :doh:
Thanks.
 
-- modified at 23:08 Thursday 29th December, 2005
QuestionHow get the Infomation about the stored procedures and so on.memberSinbaQL29 Dec '05 - 14:45 
I don't know how to search these objects. Such as search some parameters in the stored procedures belong to the selected sever and database.
Thanks.Smile | :)

GeneralNew link for DB GrepmemberEnrico Detoma26 Dec '05 - 23:29 
Hi,
 
the link for DB Grep on GotDotNet is broken.
Here is the new link: http://www.gotdotnet.com/workspaces/workspace.aspx?id=f83af6a8-fa84-4af8-bd8f-f2daa568c7a6[^]
 
Thank you for sharing! Smile | :)
 
Enrico

GeneralRe: New link for DB GrepmemberSinbaQL27 Dec '05 - 22:05 
Big Grin | :-D
Thanks. I love all of you.
GeneralNew Class supportmemberwschlichtman10 Sep '05 - 14:00 
As of .NET 2.0, you can do the same thing with the following:
 
using System.Data.Sql;
using System.Windows.Forms;
 
private bool GetServers()
{
SqlDataSourceEnumerator sqlDse = SqlDataSourceEnumerator.Instance;
DataTable dt = sqlDse.GetDataSources();
 
foreach (System.Data.DataRow row in dt.Rows)
{
listBox1.Items.Add((string)row["ServerName"]);
}
return (listBox1.Items.Count > 0);
}
 

GeneralNice work!memberkris.mackintosh14 Jul '05 - 12:43 
I dont supose you would consider adding the source to the connection string editor you have in your application, im currently using the standard "data link" but i'd like to customize it more to what you have
thanks in advance
 
-Kris
Questionmanipulating server?memberUnruled Boy19 Jun '05 - 17:41 
start/pause/stop the ms sql serverD'Oh! | :doh:
 
Regards,
unruledboy@hotmail.com
QuestionI need to help: how to get sever name, database name to update connection string?memberheovissan2 Jun '05 - 17:23 
Hi all,
I'm doing a minor project. A part of it is: I intend to write a form which can load all the current sql server name and also the database name equivalent to each server. The user can choose it from combobox and test connection whether success or not. The server name and database name will affect to my connection string which used to access that database. Could you solved this problem? Thank you!
AnswerRe: I need to help: how to get sever name, database name to update connection string?memberSinbaQL28 Dec '05 - 2:54 
I can't understant very clearly.
connection string??
Do you mean the SQLBrowseConnectConfused | :confused:
GeneralProblem ...please helpmemberpubududilena8 May '05 - 16:56 
hi all,
I have used above theory to find SQL Server and databases in My C# Application. I have check it in our Computers which are in NETwork.
In one computer ,I have taken this serious probelm.

I have taken SQL Server Names in the Database List BOX..SQL Server List also showing the SQL Server List Box.I didn't change any code part there.
..
 
Can u please tell me..what's wrong in there??
GeneralRe: Problem ...please helpmemberMichael Potter9 May '05 - 2:43 
I don't understand the problem. I am assuming that english is not your primary language. Can you restate it in a different manner?
GeneralCorrectionmemberDavid M. Kean23 Feb '05 - 17:41 
The following line is incorrect:
 
if (henv != IntPtr.Zero)
{
SQLFreeHandle(SQL_HANDLE_ENV,hconn);
}
 
it should be
 
if (henv != IntPtr.Zero)
{
SQLFreeHandle(SQL_HANDLE_ENV,henv);
}
 
David M. Kean
My Blog: Managed from Down Under
GeneralRe: CorrectionmemberDavid M. Kean23 Feb '05 - 18:24 
I also found that I needed to call SQLDisconnect on the connection handle before freeing it.
 
David M. Kean
My Blog: Managed from Down Under
GeneralRe: CorrectionmemberMichael Potter24 Feb '05 - 3:35 
David,
 
Thanks for finding the bugs. Can you send me your corrected code so that I can make sure I don't 'mis-correct'.
 
Thanks,
Mike Potter
mdpotter55@yahoo.com
GeneralGreat Help - Note on multiple instancesmemberJohn Albright1 Jan '05 - 14:34 
Thanks for the code it is a great help saved me a lot of time.
 
Noticed some messages on mulitple instances. Even Microsofts Enterprise Manager will not discover a second instance when you try to register a server the name must be entered.
 
I noticed that a second instance uses a random port number. It appears the discovery process only checks the default port. Makes sense since it would be time consuming to check all prots and see if SQL server was the rpogram responding. Even with named pipes the second instance uses a specific pipe with the instance name as part of the pipe so there would be no way for the program to auto discover the pipe.
 
So it appears as with the Microsoft products for a second instance the user will always be forced to enter the name.
 
John Albright
GeneralRe: Great Help - Note on multiple instancesmemberJohn Albright2 Jan '05 - 5:26 
Not sure why but my second instance on a server is now identified with this utility. And it also shows up in Microsoft Enterprise Manager.
 
Only change I made was playing with network settings. Changed port on default instance to 1434 and both instances showed up. Changed port back to default of 1433 and they still both show up. Could be the stopping and starting of services for network change, or refreshing from making changes to settings.
 
Would need to experiment with a fresh server and is probably not worth the effort.

 
John Albright
QuestionCan not find the local MSDE whit XP Prof SP2 an active firewallmemberMarkus Eurisch14 Dec '04 - 3:08 
When i install the windows XP Prof service pack 2 and activate the firewall, then i cant see me lokal msde db. when i deactivate the firewall it works great.
What can i do? When i wouldn't like to deactivate the firewall.
Thanks a lot
mib4
AnswerRe: Can not find the local MSDE whit XP Prof SP2 an active firewallmemberMarkus Eurisch15 Dec '04 - 4:41 
I found the problem! The Port UDP 1434 musst been open for the request of the local database.
1434 is the ms-sql-m standard port and can be changed on the installation.
 
it's great Smile | :)
GeneralDataTable question..membermeyi26 Sep '04 - 4:50 
Hi there..
 
How do I code the syntax :
myTable.Columns["mycolumnName"].myProperty = "value";
 
I have
a table class 'myTable' that inherits from System.Data.DataTable.
a column class 'myColumn' inherits from System.Data.Datacolumn.
 
As it is now I don't have acces to 'myProperty' that is a member of 'myColumn'.
-To get access I first have to convert it to 'myColumn' see below ???
 
((myColumn) myTable.Columns["mycolumnName"]).myProperty = "value";
 
thx..
 


QuestionHow to runmemberMattFritzOO79 Sep '04 - 7:53 
Confused | :confused: I hope you can help me.   I am tasked to find all the sql servers on our network, and i came across your code which seems like the perfect solution.   The problem I am encountering is due to my lack of skill.   How do I take your code and run it?   Can you please give me some assistance on this.
 

 
Thank You,
Matt Fritz
GeneralBrilliantmemberCodeGimp19 Aug '04 - 0:27 
...absolutely bloody brilliant! EXACTLY what I needed; you've saved me ages. Thanks, and FANTASTIC work fella!
 
Smile | :)
GeneralRe: BrilliantmemberMichael Potter21 Aug '04 - 5:28 
Thanks
GeneralRe: BrilliantmemberAlexander Ruscle25 Jan '05 - 8:07 
Saved me hours. Kudos!
 
-ar
GeneralRe: BrilliantmemberHyperX1 Aug '05 - 20:10 
Just exactly what I'm looking for! Spent lot of time writing my own code populating SQL servers in my network, this is the only one that worked well and up to my satisfaction.
 
Good job. Will keep an eye on your next article. Thanks.
 
HyperX Wink | ;)
GeneralRe: BrilliantmemberSinbaQL27 Dec '05 - 14:28 
Just exactly what I am looking for,too.
Very brilliant!!
I hope that we can appreciate the super DB Grep soon.;)
Generalisqlmemberalanshen20929 Jul '04 - 17:00 
How about using "isql -L" and analyse the result!
 

 

Alan Shen
 
MCAD for .NET Version
^~^~^~^~^~^~^~^~^~^~^
Great idea is the beginging of success!
GeneralRe: isqlsussAnonymous30 Jul '04 - 15:43 
If isql is present and you know the password - it would be a good solution.
GeneralGreate but work only if a network is presentmemberQuerton8 Jun '04 - 22:27 
Hello,
 
I've tested this code on my desktop computer with success. but this computer is connected to a lan.
 
But if I try to run the code on my laptop, that is not connected to any kind of network, the code doesn't return any sql server. However, there is a local and running sql server that is never detected Cry | :(( .
 
What can I do to use this code in all situation (I need to work with the laptop that can be or not connected to lan) ??!!?
 
Otherwise, it was exactly what I've looking for Smile | :)
 

Thanks
 

 
Pierre-Benoît
GeneralRe: Greate but work only if a network is presentmemberMichael Potter9 Jun '04 - 3:08 
The is code is based on Microsoft's ODBC architecture. I don't have any control over how it searches for servers. This code only responds to the results of the search.
 
I think your left with forcing the user to type in a connection string in these cases.
 
Sorry I can't be of more help....
GeneralRe: Greate but work only if a network is presentmemberJorge Da Silva8 Jul '04 - 5:16 
Detect if the network is present if not search the registry and get the local installed instances.
Hope this helps.
GeneralRe: Greate but work only if a network is presentmemberStefan Wey17 Sep '04 - 4:11 
I've exactly the same problem. Have you got a good idea to detect the network?
GeneralRe: Greate but work only if a network is presentmemberDom24722 Nov '04 - 6:32 
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState( out int Description, int ReservedValue ) ;
 

int o_iDesc;
return InternetGetConnectedState( out o_iDesc, 0 ) ;

 
Sunil
GeneralServer Databases Listmembernlaham11 May '04 - 12:07 
This is a great help. I am trying to extend the use of this code by calling SQLBrowseConnect one more time to get the next attribute level (Databases) so I can have an Enumerated server databases. I do that by using the same connection handle with specificly identifying the Server=MyServer. However, the returned results are always the list of servers instead of the list of databases. So the new string builder holds "SERVER=MyServer;UID=MyName;PWD=MyPass" when SQLBrowseConnect is called one more time. Any idea why I am not getting the list of databases?
 
Here is the link to MSDE example about all SQLBrowseConnect levels:
 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcsql_server_browsing_example.asp
 
Nadim Laham
GeneralRe: Server Databases ListmemberMichael Potter11 May '04 - 17:28 
It certainly sounds like you are doing everything correctly. I have no idea why it is not working.
 
I have always found it easier to use ADO.Net to enumerate the databases on a server. Just connect to Master (which you know is present) and execute:
 
SELECT CATALOG_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
 

If you lookup INFORMATION_SCHEMA in BOL you will find a lot of structure information is available.
 


GeneralRe: Server Databases Listmembernlaham12 May '04 - 5:08 
Thanks Michael for the prompt reply.
 
Yes - the query you've mentioned works if one knows the sa password of master database or if a user is defined for master that have select privs only. Most of the time I do not know the master password to get me in - Unless, if there is a fixed user name and password that is available by all masters, which I am not aware of. Is there such a thing ? forgive me if it is such an obvious answer to this question; but I am an Oracle database developer and this is my first time dealing with SQL Servers.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 23 Dec 2003
Article Copyright 2003 by Michael Potter
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid