明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

在VC中動態(tài)加載ODBC的方法

[摘要]武漢理工大學信息工程學院 陳建勇 袁景凌  在使用 VC、 VB、 Delphi等高級語言編寫數(shù)據(jù)庫應(yīng)用程序時,往往需要用戶自己在控制面板中配置 ODBC數(shù)據(jù)源。對于一般用戶而言,配置 ODBC數(shù)據(jù)源可能是一件比較困難的工作。而且,在實際應(yīng)用中,用戶往往要求在同一個應(yīng)用程序中訪問不同的數(shù)據(jù)源,因此...
武漢理工大學信息工程學院 陳建勇 袁景凌

  在使用 VC、 VB、 Delphi等高級語言編寫數(shù)據(jù)庫應(yīng)用程序時,往往需要用戶自己在控制面板中配置 ODBC數(shù)據(jù)源。對于一般用戶而言,配置 ODBC數(shù)據(jù)源可能是一件比較困難的工作。而且,在實際應(yīng)用中,用戶往往要求在同一個應(yīng)用程序中訪問不同的數(shù)據(jù)源,因此采用一般的加載方法就有了無法克服的缺陷。為能在程序中完成這一工作,方便應(yīng)用程序的使用,本文以 VC為開發(fā)環(huán)境介紹兩種在應(yīng)用程序中動態(tài)加載 ODBC系統(tǒng)數(shù)據(jù)源的方法。

方法一:修改注冊表

設(shè)計思路

一般情況下,當用戶在控制面板中配置好 ODBC數(shù)據(jù)源后, Windows系統(tǒng)便在注冊表中加入了一些子鍵來存儲用戶的配置結(jié)果。當應(yīng)用程序需要用到數(shù)據(jù)源時, Windows便會通知底層接口查閱注冊表中該數(shù)據(jù)源的配置。如果用戶刪除了某個 ODBC數(shù)據(jù)源,那么也會在注冊表中有所反應(yīng)。如果配置的數(shù)據(jù)源是用戶數(shù)據(jù)源, Windows系統(tǒng)便會修改注冊表的 HKEY_CURRENT_USER\SOFTWARE\ODBC\ODBC.INI子鍵;如果配置的數(shù)據(jù)源是系統(tǒng)數(shù)據(jù)源, Windows系統(tǒng)便會修改注冊表的 HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBC.

INI主鍵。因此,我們可以在應(yīng)用程序中使用 Windows API中的注冊表編輯函數(shù)來完成 Windows所做的工作,這樣就可以達到動態(tài)加載數(shù)據(jù)源的目的。具體實現(xiàn)對于不同類型的數(shù)據(jù)源,注冊表的修改也各有不同,但基本上都要修改兩個地方。一個是在 ODBC.INI子鍵下建立一個與數(shù)據(jù)源描述名同名的子鍵,并在該子鍵下建立與數(shù)據(jù)源配置相關(guān)的項;另一個是在 \ODBC.INI\ODBC Data Sources子鍵下建立一個新項以便告訴驅(qū)動程序管理器 ODBC數(shù)據(jù)源的類型。下面以配置一個 Microsoft Access數(shù)據(jù)源為例給出實現(xiàn)此功能的函數(shù)的代碼。

