在LabWindows/CVI和LabVIEW中配置ODBC数据源

1 前言
ADO作为Microsoft开发数据库应用程序的最新接口,是一种提供访问各种数据类型的连接机制。由于它提供了比 DAO和RDO更加灵活的技术和更为广泛的应用,各种高级语言都用它来编制数据库应用程序。LabWindows/CVI和LabVIEW作为目前最流行的虚拟仪器开发工具之,通过ActiveX控件技术来支持利用ADO技术来访问数据库,ADO技术是LabWindows/CVI和LabVIEW访问数据库最理想的方式,它不仅编程简单,而且支持多种类型的数据库。
ADO是通过DSN(数据源名)来访问数据库的。DSN是应用程序用以请求一个连到ODBC数据源的连接(CONNECTION)名字,它隐藏了诸如数据库文件名、所在目录、数据库驱动程序、用户ID、密码等细节。当建立一个连接时,不用去考虑数据库文件名、路径等等,只要给出它在ODBC中的DSN即可。因此,在使用ADO访问数据库前,先要配置ODBC数据源,即建立DSN与数据库文件名、所在目录、数据库驱动程序、用户ID、密码之间的对应关系。在一般情况下,可以用Windows系统下ODBC数据源管理器手动完成ODBC数据源的配置。可是,当改变数据源位置或者要将程序(包含数据源)安装到其他计算机上时,必须重新配置ODBC数据源,这样做不仅麻烦,而且给用户使用应用程序带来了困难。
在一些高级语言中(如VB,C++)可以通过数据库引擎或在注册表中创建ODBC数据源键值的方法来实现ODBC数据源的自动配置。由于LabWindows/CVI和LabVIEW中没有提供数据库引擎或者类似的工具来完成ODBC的自动配置,因此第一种方法不能实现;第二种方法,在LabWindows/CVI和LabVIEW中可以实现,直接用LabWindows/CVI或者LabVIEW提供的注册表操作函数创建键值,对于SQL SERVER数据库来说,并不需要很深的注册表相关的知识。
下面我们分别通过LabWindows/CVI和LabVIEW介绍怎样通过创建注册表文件的方法来实现ODBC数据源自动配置,这种方法不仅可行而且编程简单,对注册表的知识也没有很高的要求。注册表由项(也叫主键或称“键”)、子项(子键)和值构成。对于SQL SERVER数据库来说,主键为:HKEY_CURRENT_USER;子键为:SOFTWARE\ODBC\ODBC.INI\BS2022,BS2022为自己定义的数据库名称;值分别为:Database:Doserate(自定义)、Driver为:C:\Windows\system32\SQLSRV32.dll;LastUser(计算机用户名);Server(服务器名)和Trusted_Connection:Yes。

2 LabVIEW创建注册表文件,动态配置ODBC数据源
不难发现,手动配置ODBC数据源实际上是将数据源的相关信息写入注册表,而应用程序又是通过注册表中的相关信息来访问数据源的。因此,只要将与手动配置相似的注册表信息导入到注册表中,并由程序控制注册表中的相关内容,就可实现ODBC数据源的自动配置。在LabVIEW中实现注册表的导入和修改并不是一件很困难的事,因此用这种方法进行其自动配置ODBC数据源是极为方便的。
LabVIEW对注册表的操作主要是使用Functions>>Conectivity>>Windows Registry>>Access Vis函数模板中的简易VIs实现的。

我们主要使用:Creat Registry Key. vi, Write Registry Value Simple. Vi 和 Close Registry Key.vi三个简易vi实现修改注册表。其中Creat Registry Key.vi: 在Windows注册表中创建项或打开已有的项; Write Registry Value Simple. Vi: 使数据写入引用句柄指定的注册表项下的值。通过连线数据至字符串/二进制数据输入端可确定要使用的多态实例,也可手动选择实例; Close Registry Key.vi: 关闭Windows注册表中的项。
源代码如下:

本例在Windows 10+LabVIEW2020上运行通过,运行效果如下:

