ODBC32.dll 파일을 Import해서 설정 되어 있는 SQL 서버를 찾는 예젭니다.
화면에 ListBox 같은데에 SQL 서버들의 리스트를 화면에 띄울 수 유용한 예젭 입니다.
참고하세요...
using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace DBGrep
{
public class SqlLocator
{
//The necessary PInvoke declarations to setup and tear down the ODBC environment are as follows
[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);
[DllImport("odbc32.dll",CharSet=CharSet.Ansi)]
//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 static extern short SQLBrowseConnect(IntPtr hconn, StringBuilder inString,
short inStringLength, StringBuilder outString, short outStringLength,
out short outLengthNeeded);
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;
private const short SQL_NEED_DATA = 99;
private const short DEFAULT_RESULT_SIZE = 1024;
private const string SQL_DRIVER_STR = "DRIVER=SQL SERVER";
private SqlLocator(){}
public static string[] GetServers()
{
string[] retval = null;
string txt = string.Empty;
IntPtr henv = IntPtr.Zero;
IntPtr hconn = IntPtr.Zero;
StringBuilder inString = new StringBuilder(SQL_DRIVER_STR);
StringBuilder outString = new StringBuilder(DEFAULT_RESULT_SIZE);
short inStringLength = (short) inString.Length;
short lenNeeded = 0;
try
{
if (SQL_SUCCESS == SQLAllocHandle(SQL_HANDLE_ENV, henv, out henv))
{
if (SQL_SUCCESS == SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(IntPtr)SQL_OV_ODBC3,0))
{
if (SQL_SUCCESS == SQLAllocHandle(SQL_HANDLE_DBC, henv, out hconn))
{
if (SQL_NEED_DATA == SQLBrowseConnect(hconn, inString, inStringLength, outString,
DEFAULT_RESULT_SIZE, out lenNeeded))
{
if (DEFAULT_RESULT_SIZE < lenNeeded)
{
outString.Capacity = lenNeeded;
if (SQL_NEED_DATA != SQLBrowseConnect(hconn, inString, inStringLength, outString,
lenNeeded,out lenNeeded))
{
throw new ApplicationException("Unabled to aquire SQL Servers from ODBC driver.");
}
}
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;
}
}
}
}
}
}
catch (Exception ex)
{
//Throw away any error if we are not in debug mode
#if (DEBUG)
MessageBox.Show(ex.Message,"Acquire SQL Servier List Error");
#endif
txt = string.Empty;
}
finally
{
if (hconn != IntPtr.Zero)
{
SQLFreeHandle(SQL_HANDLE_DBC,hconn);
}
if (henv != IntPtr.Zero)
{
SQLFreeHandle(SQL_HANDLE_ENV,hconn);
}
}
if (txt.Length > 0)
{
retval = txt.Split(",".ToCharArray());
}
return retval;
}
}
}
//위 클래스의 함수를 다른 곳에서 호출하기 위해서는 아래 처럼 하시면 됩니다.
//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,
//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.");
// }
댓글 없음:
댓글 쓰기