在使用VC、VB、Delphi等高级语言编写数据库应用程序时,往往需要用户自己在控制面板中配置ODBC数据源。对于一般用户而言,配置ODBC数据源可能是一件比较困难的工作。而且,在实际应用中,用户往往要求在同一个应用程序中访问不同的数据源,因此采用一般的加载方法就有了无法克服的缺陷。为能在程序中完成这一工作,方便应用程序的使用,本文以VC为开发环境介绍两种在应用程序中动态加载ODBC系统数据源的方法。

方法一:修改注册表

设计思路

一般情况下,当用户在控制面板中配置好ODBC数据源后,Windows系统便在注册表中加入了一些子键来存储用户的配置结果。当应用程序需要用到数据源时,Windows便会通知底层接口查阅注册表中该数据源的配置。如果用户删除了某个ODBC数据源,那么也会在注册表中有所反应。如果配置的数据源是用户数据源, Windows系统便会修改注册表的HKEY_CURRENT_USER\SOFTWARE\ODBC\ODBC.INI子键;如果配置的数据源是系统数据源,Windows系统便会修改注册表的HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBC.INI主键。因此,我们可以在应用程序中使用Windows API中的注册表编辑函数来完成Windows所做的工作,这样就可以达到动态加载数据源的目的。

具体实现

对于不同类型的数据源,注册表的修改也各有不同,但基本上都要修改两个地方。一个是在 ODBC.INI子键下建立一个与数据源描述名同名的子键,并在该子键下建立与数据源配置相关的项;另一个是在ODBC.INI\ODBC Data Sources子键下建立一个新项以便告诉驱动程序管理器ODBC数据源的类型。下面以配置一个Microsoft Access数据源为例给出实现此功能的函数的代码。

/*strSourceName是要创建的数据源名,strSourceDb是数据库存放路径,strDescription是数据源的描述字符串。*/

BOOL CLoadOdbcDlg::LoadDbSource(CString strSourceName, CString strSourceDb, CString strDescription)
{
  //存放打开的注册表键
  HKEY hKey;
  DWORD dw;

//存放注册表API函数执行的返回值
  LONG lReturn;

//存放要打开的子键
  CString strSubKey;

//检测是否安装了MS Access ODBC driver:odbcjt32.dll
  //获得 Windows系统目录
  char sysDir[MAX_PATH];
  char drvName[]="\\odbcjt32.dll";
  ::GetSystemDirectory(sysDir, MAX_PATH);
  strcat(sysDir,drvName);
  CFileFind findFile;
  if(!findFile.FindFile(sysDir))
  {
    AfxMessageBox("您的计算机系统中没有安装MS Access的ODBC驱动程序odbcjt32.dll,您将无法加载该类数据源。" ,MB_OK | MB_ICONSTOP);
    return false;
  }

strSubKey="SOFTWARE\\ODBC\\ODBC.INI\\" + strSourceName;
  //创建 ODBC数据源在注册表中的子键
  lReturn=::RegCreateKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)strSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey,&dw);
  if(lReturn != ERROR_SUCCESS)
    return false;

//设置数据源的各项参数
  CString strDbq = strSourceDb;
  CString strDriver = sysDir;
  DWORD dwDriverId = 25;
  CString strFil = "MS Access;";
  CString strPwd = strSourceName;
  DWORD dwSafeTransactions = 0;
  CString strUid = strSourceName;
  ::RegSetValueEx(hKey, "DBQ", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strDbq), strDbq.GetLength());
  ::RegSetValueEx(hKey, "Description", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strDescription), strDescription.GetLength());
  ::RegSetValueEx(hKey, "Driver", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strDriver), strDriver.GetLength());
  ::RegSetValueEx(hKey, "DriverId", 0L, REG_DWORD, (CONST BYTE*)(&dwDriverId), sizeof(dw));
  ::RegSetValueEx(hKey, "FIL", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strFil),strFil .GetLength ());
  ::RegSetValueEx(hKey, "PWD", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strPwd),strPwd.GetLength ());
  ::RegSetValueEx(hKey, "SafeTransactions", 0L, REG_DWORD, (CONST BYTE*)(&dwSafeTransactions), sizeof(dw));
  ::RegSetValueEx(hKey, "UID", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strUid),strUid.GetLength());
  ::RegCloseKey(hKey);

//创建 ODBC数据源的Jet子键
  strSubKey += "\\Engines\\Jet";
  lReturn = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)strSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dw);
  if(lReturn != ERROR_SUCCESS)
    return false;

