如何使用 C# 创建 ODBC DSN 条目?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/334939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:40:07  来源:igfitidea点击:

How do I create an ODBC DSN entry using C#?

c#odbc

提问by Neil Barnwell

I'm working on a legacy application that has a C++ extended stored procedure. This xsproc uses ODBC to connect to the database, which means it requires a DSN to be configured.

我正在处理具有 C++ 扩展存储过程的遗留应用程序。这个 xsproc 使用 ODBC 连接到数据库,这意味着它需要配置一个 DSN。

I'm updating the installer (created using Visual Studio 2008 setup project), and want to have a custom action that can create the ODBC DSN entry, but am struggling to find useful information on Google.

我正在更新安装程序(使用 Visual Studio 2008 安装项目创建),并且想要一个可以创建 ODBC DSN 条目的自定义操作,但我正在努力在 Google 上找到有用的信息。

Can anyone help?

任何人都可以帮忙吗?

采纳答案by Neil Barnwell

I actually solved this myself in the end by manipulating the registry. I've created a class to contain the functionality, the contents of which I've included here:

最后我自己通过操作注册表解决了这个问题。我创建了一个包含功能的类,其中的内容已包含在此处:

///<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();
    }
}

回答by Rob Prouse

There is a CodeProject page on reading ODBC information.

有一个关于阅读 ODBC 信息CodeProject 页面

Reading that should give you the information you need to reverse engineer writing the registry entries you need.

阅读应该为您提供反向工程编写您需要的注册表项所需的信息。

From that code;

从那个代码;

  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\";

回答by Neil Barnwell

Thanks for providing this code, I have used it myself. I had to change two things tough:

感谢提供这个代码,我自己也用过。我不得不改变两件艰难的事情:

To get the driverNameI had to use OpenSubKeyinstead of CreateSubKeyto get the values:

为了获得driverName我必须使用OpenSubKey而不是CreateSubKey获取值:

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

Since I am running Vista, I had to use an application manifest and set the requestedPrivilegesto:

由于我运行的是 Vista,我不得不使用应用程序清单并将其设置requestedPrivileges为:

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

The following article helped me to find the OpenSubKeyissue: http://www.daveoncsharp.com/2009/08/read-write-delete-from-windows-registry-with-csharp/

以下文章帮助我找到了OpenSubKey问题:http: //www.daveoncsharp.com/2009/08/read-write-delete-from-windows-registry-with-csharp/

回答by dlchambers

+1 for Barnwell's code!

+1 Barnwell 的代码!

However, I thinkhis DSNExists() is querying the wrong key. I thinkit should be this:

但是,我认为他的 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; 
} 

回答by chrfalch

There is an API for doing stuff like this. Using the API will also make sure that your application will stay compatible with newer versions of Windows. The API can be found here:

有一个 API 可以做这样的事情。使用 API 还可以确保您的应用程序与较新版本的 Windows 保持兼容。API可以在这里找到:

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

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

PInvoking this function in c# can be found on PInvoke.net.

可以在 PInvoke.net 上找到在 c# 中 PInvoking 这个函数。

回答by Edgar

thanks it was a great help if you are making a dsn to excel maybe need add something like this

谢谢,如果你正在制作一个 dsn 来 excel 可能需要添加这样的东西,这是一个很大的帮助

 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")

回答by ljs

Further to chrfalch's post, here is some sample code for updating a DSN (I know the OP is asking for creation, however this code is easily translatable to whatever you need to do) using the API call rather than via the registry direct (using the information from the pinvoke.net page):-

chrfalch 的帖子之后,这里有一些用于更新 DSN 的示例代码(我知道 OP 要求创建,但是此代码很容易转换为您需要做的任何事情)使用 API 调用而不是通过注册表直接(使用来自pinvoke.net 页面的信息):-

[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 + "##代码##");

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