SqlDataSourceEnumerator.Instance.GetDataSources()找不到本地SQL Server 2008实例

sea*_*717 4 c# sql-server sql-server-2005 sql-server-2008

我使用以下代码列出所有远程和本地SQL Server实例:

public static void LocateSqlInstances()
  {
     using( DataTable sqlSources = SqlDataSourceEnumerator.Instance.GetDataSources())
     {
        foreach(DataRow source in sqlSources.Rows )
        {
           string instanceName = source["InstanceName"].ToString();

           if (!string.IsNullOrEmpty(instanceName))
           {
              Console.WriteLine(" Server Name:{0}", source["ServerName"]);
              Console.WriteLine("   Instance Name:{0}", source["InstanceName"]);
              Console.WriteLine("   Version:{0}", source["Version"]);
              Console.WriteLine();
           }
        }
        Console.ReadKey();
     }
  }
Run Code Online (Sandbox Code Playgroud)

在我的本地计算机上运行代码.代码可以查找并列出已安装的SQL Server express实例(版本9.0.5000),但无法列出其他SQL Server实例(版本10.0.1600).

我在互联网上做了很多研究,并确保1-Sql Broswer正在运行,2 - UDP端口1434是开放的.

谁知道为什么?谢谢.

Mit*_*eat 16

您正在跳过未命名实例的服务器.修改你的代码:

public static void LocateSqlInstances()
  {
     using (DataTable sqlSources = SqlDataSourceEnumerator.Instance.GetDataSources())
     {
        foreach (DataRow source in sqlSources.Rows )
        {
           string servername;
           string instanceName = source["InstanceName"].ToString();

           if (!string.IsNullOrEmpty(instanceName))
           {
              servername =  source["InstanceName"] + '\\' + source["ServerName"];
           }
           else
           {
              servername =  source["ServerName"];
           }
           Console.WriteLine(" Server Name:{0}", servername );
           Console.WriteLine("     Version:{0}", source["Version"]);
           Console.WriteLine();

        }
        Console.ReadKey();
     }
  }
Run Code Online (Sandbox Code Playgroud)

请注意:SqlDataSourceEnumerator.Instance.GetDataSources()有缺点:

  • 受防火墙规则限制(阻止的TCP/IP 1433和UDP 1434)
  • 如果SQL浏览器关闭,则找不到SQL Server
  • 如果隐藏SQL Server,则找不到它们
  • 列表内容不保证可重复(由于超时).实际上,根据网络I/O,服务器性能,网络上的服务器数量以及其他与时间相关的约束,后续调用很可能会给出不同的列表.

有几个消息来源说你要打2个电话SqlDataSourceEnumerator.Instance.GetDataSources() ......

参考文献:


sea*_*717 8

非常感谢Mitch为他提出的最佳答案.但是,我最终完成的工作如下:

我有两个单独的方法来分别获取本地和远程服务器实例.从注册表中检索本地实例.您需要搜索WOW64和WOW3264配置单元以获取SQL Server 2008(64位)和SQL Server Express(32位)

这是我使用的代码:

/// <summary>
  ///  get local sql server instance names from registry, search both WOW64 and WOW3264 hives
  /// </summary>
  /// <returns>a list of local sql server instance names</returns>
  public static IList<string> GetLocalSqlServerInstanceNames()
  {
     RegistryValueDataReader registryValueDataReader = new RegistryValueDataReader();

     string[] instances64Bit = registryValueDataReader.ReadRegistryValueData(RegistryHive.Wow64,
                                                                             Registry.LocalMachine,
                                                                             @"SOFTWARE\Microsoft\Microsoft SQL Server",
                                                                             "InstalledInstances");

     string[] instances32Bit = registryValueDataReader.ReadRegistryValueData(RegistryHive.Wow6432,
                                                                             Registry.LocalMachine,
                                                                             @"SOFTWARE\Microsoft\Microsoft SQL Server",
                                                                             "InstalledInstances");

     FormatLocalSqlInstanceNames(ref instances64Bit);
     FormatLocalSqlInstanceNames(ref instances32Bit);

     IList<string> localInstanceNames = new List<string>(instances64Bit);

     localInstanceNames = localInstanceNames.Union(instances32Bit).ToList();

     return localInstanceNames;
  }
Run Code Online (Sandbox Code Playgroud)
public enum RegistryHive
{
  Wow64,
  Wow6432
}

public class RegistryValueDataReader
{
  private static readonly int KEY_WOW64_32KEY = 0x200;
  private static readonly int KEY_WOW64_64KEY = 0x100;

  private static readonly UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;

  private static readonly int KEY_QUERY_VALUE = 0x1;

  [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyEx")]
  static extern int RegOpenKeyEx(
              UIntPtr hKey,
              string subKey,
              uint options,
              int sam,
              out IntPtr phkResult);


  [DllImport("advapi32.dll", SetLastError = true)]
  static extern int RegQueryValueEx(
              IntPtr hKey,
              string lpValueName,
              int lpReserved,
              out uint lpType,
              IntPtr lpData,
              ref uint lpcbData);

  private static int GetRegistryHiveKey(RegistryHive registryHive)
  {
     return registryHive == RegistryHive.Wow64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
  }

  private static UIntPtr GetRegistryKeyUIntPtr(RegistryKey registry)
  {
     if (registry == Registry.LocalMachine)
     {
        return HKEY_LOCAL_MACHINE;
     }

     return UIntPtr.Zero;
  }

  public string[] ReadRegistryValueData(RegistryHive registryHive, RegistryKey registryKey, string subKey, string valueName)
  {
     string[] instanceNames = new string[0];

     int key = GetRegistryHiveKey(registryHive);
     UIntPtr registryKeyUIntPtr = GetRegistryKeyUIntPtr(registryKey);

     IntPtr hResult;

     int res = RegOpenKeyEx(registryKeyUIntPtr, subKey, 0, KEY_QUERY_VALUE | key, out hResult);

     if (res == 0)
     {
        uint type;
        uint dataLen = 0;

        RegQueryValueEx(hResult, valueName, 0, out type, IntPtr.Zero, ref dataLen);

        byte[] databuff = new byte[dataLen];
        byte[] temp = new byte[dataLen];

        List<String> values = new List<string>();

        GCHandle handle = GCHandle.Alloc(databuff, GCHandleType.Pinned);
        try
        {
           RegQueryValueEx(hResult, valueName, 0, out type, handle.AddrOfPinnedObject(), ref dataLen);
        }
        finally
        {
           handle.Free();
        }

        int i = 0;
        int j = 0;

        while (i < databuff.Length)
        {
           if (databuff[i] == '\0')
           {
              j = 0;
              string str = Encoding.Default.GetString(temp).Trim('\0');

              if (!string.IsNullOrEmpty(str))
              {
                 values.Add(str);
              }

              temp = new byte[dataLen];
           }
           else
           {
              temp[j++] = databuff[i];
           }

           ++i;
        }

        instanceNames = new string[values.Count];
        values.CopyTo(instanceNames);
     }

     return instanceNames;
  }
}


SqlDataSourceEnumerator.Instance.GetDataSources() is used to get remote sql server instances. 
Run Code Online (Sandbox Code Playgroud)

最后,我只是合并远程实例列表和本地实例列表以生成最终结果.

  • visual studio不识别functrion:FormatLocalSqlInstanceNames(ref instances64Bit); FormatLocalSqlInstanceNames(ref instances32Bit); (2认同)