Freigeben über


Visual C++-ADO-Programmierung

Die ADO-API-Referenz beschreibt die Funktionalität der ADO-Anwendungsprogrammierschnittstelle (API) mithilfe einer Syntax, die Microsoft Visual Basic ähnelt. Obwohl die beabsichtigte Zielgruppe alle Benutzer ist, verwenden ADO-Programmierer verschiedene Sprachen wie Visual Basic, Visual C++ (mit und ohne die #import-Direktive) und Visual J++ (mit dem ADO/WFC-Klassenpaket).

Anmerkung

Microsoft hat den Support für Visual J++ im Jahr 2004 beendet.

Um diese Vielfalt zu berücksichtigen, stellen die ADO für Visual C++-Syntaxindizes eine sprachspezifische Visual C++-Syntax mit Links zu allgemeinen Beschreibungen von Funktionen, Parametern, außergewöhnlichen Verhaltensweisen usw. in der API-Referenz bereit.

ADO wird mit COM-Schnittstellen (Component Object Model) implementiert. Allerdings ist es für Programmierer einfacher, mit COM in bestimmten Programmiersprachen als anderen zu arbeiten. Beispielsweise werden fast alle Details der Verwendung von COM implizit für Visual Basic-Programmierer behandelt, während Visual C++-Programmierer selbst an diesen Details teilnehmen müssen.

In den folgenden Abschnitten werden Details für C- und C++-Programmierer mit ADO und der #import direktive zusammengefasst. Es konzentriert sich auf Datentypen, die spezifisch für COM- (Variant, BSTR-und SafeArray-) sowie Fehlerbehandlung (_com_error) sind.

Verwenden der #import Compilerdirektive

Die #import Visual C++-Compilerdirektive vereinfacht das Arbeiten mit den ADO-Methoden und -Eigenschaften. Die Direktive verwendet den Namen einer Datei, die eine Typbibliothek enthält, z. B. die ADO-.dll (Msado15.dll) und generiert Headerdateien, die Typedef-Deklarationen, intelligente Zeiger für Schnittstellen und aufgezählte Konstanten enthalten. Jede Schnittstelle wird in einer Klasse gekapselt oder umschlossen.

Für jeden Vorgang innerhalb einer Klasse (d. h. einer Methode oder eines Eigenschaftsaufrufs) gibt es eine Deklaration, um den Vorgang direkt aufzurufen (d. h. die "rohe" Form des Vorgangs), und eine Deklaration zum Aufrufen des unformatierten Vorgangs und Auslösen eines COM-Fehlers, wenn der Vorgang nicht erfolgreich ausgeführt werden kann. Wenn es sich bei dem Vorgang um eine Eigenschaft handelt, gibt es in der Regel eine Compilerdirektive, die eine alternative Syntax für den Vorgang mit Syntax wie Visual Basic erstellt.

Vorgänge, die den Wert einer Eigenschaft abrufen, haben Namen nach dem Muster GetEigenschaft. Vorgänge, die den Wert einer Eigenschaft festlegen, haben Namen des Musters PutProperty. Vorgänge, die den Wert einer Eigenschaft mit einem Zeiger auf ein ADO-Objekt festlegen, weisen Namen des Formulars auf, PutRefProperty.

Sie können eine Eigenschaft mit Aufrufen dieser Formulare abrufen oder festlegen:

variable = objectPtr->GetProperty(); // get property value   
objectPtr->PutProperty(value);       // set property value  
objectPtr->PutRefProperty(&value);   // set property with object pointer  

Verwenden von Eigenschaftsdirektiven

Die __declspec(property...) Compilerdirektive ist eine microsoftspezifische C-Spracherweiterung, die eine Funktion deklariert, die als Eigenschaft verwendet wird, um eine alternative Syntax zu haben. Daher können Sie Werte einer Eigenschaft auf eine ähnliche Weise wie Visual Basic festlegen oder abrufen. Sie können beispielsweise eine Eigenschaft auf diese Weise festlegen und abrufen:

objectPtr->property = value;        // set property value  
variable = objectPtr->property;     // get property value  

Beachten Sie, dass Sie keinen Code erstellen müssen:

objectPtr->PutProperty(value);      // set property value  
variable = objectPtr->GetProperty;  // get property value  

Der Compiler generiert den entsprechenden Get-, Put-, oder PutRefProperty Aufruf, abhängig von der deklarierten alternativen Syntax und davon, ob die Eigenschaft gelesen oder geschrieben wird.

Die __declspec(property...) Compilerdirektive kann nur deklarieren, abrufen, platzieren oder abrufen und alternative Syntax für eine Funktion einfügen. Nur-lesende Vorgänge verfügen nur über eine lesen Deklaration; nur-schreibende Vorgänge weisen nur eine schreiben Deklaration auf; Vorgänge, die sowohl lesen als auch schreiben umfassen, verfügen sowohl über lesen als auch über schreiben Deklarationen.

Mit dieser Richtlinie sind nur zwei Deklarationen möglich; jedoch verfügt jede Eigenschaft möglicherweise über drei Eigenschaftsfunktionen: GetProperty, PutPropertyund PutRefProperty. In diesem Fall weisen nur zwei Formen der Eigenschaft die alternative Syntax auf.

Beispielsweise wird die Command-Eigenschaft ActiveConnection mit einer alternativen Syntax für GetActiveConnection und PutRefActiveConnectiondeklariert. Die PutRef-- Syntax ist eine gute Wahl, da In der Praxis normalerweise ein geöffnetes Connection -Objekt (d. h. ein Connection Objektzeiger) in dieser Eigenschaft platziert werden soll. Andererseits verfügt das Recordset-Objekt über Get-, Put-- und PutRefActiveConnection--Vorgänge, aber keine alternative Syntax.

Auflistungen, die GetItem-Methode und die Item-Eigenschaft

ADO definiert mehrere Auflistungen, einschließlich Fields, Parameters, Propertiesund Errors. In Visual C++ gibt die GetItem(Index) Methode ein Element der Auflistung zurück. Index- ist ein Variant, dessen Wert entweder ein numerischer Index des Elements in der Auflistung ist, oder eine Zeichenfolge, die den Namen des Elements enthält.

Die __declspec(property...) Compilerdirektive deklariert die Eigenschaft Item als eine alternative Syntax zur grundlegenden GetItem()-Methode jeder Auflistung. Die alternative Syntax verwendet eckige Klammern und sieht ähnlich wie ein Arrayverweis aus. Im Allgemeinen sehen die beiden Formulare wie folgt aus:

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

Zum Beispiel weisen Sie einem Feld eines Recordset-Objekts, das den Namen rshat, einen Wert zu, das von der Autoren-Tabelle der Pubs-Datenbank abgeleitet wurde. Verwenden Sie die Item()-Eigenschaft, um auf das dritte Feld der Recordset-Objekt Fields-Auflistung zuzugreifen (Auflistungen werden von Null indiziert; gehen Sie davon aus, dass das dritte Feld au_fnamebenannt ist). Rufen Sie dann die Value()-Methode für das Field-Objekt auf, um einen Zeichenfolgenwert zuzuweisen.

Dies kann in Visual Basic auf vier Arten ausgedrückt werden (die letzten beiden Formulare sind für Visual Basic eindeutig; andere Sprachen haben keine Entsprechungen):

rs.Fields.Item(2).Value = "value"  
rs.Fields.Item("au_fname").Value = "value"  
rs(2) = "value"  
rs!au_fname = "value"  

Das Äquivalent in Visual C++ zu den ersten beiden obigen Formularen lautet:

rs->Fields->GetItem(long(2))->PutValue("value");   
rs->Fields->GetItem("au_fname")->PutValue("value");  

-or- (die alternative Syntax für die eigenschaft Value wird ebenfalls angezeigt)

rs->Fields->Item[long(2)]->Value = "value";  
rs->Fields->Item["au_fname"]->Value = "value";  

Beispiele für das Durchlaufen einer Auflistung finden Sie im Abschnitt "ADO Collections" von "ADO Reference".

COM-Specific Datentypen

Im Allgemeinen verfügt jeder visual Basic-Datentyp, den Sie in der ADO-API-Referenz finden, über ein Visual C++-Äquivalent. Dazu gehören Standarddatentypen wie ungezeichnetes Zeichen für ein Visual Basic Byte, Short für Integerund Long für Long. Suchen Sie in den Syntaxindizes, um genau zu sehen, was für die Operanden einer bestimmten Methode oder Eigenschaft erforderlich ist.

Die Ausnahmen von dieser Regel sind die Datentypen, die für COM spezifisch sind: Variant, BSTRund SafeArray.

Variante

Ein Variant- ist ein strukturierter Datentyp, der ein Wertelement und ein Datentypmitglied enthält. Ein Variant- kann eine vielzahl anderer Datentypen enthalten, einschließlich eines anderen Variant-, BSTR-, Booleschen, IDispatch- oder IUnknown-Zeigers, Währung, Datum usw. COM stellt außerdem Methoden bereit, mit denen ein Datentyp leicht in einen anderen konvertiert werden kann.

Die _variant_t Klasse kapselt und verwaltet den datentyp Variant.

Wenn die ADO-API-Referenz angibt, dass ein Methoden- oder Eigenschaftenoperand einen Wert akzeptiert, bedeutet dies in der Regel, dass der Wert in einem _variant_tübergeben wird.

Diese Regel gilt explizit, wenn der Abschnitt Parameters in den Themen der ADO API-Referenz besagt, dass ein Operand eine Variante vom Typ ist. Eine Ausnahme ist, wenn in der Dokumentation explizit angegeben wird, dass der Operand einen Standarddatentyp verwendet, z. B. Long oder Byte-oder eine Enumeration. Eine weitere Ausnahme ist, wenn der Operand eine Stringnimmt.

BSTR

Ein BSTR- (Basic STRing) ist ein strukturierter Datentyp, der eine Zeichenfolge und deren Länge enthält. COM stellt Methoden zum Zuweisen, Bearbeiten und Freigeben eines BSTR-bereit.

Die _bstr_t Klasse kapselt und verwaltet den BSTR- Datentyp.

Wenn die ADO-API-Referenz besagt, dass eine Methode oder Eigenschaft einen String--Wert annimmt, heißt das, der Wert steht in der Form von _bstr_t.

Umwandlung der _variant_t- und _bstr_t-Klassen

Häufig ist es nicht erforderlich, ein _variant_t oder _bstr_t als Argument für eine Operation explizit zu programmieren. Wenn die _variant_t- oder _bstr_t-Klasse über einen Konstruktor verfügt, der dem Datentyp des Arguments entspricht, generiert der Compiler die entsprechende _variant_t oder _bstr_t.

Wenn das Argument jedoch mehrdeutig ist, d. h. der Datentyp des Arguments mit mehreren Konstruktoren übereinstimmt, müssen Sie das Argument mit dem entsprechenden Datentyp umwandeln, um den richtigen Konstruktor aufzurufen.

Die Deklaration für das Recordset::Open-Methode lautet beispielsweise:

    HRESULT Open (  
        const _variant_t & Source,  
        const _variant_t & ActiveConnection,  
        enum CursorTypeEnum CursorType,  
        enum LockTypeEnum LockType,  
        long Options );  

Das ActiveConnection-Argument verwendet einen Verweis auf eine _variant_t, die Sie als Verbindungszeichenfolge oder als Zeiger auf ein geöffnetes Connection-Objekt codieren können.

Die richtige _variant_t wird implizit erstellt, wenn Sie eine Zeichenfolge wie "DSN=pubs;uid=MyUserName;pwd=<password>;" oder einen Zeiger wie "(IDispatch *) pConn" übergeben.

Anmerkung

Wenn Sie eine Verbindung mit einem Datenquellenanbieter herstellen, der die Windows-Authentifizierung unterstützt, sollten Sie Trusted_Connection=yes oder Integrated Security = SSPI anstelle von Benutzer-ID- und Kennwortinformationen in der Verbindungszeichenfolge angeben.

Sie können auch explizit einen _variant_t kodieren, der einen Zeiger wie "_variant_t((IDispatch *) pConn, true)" enthält. Die Umwandlung, (IDispatch *), löst die Mehrdeutigkeit mit einem anderen Konstruktor auf, der einen Zeiger auf eine IUnknown-Schnittstelle verwendet.

Es ist eine wichtige, aber selten erwähnte Tatsache, dass ADO eine IDispatch-Schnittstelle ist. Wenn ein Zeiger auf ein ADO-Objekt als Variant-übergeben werden muss, muss dieser Zeiger als Zeiger auf eine IDispatch-Schnittstelle umgewandelt werden.

Im letzten Fall wird das zweite boolesche Argument des Konstruktors explizit mit dem optionalen Standardwert truecodest. Dieses Argument bewirkt, dass der Variant--Konstruktor seine AddRef-()-Methode aufruft, was dafür sorgt, dass das automatische Aufrufen der _variant_t::Release-()-Methode durch ADO, wenn die ADO-Methode oder der Eigenschaftenaufruf abgeschlossen ist, kompensiert wird.

SafeArray

Ein SafeArray- ist ein strukturierter Datentyp, der ein Array anderer Datentypen enthält. Ein SafeArray- wird als safe bezeichnet, weil es Informationen über die Grenzen jeder Arraydimension enthält und den Zugriff auf Arrayelemente innerhalb dieser Grenzen einschränkt.

Wenn die ADO-API-Referenz besagt, dass eine Methode oder Eigenschaft ein Array verwendet oder zurückgibt, bedeutet dies, dass die Methode oder Eigenschaft ein SafeArray-und kein systemeigenes C/C++-Array verwendet oder zurückgibt.

Der zweite Parameter der Methode OpenSchema des Connection-Objekts erfordert ein Array von Variant--Werten. Diese Variant--Werte müssen als Elemente eines SafeArray-übergeben werden, und dass SafeArray- als Wert eines anderen Variant-festgelegt werden muss. Jene andere Variant wird als zweites Argument an OpenSchemaübergeben.

Als weitere Beispiele ist das erste Argument der Find-Methode ein Variant-, dessen Wert ein eindimensionales SafeArray-ist; jedes der optionalen ersten und zweiten Argumente von AddNew ist ein eindimensionales SafeArray-; und der Rückgabewert der GetRows--Methode ist ein Variant-, dessen Wert ein zweidimensionales SafeArray-ist.

Fehlende und Standardparameter

Visual Basic ermöglicht fehlende Parameter in Methoden. Das Recordset-Objekt-Objekt Open-Methode verfügt beispielsweise über fünf Parameter, Sie können jedoch Zwischenparameter überspringen und nachfolgende Parameter verlassen. Ein Standard-BSTR- oder Variant- wird je nach Datentyp des fehlenden Operanden ersetzt.

In C/C++ müssen alle Operanden angegeben werden. Wenn Sie einen fehlenden Parameter angeben möchten, dessen Datentyp eine Zeichenfolge ist, geben Sie eine _bstr_t an, die eine NULL-Zeichenfolge enthält. Wenn Sie einen fehlenden Parameter angeben möchten, dessen Datentyp ein Variant-ist, geben Sie eine _variant_t mit dem Wert DISP_E_PARAMNOTFOUND und einen Typ von VT_ERROR an. Geben Sie alternativ die entsprechende _variant_t Konstante vtMissingan, die von der #import-Richtlinie zur Verfügung gestellt wird.

Drei Methoden sind Ausnahmen von der typischen Verwendung von vtMissing. Dies sind die Execute Methoden der Connection- und Command--Objekte sowie die NextRecordset-Methode des Recordset-Objekts. Im Folgenden sind ihre Signaturen aufgeführt:

_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  

Die Parameter RecordsAffected und Parameterssind Zeiger auf einen Variant. Parameter ist ein Eingabeparameter, der die Adresse eines Variant- angibt, der einen einzelnen Parameter oder ein Array von Parametern enthält, die den auszuführenden Befehl ändern. RecordsAffected ist ein Ausgabeparameter, der die Adresse eines Variant-angibt, wobei die Anzahl der zeilen, die von der Methode betroffen sind, zurückgegeben wird.

Geben Sie im Command-Objekt Execute-Methode an, dass keine Parameter angegeben werden, indem Sie Parameter festlegen, entweder auf &vtMissing (empfohlen) oder auf den NULL-Zeiger (d. a. NULL oder Null (0)). Wenn der Parameter auf den Nullzeiger festgelegt ist, ersetzt die Methode intern das Äquivalent von vtMissingund schließt dann den Vorgang ab.

Geben Sie in allen Methoden an, dass die Anzahl der betroffenen Datensätze nicht zurückgegeben werden soll, indem Sie RecordsAffected auf den Nullzeiger festlegen. In diesem Fall ist der NULL-Zeiger nicht so viel ein fehlender Parameter als Hinweis darauf, dass die Methode die Anzahl der betroffenen Datensätze verwerfen sollte.

Daher ist es für diese drei Methoden gültig, etwas zu codieren, zum Beispiel:

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

Fehlerbehandlung

In COM geben die meisten Vorgänge einen HRESULT-Rückgabecode zurück, der angibt, ob eine Funktion erfolgreich abgeschlossen wurde. Die #import-Direktive generiert Wrapper-Code, der jede "raw"-Methode oder -Eigenschaft umgibt und das zurückgegebene HRESULT überprüft. Wenn der HRESULT einen Fehler anzeigt, löst der Wrapper-Code einen COM-Fehler aus, indem er _com_issue_errorex() mit dem HRESULT-Rückgabecode als Argument aufruft. COM-Fehlerobjekte können in einem try-catch Block abgefangen werden. (Aus Effizienzgründen können Sie einen Verweis auf ein _com_error-Objekt erfassen.)

Denken Sie daran, dass dies ADO-Fehler sind: Sie führen zu einem Fehler des ADO-Vorgangs. Fehler, die vom zugrunde liegenden Anbieter zurückgegeben werden, erscheinen als Error-Objekte in der Auflistung Errors des Connection-Objekts.

Die #import-Direktive erstellt nur Fehlerbehandlungsroutinen für Methoden und Eigenschaften, die im ADO-.dlldeklariert sind. Sie können jedoch den gleichen Fehlerbehandlungsmechanismus nutzen, indem Sie Ihr eigenes Fehlerüberprüfungsmakro oder eine Inlinefunktion schreiben. Beispiele finden Sie im Thema Visual C++-Erweiterungenoder im Code in den folgenden Abschnitten.

Visual C++-Entsprechungen von Visual Basic-Konventionen

Es folgt eine Zusammenfassung mehrerer Konventionen in der ADO-Dokumentation, codiert in Visual Basic sowie deren Entsprechungen in Visual C++.

Deklarieren eines ADO-Objekts

In Visual Basic wird eine ADO-Objektvariable (in diesem Fall für ein Recordset-Objekt) wie folgt deklariert:

Dim rst As ADODB.Recordset  

Die Klausel "ADODB.Recordset" ist die ProgID des Recordset-Objekts, wie in der Registrierung definiert. Eine neue Instanz eines Record-Objekts wird wie folgt deklariert:

Dim rst As New ADODB.Recordset  

-oder-

Dim rst As ADODB.Recordset  
Set rst = New ADODB.Recordset  

In Visual C++ generiert die #import direktive intelligente Zeigertypdeklarationen für alle ADO-Objekte. Eine Variable, die auf ein _Recordset-Objekt verweist, weist z. B. den Typ _RecordsetPtrauf und wird wie folgt deklariert:

_RecordsetPtr  rs;  

Eine Variable, die auf eine neue Instanz eines _Recordset-Objekts verweist, wird wie folgt deklariert:

_RecordsetPtr  rs("ADODB.Recordset");  

-oder-

_RecordsetPtr  rs;  
rs.CreateInstance("ADODB.Recordset");  

-oder-

_RecordsetPtr  rs;  
rs.CreateInstance(__uuidof(_Recordset));  

Nachdem die CreateInstance- Methode aufgerufen wurde, kann die Variable wie folgt verwendet werden:

rs->Open(...);  

Beachten Sie, dass in einem Fall der Operator "." verwendet wird, als wäre die Variable eine Instanz einer Klasse (rs.CreateInstance), und in einem anderen Fall wird der Operator "->" verwendet, als wäre die Variable ein Zeiger auf eine Schnittstelle (rs->Open).

Eine Variable kann auf zwei Arten verwendet werden, da der Operator "->" überladen ist, damit eine Instanz einer Klasse sich wie ein Zeiger auf eine Schnittstelle verhält. Ein privates Klassenelement der Instanzvariable enthält einen Zeiger auf die _Recordset Schnittstelle; der Operator "->" gibt diesen Zeiger zurück; und der zurückgegebene Zeiger greift auf die Elemente des _Recordset-Objekts zu.

Codieren eines fehlenden Parameters - Zeichenfolge

Wenn Sie einen fehlenden String- Operanden in Visual Basic codieren müssen, lassen Sie lediglich den Operanden aus. Sie müssen den Operanden in Visual C++ angeben. Codiert eine _bstr_t mit einer leeren Zeichenfolge als Wert.

_bstr_t strMissing(L"");  

Codieren eines fehlenden Parameters - Variant

Wenn Sie einen fehlenden Variant- Operanden in Visual Basic codieren müssen, lassen Sie lediglich den Operanden aus. Sie müssen alle Operanden in Visual C++ angeben. Programmiere einen fehlenden -Varianten--Parameter mit einem _variant_t, der auf den speziellen Wert DISP_E_PARAMNOTFOUND und den Typ VT_ERROR gesetzt ist. Geben Sie alternativ vtMissingan, bei dem es sich um eine gleichwertige vordefinierte Konstante handelt, die von der #import-Direktive bereitgestellt wird.

_variant_t  vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);   

