在VC中動態加載ODBC的方法
發表時間:2024-02-23 來源:明輝站整理相關軟件相關文章人氣:
[摘要]武漢理工大學信息工程學院 陳建勇 袁景凌 在使用 VC、 VB、 Delphi等高級語言編寫數據庫應用程序時,往往需要用戶自己在控制面板中配置 ODBC數據源。對于一般用戶而言,配置 ODBC數據源可能是一件比較困難的工作。而且,在實際應用中,用戶往往要求在同一個應用程序中訪問不同的數據源,因此...
武漢理工大學信息工程學院 陳建勇 袁景凌
在使用 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," ImplictCommitSync" ,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* )((LCTSTR)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編輯框中增加 odbc32.lib,同時保證系統目錄 system32下有文件 odbccp32.dll。
仍以 Microsoft Access為例,設置數據源名為 demo,數據源描述為 "示例數據源 ",那么在需要動態加載數據源的地方加入下列代碼即可:
::SQLConfigDataSource (NULL,ODBC_ADD_SYS_DSN," Microsoft Access Driver (* .mdb)"," DSN=demo\0Descirption=示例數據庫 " );
小結
上述兩種方法都可以實現動態加載各種類型的 ODBC數據源,并且在 Windows95/98/NT/2000環境下調試通過。方法一在實現時需要較多的代碼,方法二所需代碼雖少,但需要額外文件的支持,而且隨著數據源配置的靈活性的增加,為了形成 lpszAttributes字符串,其代碼長度也會相應增加。由于從控制面板配置數據源使得程序員可以獲得更加直觀的理解,所以對于注冊表中各項值以及相應項名稱的獲得除了可以查閱相關驅動程序的文檔外,程序員也可以在編程前先通過控制面板配置 ODBC數據源,然后根據注冊表中相應部分的內容進行編程。