3 LabWindows/CVI创建注册表文件,动态配置ODBC数据源
同样在LabWindows/CVI中实现注册表的导入和修改并也不是一件很困难的事,用这种方法进行其自动配置ODBC数据源是极为方便的。
LabWindows/CVI对注册表的操作主要是使用:RegOpenKeyEx函数,RegWriteString函数及RegCloseKey函数。
RegOpenKeyEx()函数功能描述:打开一个指定的注册表键
原型:
LONG RegOpenKeyEx(HKEY hKey, // 需要打开的主键的名称
LPCTSTR lpSubKey, //需要打开的子键的名称
DWORD ulOptions, // 保留,设为0
REGSAM samDesired, // 安全访问标记,也就是权限
PHKEY phkResult // 得到的将要打开键的句柄
)
参数
hkey:当前打开的密钥或以下预定义密钥之一的句柄
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
Windows NT/2000/XP: HKEY_PERFORMANCE_DATA
Windows 95/98/Me: HKEY_DYN_DATA
lpSubKey:指向一个空终止字符串的指针,该字符串包含要打开的子键的名称。如果该参数为NULL或指向空字符串的指针,则函数将为由hKey参数标识的键打开一个新句柄。在这种情况下,函数将不会关闭先前打开的句柄。
ulOptions:保留;必须是零。
samDesired:一个访问掩码,它指定对密钥的期望访问权限。这个参数可以是以下值的组合。KEY_CREATE_LINK、KEY_CREATE_SUB_KEY、KEY_ENUMERATE_SUB_KEYS、KEY_EXECUTE、KEY_NOTIFY、KEY_QUERY_VALUE、KEY_SET_VALUE、KEY_ALL_ACCESS、KEY_READ、KEY_WOW64_64KEY、KEY_WOW64_32KEY、KEY_WRITE。
phkResult:指向变量的指针,该变量接收打开的键的句柄。当您不再需要返回的句柄时,请调用RegCloseKey函数来关闭它。
返回值
如果函数成功,返回值为ERROR_SUCCESS。 如果函数失败,返回值是Winerror.h中定义的非零错误代码。您可以使用FormatMessage函数和FORMAT_MESSAGE_FROM_SYSTEM标志来获得错误的通用描述。
RegWriteString()函数功能描述: 此函数将以 NUL 结尾的 ASCII 字符串写入 Windows 注册表中的指定键值。您必须指定一个根键、该根键的一个子键以及要向其写入数据的那个子键的实际值。
原型:
int RegWriteString (unsigned int rootKey, const char subkeyName[], const char valueName[], const unsigned char stringBuffer[]);
参数
rootKey:主键,包括HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS、 HKEY_CURRENT_CONFIG、HKEY_CURRENT_CONFIG。
subkeyName[]:子键名。
valueName[];子键键值名,如果值不存在,则由系统创造
stringBuffer[]:子键键值,一般为ASCII字符串,如果值不存在,则由系统创造
返回值
如果函数成功,返回值为0。 如果函数失败,返回值是负数。
RegCloseKey()函数功能描述:释放指定注册键的句柄。
原型
LONG RegCloseKey(
HKEY hKey // 释放键的句柄
);
参数
hKey : [ ] 想要关闭的已经打开的键。
返回值: 如果过程执行成功,返回值是 ERROR_SUCCESS。如果功能失败,返回一个非零值。
头文件应包含:#include <windows.h>和#include "winreg.h"。
源代码如下:
const unsigned char Database[]="Doserate";
const unsigned char Driver[]="C:\\Windows\\system32\\SQLSRV32.dll";
const unsigned char Trusted[]="Yes";
const char subkeyName[]="SOFTWARE\\ODBC\\ODBC.INI\\BS2022";
int sBufSize = MAX_COMPUTERNAME_LENGTH + 1;;
const unsigned char computerName[sBufSize];
DWORD bufSizeP = sBufSize;
DWORD size = UNLEN + 1;
const unsigned char buf[size];
GetComputerName(computerName, &bufSizeP);
GetUserName(buf,&size);
RegOpenKeyEx (HKEY_CURRENT_USER, subkeyName, 0, KEY_ALL_ACCESS, &hkey);
RegWriteString (REGKEY_HKCU, subkeyName, "Database", Database);
RegWriteString (REGKEY_HKCU, subkeyName, "Driver", Driver);
RegWriteString (REGKEY_HKCU, subkeyName, "LastUser", buf);
RegWriteString (REGKEY_HKCU, subkeyName, "Server", computerName);
RegWriteString (REGKEY_HKCU, subkeyName, "Trusted_Connection",Trusted);
RegCloseKey(hkey);

本例在Windows 10+LabWindows/CVI 2020上运行通过,效果与使用LabVIEW 2020相同。
4 结论
实例运行结果表明,程序能正确找到ODBC数据源,这说明用该方法能实现自动配置 ODBC数据源。与编写DLL和创建键值实现动态调用相比,写入注册表文件的方法编程简单,操作方便。通过写入注册表文件,不失为LabWindows/CVI和LabVIEW中实现自动配置ODBC数据源的一种理想方法。