- oder verwenden -

...vtMissing...;  

Deklarieren einer Variante

In Visual Basic wird ein Variant- wie folgt mit der Dim-Anweisung deklariert:

Dim VariableName As Variant  

Deklarieren Sie in Visual C++ eine Variable als Typ _variant_t. Nachfolgend finden Sie einige schematische _variant_t Deklarationen.

Anmerkung

Diese Deklarationen geben lediglich eine grobe Vorstellung davon, was Sie in Ihrem eigenen Programm codieren würden. Weitere Informationen finden Sie in den folgenden Beispielen und in der Visual C++-Dokumentation.

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

Verwendung von Varianten-Arrays

In Visual Basic können Arrays von Variants- mit der Dim-Anweisung codiert werden, oder Sie können die funktion Array verwenden, wie im folgenden Beispielcode veranschaulicht:

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  

Das folgende Visual C++-Beispiel demonstriert die Verwendung eines SafeArray, das zusammen mit einem _variant_tverwendet wird.

Notizen

Die folgenden Hinweise entsprechen kommentierten Abschnitten im Codebeispiel.

  1. Erneut wird die Inlinefunktion TESTHR() definiert, um den vorhandenen Fehlerbehandlungsmechanismus zu nutzen.

  2. Sie benötigen nur ein eindimensionales Array, sodass Sie SafeArrayCreateVectoranstelle der allgemeinen SAFEARRAYBOUND Deklaration und SafeArrayCreate-Funktion verwenden können. Der folgende Code würde mit SafeArrayCreateaussehen:

       SAFEARRAYBOUND   sabound[1];  
       sabound[0].lLbound = 0;  
       sabound[0].cElements = 4;  
       pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);  
    
  3. Das durch die aufgezählte Konstante identifizierte Schema, adSchemaColumns, ist vier Einschränkungsspalten zugeordnet: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME und COLUMN_NAME. Daher wird ein Array von Variant- Werten mit vier Elementen erstellt. Anschließend wird ein Einschränkungswert angegeben, der der dritten Spalte TABLE_NAME entspricht.

    Das Recordset-, das zurückgegeben wird, besteht aus mehreren Spalten, deren Teilmenge die Einschränkungsspalten sind. Die Werte der Einschränkungsspalten für jede zurückgegebene Zeile müssen mit den entsprechenden Einschränkungswerten übereinstimmen.

  4. Diejenigen, die mit SafeArrays vertraut sind, sind möglicherweise überrascht, dass SafeArrayDestroy-() nicht vor dem Beenden aufgerufen wird. Tatsächlich führt das Aufrufen von SafeArrayDestroy() in diesem Fall zu einer Laufzeitausnahme. Der Grund dafür ist, dass der Destruktor für vtCriteriaVariantClear() aufruft, wenn die _variant_t außerhalb des Gültigkeitsbereichs liegt, wodurch die SafeArray-freigegeben wird. Wenn Sie SafeArrayDestroy-aufrufen, ohne den _variant_tmanuell zu löschen, würde der Destruktor versuchen, einen ungültigen SafeArray Zeiger zu löschen.

    Wenn SafeArrayDestroy aufgerufen wurde, würde der Code wie folgt aussehen:

          TESTHR(SafeArrayDestroy(pSa));  
       vtCriteria.vt = VT_EMPTY;  
          vtCriteria.parray = NULL;  
    

    Es ist jedoch viel einfacher, wenn die _variant_t die SafeArrayverwaltet.

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

