ADO VC++ Extensions是ADO 2.0 版本提供的新接口,它支持不通過 VARIANT 便可將數據檢索到本地的 C/C++ 數據類型中。此外,它還提供能簡化接口使用過程的預處理宏,這些擴展程序使用簡便並且性能良好。
ADO VC++ Extensions 可將 Recordset 對象的字段映射到 C/C++ 變量,字段與變量的映射稱為綁定條目。預處理宏用來定義數值、定長和變長變量的綁定。
我們以一個簡單的程序為例,說明如何在VC++中使用帶Extensions 的ADO訪問SQL SERVER數據庫。我們假定安裝了SQL SERVER數據庫的Netbios名為nt_sqlserver,要訪問的數據庫名為pubs,操作的表名為authors。
我們可以新建一個空的工程,選擇Win32 Console Application類型。先加入一個頭文件,並命名為ADOtest.h,源代碼如下:
//要使用 VC++ Extensions,必須在應用程序中包含的頭文件:
#include "icrsint.h"
// 該類從"authors"表中 摘取出 fname, lname, city和state 四個字段
class CAuthorsRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CAuthorsRs)
ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_au_fname,
sizeof(m_au_fname), l_fnameStatus, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_au_lname,
sizeof(m_au_lname), l_lnameStatus, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2(3, adVarChar, m_au_city,
sizeof(m_au_city), l_cityStatus, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2(4, adChar, m_au_state,
sizeof(m_au_state), l_stateStatus, TRUE)
END_ADO_BINDING()
public:
char m_au_fname[21];
ULONG l_fnameStatus;
char m_au_lname[41];
ULONG l_lnameStatus;
char m_au_city[21];
ULONG l_cityStatus;
char m_au_state[3];
ULONG l_stateStatus;
};
注意,將 BEGIN_ADO_BINDING 和 END_ADO_BINDING 宏之間的綁定條目用括號括起。不要在綁定條目結尾使用逗號或分號,因為這些定界符僅限在宏中使用。
ADO_VARIABLE_LENGTH_BINDING
_ENTRY2的參數說明如下:
參數1:按順序的字段號碼,1為標識記錄集中第一字段,2為標識記錄集中第二字段,依此類推。
參數2:儲存已轉換字段的變量的數據類型。
參數3:臨時的工作緩沖區,用於將字段值從 VARIANT轉換為C/C++ 變量。
參數4:變長變量所需的字節數。
參數5:指示字段轉換是否成功。
參數6:布爾標志。如果為 TRUE,則表明 ADO 可以更新綁定的字段。如只檢查字段而不將其更改,可設置為 FALSE。
其中第5個參數為狀態參數,它可告訴你從 Recordset 字段到C或C++變量的轉換是否成功以及變量的內容是否有效。該參數的兩個最重要的值是adFldOK(意味著轉換成功)和adFldNull(意味著字段是NULL,即無值可供轉換)。程序中要檢測該參數以決定C或C++變量是否有效。例如,如果字段具有有效的行內容,狀態將會是adFldOK,如果移動到另一個字段為 NULL 的行,則狀態將是 adFldNull。
源程序代碼如下:
#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
no_namespace rename("EOF", "EndOfFile")
#include 〈stdio.h〉
#include 〈ole2.h〉
#include "ADOtest.h"
void main()
{
if(FAILED(::CoInitialize(NULL)))
return;
// 定義ADO 智能指針類的實例,並初始化
RecordsetPtr pRstAuthors = NULL;
//定義其它變量
//接口指針聲明
IADORecordBinding picRs = NULL; CAuthorsRs authorsrs;
//ADO函數要返回HRESULT,宏代碼可以幫我們解釋HRESULT的含義
HRESULT hr;
// 打開 位於nt_sqlserver服務器上的 pubs數據庫中的 Authors 表
bstr_t strCnn("Provider=sqloledb;Data Source=nt_sqlserver;"
"Initial Catalog=pubs;User Id=sa;Password=;");
try
{
// 從 Authors 表中打開記錄集
if FAILED(hr = pRstAuthors.CreateInstance(__uuidof(Recordset)))
com_issue_error(hr);
pRstAuthors-〉CursorType = adOpenStatic;
// 使用 client 游標 ,從而可以使用 AbsolutePosition 屬性pRstAuthors-〉CursorLocation = adUseClient;
pRstAuthors-〉Open("SELECT au_fname, au_lname, city, "
"state FROM Authors ORDER BY au_id", strCnn, adOpenStatic,
adLockReadOnly, adCmdText);
// 打開一個 IADORecordBinding 接口指針(用來對記錄集和C++類的綁定)
if FAILED(hr = pRstAuthors-〉QueryInterface(_uuidof(IADORecordBinding),(LPVOID)&&picRs))
_com_issue_error(hr);
// 調用 BindToRecordset 接口方法可使 Recordset 字段關聯(或綁定)到C/C++ 變量,無論何時更改 Recordset 對象的當前行,C/C++ 變量都將自動更新
if FAILED(hr = picRs-〉BindToRecordset(&&authorsrs))
_com_issue_error(hr);
pRstAuthors-〉MoveFirst();
while(true)
{
// 顯示當前記錄的信息
printf("Record %ld of %d\n", pRstAuthors-〉AbsolutePosition, pRstAuthors-〉RecordCount);
printf("Author: %s %s\n ",
authorsrs.l_fnameStatus == adFldOK ?
authorsrs.m_au_fname : "〈NULL〉",
authorsrs.l_lnameStatus == adFldOK ?
authorsrs.m_au_lname : "〈NULL〉");
printf("Location: %s, %s\n",
authorsrs.l_cityStatus == adFldOK ?
authorsrs.m_au_city : "〈NULL〉",
authorsrs.l_stateStatus == adFldOK ?
authorsrs.m_au_state : "〈NULL〉");
pRstAuthors-〉MoveNext();
if(pRstAuthors-〉EndOfFile)
{
break;
}
}
// 退出前釋放對象
pRstAuthors-〉Close();
// 這裡釋放 IADORecordset 接口
if (picRs)
picRs-〉Release();
}
catch(_com_error &&e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
printf("Error\n");
printf("\tCode = %08lx\n", e.Error());
printf("\tCode meaning = %s\n", e.ErrorMessage());
printf("\tSource = %s\n", (LPCSTR) bstrSource);
printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
}
::CoUninitialize();
}
編譯鏈接之後,程序就可以運行了。這個例子的作用是將SQL SERVER中pubs庫中authors表中的記錄按字段au_id排序後,將記錄在記錄集中的位置、姓名、城市等幾個字段的內容依次顯示在屏幕上。