盧志強(qiáng)
摘要:面對(duì)客戶(hù)提出的數(shù)據(jù)庫(kù)中心需要由固定IP地址改為可動(dòng)態(tài)修改的IP,以適應(yīng)機(jī)房變更的需求,而且可能會(huì)在同一個(gè)應(yīng)用程序中訪(fǎng)問(wèn)不同的數(shù)據(jù)庫(kù),作者在程序中自動(dòng)完成這一工作的方法,快速滿(mǎn)足了客戶(hù)的需求。該文將詳細(xì)介紹動(dòng)態(tài)配置數(shù)據(jù)源的方法。
關(guān)鍵詞:ODBC 數(shù)據(jù)源;動(dòng)態(tài)配置;VC
中圖分類(lèi)號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2018)18-0063-01
1 引言
本人項(xiàng)目組開(kāi)發(fā)了某消防監(jiān)控系統(tǒng),采用VC開(kāi)發(fā)實(shí)現(xiàn),使用固定配置的ODBC數(shù)據(jù)源,而系統(tǒng)交付后遇到客戶(hù)需求更改,提出原設(shè)計(jì)的數(shù)據(jù)庫(kù)中心需要由固定IP地址改為可動(dòng)態(tài)修改的IP,以適應(yīng)機(jī)房變更的需求,而且可能會(huì)在同一個(gè)應(yīng)用程序中訪(fǎng)問(wèn)不同的數(shù)據(jù)庫(kù),因此采用一般的加載方法就有了無(wú)法克服的缺陷。如果能在程序中自動(dòng)完成這一工作,將能快速滿(mǎn)足客戶(hù)的需求。那么該如何通過(guò)程序代碼完成數(shù)據(jù)源的注冊(cè)呢?本文將詳細(xì)介紹動(dòng)態(tài)配置數(shù)據(jù)源的方法。
2 VC中加載數(shù)據(jù)源的具體實(shí)現(xiàn)
在VC中注冊(cè)O(shè)DBC數(shù)據(jù)源一般有兩種方法:利用函數(shù)SQLConfigDataSource和修改注冊(cè)表。本文重點(diǎn)介紹利用函數(shù)SQLConfigDataSource的方法。
如果只是靜態(tài)的配置ODBC數(shù)據(jù)源,即數(shù)據(jù)源各參數(shù)(數(shù)據(jù)源名稱(chēng)、服務(wù)器、數(shù)據(jù)庫(kù)文件路徑、數(shù)據(jù)庫(kù)名等)是固定的,那么使用SQLConfigDataSource函數(shù)可以輕松的實(shí)現(xiàn)程序配置數(shù)據(jù)源,舉例如下:
if(SQLConfigDataSource(NULL, ODBC_ADD_DSN, "SQL Server",
"DSN=EINet\0"
"SERVER=192.168.1.100\0"
"DATABASE=myEIfireDB\0"
"Trusted_Connection=Yes\0")==1)
AfxMessageBox("Success!");
上面的代碼也可以寫(xiě)成:
if(SQLConfigDataSource(NULL, ODBC_ADD_DSN, "SQL Server", "DSN=EINet\0SERVER=192.168.1.100\0DATABASE=myEIfireDB\0Trusted_Connection=Yes")==1)
AfxMessageBox("Success!");
函數(shù)最后一個(gè)參數(shù)(lpszAttributes)為一連串的"KeyName = value"字符串,每?jī)蓚€(gè)KeyName值之間用""隔開(kāi),連續(xù)的兩個(gè)引號(hào),相當(dāng)于連接符號(hào),使用它們可以便于新代碼排版,這比在行結(jié)尾處加連接符"\"更方便。lpszAttributes的具體設(shè)置,可以參考Windows系統(tǒng)目錄下幫助文件odbcjtn.hlp主題目錄標(biāo)簽中的“ODBC API函數(shù)改變|SQLConfigDataSource”條目。而尤其值得說(shuō)明的是每個(gè)"KeyName = value"字符串都必須以"\0"結(jié)尾,這就造成了動(dòng)態(tài)設(shè)定lpszAttributes的困難,先看這段代碼:
CString strSource;
CString strIP = _T("192.168.1.100");
strSource.Format("DSN=EINet\0SERVER=\"%s\"\0DATABASE=myEIfireDB\0Trusted_Connection=Yes",strIP);
LPCSTR lpszAttributes = (LPCSTR)strSource;
if(SQLConfigDataSource(NULL,ODBC_ADD_DSN,"SQL Server",lpszAttributes)==1)
AfxMessageBox("Success!");
else
AfxMessageBox("Fail!");
運(yùn)行結(jié)果:Fail!
單步調(diào)試觀(guān)察變量變化:
發(fā)現(xiàn)lpszAttributes僅包含"DSN=EINet"的信息,其他配置數(shù)據(jù)源的信息都丟失了,原因在于CString默認(rèn)以"\0"作為字符串的結(jié)束標(biāo)志,在強(qiáng)制類(lèi)型轉(zhuǎn)換時(shí)造成了數(shù)據(jù)丟失。
解決辦法為:使用編碼轉(zhuǎn)換,在堆棧中分配內(nèi)存,創(chuàng)建一個(gè)char型數(shù)組,將lpszAttributes中的"\0"用"#"來(lái)表示,然后將數(shù)組中的字符賦給CString字符串,用CString的Replace方法再將"#"替換為"\0"。
具體代碼如下:
BOOL AddDSN(CString strServerIP)
{
USES_CONVERSION;
_TCHAR buffer[MAX_PATH] = {0};
LPCTSTR lpstrServerIP = strServerIP;
_stprintf(buffer, _T("DSN= eiSource #")_T("SERVER=%s#") _T("DATABASE=eiDB#")_T("Trusted_Connection=Yes#"),lpstrServerIP);
CString strAttributes = buffer;
int len = strAttributes.GetLength();
strAttributes.Replace(_T('#'), _T('\0'));
return SQLConfigDataSource(NULL, ODBC_ADD_DSN, "SQL Server", strAttributes.GetBuffer(len));
}
上面兩個(gè)函數(shù)中用到的USES_CONVERSION是ATL中的一個(gè)宏定義。用于編碼轉(zhuǎn)換(用的比較多的是CString的LPCWSTR轉(zhuǎn)換)。在ATL下使用要包含頭文件atlconv.h,使用時(shí)一定要小心,它們從堆棧上分配內(nèi)存,直到調(diào)用它的函數(shù)返回,該內(nèi)存不會(huì)被釋放。如果在一個(gè)循環(huán)中,這個(gè)宏被反復(fù)調(diào)用幾次,將不可避免的產(chǎn)生stackoverflow。為避免這種情況發(fā)生,同時(shí)減小代碼量,在VC下可以更方便地直接使用下列代碼:
BOOL ConfigDSN(CString strServerIP){
_TCHAR buffer[MAX_PATH] = {0};
LPCTSTR lpstrServerIP = strServerIP;
sprintf(buffer, _T("DSN= eiSource #")_T("SERVER=%s#") _T("DATABASE=eiDB#")_T("Trusted_Connection=Yes#"),lpstrServerIP);
CString strAttributes = buffer;
strAttributes.Replace(_T('#'), _T('\0'));
return SQLConfigDataSource(NULL, ODBC_CONFIG_DSN, "SQL Server", strAttributes);
}
調(diào)用上述自定義函數(shù):
CString strServerIP = _T("192.168.1.100");
if(AddDSN(strServerIP))
AfxMessageBox("Success!");
執(zhí)行代碼后結(jié)果:Success!
可以看到,程序順利地執(zhí)行,成功配置好了數(shù)據(jù)源。
3 結(jié)束語(yǔ)
從以上分析和運(yùn)行結(jié)果可以看出:利用函數(shù)SQLConfigDataSource和修改注冊(cè)表,都可以實(shí)現(xiàn)動(dòng)態(tài)修改數(shù)據(jù)源,尤其是可以實(shí)現(xiàn)多個(gè)數(shù)據(jù)源的切換,從而實(shí)現(xiàn)同一個(gè)應(yīng)用程序中訪(fǎng)問(wèn)不同的數(shù)據(jù)庫(kù)甚至通過(guò)IP地址切換實(shí)現(xiàn)訪(fǎng)問(wèn)同一數(shù)據(jù)源名的多個(gè)遠(yuǎn)程服務(wù)器。