using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace Sdaleo.Systems.SQLServer { /// /// Summary description for SQLInfoEnumerator. /// This class Enumerates a network for SQL Server instances and returns a list. /// For a given SQL Server instance a list of all available databases is returned /// For more information see /// /// /// internal class SQLInfoEnumerator { #region ODBC32 external function definitions [DllImport("odbc32.dll")] private static extern short SQLAllocHandle(short handleType, IntPtr inputHandle, out IntPtr outputHandlePtr); [DllImport("odbc32.dll")] private static extern short SQLSetEnvAttr(IntPtr environmentHandle, int attribute, IntPtr valuePtr, int stringLength); [DllImport("odbc32.dll")] private static extern short SQLFreeHandle(short hType, IntPtr Handle); [DllImport("odbc32.dll", CharSet = CharSet.Ansi)] private static extern short SQLBrowseConnect(IntPtr handleConnection, StringBuilder inConnection, short stringLength, StringBuilder outConnection, short bufferLength, out short stringLength2Ptr); #endregion #region Constants private const string SQL_DRIVER_STR = "DRIVER={SQL SERVER};"; private const short SQL_SUCCESS = 0; private const short SQL_SUCCESS_WITH_INFO = 1; 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_NEED_DATA = 99; private const short DEFAULT_RESULT_SIZE = 1024; private const string START_STR = "{"; private const string END_STR = "}"; #endregion /// /// Enumerate the SQL Servers returning a list (if any exist) /// /// internal static string[] EnumerateSQLServers() { return RetrieveInformation(SQL_DRIVER_STR); } /// /// Enumerate the specified SQL server returning a list of databases (if any exist) /// /// internal static string[] EnumerateSQLServersDatabases(string SQLServerNInstance) { return RetrieveInformation(SQL_DRIVER_STR + "SERVER=" + SQLServerNInstance + ";"); } /// /// Enumerate the specified SQL server returning a list of databases (if any exist) /// /// internal static string[] EnumerateSQLServersDatabases(string SQLServerNInstance, string Username, string Password) { return RetrieveInformation(SQL_DRIVER_STR + "SERVER=" + SQLServerNInstance + ";" + "UID=" + Username + ";" + "PWD=" + Password + ";"); } /// /// 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 /// /// A valid string to query for /// private static string[] RetrieveInformation(string InputParam) { IntPtr m_environmentHandle = IntPtr.Zero; IntPtr m_connectionHandle = IntPtr.Zero; StringBuilder inConnection = new StringBuilder(InputParam); short stringLength = (short)inConnection.Length; StringBuilder outConnection = new StringBuilder(DEFAULT_RESULT_SIZE); short stringLength2Ptr = 0; bool bConnectSuccessful = false; try { // Prepare the SQL Environment Handles if ((IsSQLSuccess(SQLAllocHandle(SQL_HANDLE_ENV, m_environmentHandle, out m_environmentHandle))) && (IsSQLSuccess(SQLSetEnvAttr(m_environmentHandle, SQL_ATTR_ODBC_VERSION, (IntPtr)SQL_OV_ODBC3, 0))) && (IsSQLSuccess(SQLAllocHandle(SQL_HANDLE_DBC, m_environmentHandle, out m_connectionHandle)))) { // Fetch the Data * First get the size of the buffer, then call it to get the buffer * if (IsSQLDataSuccess(SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, null, 0, out stringLength2Ptr)) && IsSQLDataSuccess(SQLBrowseConnect(m_connectionHandle, inConnection, stringLength, outConnection, stringLength2Ptr, out stringLength2Ptr)) ) { bConnectSuccessful = true; } } } catch { /* ignore */ } finally { FreeConnection(m_connectionHandle); FreeConnection(m_environmentHandle); } if (bConnectSuccessful && outConnection.ToString() != "") { return ParseSQLOutConnection(outConnection.ToString()); } else { return null; } } #region Helper Functions /// /// For quick SQL Return value evaluation /// private static bool IsSQLSuccess(short SQL_VALUE) { if (SQL_VALUE == SQL_SUCCESS || SQL_VALUE == SQL_SUCCESS_WITH_INFO) return true; else return false; } /// /// For quick SQL Return value evaluation /// private static bool IsSQLDataSuccess(short SQL_VALUE) { if (SQL_VALUE == SQL_SUCCESS || SQL_VALUE == SQL_SUCCESS_WITH_INFO || SQL_VALUE == SQL_NEED_DATA) return true; else return false; } /// /// Parse an outConnection string returned from SQLBrowseConnect /// /// string to parse /// Parsed Server names, or Empty Array if none found private static string[] ParseSQLOutConnection(string outConnection) { int m_Start = outConnection.IndexOf(START_STR) + 1; int m_lenString = outConnection.IndexOf(END_STR) - m_Start; if ((m_Start > 0) && (m_lenString > 0)) { outConnection = outConnection.Substring(m_Start, m_lenString); } else { outConnection = string.Empty; } return outConnection.Split(",".ToCharArray()); } /// /// Call this to Free a SQL handle /// private static void FreeConnection(IntPtr handleToFree) { if (handleToFree != IntPtr.Zero) SQLFreeHandle(SQL_HANDLE_DBC, handleToFree); } #endregion } }