2008-12-02 14 views
27

Estoy trabajando en una aplicación heredada que tiene un procedimiento almacenado extendido C++. Este xsproc usa ODBC para conectarse a la base de datos, lo que significa que requiere la configuración de un DSN.¿Cómo creo una entrada de ODBC DSN usando C#?

Estoy actualizando el instalador (creado con el proyecto de instalación de Visual Studio 2008) y quiero tener una acción personalizada que pueda crear la entrada ODBC DSN, pero me cuesta encontrar información útil en Google.

¿Alguien puede ayudar?

Respuesta

31

En realidad resolví esto al final al manipular el registro. He creado una clase para contener la funcionalidad, el contenido de las cuales he incluido aquí:

///<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

a mí me funcionó, acaba de cambiar uno entrada de "Servidor" a "Nombre de servidor". Quizás esto sea un cambio en Windows 7. – newenglander

2

Hay un CodeProject page on reading ODBC information.

Lectura que debería darle la información que necesita para aplicar ingeniería inversa escribiendo las entradas de registro que necesita.

Desde ese código;

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

Gracias por proporcionar este código, he utilizado yo mismo. Tenía que cambiar dos cosas difíciles:

Para obtener el driverName tuve que usar OpenSubKey en lugar de CreateSubKey para obtener los valores:

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

Desde que estoy ejecutando Vista, tuve que usar un manifiesto de aplicación y establecer el requestedPrivileges a:

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

el siguiente artículo me ha ayudado a encontrar el tema OpenSubKey: http://www.daveoncsharp.com/2009/08/read-write-delete-from-windows-registry-with-csharp/

2

+1 para el código de Barnwell!

Sin embargo, I piensa su DSNExists() está preguntando la clave incorrecta. Yo creo que debería ser la siguiente:

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

¡Eso es cierto! y otra cosa que ver es la virtualización. En OS de 64 bits de la clave puede ser "SOFTWARE \ Wow6432Node \ ODBC \ \ ODBC.INI fuentes de datos ODBC" – gsubiran

0

gracias fue una gran ayuda si usted está haciendo un DSN para sobresalir necesita quizá agregar algo como esto

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

Además de chrfalch's post, aquí algunos ejemplos de código para la actualización de un DSN (sé que el PO es pidiendo la creación, sin embargo, este código es fácilmente traducible a lo que usted tiene que hacer) utilizando la llamada a la API en lugar de a través del registro directo (usando la información de la 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

me gusta mucho más el enfoque sobre la API al rededor con el registro, más API de aquí http://support.microsoft.com/kb/142216 – PeskyGnat

Cuestiones relacionadas