Visual C++ ADO 程式設計
ADO API 參考使用類似於 Microsoft Visual Basic 的語法,描述 ADO 應用程式開發介面 (API) 的功能。 雖然預期對象是所有使用者,但 ADO 程式設計人員會採用各種語言,例如 Visual Basic、Visual C++ (搭配和不搭配 #import 指示詞) 以及 Visual J++ (使用 ADO/WFC 類別套件)。
注意
Microsoft 已在 2004 年終止 Visual J++ 的支援。
為了因應此多樣性,適用於 Visual C++ 的 ADO 語法索引提供 Visual C++ 語言特定語法,其中包含 API 參考中功能、參數、例外狀況行為等常見描述的連結。
ADO 是使用 COM (元件物件模型) 介面來實作。 不過,程式設計人員比其他人更容易在特定程式設計語言中使用 COM。 例如,幾乎所有使用 COM 的詳細資料都會為 Visual Basic 程式設計人員隱含處理,而 Visual C++ 程式設計人員則必須自行處理這些詳細資料。
下列各節摘要說明 C 和 C++ 程式設計人員使用 ADO 和 #import 指示詞的詳細資料。 其著重於 COM 特定的資料類型 (Variant、BSTR 和 SafeArray),以及錯誤處理 (_com_error)。
使用 #import 編譯器指示詞
#import Visual C++ 編譯器指示詞可簡化 ADO 方法和屬性的使用。 該指示詞接受包含型別程式庫的檔案名稱 (例如 ADO .dll (Msado15.dll)),並產生包含 typedef 宣告、介面智慧型指標和列舉常數的標頭檔。 每個介面都會封裝或包裝在類別中。
對於類別內的每個作業 (即方法或屬性呼叫),會有一個宣告可直接呼叫作業 (即作業的「原始」形式),以及一個宣告可呼叫原始作業,並在作業無法成功執行時擲回 COM 錯誤。 如果作業是屬性,通常會有編譯器指示詞為具有 Visual Basic 等語法的作業建立替代語法。
擷取屬性值的作業以形式 GetProperty 為名。 設定屬性值的作業以形式 PutProperty 為名。 設定具有 ADO 物件指標之屬性值的作業以形式 PutRefProperty 為名。
您可以呼叫這些形式來取得或設定屬性:
variable = objectPtr->GetProperty(); // get property value
objectPtr->PutProperty(value); // set property value
objectPtr->PutRefProperty(&value); // set property with object pointer
使用屬性指示詞
__declspec(property...) 編譯器指示詞是 Microsoft 特定的 C 語言延伸模組,宣告作為屬性的函數具有替代語法。 因此,您可以透過類似於 Visual Basic 的方式來設定或取得屬性值。 例如,您可以透過下列方式來設定和取得屬性:
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
請注意,您不需要編碼:
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
編譯器會根據宣告的替代語法以及正在讀取或寫入屬性,產生適當的 Get-、Put 或 PutRefProperty 呼叫。
__declspec(property...) 編譯器指示詞只能宣告函數的 get、put 或 get 以及 put 替代語法。 唯讀作業只有 get 宣告;唯寫作業只有 put 宣告;讀取及寫入作業則同時有 get 和 put 宣告。
只有兩個宣告能搭配此指示詞;不過,每個屬性都能有三個屬性函數:GetProperty、PutProperty 和 PutRefProperty。 在此情況下,只有兩種屬性形式具有替代語法。
例如,Command 物件 ActiveConnection 屬性是以 GetActiveConnection 和 PutRefActiveConnection 的替代語法宣告。 PutRef 語法是不錯的選擇,因為實際上,您通常會想要將開啟的 Connection 物件 (即 Connection 物件指標) 放在此屬性中。 另一方面,Recordset 物件具有 Get、Put 和 PutRefActiveConnection 作業,但沒有替代語法。
集合、GetItem 方法和 Item 屬性
ADO 會定義數個集合,包括 Fields、Parameters、Properties 和 Errors。 在 Visual C++ 中,GetItem(index) 方法會傳回集合的成員。 Index 是一種 Variant,其值為集合中成員的數值索引,或是包含成員名稱的字串。
__declspec(property...) 編譯器指示詞會將 Item 屬性宣告為每個集合之基本 GetItem() 方法的替代語法。 替代語法使用方括弧,看起來類似於陣列參考。 一般而言,這兩種形式看起來如下:
collectionPtr->GetItem(index);
collectionPtr->Item[index];
例如,將值指派給 Recordset 物件欄位,其名稱為 rs,衍生自 pubs 資料庫的 authors 資料表。 使用 Item() 屬性存取 Recordset 物件 Fields 集合的第三個 Field (集合從零開始編製索引;假設第三個欄位的名稱為 au_fname)。 然後在 Field 物件上呼叫 Value() 方法,以指派字串值。
這在 Visual Basic 中可透過下列四種方式表示 (最後兩種形式是 Visual Basic 特有的;其他語言沒有對等項目):
rs.Fields.Item(2).Value = "value"
rs.Fields.Item("au_fname").Value = "value"
rs(2) = "value"
rs!au_fname = "value"
在 Visual C++ 中,上述前兩種形式的對等項目為:
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
-或- (也會顯示 Value 屬性的替代語法)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
如需逐一查看集合的範例,請參閱「ADO 參考」的「ADO 集合」部分。
COM 特定的資料類型
一般而言,您在 ADO API 參考中找到的任何 Visual Basic 資料類型都有 Visual C++ 對等項目。 這包括標準資料類型,例如 unsigned char 代表 Visual Basic Byte、short 代表 Integer,而 long 代表 Long。 請查看語法索引,以了解指定方法或屬性的運算元所需的確切語法。
此規則的例外是 COM 特定的資料類型:Variant、BSTR 和 SafeArray。
Variant
Variant 是包含值成員和資料類型成員的結構化資料類型。 Variant 可能包含各種不同的其他資料類型,包括另一個 Variant、BSTR、布林值、IDispatch 或 IUnknown 指標、貨幣、日期等。 COM 也提供方法,讓您輕鬆地將某個資料類型轉換成另一種資料類型。
_variant_t 類別可封裝和管理 Variant 資料類型。
當 ADO API 參考指出方法或屬性運算元接受值時,通常表示該值會傳入 _variant_t。
當 ADO API 參考主題中的 Parameters 部分指出運算元是 Variant 時,此規則明確為真。 一個例外是當文件明確指出運算元接受標準資料類型 (例如 Long 或 Byte) 或是列舉時。 另一個例外是當運算元接受 String 時。
BSTR
BSTR (Basic STRing) 是包含字元字串和字串長度的結構化資料類型。 COM 提供配置、操作和釋放 BSTR 的方法。
_bstr_t 類別可封裝和管理 BSTR 資料類型。
當 ADO API 參考指出方法或屬性接受 String 值時,表示該值的格式為 _bstr_t。
轉換 _variant_t 和 _bstr_t 類別
通常不需要在作業的引數中明確編碼 _variant_t 或 _bstr_t。 如果 _variant_t 或 _bstr_t 類別具有符合引數資料類型的建構函式,編譯器就會產生適當的 _variant_t 或 _bstr_t。
不過,如果引數模棱兩可,也就是引數的資料類型符合多個建構函式,則必須使用適當的資料類型轉換引數,以叫用正確的建構函式。
例如,Recordset::Open 方法的宣告為:
HRESULT Open (
const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options );
ActiveConnection
引數會參考 _variant_t,您可以將其編碼為連接字串或開啟的 Connection 物件指標。
如果您傳遞字串 (例如"DSN=pubs;uid=MyUserName;pwd=MyPassword;
") 或指標 (例如"(IDispatch *) pConn
"),則會隱含建構正確的 _variant_t。
注意
如果您要連線到支援 Windows 驗證的資料來源提供者,您應該指定 Trusted_Connection=yes 或 Integrated Security = SSPI,而不是在連接字串中指定使用者識別碼和密碼資訊。
或者,您可以將 _variant_t 明確編碼為包含指標,例如 "_variant_t((IDispatch *) pConn, true)
"。 轉換 (IDispatch *)
會以另一個接受 IUnknown 介面指標的建構函式來解決此模棱兩可的情況。
雖然很少提及,但 ADO 是 IDispatch 介面這點至關重要。 每當 ADO 物件的指標必須以 Variant 形式傳遞時,該指標必須轉換成 IDispatch 介面的指標。
最後一個案例會使用選擇性預設值 true
明確編碼建構函式的第二個布林值引數。 此引數會使 Variant 建構函式呼叫其 AddRef() 方法,以彌補 ADO 在 ADO 方法或屬性呼叫完成時自動呼叫 _variant_t::Release() 方法。
SafeArray
SafeArray 是包含其他資料類型陣列的結構化資料類型。 SafeArray 之所以稱為「安全」,是因為其包含每個陣列維度界限的相關資訊,並限制存取這些界限內的陣列元素。
當 ADO API 參考指出方法或屬性接受或傳回陣列時,表示方法或屬性會接受或傳回 SafeArray,而不是原生 C/C++ 陣列。
例如,Connection 物件 OpenSchema 方法的第二個參數需要 Variant 值的陣列。 這些 Variant 值必須以 SafeArray 的元素形式傳遞,且 SafeArray 必須設定為另一個 Variant 的值。 而此另一個 Variant 會以 OpenSchema 的第二個引數形式傳遞。
進一步舉例說明,Find 方法的第一個引數是 Variant,其值是一維 SafeArray;AddNew 的第一個和第二個選擇性引數各是一維 SafeArray;而 GetRows 方法的傳回值是 Variant,其值是二維 SafeArray。
遺失參數和預設參數
Visual Basic 允許方法中有遺失參數。 例如,Recordset 物件 Open 方法有五個參數,但您可以略過中間參數並捨棄尾端參數。 系統會根據遺失運算元的資料類型,以預設 BSTR 或 Variant 替代。
在 C/C++ 中,必須指定所有運算元。 如果您想要指定資料類型為字串的遺失參數,請指定包含 Null 字串的 _bstr_t。 如果您想要指定資料類型為 Variant 的遺失參數,請使用值 DISP_E_PARAMNOTFOUND 和類型 VT_ERROR 指定 _variant_t。 或者,指定 #import 指示詞所提供的對等 _variant_t 常數 vtMissing。
有三種方法不是 vtMissing 的典型用法。 這些方法分別是 Connection 和 Command 物件的 Execute 方法,以及 Recordset 物件的 NextRecordset 方法。 以下是其特徵標記:
_RecordsetPtr <A HREF="mdmthcnnexecute.htm">Execute</A>( _bstr_t CommandText, VARIANT * RecordsAffected,
long Options ); // Connection
_RecordsetPtr <A HREF="mdmthcmdexecute.htm">Execute</A>( VARIANT * RecordsAffected, VARIANT * Parameters,
long Options ); // Command
_RecordsetPtr <A HREF="mdmthnextrec.htm">NextRecordset</A>( VARIANT * RecordsAffected ); // Recordset
參數 RecordsAffected 和 Parameters 是 Variant 的指標。 Parameters 是指定 Variant 位址的輸入參數,其中包含可修改所執行命令的單一參數或參數陣列。 RecordsAffected 是指定 Variant 位址的輸出參數,其中會傳回受方法影響的資料列數目。
在 Command 物件 Execute 方法中,將 Parameters 設定為 &vtMissing
(建議使用) 或 null 指標 (即 NULL 或零 (0)),表示未指定任何參數。 如果將 Parameters 設定為 null 指標,則方法會在內部替代 vtMissing 的對等項目,然後完成作業。
在所有方法中,將 RecordsAffected 設定為 null 指標,表示不應傳回受影響的記錄數目。 在此情況下,null 指標不是指遺失參數,而是表示方法應該捨棄受影響的記錄數目。
因此,針對這三種方法,可編碼如下:
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
錯誤處理
在 COM 中,大部分作業都會傳回 HRESULT 傳回碼,指出函數是否已順利完成。 #import 指示詞會針對每個「原始」方法或屬性產生包裝函式程式碼,並檢查傳回的 HRESULT。 如果 HRESULT 指出失敗,包裝函式程式碼會呼叫 _com_issue_errorex() 並以 HRESULT 傳回碼作為引數來擲回 COM 錯誤。 COM 錯誤物件可以在 try-catch 區塊中攔截。 (為了提高效率,請攔截 _com_error 物件的參考)。
請記住,這些是因 ADO 作業失敗而產生的 ADO 錯誤。 基礎提供者所傳回的錯誤會顯示為 Connection 物件 Errors 集合中的 Error 物件。
#import 指示詞只會為 ADO .dll 中宣告的方法和屬性建立錯誤處理常式。 不過,您可以撰寫自己的錯誤檢查巨集或內嵌函數來利用此相同的錯誤處理機制。 如需範例,請參閱 Visual C++ 延伸模組主題或下列各節中的程式碼。
Visual Basic 慣例的 Visual C++ 對等項目
以下摘要說明 ADO 文件中以 Visual Basic 編碼的數個慣例,以及其在 Visual C++ 中的對等項目。
宣告 ADO 物件
在 Visual Basic 中,ADO 物件變數 (在此案例中為 Recordset 物件) 宣告如下:
Dim rst As ADODB.Recordset
子句 "ADODB.Recordset
" 是 Recordset 物件的 ProgID,如登錄中所定義。 Record 物件的新執行個體宣告如下:
Dim rst As New ADODB.Recordset
-或-
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
在 Visual C++ 中,#import 指示詞會為所有 ADO 物件產生智慧型指標類型宣告。 例如,指向 _Recordset 物件的變數類型為 _RecordsetPtr,並宣告如下:
_RecordsetPtr rs;
指向 _Recordset 物件之新執行個體的變數宣告如下:
_RecordsetPtr rs("ADODB.Recordset");
-或-
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
-或-
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
呼叫 CreateInstance 方法之後,可使用變數如下:
rs->Open(...);
請注意,在其中一個案例中,".
" 運算子的使用方式會如同變數是類別的執行個體 (rs.CreateInstance
),而在另一個案例中,"->
" 運算子的使用方式會如同變數是介面的指標 (rs->Open
)。
一個變數可以有兩種使用方式,因為 "->
" 運算子已多載來允許類別的執行個體像介面的指標一樣運作。 執行個體變數的私用類別成員包含 _Recordset 介面的指標;"->
" 運算子會傳回該指標;而傳回的指標會存取 _Recordset 物件的成員。
編碼遺失參數 - String
當您需要在 Visual Basic 中編碼遺失的 String 運算元時,您只需要省略該運算元。 您必須在 Visual C++ 中指定該運算元。 將 _bstr_t 編碼為以空字串作為值。
_bstr_t strMissing(L"");
編碼遺失參數 - Variant
當您需要在 Visual Basic 中編碼遺失的 Variant 運算元時,您只需要省略該運算元。 您必須在 Visual C++ 中指定所有運算元。 編碼遺失的 Variant 參數,將 _variant_t 設定為特殊值 DISP_E_PARAMNOTFOUND,並將類型設定為 VT_ERROR。 或者,指定 vtMissing,這是 #import 指示詞所提供的對等預先定義常數。
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
-或使用-
...vtMissing...;
宣告 Variant
在 Visual Basic 中,Variant 是以 Dim 陳述式宣告,如下所示:
Dim VariableName As Variant
在 Visual C++ 中,將變數宣告為類型 _variant_t。 以下顯示一些結構描述 _variant_t 宣告。
注意
這些宣告只是為了讓您大致了解在自己的程式中編碼的內容。 如需詳細資訊,請參閱下列範例及 Visual C++ 文件。
_variant_t VariableName(value);
_variant_t VariableName((data type cast) value);
_variant_t VariableName(value, VT_DATATYPE);
_variant_t VariableName(interface * value, bool fAddRef = true);
使用 Variants 的陣列
在 Visual Basic 中,Variants 的陣列可使用 Dim 陳述式編碼,或者您可以使用 Array 函數,如下列範例程式碼所示:
Public Sub ArrayOfVariants
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim fld As ADODB.Field
cn.Open "DSN=pubs"
rs = cn.OpenSchema(adSchemaColumns, _
Array(Empty, Empty, "authors", Empty))
For Each fld in rs.Fields
Debug.Print "Name = "; fld.Name
Next fld
rs.Close
cn.Close
End Sub
下列 Visual C++ 範例示範如何使用與 _variant_t 並用的 SafeArray。
備註
下列注意事項會對應至程式碼範例中的註解區段。
再次重申,您可以定義 TESTHR() 內嵌函數來利用現有的錯誤處理機制。
您只需要一維陣列,因此您可以使用 SafeArrayCreateVector,而不是一般用途 SAFEARRAYBOUND 宣告和 SafeArrayCreate 函數。 使用 SafeArrayCreate 的程式碼看起來如下:
SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);
列舉常數 adSchemaColumns 所識別的結構描述與四個條件約束資料行相關聯:TABLE_CATALOG、TABLE_SCHEMA、TABLE_NAME 和 COLUMN_NAME。 因此,會建立具有四個元素的 Variant 值陣列。 然後會指定對應至第三個資料行 TABLE_NAME 的條件約束值。
傳回的 Recordset 是由數個資料行所組成,其子集為條件約束資料行。 每個傳回資料列的條件約束資料行值必須與對應的條件約束值相同。
熟悉 SafeArrays 的人員可能會對未呼叫 SafeArrayDestroy() 即結束感到意外。 事實上,在此情況下呼叫 SafeArrayDestroy() 會造成執行階段例外狀況。 原因是當 _variant_t 超出範圍時,
vtCriteria
的解構函式會呼叫 VariantClear(),這會釋放 SafeArray。 呼叫 SafeArrayDestroy 而未手動清除 _variant_t,會導致解構函式嘗試清除無效的 SafeArray 指標。如果呼叫 SafeArrayDestroy,程式碼看起來如下:
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
不過,讓 _variant_t 管理 SafeArray 會比較簡單。
// Visual_CPP_ADO_Prog_1.cpp
// compile with: /EHsc
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")
// Note 1
inline void TESTHR( HRESULT _hr ) {
if FAILED(_hr)
_com_issue_error(_hr);
}
int main() {
CoInitialize(NULL);
try {
_RecordsetPtr pRs("ADODB.Recordset");
_ConnectionPtr pCn("ADODB.Connection");
_variant_t vtTableName("authors"), vtCriteria;
long ix[1];
SAFEARRAY *pSa = NULL;
pCn->Provider = "sqloledb";
pCn->Open("Data Source='(local)';Initial Catalog='pubs';Integrated Security=SSPI", "", "", adConnectUnspecified);
// Note 2, Note 3
pSa = SafeArrayCreateVector(VT_VARIANT, 1, 4);
if (!pSa)
_com_issue_error(E_OUTOFMEMORY);
// Specify TABLE_NAME in the third array element (index of 2).
ix[0] = 2;
TESTHR(SafeArrayPutElement(pSa, ix, &vtTableName));
// There is no Variant constructor for a SafeArray, so manually set the
// type (SafeArray of Variant) and value (pointer to a SafeArray).
vtCriteria.vt = VT_ARRAY | VT_VARIANT;
vtCriteria.parray = pSa;
pRs = pCn->OpenSchema(adSchemaColumns, vtCriteria, vtMissing);
long limit = pRs->GetFields()->Count;
for ( long x = 0 ; x < limit ; x++ )
printf( "%d: %s\n", x + 1, ((char*) pRs->GetFields()->Item[x]->Name) );
// Note 4
pRs->Close();
pCn->Close();
}
catch (_com_error &e) {
printf("Error:\n");
printf("Code = %08lx\n", e.Error());
printf("Code meaning = %s\n", (char*) e.ErrorMessage());
printf("Source = %s\n", (char*) e.Source());
printf("Description = %s\n", (char*) e.Description());
}
CoUninitialize();
}
使用 Property Get/Put/PutRef
在 Visual Basic 中,屬性的名稱不是藉由其是擷取、指派或指派參考來限定。
Public Sub GetPutPutRef
Dim rs As New ADODB.Recordset
Dim cn As New ADODB.Connection
Dim sz as Integer
cn.Open "Provider=sqloledb;Data Source=yourserver;" & _
"Initial Catalog=pubs;Integrated Security=SSPI;"
rs.PageSize = 10
sz = rs.PageSize
rs.ActiveConnection = cn
rs.Open "authors",,adOpenStatic
' ...
rs.Close
cn.Close
End Sub
此 Visual C++ 範例示範 Get/Put/PutRefProperty。
備註
下列注意事項會對應至程式碼範例中的註解區段。
此範例會使用兩種遺失字串引數形式:明確常數 strMissing,以及編譯器將用來建立暫存 _bstr_t 以存在於 Open 方法範圍內的字串。
不需要將
rs->PutRefActiveConnection(cn)
的運算元轉換成(IDispatch *)
,因為運算元的類型已經是(IDispatch *)
。
// Visual_CPP_ado_prog_2.cpp
// compile with: /EHsc
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")
int main() {
CoInitialize(NULL);
try {
_ConnectionPtr cn("ADODB.Connection");
_RecordsetPtr rs("ADODB.Recordset");
_bstr_t strMissing(L"");
long oldPgSz = 0, newPgSz = 5;
// Note 1
cn->Provider = "sqloledb";
cn->Open("Data Source='(local)';Initial Catalog=pubs;Integrated Security=SSPI;", strMissing, "", adConnectUnspecified);
oldPgSz = rs->GetPageSize();
// -or-
// oldPgSz = rs->PageSize;
rs->PutPageSize(newPgSz);
// -or-
// rs->PageSize = newPgSz;
// Note 2
rs->PutRefActiveConnection( cn );
rs->Open("authors", vtMissing, adOpenStatic, adLockReadOnly, adCmdTable);
printf("Original pagesize = %d, new pagesize = %d\n", oldPgSz, rs->GetPageSize());
rs->Close();
cn->Close();
}
catch (_com_error &e) {
printf("Description = %s\n", (char*) e.Description());
}
::CoUninitialize();
}
使用 GetItem(x) 和 Item[x]
此 Visual Basic 範例示範 Item() 的標準和替代語法。
Public Sub GetItemItem
Dim rs As New ADODB.Recordset
Dim name as String
rs = rs.Open "authors", "DSN=pubs;", adOpenDynamic, _
adLockBatchOptimistic, adTable
name = rs(0)
' -or-
name = rs.Fields.Item(0)
rs(0) = "Test"
rs.UpdateBatch
' Restore name
rs(0) = name
rs.UpdateBatch
rs.Close
End Sub
此 Visual C++ 範例示範 Item。
注意
下列注意事項對應至程式碼範例中的註解區段:使用 Item 存取集合時,索引 2 必須轉換成 long,才能叫用適當的建構函式。
// Visual_CPP_ado_prog_3.cpp
// compile with: /EHsc
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")
void main() {
CoInitialize(NULL);
try {
_ConnectionPtr cn("ADODB.Connection");
_RecordsetPtr rs("ADODB.Recordset");
_variant_t vtFirstName;
cn->Provider = "sqloledb";
cn->Open("Data Source='(local)';Initial Catalog=pubs;Integrated Security=SSPI;", "", "", adConnectUnspecified);
rs->PutRefActiveConnection( cn );
rs->Open("authors", vtMissing, adOpenStatic, adLockOptimistic, adCmdTable);
rs->MoveFirst();
// Note 1. Get a field.
vtFirstName = rs->Fields->GetItem((long)2)->GetValue();
// -or-
vtFirstName = rs->Fields->Item[(long)2]->Value;
printf( "First name = '%s'\n", (char*)( (_bstr_t)vtFirstName) );
rs->Fields->GetItem((long)2)->Value = L"TEST";
rs->Update(vtMissing, vtMissing);
// Restore name
rs->Fields->GetItem((long)2)->PutValue(vtFirstName);
// -or-
rs->Fields->GetItem((long)2)->Value = vtFirstName;
rs->Update(vtMissing, vtMissing);
rs->Close();
}
catch (_com_error &e) {
printf("Description = '%s'\n", (char*) e.Description());
}
::CoUninitialize();
}
使用 (IDispatch *) 轉換 ADO 物件指標
下列 Visual C++ 範例示範如何使用 (IDispatch *) 轉換 ADO 物件指標。
備註
下列注意事項會對應至程式碼範例中的註解區段。
在明確編碼的 Variant 中指定開啟的 Connection 物件。 使用 (IDispatch *) 進行轉換,以便叫用正確的建構函式。 此外,將第二個 _variant_t 參數明確設定為預設值 true,以便在 Recordset::Open 作業結束時,物件參考計數會正確。
運算式
(_bstr_t)
不是轉換,而是從 Value 所傳回的 Variant 擷取 _bstr_t 字串的 _variant_t 運算子。
運算式 (char*)
不是轉換,而是擷取 _bstr_t 物件中封裝字串指標的 _bstr_t 運算子。
這一節的程式碼示範 _variant_t 和 _bstr_t 運算子的一些實用行為。
// Visual_CPP_ado_prog_4.cpp
// compile with: /EHsc
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")
int main() {
CoInitialize(NULL);
try {
_ConnectionPtr pConn("ADODB.Connection");
_RecordsetPtr pRst("ADODB.Recordset");
pConn->Provider = "sqloledb";
pConn->Open("Data Source='(local)';Initial Catalog='pubs';Integrated Security=SSPI", "", "", adConnectUnspecified);
// Note 1.
pRst->Open("authors", _variant_t((IDispatch *) pConn, true), adOpenStatic, adLockReadOnly, adCmdTable);
pRst->MoveLast();
// Note 2.
printf("Last name is '%s %s'\n",
(char*) ((_bstr_t) pRst->GetFields()->GetItem("au_fname")->GetValue()),
(char*) ((_bstr_t) pRst->Fields->Item["au_lname"]->Value));
pRst->Close();
pConn->Close();
}
catch (_com_error &e) {
printf("Description = '%s'\n", (char*) e.Description());
}
::CoUninitialize();
}