//设置该子键下的各项参数
  CString strImplict="";
  CString strUserCommit="Yes";
  DWORD dwPageTimeout=5;
  DWORD dwThreads=3;
  DWORD dwMaxBufferSize=2048;
  ::RegSetValueEx(hKey, "ImplicitCommitSync", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strImplict), strImplict.GetLength()+1);
  ::RegSetValueEx(hKey, "MaxBufferSize", 0L, REG_DWORD, (CONST BYTE*)(&dwMaxBufferSize), sizeof(dw));
  ::RegSetValueEx(hKey, "PageTimeout", 0L, REG_DWORD, (CONST BYTE*)(&dwPageTimeout), sizeof(dw));
  ::RegSetValueEx(hKey, "Threads", 0L, REG_DWORD, (CONST BYTE*)(&dwThreads), sizeof(dw));
  ::RegSetValueEx(hKey, "UserCommitSync", 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strUserCommit), strUserCommit.GetLength());
  ::RegCloseKey(hKey);

//设置ODBC数据库引擎名称
  lReturn=::RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources", 0L, KEY_WRITE, &hKey);
  if(lReturn != ERROR_SUCCESS)
    return false;
  CString strDbType="Microsoft Access Driver (*.mdb)";
  ::RegSetValueEx(hKey, strSourceName, 0L, REG_SZ, (CONST BYTE*)((LPCTSTR)strDbType), strDbType.GetLength());

return true;
}

由于在动态加载中,一般只会改变数据库文件、数据源说明以及数据源描述,故上述函数可以实现应用中的大部分要求。如果应用中还需要作更多的改变,那么也可以通过改变函数参数的方式加以实现。对于需要动态加载多种类型数据源的情况,可以用具有不同参数的重载函数去实现。

方法二:利用DLL

设计思路

Windows系统子目录中的动态链接库Odbcinst.dll提供了一个可以动态地增加、修改和删除数据源的函数SQLConfigDataSource()。该函数的原型如下:

BOOL SQLConfigDataSource(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszAttributes);

hwndParent参数是父窗口句柄。如果该值为NULL,将不会显示与父窗口有关的对话框。

fRequest参数可以设置为下面的数值之一:

ODBC_ADD_DSN:增加一个新的用户数据源;
ODBC_CONFIG_DSN:修改(配置)一个已经存在的用户数据源;
ODBC_REMOVE_DSN:删除一个已经存在的用户数据源;
ODBC_ADD_SYS_DSN:增加一个新的系统数据源;
ODBC_CONFIG_SYS_DSN:修改 (配置)一个已经存在的系统数据源;
ODBC_REMOVE_SYS_DSN:删除一个已经存在的系统数据源。

lpszDriver参数用于传递数据库引擎的名字,等同于方法一中strDbType变量。

lpszAttirbutes参数是关键字的值,即一连串的"keyname=value"字符串,每两个字符串之间用 "\"隔开,如 DSN = Personnel Data\0UID=Smith\0DATABASE=Personnel。关于该参数的详细设置请参阅MSDN中SQLConfigDataSource()函数的帮助文档和各种ODBC驱动程序文档。

具体实现

由于VC的缺省库文件中不包含SQLConfigDataSource()函数,因此使用该函数之前需要将odbcinst.h文件包含在工程的头文件中,在工程的Settings属性对话框Link属性页的Object/library modules编辑框中增加odbccp32.lib,同时保证系统目录system32下有文件odbccp32.dll。

仍以Microsoft Access为例,设置数据源名为demo,数据源描述为"示例数据源",那么在需要动态加载数据源的地方加入下列代码即可:
 
    ::SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, "Microsoft Access Driver (*.mdb)", "DSN=demo\0Description=示例数据库");

小结

上述两种方法都可以实现动态加载各种类型的ODBC数据源,并且在Windows95/98/NT/2000环境下调试通过。方法一在实现时需要较多的代码,方法二所需代码虽少,但需要额外文件的支持,而且随着数据源配置的灵活性的增加,为了形成lpszAttributes字符串,其代码长度也会相应增加。由于从控制面板配置数据源使得程序员可以获得更加直观的理解,所以对于注册表中各项值以及相应项名称的获得除了可以查阅相关驱动程序的文档外,程序员也可以在编程前先通过控制面板配置ODBC数据源,然后根据注册表中相应部分的内容进行编程。