Verwenden von Property Get/Put/PutRef

In Visual Basic wird der Name einer Eigenschaft nicht dadurch qualifiziert, ob sie abgerufen, zugewiesen oder eine Referenz zugewiesen wird.

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  

In diesem Visual C++-Beispiel wird die Get/Put/PutRefPropertyveranschaulicht.

Notizen

Die folgenden Hinweise entsprechen kommentierten Abschnitten im Codebeispiel.

  1. In diesem Beispiel werden zwei Formen eines fehlenden Zeichenfolgenarguments verwendet: eine explizite Konstante, strMissing, und eine Zeichenfolge, die der Compiler verwendet, um eine temporäre _bstr_t zu erstellen, die im Gültigkeitsbereich der Open-Methode vorhanden ist.

  2. Es ist nicht notwendig, den Operanden von rs->PutRefActiveConnection(cn) in (IDispatch *) zu umwandeln, da der Operandtyp bereits (IDispatch *)ist.

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

Verwenden von GetItem(x) und Item[x]

In diesem Visual Basic-Beispiel wird die Standard- und alternative Syntax für Item() veranschaulicht.

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  

In diesem Visual C++-Beispiel wird Itemveranschaulicht.

Anmerkung

Der folgende Hinweis bezieht sich auf die kommentierten Abschnitte im Codebeispiel: Wenn auf die Auflistung mit Itemzugegriffen wird, muss der Index 2zu long umgewandelt werden, damit ein entsprechender Konstruktor aufgerufen wird.

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

