2008-12-02 5 views
27

Я работаю над устаревшим приложением с расширенной хранимой процедурой C++. Этот xsproc использует ODBC для подключения к базе данных, а это значит, что для настройки DSN требуется настройка.Как создать запись DSN ODBC с использованием C#?

Я обновляю установщик (созданный с помощью проекта установки Visual Studio 2008) и хочу иметь настраиваемое действие, которое может создать запись DSN ODBC, но я изо всех сил пытаюсь найти полезную информацию о Google.

Может ли кто-нибудь помочь?

ответ

31

Я на самом деле решил это сам, в конце концов, манипулируя реестром. Я создал класс, чтобы содержать функциональные возможности, содержание которых я включил здесь:

///<summary> 
/// Class to assist with creation and removal of ODBC DSN entries 
///</summary> 
public static class ODBCManager 
{ 
    private const string ODBC_INI_REG_PATH = "SOFTWARE\\ODBC\\ODBC.INI\\"; 
    private const string ODBCINST_INI_REG_PATH = "SOFTWARE\\ODBC\\ODBCINST.INI\\"; 

    /// <summary> 
    /// Creates a new DSN entry with the specified values. If the DSN exists, the values are updated. 
    /// </summary> 
    /// <param name="dsnName">Name of the DSN for use by client applications</param> 
    /// <param name="description">Description of the DSN that appears in the ODBC control panel applet</param> 
    /// <param name="server">Network name or IP address of database server</param> 
    /// <param name="driverName">Name of the driver to use</param> 
    /// <param name="trustedConnection">True to use NT authentication, false to require applications to supply username/password in the connection string</param> 
    /// <param name="database">Name of the datbase to connect to</param> 
    public static void CreateDSN(string dsnName, string description, string server, string driverName, bool trustedConnection, string database) 
    { 
     // Lookup driver path from driver name 
     var driverKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + driverName); 
     if (driverKey == null) throw new Exception(string.Format("ODBC Registry key for driver '{0}' does not exist", driverName)); 
     string driverPath = driverKey.GetValue("Driver").ToString(); 

     // Add value to odbc data sources 
     var datasourcesKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + "ODBC Data Sources"); 
     if (datasourcesKey == null) throw new Exception("ODBC Registry key for datasources does not exist"); 
     datasourcesKey.SetValue(dsnName, driverName); 

     // Create new key in odbc.ini with dsn name and add values 
     var dsnKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + dsnName); 
     if (dsnKey == null) throw new Exception("ODBC Registry key for DSN was not created"); 
     dsnKey.SetValue("Database", database); 
     dsnKey.SetValue("Description", description); 
     dsnKey.SetValue("Driver", driverPath); 
     dsnKey.SetValue("LastUser", Environment.UserName); 
     dsnKey.SetValue("Server", server); 
     dsnKey.SetValue("Database", database); 
     dsnKey.SetValue("Trusted_Connection", trustedConnection ? "Yes" : "No"); 
    } 

    /// <summary> 
    /// Removes a DSN entry 
    /// </summary> 
    /// <param name="dsnName">Name of the DSN to remove.</param> 
    public static void RemoveDSN(string dsnName) 
    { 
     // Remove DSN key 
     Registry.LocalMachine.DeleteSubKeyTree(ODBC_INI_REG_PATH + dsnName); 

     // Remove DSN name from values list in ODBC Data Sources key 
     var datasourcesKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + "ODBC Data Sources"); 
     if (datasourcesKey == null) throw new Exception("ODBC Registry key for datasources does not exist"); 
     datasourcesKey.DeleteValue(dsnName); 
    } 

    ///<summary> 
    /// Checks the registry to see if a DSN exists with the specified name 
    ///</summary> 
    ///<param name="dsnName"></param> 
    ///<returns></returns> 
    public static bool DSNExists(string dsnName) 
    { 
     var driversKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + "ODBC Drivers"); 
     if (driversKey == null) throw new Exception("ODBC Registry key for drivers does not exist"); 

     return driversKey.GetValue(dsnName) != null; 
    } 

    ///<summary> 
    /// Returns an array of driver names installed on the system 
    ///</summary> 
    ///<returns></returns> 
    public static string[] GetInstalledDrivers() 
    { 
     var driversKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + "ODBC Drivers"); 
     if (driversKey == null) throw new Exception("ODBC Registry key for drivers does not exist"); 

     var driverNames = driversKey.GetValueNames(); 

     var ret = new List<string>(); 

     foreach (var driverName in driverNames) 
     { 
      if (driverName != "(Default)") 
      { 
       ret.Add(driverName); 
      } 
     } 

     return ret.ToArray(); 
    } 
} 
+1

работал для меня, просто изменил один запись с «Server» на «Servername». Возможно, это изменение в Windows 7. – newenglander 2011-11-29 16:15:22