在VC中动态加载ODBC的方法的更多相关文章

  1. 某APK中使用了动态注册BroadcastReceiver,Launcher中动态加载此APK出现java.lang.SecurityException异常的解决方法

    在某APK中,通过如下方法动态注册了一个BroadcastReceiver,代码参考如下: @Override protected void onAttachedToWindow() { super. ...

  2. 在ASP.NET中动态加载内容(用户控件和模板)

    在ASP.NET中动态加载内容(用户控件和模板) 要点: 1. 使用Page.ParseControl 2. 使用base.LoadControl 第一部分:加载模板 下 面是一个模板“<tab ...

  3. 在MVC应用程序中动态加载PartialView

    原文:在MVC应用程序中动态加载PartialView 有时候,我们不太想把PartialView直接Render在Html上,而是使用jQuery来动态加载,或是某一个事件来加载.为了演示与做好这个 ...

  4. WPF中动态加载XAML中的控件

    原文:WPF中动态加载XAML中的控件 using System; using System.Collections.Generic; using System.Linq; using System. ...

  5. vue中动态加载img

    想实现动态加载图片,当点击“首页”时,图片变色 代码如下: <mt-tabbar v-model="selected" fixed class="border-1p ...

  6. js实现动态加载脚本的方法实例汇总

      本文实例讲述了js实现动态加载脚本的方法.分享给大家供大家参考,具体如下: 最近公司的前端地图产品需要做一下模块划分,希望用户用到哪一块的功能再加载哪一块的模块,这样可以提高用户体验. 所以到处查 ...

  7. Linux下C++动态加载so 调用方法

    Windows 下的C++动态加载DLL调用方法 文献参考 http://man7.org/linux/man-pages/man0/dlfcn.h.0p.html http://man7.org/l ...

  8. Java_Java中动态加载jar文件和class文件

    转自:http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下 ...

  9. C#中动态加载和卸载DLL

    在C++中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方卸载.在C#中我们也能使用Assembly.LoadFile实 ...

随机推荐

  1. 【Luogu】P3758可乐(矩阵优化DP)

    题目链接 一开始想到这可能能用矩阵优化,但以为暴力就能卡过……T成二十分 首先我们回顾一下我们的暴力转移方程 用f[i][j][0/1]表示在i时刻,j点,1不爆炸,0已爆炸的方案数,那么f[i][j ...

  2. [BZOJ3611] [Heoi2014]大工程(DP + 虚树)

    传送门 $dp[i][0]$表示节点i到子树中的所有点的距离之和 $dp[i][1]$表示节点i到子树中最近距离的点的距离 $dp[i][2]$表示节点i到子树中最远距离的点的距离 建好虚树后dp即可 ...

  3. [BZOJ4989] [Usaco2017 Feb]Why Did the Cow Cross the Road(树状数组)

    传送门 发现就是逆序对 可以树状数组求出 对于旋转操作,把一个序列最后面一个数移到开头,假设另一个序列的这个数在位置x,那么对答案的贡献 - (n - x) + (x - 1) #include &l ...

  4. 刷题总结——bzoj2243染色

    题目: 题目背景 SDOI2011 DAY1 T3 题目描述 给定一棵有 n 个节点的无根树和 m 个操作,操作有 2 类:1.将节点 a 到节点 b 路径上所有点都染成颜色 c :2.询问节点 a  ...

  5. 【bzoj2733】[HNOI2012]永无乡 线段树合并

    Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...

  6. Linux(6):定时任务

    定时任务 定时任务的说明和分类 # 定时任务分类: 1. crond(crontab) 定时任务软件(软件包 cronie) 2. atd 运行一次 3. anacron 非7*24小时运行的服务器 ...

  7. C Looooops(poj 2115)

    大致题意: 对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束. 若在有限次内结束,则输出循环次数. 否则输出死循环. 解题思路: 题意不难理解,只是利用 ...

  8. *Codeforces587E. Duff as a Queen

    $n \leq 200000$的序列,支持以下$q \leq 4e4$个操作:区间异或$k$:查询区间能异或出多少不同的数.数字$0 \leq a_i \leq 1e9$. 大概是要区间线性基.区间修 ...

  9. 【Tomcat】linux下实时查看tomcat运行日志

    今天在部署一个项目到linux服务器的时候一直报错,可是在日志文件中也没有记录.但是在本地测试的时候都没有错误,在windoesServer服务器上也没错误,实在找不到原因,因此想的实时查看tomca ...

  10. 安装sqlServer2012失败补救

    今天拿着新电脑win10,装数据库2012,装了第一次,没装上,有一半的工具都失败了,慌了.. 连management studio都没装上,我用navicat也连不上. 卸了,第二次安装,装一半卡住 ...