/* strSourceName是要創(chuàng)建的數(shù)據(jù)源名, strSourceDb是數(shù)據(jù)庫存放路徑, strDescription是數(shù)據(jù)源的描述字符串。* /

BOOL CLoadOdbcDlg:: LoadDbSource(CString strSourceName,CString strSourceDb, CString strDescription)

{

//存放打開的注冊表鍵

HKEY hKey;

DWORD dw;

//存放注冊表 API函數(shù)執(zhí)行的返回值

LONG lReturn;

//存放要打開的子鍵

CString strSubKey;

//檢測是否安裝了 MS Access ODBC driver:odbcjt32.dll

//獲得 Windows系統(tǒng)目錄

char sysDir[MAX_PATH];

char drvName[]=" \\odbcjt32.dll" ;

::GetSystemDirectory (sysDir,MAX_PATH);

strcat(sysDir,drvName);

CFileFind findFile;

if(!findFile.FindFile (sysDir))

{

AfxMessageBox("您的計算機系統(tǒng)中沒有安裝 MS Access的 ODBC驅(qū)動程序 odbcjt32.dll,您將無法加載該類數(shù)據(jù)源。 " ,MB_OK MB_ICONSTOP);

return false;

}

strSubKey=" SOFTWARE\\ODBC\\ODBC.INI\\"+ strSourceName;

//創(chuàng)建 ODBC數(shù)據(jù)源在注冊表中的子鍵

lReturn=::RegCreateKeyEx(HKEY_LOCAL_

MACHINE,(LPCTSTR)strSubKey,0,NULL,REG_OPTION

_NON_VOLATILE,KEY_WRITE,NULL,& hKey,& dw);

if(lReturn != ERROR_SUCCESS)

return false;

//設(shè)置數(shù)據(jù)源的各項參數(shù)

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

//創(chuàng)建 ODBC數(shù)據(jù)源的 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;

//設(shè)置該子鍵下的各項參數(shù)

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

//設(shè)置 ODBC數(shù)據(jù)庫引擎名稱

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;

}

由于在動態(tài)加載中,一般只會改變數(shù)據(jù)庫文件、數(shù)據(jù)源說明以及數(shù)據(jù)源描述,故上述函數(shù)可以實現(xiàn)應(yīng)用中的大部分要求。如果應(yīng)用中還需要作更多的改變,那么也可以通過改變函數(shù)參數(shù)的方式加以實現(xiàn)。對于需要動態(tài)加載多種類型數(shù)據(jù)源的情況,可以用具有不同參數(shù)的重載函數(shù)去實現(xiàn)。

方法二:利用 DLL

設(shè)計思路

Windows系統(tǒng)子目錄中的動態(tài)鏈接庫 Odbcinst.dll提供了一個可以動態(tài)地增加、修改和刪除數(shù)據(jù)源的函數(shù) SQLConfigDataSource()。該函數(shù)的原型如下:

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

hwndParent參數(shù)是父窗口句柄。如果該值為 NULL,將不會顯示與父窗口有關(guān)的對話框。

fRequest參數(shù)可以設(shè)置為下面的數(shù)值之一:

 ODBC_ADD_DSN:增加一個新的用戶數(shù)據(jù)源;

 ODBC_CONFIG_DSN:修改(配置)一個已經(jīng)存在的用戶數(shù)據(jù)源;

 ODBC_REMOVE_DSN:刪除一個已經(jīng)存在的用戶數(shù)據(jù)源;

 ODBC_ADD_SYS_DSN:增加一個新的系統(tǒng)數(shù)據(jù)源;

 ODBC_CONFIG_SYS_DSN:修改 (配置 )一個已經(jīng)存在的系統(tǒng)數(shù)據(jù)源;

 ODBC_REMOVE_SYS_DSN:刪除一個已經(jīng)存在的系統(tǒng)數(shù)據(jù)源。

lpszDriver參數(shù)用于傳遞數(shù)據(jù)庫引擎的名字,等同于方法一中 strDbType變量。

lpszAttirbutes參數(shù)是關(guān)鍵字的值,即一連串的 " keyname=value"字符串,每兩個字符串之間用 " \"隔開,如 DSN=Personnel Data\0UID=Smith\0DATABASE=Personnel。關(guān)于該參數(shù)的詳細設(shè)置請參閱 MSDN中 SQLConfigDataSource()函數(shù)的幫助文檔和各種 ODBC驅(qū)動程序文檔。

具體實現(xiàn)

由于 VC的缺省庫文件中不包含 SQLConfigDataSource()函數(shù),因此使用該函數(shù)之前需要將 odbcinst.h文件包含在工程的頭文件中,在工程的 Settings屬性對話框 Link屬性頁的 Object/library modules編輯框中增加 odbc32.lib,同時保證系統(tǒng)目錄 system32下有文件 odbccp32.dll。

仍以 Microsoft Access為例,設(shè)置數(shù)據(jù)源名為 demo,數(shù)據(jù)源描述為 "示例數(shù)據(jù)源 ",那么在需要動態(tài)加載數(shù)據(jù)源的地方加入下列代碼即可:

::SQLConfigDataSource (NULL,ODBC_ADD_SYS_DSN," Microsoft Access Driver (* .mdb)"," DSN=demo\0Descirption=示例數(shù)據(jù)庫 " );

小結(jié)

上述兩種方法都可以實現(xiàn)動態(tài)加載各種類型的 ODBC數(shù)據(jù)源,并且在 Windows95/98/NT/2000環(huán)境下調(diào)試通過。方法一在實現(xiàn)時需要較多的代碼,方法二所需代碼雖少,但需要額外文件的支持,而且隨著數(shù)據(jù)源配置的靈活性的增加,為了形成 lpszAttributes字符串,其代碼長度也會相應(yīng)增加。由于從控制面板配置數(shù)據(jù)源使得程序員可以獲得更加直觀的理解,所以對于注冊表中各項值以及相應(yīng)項名稱的獲得除了可以查閱相關(guān)驅(qū)動程序的文檔外,程序員也可以在編程前先通過控制面板配置 ODBC數(shù)據(jù)源,然后根據(jù)注冊表中相應(yīng)部分的內(nèi)容進行編程。