2

Существует CodeProject page on reading ODBC information.

Чтение, которое должно предоставить вам информацию, необходимую для обратного проектирования записи нужных записей в реестре.

От этого кода;

private const string ODBC_LOC_IN_REGISTRY = "SOFTWARE\\ODBC\\"; 
    private const string ODBC_INI_LOC_IN_REGISTRY = 
      ODBC_LOC_IN_REGISTRY + "ODBC.INI\\"; 

    private const string DSN_LOC_IN_REGISTRY = 
      ODBC_INI_LOC_IN_REGISTRY + "ODBC Data Sources\\"; 

    private const string ODBCINST_INI_LOC_IN_REGISTRY = 
      ODBC_LOC_IN_REGISTRY + "ODBCINST.INI\\"; 

    private const string ODBC_DRIVERS_LOC_IN_REGISTRY = 
      ODBCINST_INI_LOC_IN_REGISTRY + "ODBC Drivers\\"; 
0

Спасибо за предоставление этого кода, я использовал его сам. Я должен был изменить две вещи жестко:

Чтобы получить driverName я должен был использовать OpenSubKey вместо CreateSubKey, чтобы получить значения:

// Lookup driver path from driver name 
var driverKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
     ODBCINST_INI_REG_PATH + driverName); 

Поскольку я бегу Vista, я должен был использовать манифест приложения и установить requestedPrivileges на:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> 

следующая статья помогла мне найти OpenSubKey вопрос: http://www.daveoncsharp.com/2009/08/read-write-delete-from-windows-registry-with-csharp/

2

+1 для кода Барнуэлла!

Тем не менее, I думаю, что его DSNExists() запрашивает неправильный ключ. Я думаю, что это должно быть так:

public static bool DSNExists(string dsnName) 
{ 
    var sourcesKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + "ODBC Data Sources"); 
    if (sourcesKey == null) throw new Exception("ODBC Registry key for sources does not exist"); 

    return sourcesKey.GetValue(dsnName) != null; 
} 
+0

Это правда! и другое, что нужно увидеть, - это виртуализация. На 64-битной ОС ключ может быть «SOFTWARE \ Wow6432Node \ ODBC \ ODBC.INI \ ODBC Источники данных» – gsubiran 2015-11-27 22:02:07

7

Существует АНИ для делать вещи, как это. Использование API также гарантирует, что ваше приложение останется совместимым с более новыми версиями Windows. API можно найти здесь:

http://msdn.microsoft.com/en-us/library/ms716476(VS.85).aspx

PInvoking эту функцию в C# можно найти на Pinvoke.net.

0

благодаря это была большая помощь, если вы делаете DSN, чтобы преуспеть, возможно, нужно добавить что-то вроде этого

var dsnKeyEng = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + dsnName + "\\Engines"); 
var dsnKeyExl = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + dsnName + "\\Engines\\Excel"); 

dsnKeyExl.SetValue("FirstRowHasNames", 01); 
dsnKeyExl.SetValue("MaxScanRows", 8); 
dsnKeyExl.SetValue("Threads",3); 
dsnKeyExl.SetValue("UserCommitSync", "Yes") 
8

Далее в chrfalch's post, вот некоторые примеры кода для обновления источника данных (я знаю, что ФП просить создания, однако этот код легко переводимый на то, что вам нужно сделать) с помощью вызова API, а не через реестр прямой (используя информацию из pinvoke.net page): -

[DllImport("ODBCCP32.DLL", CharSet = CharSet.Unicode, SetLastError = true)] 
static extern bool SQLConfigDataSourceW(UInt32 hwndParent, RequestFlags fRequest, string lpszDriver, string lpszAttributes); 

enum RequestFlags : int 
{ 
    ODBC_ADD_DSN = 1, 
    ODBC_CONFIG_DSN = 2, 
    ODBC_REMOVE_DSN = 3, 
    ODBC_ADD_SYS_DSN = 4, 
    ODBC_CONFIG_SYS_DSN = 5, 
    ODBC_REMOVE_SYS_DSN = 6, 
    ODBC_REMOVE_DEFAULT_DSN = 7 
} 

bool UpdateDsnServer(string name, string server) 
{ 
    var flag = RequestFlags.ODBC_CONFIG_SYS_DSN; 
    string dsnNameLine = "DSN=" + name; 
    string serverLine = "Server=" + server; 

    string configString = new[] { dsnNameLine, serverLine }.Aggregate("", (str, line) => str + line + "\0"); 

    return SQLConfigDataSourceW(0, flag, "SQL Server", configString); 
} 
+0

Я очень предпочитаю API-подход к работе с реестром, больше API здесь http://support.microsoft.com/kb/142216 – PeskyGnat 2012-01-26 16:49:02

Смежные вопросы