Umwandeln von ADO-Objektzeigern mit (IDispatch *)

Im folgenden Visual C++-Beispiel wird die Verwendung von (IDispatch *) zum Umwandeln von ADO-Objektzeigern veranschaulicht.

Notizen

Die folgenden Hinweise entsprechen kommentierten Abschnitten im Codebeispiel.

  1. Geben Sie ein geöffnetes Verbindungs--Objekt in einer explizit codierten -Variantean. Casten Sie es mit (IDispatch *), damit der richtige Konstruktor aufgerufen wird. Legen Sie außerdem explizit den zweiten _variant_t-Parameter auf den Standardwert truefest, sodass die Objektverweisanzahl korrekt ist, wenn der Recordset::Open-Vorgang endet.

  2. Der Ausdruck (_bstr_t)ist keine Umwandlung, sondern ein _variant_t-Operator, der eine _bstr_t Zeichenfolge aus der Variant extrahiert, die von Valuezurückgegeben wird.

Der Ausdruck (char*)ist keine Umwandlung, sondern ein _bstr_t--Operator, der einen Zeiger auf die gekapselte Zeichenfolge in einem _bstr_t--Objekt extrahiert.

In diesem Codeabschnitt werden einige nützliche Verhaltensweisen von _variant_t und _bstr_t Operatoren veranschaulicht.

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