Programmation ADO Visual C++
La référence de l’API ADO décrit les fonctionnalités de l’interface de programmation d’applications (API) ADO à l’aide d’une syntaxe similaire à Microsoft Visual Basic. Bien qu’elle soit destinée à tous les utilisateurs, les programmeurs ADO utilisent différents langages comme Visual Basic, Visual C++ (avec et sans la directive #import ) et Visual J++ (avec le package de classe ADO/WFC).
Notes
Microsoft a mis fin à la prise en charge de Visual J++ en 2004.
Pour répondre à cette diversité, les index de syntaxe ADO pour Visual C++ fournissent une syntaxe propre au langage Visual C++ avec des liens vers des descriptions courantes des fonctionnalités, des paramètres, des comportements exceptionnels, et ainsi de suite, dans la référence de l’API.
ADO est implémenté avec des interfaces COM (Component Object Model). Toutefois, il est plus facile pour les programmeurs d’utiliser COM dans certains langages de programmation que d’autres. Par exemple, presque tous les détails de l’utilisation de COM sont gérés implicitement pour les programmeurs Visual Basic, tandis que les programmeurs Visual C++ doivent veiller à ces détails eux-mêmes.
La section suivante résume les détails pour les programmeurs C et C++ utilisant ADO et la directive #import. Elle se concentre sur les types de données spécifiques à COM (Variant, BSTR et SafeArray) et à la gestion des erreurs (_com_error).
Utilisation de la directive de compilateur #import
La directive de compilateur #import Visual C++ simplifie l’utilisation des méthodes et propriétés ADO. La directive prend le nom d’un fichier contenant une bibliothèque de types, comme le .dll ADO (Msado15.dll), et génère des fichiers d’en-tête contenant des déclarations typedef, des pointeurs intelligents pour les interfaces et des constantes énumérées. Chaque interface est encapsulée (ou « incluse dans un wrapper ») dans une classe.
Pour chaque opération au sein d’une classe (autrement dit, une méthode ou un appel de propriété), il existe une déclaration pour appeler l’opération directement (autrement dit, la forme « brute » de l’opération) et une déclaration pour appeler l’opération brute et lever une erreur COM si l’opération ne parvient pas à s’exécuter correctement. Si l’opération est une propriété, il existe généralement une directive du compilateur qui crée une autre syntaxe pour l’opération qui a une syntaxe comme Visual Basic.
Les opérations qui récupèrent la valeur d’une propriété ont des noms de la forme GetProperty. Les opérations qui définissent la valeur d’une propriété ont des noms de la forme PutProperty. Les opérations qui définissent la valeur d’une propriété avec un pointeur vers un objet ADO ont des noms de la forme PutRefProperty.
Vous pouvez obtenir ou définir une propriété avec des appels des formes suivantes :
variable = objectPtr->GetProperty(); // get property value
objectPtr->PutProperty(value); // set property value
objectPtr->PutRefProperty(&value); // set property with object pointer
Utilisation des directives de propriété
La directive de compilateur __declspec(property...) est une extension de langage C spécifique à Microsoft qui déclare une fonction utilisée comme propriété pour avoir une syntaxe alternative. Par conséquent, vous pouvez définir ou obtenir des valeurs d’une propriété d’une manière similaire à Visual Basic. Par exemple, vous pouvez définir et obtenir une propriété de cette façon :
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
Notez que vous n’avez pas besoin de coder :
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
Le compilateur génère l’appel Get-, Put- ou PutRefProperty approprié en fonction de la syntaxe alternative déclarée et du fait que la propriété est lue ou écrite.
La directive de compilateur __declspec(property...) ne peut déclarer que la syntaxe alternative get, put, ou get et put pour une fonction. Les opérations en lecture seule ont uniquement une déclaration get ; les opérations en écriture seule ont uniquement une déclaration put ; les opérations de lecture et d’écriture ont des déclarations get et put.
Seules deux déclarations sont possibles avec cette directive ; toutefois, chaque propriété peut avoir trois fonctions de propriété : GetProperty, PutProperty et PutRefProperty. Dans ce cas, seules deux formes de la propriété ont la syntaxe alternative.
Par exemple, la propriété ActiveConnection de l’objet Command est déclarée avec une autre syntaxe pour GetActiveConnection et PutRefActiveConnection. La syntaxe PutRef- est un bon choix, car dans la pratique, vous souhaiterez généralement placer un objet Connection ouvert (autrement dit, un pointeur d’objet Connection) dans cette propriété. En revanche, l’objet Recordset a des opérations Get-, Put- et PutRefActiveConnection, mais pas de syntaxe alternative.
Collections, méthode GetItem et propriété Item
ADO définit plusieurs collections, notamment Fields, Parameters, Properties et Errors. Dans Visual C++, la méthode GetItem(index) retourne un membre de la collection. Index est un Variant, dont la valeur est soit un index numérique du membre dans la collection, soit une chaîne contenant le nom du membre.
La directive __declspec(property...) déclare la propriété Item comme une syntaxe alternative à la méthode GetItem() fondamentale de chaque collection. La syntaxe alternative utilise des crochets et ressemble à une référence de tableau. En général, les deux formes ressemblent à ce qui suit :
collectionPtr->GetItem(index);
collectionPtr->Item[index];
Par exemple, affectez une valeur à un champ d’un objet Recordset, nommé rs, dérivé de la table authors de la base de données pubs. Utilisez la propriété Item() pour accéder au troisième Field de la collection Fields de l’objet Recordset (les collections sont indexées à partir de zéro ; supposez que le troisième champ s’appelle au_fname). Appelez ensuite la méthode Value() sur l’objet Field pour affecter une valeur String.
Cela peut être exprimé en Visual Basic des quatre manières suivantes (les deux dernières formes sont propres à Visual Basic ; les autres langages n’ont pas d’équivalents) :
rs.Fields.Item(2).Value = "value"
rs.Fields.Item("au_fname").Value = "value"
rs(2) = "value"
rs!au_fname = "value"
L’équivalent en Visual C++ des deux premières formes ci-dessus est le suivant :
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
-ou- (la syntaxe alternative pour la propriété Value est également affichée)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
Pour obtenir des exemples d’itération dans une collection, consultez la section « Collections ADO » de la « Référence ADO ».
Types de données spécifiques à COM
En général, tout type de données Visual Basic que vous trouvez dans la référence de l’API ADO a un équivalent Visual C++. Il s’agit notamment de types de données standard tels que unsigned char pour un Byte Visual Basic, short pour Integer et long pour Long. Examinez l’index de syntaxe pour voir exactement ce qui est requis pour les opérandes d’une méthode ou d’une propriété donnée.
Les exceptions à cette règle sont les types de données spécifiques à COM : Variant, BSTR et SafeArray.
Variant
Un Variant est un type de données structuré qui contient un membre valeur et un membre type de données. Un Variant peut contenir un large éventail d’autres types de données, notamment un autre Variant, BSTR, Boolean, IDispatch ou IUnknown, currency, date, et ainsi de suite. COM fournit également des méthodes qui facilitent la conversion d’un type de données en un autre.
La classe _variant_t encapsule et gère le type de données Variant.
Lorsque la référence de l’API ADO indique qu’une méthode ou un opérande de propriété prend une valeur, cela signifie généralement que la valeur est passée dans un _variant_t.
Cette règle est explicitement vraie lorsque la section Paramètres dans les rubriques de la référence de l’API ADO indique qu’un opérande est un Variant. Une exception est quand la documentation indique explicitement que l’opérande prend un type de données standard, comme Long ou Byte, ou une énumération. Une autre exception est quand l’opérande prend une valeur String.
BSTR
Un BSTR (Basic STRing) est un type de données structuré qui contient une chaîne de caractères et la longueur de la chaîne. COM fournit des méthodes pour allouer, manipuler et libérer un BSTR.
La classe _bstr_t encapsule et gère le type de données BSTR.
Lorsque la référence de l’API ADO indique qu’une méthode ou une propriété prend une valeur string, cela signifie que la valeur est sous la forme d’un _bstr_t.
Cast des classes _variant_t et _bstr_t
Il n’est souvent pas nécessaire de coder explicitement un _variant_t ou _bstr_t dans un argument d’une opération. Si la classe _variant_t ou _bstr_t a un constructeur qui correspond au type de données de l’argument, le compilateur génère le _variant_t ou _bstr_t approprié.
Toutefois, si l’argument est ambigu, autrement dit, si le type de données de l’argument correspond à plusieurs constructeurs, vous devez caster l’argument avec le type de données approprié pour appeler le bon constructeur.
Par exemple, la déclaration de la méthode Recordset::Open est la suivante :
HRESULT Open (
const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options );
L’argument ActiveConnection
prend une référence à un _variant_t, que vous pouvez coder en tant que chaîne de connexion ou pointeur vers un objet Connection ouvert.
Le _variant_t correct sera construit implicitement si vous passez une chaîne comme « DSN=pubs;uid=MyUserName;pwd=MyPassword;
» ou un pointeur comme « (IDispatch *) pConn
».
Notes
Si vous vous connectez à un fournisseur de sources de données qui prend en charge l’authentification Windows, vous devez spécifier Trusted_Connection=yes ou Integrated Security = SSPI au lieu des informations d’ID utilisateur et de mot de passe dans la chaîne de connexion.
Vous pouvez également coder explicitement un _variant_t contenant un pointeur comme « _variant_t((IDispatch *) pConn, true)
». Le cast, (IDispatch *)
, résout l’ambiguïté avec un autre constructeur qui prend un pointeur vers une interface IUnknown.
C’est un fait crucial, bien que rarement mentionné, que ADO est une interface IDispatch. Chaque fois qu’un pointeur vers un objet ADO doit être passé en tant que Variant, ce pointeur doit être converti en pointeur vers une interface IDispatch.
Le dernier cas code explicitement le deuxième argument booléen du constructeur avec sa valeur optionnelle par défaut de true
. Cet argument fait en sorte que le constructeur Variant appelle sa méthode AddRef(), qui compense l’appel automatique d’ADO à la méthode _variant_t::Release() lorsque l’appel de propriété ou de méthode ADO se termine.
SafeArray
Un SafeArray est un type de données structuré qui contient un tableau d’autres types de données. Un SafeArray est appelé safe, car il contient des informations sur les limites de chaque dimension de tableau et limite l’accès aux éléments de tableau dans ces limites.
Lorsque la référence de l’API ADO indique qu’une méthode ou une propriété prend ou retourne un tableau, cela signifie que la méthode ou la propriété prend ou retourne un SafeArray, et non un tableau C/C++ natif.
Par exemple, le deuxième paramètre de la méthode OpenSchema de l’objet Connection nécessite un tableau de valeurs Variant. Ces valeurs Variant doivent être passées en tant qu’éléments d’un SafeArray, et le SafeArray doit être défini comme valeur d’un autre Variant. Il s’agit d’un autre Variant passé comme deuxième argument d’OpenSchema.
Pour donner d’autres exemples, le premier argument de la méthode Find est un Variant dont la valeur est un SafeArray unidimensionnel ; chacun des premier et deuxième arguments facultatifs d’AddNew est un SafeArray unidimensionnel ; et la valeur de retour de la méthode GetRows est un Variant dont la valeur est un SafeArray à deux dimensions.
Paramètres manquants et par défaut
Visual Basic autorise les paramètres manquants dans les méthodes. Par exemple, la méthode Open de l’objet Recordset a cinq paramètres, mais vous pouvez ignorer les paramètres intermédiaires et laisser les paramètres de fin. Un BSTR ou Variant par défaut sera remplacé en fonction du type de données de l’opérande manquant.
En C/C++, tous les opérandes doivent être spécifiés. Si vous souhaitez spécifier un paramètre manquant dont le type de données est une chaîne, spécifiez un _bstr_t contenant une chaîne null. Si vous souhaitez spécifier un paramètre manquant dont le type de données est un Variant, spécifiez un _variant_t avec une valeur de DISP_E_PARAMNOTFOUND et un type de VT_ERROR. Vous pouvez également spécifier la constante _variant_t équivalente, vtMissing, fournie par la directive #import.
Trois méthodes sont des exceptions à l’utilisation habituelle de vtMissing. Il s’agit des méthodes Execute des objets Connection et Command et de la méthode NextRecordset de l’objet Recordset. Voici les signatures suivantes :
_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
Les paramètres, RecordsAffected et Parameters, sont des pointeurs vers un Variant. Parameters est un paramètre d’entrée qui spécifie l’adresse d’un Variant contenant un paramètre unique ou un tableau de paramètres, qui modifie la commande en cours d’exécution. RecordsAffected est un paramètre de sortie qui spécifie l’adresse d’un Variant, où le nombre de lignes affectées par la méthode est retourné.
Dans la méthode Command de l’objet Execute, indiquez qu’aucun paramètre n’est spécifié en donnant à Parameters la valeur &vtMissing
(ce qui est recommandé) ou le pointeur null (c’est-à-dire NULL ou zéro (0)). Si Parameters est défini sur le pointeur null, la méthode remplace en interne l’équivalent de vtMissing, puis termine l’opération.
Dans toutes les méthodes, indiquez que le nombre d’enregistrements affectés ne doit pas être retourné en définissant RecordsAffected sur le pointeur null. Dans ce cas, le pointeur null n’est pas tant un paramètre manquant qu’une indication que la méthode doit ignorer le nombre d’enregistrements affectés.
Par conséquent, pour ces trois méthodes, il est valide de coder quelque chose comme :
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
Gestion des erreurs
Dans COM, la plupart des opérations retournent un code de retour HRESULT qui indique si une fonction s’est terminée correctement. La directive #import génère du code wrapper autour de chaque méthode ou propriété « brute » et vérifie le HRESULT retourné. Si HRESULT indique un échec, le code du wrapper lève une erreur COM en appelant _com_issue_errorex() avec le code de retour HRESULT en tant qu’argument. Les objets d’erreur COM peuvent être interceptés dans un bloc try-catch. (Par souci d’efficacité, interceptez une référence à un objet _com_error.)
N’oubliez pas qu’il s’agit d’erreurs ADO : elles résultent de l’échec de l’opération ADO. Les erreurs retournées par le fournisseur sous-jacent apparaissent sous forme d’objets Error dans la collection Errors de l’objet Connection.
La directive #import crée uniquement des routines de gestion des erreurs pour les méthodes et les propriétés déclarées dans le .dll ADO. Toutefois, vous pouvez tirer parti de ce même mécanisme de gestion des erreurs en écrivant votre propre macro de vérification des erreurs ou fonction inline. Consultez la rubrique Extensions Visual C++ ou le code des sections suivantes pour obtenir des exemples.
Équivalents Visual C++ des conventions Visual Basic
Voici un résumé de plusieurs conventions de la documentation ADO, codées en Visual Basic, ainsi que leurs équivalents en Visual C++.
Déclaration d’un objet ADO
En Visual Basic, une variable objet ADO (dans ce cas pour un objet Recordset) est déclarée comme suit :
Dim rst As ADODB.Recordset
La clause « ADODB.Recordset
» est le ProgID de l’objet Recordset comme défini dans le Registre. Une nouvelle instance d’un objet Record est déclarée comme suit :
Dim rst As New ADODB.Recordset
-ou-
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
Dans Visual C++, la directive #import génère des déclarations de type pointeur intelligent pour tous les objets ADO. Par exemple, une variable qui pointe vers un objet _Recordset est de type _RecordsetPtr et est déclarée comme suit :
_RecordsetPtr rs;
Une variable qui pointe vers une nouvelle instance d’un objet _Recordset est déclarée comme suit :
_RecordsetPtr rs("ADODB.Recordset");
- ou -
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
- ou -
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
Une fois la méthode CreateInstance appelée, la variable peut être utilisée comme suit :
rs->Open(...);
Notez que dans un cas, l’opérateur « .
» est utilisé comme si la variable était une instance d’une classe (rs.CreateInstance
) et, dans un autre cas, l’opérateur « ->
» est utilisé comme si la variable était un pointeur vers une interface (rs->Open
).
Une variable peut être utilisée de deux façons, car l’opérateur « ->
» est surchargé pour permettre à une instance d’une classe de se comporter comme un pointeur vers une interface. Un membre de classe privée de la variable d’instance contient un pointeur vers l’interface _Recordset ; l’opérateur « ->
» retourne ce pointeur ; et le pointeur retourné accède aux membres de l’objet _Recordset.
Codage d’un paramètre manquant - String
Lorsque vous devez coder un opérande String manquant en Visual Basic, il vous suffit d’omettre l’opérande. Vous devez spécifier l’opérande dans Visual C++. Codez un _bstr_t qui a une chaîne vide en tant que valeur.
_bstr_t strMissing(L"");
Codage d’un paramètre manquant - Variant
Lorsque vous devez coder un opérande Variant manquant en Visual Basic, il vous suffit d’omettre l’opérande. Vous devez spécifier tous les opérandes dans Visual C++. Codez un paramètre Variant manquant avec un _variant_t défini sur la valeur spéciale DISP_E_PARAMNOTFOUND et le type VT_ERROR. Vous pouvez également spécifier vtMissing, qui est une constante prédéfinie équivalente fournie par la directive #import.
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
- Ou utilisez -
...vtMissing...;
Déclaration d’un Variant
En Visual Basic, un Variant est déclaré avec l’instruction Dim comme suit :
Dim VariableName As Variant
Dans Visual C++, déclarez une variable en tant que type _variant_t. Voici quelques déclarations _variant_t schématiques.
Notes
Ces déclarations donnent simplement une idée approximative de ce que vous coderiez dans votre propre programme. Pour plus d’informations, consultez les exemples ci-dessous et la documentation 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);
Utilisation de tableaux de Variants
En Visual Basic, les tableaux de Variants peuvent être codés avec l’instruction Dim, ou vous pouvez utiliser la fonction Array, comme illustré dans l’exemple de code suivant :
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
L’exemple Visual C++ suivant illustre l’utilisation d’un SafeArray utilisé avec un _variant_t.
Notes
Les notes suivantes correspondent aux sections commentées dans l’exemple de code.
Une fois de plus, la fonction inline TESTHR() est définie pour tirer parti du mécanisme de gestion des erreurs existant.
Vous n’avez besoin que d’un tableau unidimensionnel. Vous pouvez donc utiliser SafeArrayCreateVector au lieu de la déclaration SAFEARRAYBOUND à usage général et de la fonction SafeArrayCreate. Voici à quoi ressemblerait ce code avec SafeArrayCreate :
SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);
Le schéma identifié par la constante énumérée, adSchemaColumns, est associé à quatre colonnes de contrainte : TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME et COLUMN_NAME. Par conséquent, un tableau de valeurs Variant avec quatre éléments est créé. Ensuite, une valeur de contrainte qui correspond à la troisième colonne, TABLE_NAME, est spécifiée.
L’objet Recordset retourné se compose de plusieurs colonnes, dont un sous-ensemble correspond aux colonnes de contrainte. Les valeurs des colonnes de contrainte pour chaque ligne retournée doivent être identiques aux valeurs de contrainte correspondantes.
Ceux qui connaissent SafeArrays peuvent être surpris de voir que SafeArrayDestroy() n’est pas appelé avant la sortie. En fait, l’appel de SafeArrayDestroy() dans ce cas provoquerait une exception d’exécution. La raison est que le destructeur pour
vtCriteria
appelle VariantClear() lorsque le _variant_t sort de la portée, ce qui libérera le SafeArray. L’appel de SafeArrayDestroy, sans effacer manuellement le _variant_t, amènerait le destructeur à tenter d’effacer un pointeur SafeArray non valide.Si SafeArrayDestroy était appelé, le code ressemblerait à ceci :
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
Toutefois, il est beaucoup plus simple de laisser _variant_t gérer le 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();
}
Utilisation de la propriété Get/Put/PutRef
En Visual Basic, le nom d’une propriété n’est pas qualifié selon qu’elle est récupérée ou affectée, ou qu’une référence lui est affectée.
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
Cet exemple Visual C++ illustre la propriétéGet/Put/PutRef.
Notes
Les notes suivantes correspondent aux sections commentées dans l’exemple de code.
Cet exemple utilise deux formes d’argument String manquant : une constante explicite, strMissing et une chaîne que le compilateur utilisera pour créer un _bstr_t temporaire qui existera pour l’étendue de la méthode Open.
Il n’est pas nécessaire d’effectuer un cast de l’opérande de
rs->PutRefActiveConnection(cn)
à(IDispatch *)
, car le type de l’opérande est déjà(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();
}
Utilisation de GetItem(x) et Item[x]
Cet exemple Visual Basic illustre la syntaxe standard et alternative pour 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
Cet exemple Visual C++ illustre Item.
Notes
La remarque suivante correspond aux sections commentées dans l’exemple de code : lorsque la collection est accessible avec Item, l’index , 2, doit être converti en Long afin qu’un constructeur approprié soit appelé.
// 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();
}
Conversion de pointeurs d’objet ADO avec (IDispatch *)
L’exemple Visual C++ suivant illustre l’utilisation de (IDispatch *) pour effectuer un cast des pointeurs d’objet ADO.
Notes
Les notes suivantes correspondent aux sections commentées dans l’exemple de code.
Spécifiez un objet Connection ouvert dans un Variant codé explicitement. Effectuez un cast avec (IDispatch *) afin que le constructeur approprié soit appelé. En outre, définissez explicitement le deuxième paramètre _variant_t sur la valeur par défaut true, afin que le nombre de références d’objet soit correct lorsque l’opération Recordset::Open se termine.
L’expression,
(_bstr_t)
n’est pas un cast, mais un opérateur _variant_t qui extrait une chaîne _bstr_t du Variant retourné par Value.
L’expression, (char*)
n’est pas un cast, mais un opérateur _bstr_t qui extrait un pointeur vers la chaîne encapsulée dans un objet _bstr_t.
Cette section de code illustre certains des comportements utiles des opérateurs _variant_t et _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();
}