共用方式為


Visual C++ ADO 程序設計

ADO API 參考會使用類似 Microsoft Visual Basic 的語法,描述 ADO 應用程式開發介面 (API) 的功能。 雖然預期的對象是所有使用者,但 ADO 程式設計人員使用各種不同的語言,例如 Visual Basic、Visual C++(有或沒有 #import 指示詞),以及 Visual J++(使用 ADO/WFC 類別套件)。

注意

Microsoft 2004 年終止了 Visual J++ 的支援。

為了適應這種多樣性,ADO for Visual C++ 語法索引 在 API 參考中提供 Visual C++ 語言特定語法,並提供功能、參數、例外行為等常見描述的連結。

ADO 是使用 COM (元件物件模型) 介面來實作。 不過,程式設計人員在某些程式設計語言中使用 COM 比其他程式設計語言更容易。 例如,幾乎所有使用 COM 的詳細數據都會隱含處理給 Visual Basic 程式設計人員,而 Visual C++程式設計人員必須自行處理這些詳細數據。

下列各節摘要說明使用 ADO 和 #import 指示詞的 C 和 C++ 程式設計人員的詳細數據。 它著重於 COM 的特定數據類型(VariantBSTRSafeArray),以及錯誤處理(_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...) 編譯程式指示詞只能宣告 getput,或 getput 作為函式的替代語法。 只讀作業只有 取得 宣告;僅限寫入作業只有 設定 宣告;同時具有讀取和寫入的作業都有 取得設定 宣告。

這個指令僅可進行兩個宣告;不過,每個屬性可能都有三個屬性方法:GetPropertyPutPropertyPutRefProperty。 在此情況下,只有兩種形式的 屬性具有替代語法。

例如,Command 物件的 ActiveConnection 屬性可以使用作為 GetActiveConnectionPutRefActiveConnection的替代語法宣告。 PutRef- 語法是不錯的選擇,因為在實務上,您通常會想要在此屬性中放置 open Connection 物件 (也就是 Connection 物件指標)。 另一方面,Recordset 物件具有 Get-、Put- 和 PutRefActiveConnection 作業,但沒有替代語法。

集合、GetItem 方法及 Item 屬性

ADO 會定義數個集合,包括 FieldsParametersPropertiesErrors。 在 Visual C++ 中,GetItem(索引 方法會傳回集合的成員。 IndexVariant,其值為集合中成員的數值索引,或是包含成員名稱的字串。

__declspec(property...) 編譯程式指示詞會將 Item 屬性宣告為每個集合基本 GetItem() 方法的替代語法。 替代語法使用方括弧,外觀上類似陣列參考。 一般而言,這兩種格式看起來如下:

  
      collectionPtr->GetItem(index);  
collectionPtr->Item[index];  

例如,將值指派給名為 rsRecordset 物件中的欄位,此物件衍生自 pubs 資料庫中的 authors 表格。 使用 Item() 屬性來存取 資料集 物件 Fields 集合中的第三個 欄位(集合是從零開始編號;假設第三個欄位名為 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";  

如需逐一查看集合的範例,請參閱一節。

COM-Specific 數據類型

一般而言,您在 ADO API 參考文件中找到的任何 Visual Basic 資料類型,都具有 Visual C++ 的等效類型。 其中包括 Visual Basic Byteunsigned charInteger的簡短,以及 longLong。 查看語法索引,以查看指定方法或屬性的操作數所需的確切內容。

此規則的例外是 COM 特有的數據類型:VariantBSTRSafeArray

變體

Variant 是包含值成員和數據類型成員的結構化數據類型。 Variant 可能包含各種不同的其他數據類型,包括其他 Variant、BSTR、布爾值、IDispatch 或 IUnknown 指標、貨幣、日期等等。 COM 也提供方法,可讓您輕鬆地將一個數據類型轉換成另一個數據類型。

_variant_t 類別會封裝和管理 Variant 數據類型。

當 ADO API 參考指出方法或屬性操作數接受值時,通常表示值會傳入 _variant_t

當 ADO API 參考主題中的 Parameters 區段指出操作數是 Variant時,此規則是明確的。 其中一個例外狀況是文件明確表示操作數採用標準數據類型,例如 LongByte或 列舉。 另一個例外狀況是當操作數接受 字串時。

BSTR

BSTRBasic 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=<password>;」這樣的字串,或像「(IDispatch *) pConn」這樣的指標,則會隱含建構正確的 _variant_t

注意

如果您要連線到支援 Windows 驗證的數據源提供者,您應該指定 Trusted_Connection=yesIntegrated 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的值。 它是作為 OpenSchema 的第二個變數傳遞的另一個 Variant

例如,Find 方法的第一個自變數是 Variant 其值為一維 SafeArray;AddNew 的每個選擇性第一個和第二個自變數都是一維 SafeArray;和 GetRows 方法的傳回值是 Variant 其值為二維 SafeArray

遺漏和預設參數

Visual Basic 允許方法中的遺漏參數。 例如,Recordset 物件 Open 方法有五個參數,但您可以略過中繼參數並離開尾端參數。 默認 BSTRVariant 會根據遺漏操作數的數據類型來取代。

在 C/C++中,必須指定所有操作數。 如果您想要指定資料類型為字串的遺漏參數,請指定包含 null 字串的 _bstr_t。 如果您想要指定一個數據類型為 Variant的遺漏參數,請指定一個值為 DISP_E_PARAMNOTFOUND 且類型為 VT_ERROR 的 _variant_t。 或者,請指定等效的 _variant_t 常數 vtMissing,這是由 #import 指令提供。

三種方法是一般使用 vtMissing 的例外狀況。 這些是 ConnectionCommand 物件的 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  

RecordsAffectedParameters這兩個參數是指向 Variant的指標。 Parameters 是一個輸入參數,指定包含單 一參數或參數陣列的 variant 位址,以修改所執行的命令。 RecordsAffected 是指定 Variant位址的輸出參數,其中會傳回方法所影響的數據列數目。

Command 物件 Execute 方法中,可將 參數 設定為 &vtMissing(建議)或 null 指標(也就是 NULL 或零(0)),以表明未指定任何參數。 如果 Parameters 設為空指針,則方法會在內部替換為相當於 vtMissing,然後完成作業。

在所有方法中,將 recordAffected 設定為 null 指標,表示不應該傳回受影響的記錄數目。 在此情況下,Null 指標不是遺漏的參數,因為表示方法應該捨棄受影響的記錄數目。

因此,針對這三種方法,編寫代碼是可以的,例如:

pConnection->Execute("commandText", NULL, adCmdText);   
pCommand->Execute(NULL, NULL, adCmdText);  
pRecordset->NextRecordset(NULL);  

錯誤處理

在 COM 中,大部分作業都會傳回 HRESULT 傳回碼,指出函式是否成功完成。 #import 指令會在每個「原始」方法或屬性周圍產生包裝程式碼,並驗證傳回的 HRESULT。 如果 HRESULT 指出失敗,包裝函式程式代碼會呼叫具有 HRESULT 傳回碼做為自變數的 _com_issue_errorex() 來擲回 COM 錯誤。 COM 錯誤物件可以在 嘗試-捕獲 區塊中捕獲。 為了提高效率,請捕捉對 _com_error 物件的引用。

請記住,這些是 ADO 錯誤:它們因 ADO 作業失敗而產生。 基礎提供者傳回的錯誤會在 Errors 集合中顯示為 Error 物件,而這些都是在 Connection 物件中。

#import 指示詞只會針對 ADO .dll中所宣告的方法和屬性,建立錯誤處理例程。 不過,您可以撰寫自己的錯誤檢查巨集或內嵌函式,以利用這個相同的錯誤處理機制。 如需範例,請參閱本主題 Visual C++ Extensions或下列各節中的程序代碼。

Visual C++ 與 Visual Basic 慣例的等價對應

以下是 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 對象的成員。

編寫缺失參數的程式碼 - 字串

當您需要在 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...;  

宣告變數種類

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

使用變數類型陣列

在 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

筆記

下列附注會對應至程式代碼範例中的批注區段。

  1. 再次定義 TESTHR() 內嵌函式,以利用現有的錯誤處理機制。

  2. 您只需要一維陣列,因此您可以使用 SafeArrayCreateVector,而不是SAFEARRAYBOUND 宣告和 SafeArrayCreate 函式的一般用途。 以下是該代碼使用 SafeArrayCreate的實現範例:

       SAFEARRAYBOUND   sabound[1];  
       sabound[0].lLbound = 0;  
       sabound[0].cElements = 4;  
       pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);  
    
  3. 列舉常數 adSchemaColumns所識別的架構會與四個條件約束數據行相關聯:TABLE_CATALOG、TABLE_SCHEMA、TABLE_NAME和COLUMN_NAME。 因此,會建立具有四個元素的 Variant 值陣列。 然後會指定對應至第三個數據行TABLE_NAME的條件約束值。

    傳回的 Recordset 包含數個數據行,其中子集是條件約束數據行。 每個傳回數據列之條件約束數據行的值必須與對應的條件約束值相同。

  4. 熟悉 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();  
}  

使用屬性 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 Get/Put/PutRefProperty

筆記

下列附注會對應至程式代碼範例中的批注區段。

  1. 這個範例使用兩種形式的遺漏字串自變數:明確常數,strMissing,以及編譯程式將用來建立 Open 方法範圍的暫時 _bstr_t

  2. 因為操作數的類型已經 (IDispatch *),所以不需要將 rs->PutRefActiveConnection(cn) 的操作數轉換成 (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,必須轉換成 長整數,才能叫用適當的建構函式。

// 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();  
}  

將 ADO 物件指標轉型為 (IDispatch *)

下列 Visual C++ 範例示範如何使用 (IDispatch *) 來轉換 ADO 物件指標。

筆記

下列附注會對應至程式代碼範例中的批注區段。

  1. 在明確指定的 Variant中指定開放的 Connection 物件。 使用 #IDispatch *) 進行轉換,因此會叫用正確的建構函式。 此外,將第二個 _variant_t 參數明確設定為預設值 true,以確保在 Recordset::Open 作業結束時,物件參考計數將正確無誤。

  2. 表達式 (_bstr_t)不是轉換,而是 _variant_t 運算符,從 Value傳回的 Variant 擷取 _bstr_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();  
}