Programación de ADO con Visual C++
Se aplica a: Access 2013, Office 2013
La Referencia de la API de ADO describe la funcionalidad de la interfaz de programación de aplicaciones (API) de ADO mediante una sintaxis similar a Microsoft Visual Basic. Aunque va dirigida a todos los usuarios, los programadores de ADO emplean diversos lenguajes, tales como Visual Basic, Visual C++ (con y sin la directiva #import) y Visual J++ (con el paquete de clases ADO/WFC).
Para dar cabida a esta diversidad, los Índices de sintaxis de ADO para Visual C++ proporcionan sintaxis específica de Visual C++ con vínculos a descripciones comunes de funcionalidad, parámetros, comportamientos excepcionales, etc., en la Referencia de la API.
ADO se implementa con interfaces COM (Modelo de objetos componentes). Sin embargo, es más fácil para los programadores trabajar con COM en algunos lenguajes de programación que en otros. Por ejemplo, casi todos los detalles del uso de COM se manejan implícitamente en Visual Basic, mientras que en Visual C++ son los programadores quienes deben manejar esos detalles.
Las siguientes secciones resumen la información para los programadores de C y C++ que utilizan ADO y la directiva #import. La atención se centra en tipos de datos específicos de COM (Variant, BSTR y SafeArray) y tratamiento de errores (_com_error).
Uso de la directiva del compilador de #import
La directiva #import del compilador de Visual C++ simplifica el trabajo con los métodos y propiedades de ADO. La directiva toma el nombre de un archivo que contiene una biblioteca de tipos, tal como la dll de ADO (Msado15.dll), y genera archivos de encabezado que contienen declaraciones typedef, punteros inteligentes para interface y constantes enumeradas. Cada interfaz se encapsula o engloba en una clase.
Para cada operación dentro de una clase (es decir una llamada a método o propiedad), existe una declaración para llamar a la operación directamente (es decir, la forma "original" de la operación) y una declaración para llamar a la operación original y generar un error COM si la operación no se ejecuta correctamente. Si la operación es una propiedad, suele existir una directiva del compilador que crea una sintaxis alternativa para la operación que tiene sintaxis similar a Visual Basic.
Las operaciones que recuperan el valor de una propiedad tienen nombres de la forma GetPropiedad. Las operaciones que establecen el valor de una propiedad tienen nombres de la forma PutPropiedad. Las operaciones que establecen el valor de una propiedad con un puntero a un objeto ADO tienen nombres de la forma PutRefPropiedad.
Puede obtener o establecer una propiedad con llamadas de este tipo:
variable = objectPtr->GetProperty(); // get property value
objectPtr->PutProperty(value); // set property value
objectPtr->PutRefProperty(&value); // set property with object pointer
Uso de directivas de propiedad
La directiva del compilador __declspec(property...) es una extensión del lenguaje C específica de Microsoft que declara una función utilizada como propiedad de modo que tenga una sintaxis alternativa. Como resultado, puede establecer u obtener valores de una propiedad de forma similar a Visual Basic. Por ejemplo, puede establecer y obtener una propiedad de este modo:
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
Tenga en cuenta que no tiene que escribir este código:
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
El compilador generará la llamada Get-, Put- o PutRefPropiedad apropiada según la sintaxis alternativa declarada y si la propiedad se va a leer o escribir.
La directiva del compilador __declspec(property...) sólo puede declarar sintaxis alternativa get, put o get y put para una función. Las operaciones de sólo lectura únicamente tienen una declaración get; las operaciones de sólo escritura únicamente tienen una declaración put; las operaciones de lectura y escritura tienen ambas declaraciones get y put.
Sólo hay dos declaraciones posibles con esta directiva; sin embargo, cada propiedad tiene tres funciones: GetPropiedad, PutPropiedad y PutRefPropiedad. En ese caso, sólo dos formas de la propiedad presentan sintaxis alternativa.
Por ejemplo, la propiedad ActiveConnection del objeto Command se declara con una sintaxis alternativa para GetActiveConnection y PutRefActiveConnection. La sintaxis de PutRef constituye una buena elección, ya que, en la práctica, deseará establecer un objeto Connection abierto (es decir, un puntero a un objetoConnection) en esta propiedad. Por otro lado, el objeto Recordset tiene operaciones Get-, Put- y PutRefActiveConnection, pero sin sintaxis alternativa.
Colecciones, el método GetItem y la propiedad Item
ADO define varias colecciones, incluidas Fields, Parameters, Properties y Errors. En Visual C++, el método GetItem(index) devuelve un miembro de la colección. Índice es de un tipo Variant, cuyo valor es el índice numérico del miembro de la colección o una cadena que contiene el nombre del miembro.
La directiva del compilador __declspec(property...) declara la propiedad Item como una sintaxis alternativa al método GetItem() fundamental de cada colección. La sintaxis alternativa utiliza corchetes y es similar a una referencia a matriz. En general, las dos formas son similares a lo siguiente:
collectionPtr->GetItem(index);
collectionPtr->Item[index];
Por ejemplo, asigne un valor a un campo de un objeto Recordset , denominado rs, derivado de la tabla authors de la base de datos pubs . Utilice la propiedad Item() para tener acceso al tercer campo de la colección Fields del objeto Recordset (las colecciones se indizan desde cero; supongamos que el tercer campo se denomina au_fname). A continuación, llame al método Value() sobre el objeto Field para asignar un valor de cadena.
Esto se puede expresar en Visual Basic de las siguientes cuatro maneras (las últimas dos formas son exclusivas de Visual Basic; otros lenguajes no tienen equivalentes):
rs.Fields.Item(2).Value = "value"
rs.Fields.Item("au_fname").Value = "value"
rs(2) = "value"
rs!au_fname = "value"
El equivalente en Visual C++ a las dos primeras formas anteriores es:
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
O bien (también se muestra la sintaxis alternativa de la propiedad Value)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
Tipos de datos específicos de COM
En general, cualquier tipo de datos de Visual Basic que se encuentra en la Referencia de la API de ADO tiene un equivalente en Visual C++. Éstos incluyen tipos de datos estándar, tales como unsigned char para un Byte de Visual Basic, short para Integer y long para Long. Busque en los Índices de la sintaxis para ver qué se requiere exactamente para los operandos de un método o una propiedad dados.
Las excepciones a esta regla son los tipo de datos específicos de COM: Variant, BSTR y SafeArray.
Variant
Un Variant es un tipo de datos estructurados que contiene un miembro de valor y un miembro de tipo de datos. Un Variant puede contener una amplia variedad de otros tipos de datos, incluidos otro Variant, BSTR, Boolean, IDispatch, puntero a IUnknown, moneda, fecha, etc. COM también proporciona métodos que facilitan la conversión de un tipo de datos en otro.
La clase _variant_t encapsula y administra el tipo de datos Variant.
Cuando la referencia a la API de ADO indica que un operando de un método o una propiedad toma un valor, suele significar que el valor se pasa en un objeto _variant_t.
Esta regla se cumple explícitamente cuando la sección Parámetros de los temas de la Referencia de la API de ADO indica que un operando es de tipo Variant. Una excepción es cuando la documentación indica explícitamente que el operandos toma un tipo de datos estándar, como Long, Byte o una enumeración. Otra excepción es cuando el operando toma un String.
BSTR
Un BSTR (Basic STRing) es un tipo de datos estructurados que contiene una cadena de caracteres y la longitud de la cadena. COM proporciona métodos para asignar, manipular y liberar un BSTR.
La clase _bstr_t encapsula y administra el tipo de datos BSTR.
Cuando la Referencia de la API de ADO indica que un método o una propiedad toman un valor String, significa que el valor existe en forma de un _bstr_ t.
Conversión de clases de _variant_t y _bstr_t
A menudo, no es necesario codificar explícitamente un _variant_t o un _bstr_ t en un argumento para una operación. Si la clase _variant_t o _bstr_ t tiene un constructor que coincide con el tipo de datos del argumento, entonces el compilador generará el _variant_ t o _bstr_ t apropiado.
Sin embargo, si el argumento es ambiguo, es decir, el tipo de datos del argumento coincide con más de un constructor, deberá convertir el argumento explícitamente al tipo de datos apropiado para llamar al constructor correcto.
Por ejemplo, la declaración para el método Recordset::Open es:
HRESULT Open (
const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options );
El argumento ActiveConnection acepta una referencia a un _variant_ t, que se puede codificar como una cadena de conexión o un puntero a un objeto Connection abierto.
El _variant_t correcto se construirá implícitamente si se pasa una cadena como "DSN=pubs; uid=sa; pwd=;", o un puntero como "(IDispatch *) pConn".
O bien, puede codificar explícitamente un _variant_t que contenga un puntero como "_variant_t((IDispatch *) pConn, true)". La conversión explícita, (IDispatch *), resuelve la ambigüedad con otro constructor que acepte un puntero a una interfaz IUnknown.
Es un hecho crucial (aunque raramente mencionado) que ADO es una interfaz IDispatch. Siempre que un puntero a un objeto ADO se deba pasar como un Variant, es necesario convertir explícitamente ese puntero a un puntero a un interfaz IDispatch.
El último caso codifica explícitamente el segundo argumento booleano del constructor con su valor predeterminado opcional true. Este argumento hace que el constructor de Variant llame a su método AddRef(), el cual compensa a ADO automáticamente llamando al método _variant_t::Release() cuando la llamada al método o la propiedad de ADO finaliza.
Safearray
Un SafeArray es un tipo de datos estructurados que contiene una matriz de otros tipos de datos. Un SafeArray se denomina safe (seguro) debido a que contiene información sobre los límites de cada dimensión de la matriz y limita el acceso a los elementos de la matriz a esos límites.
Cuando la Referencia de la API de ADO indica que un método o una propiedad acepta o devuelve una matriz, significa que el método o la propiedad acepta o devuelve un SafeArray no una matriz nativa de C/C++.
Por ejemplo, el segundo parámetro del método OpenSchema del objeto Conection requiere una matriz de valores Variant. Esos valores Variant se deben pasar como elementos de un SafeArray, y ese SafeArray se debe establecer como el valor de otro Variant. Es ese otro Variant el que se pasa como el segundo argumento de OpenSchema.
Como ejemplos adicionales, el primer argumento del método Find es un Variant cuyo valor es un SafeArray unidimensional, cada uno de los argumentos primero y segundo opcionales de AddNew es un SafeArray unidimensional y el valor devuelto del método GetRows es un Variant cuyo valor es un SafeArray bidimensional.
Parámetros predeterminados y que faltan
Visual Basic permite que falten parámetros en los métodos. Por ejemplo, el método Open de un objeto Recordset tiene cinco parámetros, pero se pueden omitir parámetros intermedios y no incluir parámetros finales. Se usará entonces un BSTR o Variant predeterminado según el tipo de datos del operando que falte.
En C/C++, se deben especificar todos los operandos. Si desea especificar un parámetro que falta cuyo tipo de datos es una cadena, especifique un _bstr_t que contenga una cadena nula. Si desea especificar un parámetro que falta cuyo tipo de datos es un Variant, especifique un _variant_t con un valor DISP_E_PARAMNOTFOUND y un tipo VT_ERROR. Como alternativa, especifique la constante _variant_t equivalente, vtMissing, la cual se suministra mediante la directiva #import.
Existen tres métodos que constituyen excepciones al uso típico de vtMissing. Éstos son los métodos Execute de los objetos Connection y Command, y el método NextRecordset del objeto Recordset. Las siguientes son sus firmas:
_RecordsetPtr Invalid DDUE based on source, error:link not allowed in code, link filename:mdmthcnnexecute_HV10294345.xml( _bstr_t CommandText, VARIANT * RecordsAffected,
long Options ); // Connection
_RecordsetPtr Invalid DDUE based on source, error:link not allowed in code, link filename:mdmthcmdexecute_HV10294344.xml( VARIANT * RecordsAffected, VARIANT * Parameters,
long Options ); // Command
_RecordsetPtr Invalid DDUE based on source, error:link not allowed in code, link filename:mdmthnextrec_HV10294541.xml( VARIANT * RecordsAffected ); // Recordset
Los parámetros RecordsAffected y Parametersson punteros a un Variant. Parameters es un parámetro de entrada que especifica la dirección de un Variant que contiene un parámetro único, o una matriz de parámetros, que modificará el comando que se va a ejecutar. RecordsAffected es un parámetro de salida que especifica la dirección de un Variant donde se devuelve el número de filas afectadas por el método.
En el método Execute del objeto Command, indique que no se especifica ningún parámetro estableciendo Parámetros en &vtMissing (que se recomienda) o en el puntero null (es decir, NULL o cero (0)). Si Parameters se establece en el puntero nulo, el método sustituye internamente el equivalente de vtMissing y, a continuación, completa la operación.
En todos los métodos, indique que no se debe devolver el número de registros afectados; puede hacerlo estableciendo RecordsAffected en un puntero nulo. En este caso, el puntero nulo no es tanto un parámetro que falta como una indicación de que el método debería descartar el número de registros afectados.
Por tanto, para estos tres métodos, es correcto codificar del siguiente modo:
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
Control de errores
In COM, most operations return an HRESULT return code that indicates whether a function completed successfully. The #import directive generates wrapper code around each "raw" method or property and checks the returned HRESULT. If the HRESULT indicates failure, the wrapper code throws a COM error by calling _com_issue_errorex() with the HRESULT return code as an argument. COM error objects can be caught in a try-catch block. (For efficiency's sake, catch a reference to a _com_error object.)
Recuerde que éstos son errores de ADO (resultado de una operación ADO). Los errores devueltos por el proveedor subyacente aparecen como objetos Error de la colección Errors del objeto Connection.
La directiva #import sólo crea rutinas de tratamiento de errores para métodos y propiedades declarados en la dll de ADO. Sin embargo, puede aprovechar este mismo mecanismo de tratamiento de errores escribiendo su propia función en línea o macro de comprobación de errores. Vea el tema Extensiones de Visual C++ o el código de la sección siguiente para obtener ejemplos.
Equivalentes de Visual C++ de convenciones de Visual Basic
A continuación, se muestra un resumen de diversas convenciones de la documentación de ADO, codificadas en Visual Basic, así como sus equivalentes en Visual C++.
Declaración de un objeto ADO
En Visual Basic, una variable de objeto ADO (en este caso, de un objeto Recordset) se declara del siguiente modo:
Dim rst As ADODB.Recordset
La cláusula , "ADODB. Recordset", es el ProgID del objeto Recordset tal como se define en el Registro. Una instancia nueva de un objeto Record se declara del siguiente modo:
Dim rst As New ADODB.Recordset
O bien
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
In Visual C++, the #import directive generates smart pointer-type declarations for all the ADO objects. Por ejemplo, una variable que apunta a un objeto _Recordset es de tipo _RecordsetPtr, y se declara del siguiente modo:
_RecordsetPtr rs;
Una variable que apunta a una instancia nueva de un objeto _Recordset se declara del siguiente modo:
_RecordsetPtr rs("ADODB.Recordset");
O bien
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
O bien
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
Después de llamar al método CreateInstance, la variable se puede utilizar de la manera siguiente:
rs->Open(...);
Observe que, en un caso, el operador "." se usa como si la variable fuera una instancia de una clase (rs. CreateInstance) y, en otro caso, el operador "->" se usa como si la variable fuera un puntero a una interfaz (rs-Open>).
Una variable se puede usar de dos maneras porque el operador "->" está sobrecargado para permitir que una instancia de una clase se comporte como un puntero a una interfaz. Un miembro de clase privada de la variable de instancia contiene un puntero a la interfaz _Recordset ; El operador "->" devuelve ese puntero y el puntero devuelto accede a los miembros del objeto _Recordset .
Codificación de un parámetro que falta
Cadena
Cuando necesite codificar en Visual Basic un operando String ausente, simplemente omita el operando. Deberá especificar el operando en Visual C++. Codifique un _bstr_t cuyo valor sea una cadena vacía.
_bstr_t strMissing(L"");
Variant
Cuando necesite codificar en Visual Basic un operando Variant ausente, simplemente omita el operando. En Visual C++, deberá especificar todos los operandos. Codifique un parámetro Variant ausente con un _variant_t con el valor especial DISP_E_PARAMNOTFOUND y escriba VT_ERROR. Como alternativa, especifique vtMissing, que es una constante equivalente predefinida suministrada por la directiva #import.
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
-o utilice-
...vtMissing...;
Declaración de una variante
En Visual Basic, un tipo Variant se declara con la instrucción Dim del siguiente modo:
Dim VariableName As Variant
En Visual C++, declare una variable como del tipo _variant_t. A continuación, se muestran algunas declaraciones esquemáticas de _variant_t.
Nota:
Estas declaraciones simplemente proporcionan una idea general de cómo podría codificar su propio programa. Para obtener más información, vea los ejemplos siguientes y la documentación de 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);
Uso de matrices de variantes
En Visual Basic, las matrices de Variants se pueden codificar con la instrucción Dim o utilizar la función Array, tal como se muestra en el código de ejemplo siguiente:
Public Sub ArrayOfVariants
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim fld As ADODB.Field
cn.Open "DSN=pubs", "sa", ""
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
En el ejemplo siguiente de Visual C++, se muestra cómo utilizar un SafeArray con un _variant_t.
Nota:
Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
Una vez más, se define la función inline TESTHR() para aprovechar el mecanismo de control de errores existente.
Sólo necesitará una matriz unidimensional, de forma que pueda utilizar SafeArrayCreateVector en lugar de la declaración de propósito general SAFEARRAYBOUND y la función SafeArrayCreate. El código que utiliza SafeArrayCreate tiene el siguiente aspecto:
SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);
El esquema identificado por la constante enumerada adSchemaColumns se asocia con cuatro columnas de restricción: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME y COLUMN_NAME. Por lo tanto, se crea una matriz de valores Variant con cuatro elementos. A continuación, se especifica un valor de restricción correspondiente a la tercera columna, TABLE_NAME. El objeto Recordset que se devuelve consta de varias columnas, entre las que se incluyen las columnas de restricción. Los valores de las columnas de restricción para cada fila devuelta deben ser los mismos que los valores de restricción correspondientes.
Aquéllos familiarizados con SafeArrays se pueden sorprender del hecho de que no se llame a SafeArrayDestroy() antes de la salida. De hecho, llamar a SafeArrayDestroy() provocará en este caso una excepción en tiempo de ejecución. La razón es que el destructor de vtCriteria llamará a VariantClear() cuando el _variant_t salga de ámbito, lo cual liberará el SafeArray. La llamada a SafeArrayDestroy sin borrar manualmente el _variant_t provocará que el destructor intente borrar un puntero SafeArray no válido. Si se hiciera la llamada a SafeArrayDestroy, el código presentaría el siguiente aspecto:
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
Sin embargo, resulta más sencillo permitir que el _variant_t administre el SafeArray.
#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
// Note 1
inline void TESTHR( HRESULT _hr )
{ if FAILED(_hr) _com_issue_error(_hr); }
void main(void)
{
CoInitialize(NULL);
try
{
_RecordsetPtr pRs("ADODB.Recordset");
_ConnectionPtr pCn("ADODB.Connection");
_variant_t vtTableName("authors"),
vtCriteria;
long ix[1];
SAFEARRAY *pSa = NULL;
pCn->Open("DSN=pubs;User ID=MyUserId;pwd=MyPassword;Provider=MSDASQL;", "", "",
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();
}
Uso de la propiedad Get/Put/PutRef
En Visual Basic, el nombre de una propiedad no indica si ésta se ha recuperado, si se le ha asignado un valor o se le ha asignado una referencia.
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
En este ejemplo de Visual C++ se muestra la propiedadGet/PutRef/.
Nota:
Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
Este ejemplo utiliza dos formas de un argumento de cadena que falta: una constante explícita, strMissing, y una cadena que el compilador utilizará para crear un _bstr_t temporal que existirá durante el ámbito del método Open.
No es necesario convertir el operando de rs-PutRefActiveConnection>(cn) a (IDispatch *) porque el tipo del operando ya está (IDispatch *).
#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile") #include <stdio.h> void main(void) { CoInitialize(NULL); try { _ConnectionPtr cn("ADODB.Connection"); _RecordsetPtr rs("ADODB.Recordset"); _bstr_t strMissing(L""); long oldPgSz = 0, newPgSz = 5; // Note 1 cn->Open("Provider=sqloledb;Data Source=MyServer;" "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(); }
Utilizar GetItem(x) e Item[x]
Este ejemplo de Visual Basic muestra la sintaxis estándar y alternativa para 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
En este ejemplo de Visual C++, se muestra el uso de Item.
Nota:
[!NOTA] La nota siguiente corresponde a secciones comentadas en el ejemplo de código.
Cuando se obtiene acceso a la colección mediante Item, el índice, 2, se debe convertir explícitamente a long para que se realice la llamada al constructor apropiado.
#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile") #include <stdio.h> void main(void) { CoInitialize(NULL); try { _RecordsetPtr rs("ADODB.Recordset"); _variant_t vtFirstName; rs->Open("authors", "Provider=sqloledb;Data Source=MyServer;" "Initial Catalog=pubs;Integrated Security=SSPI;", 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(); }
Convertir explícitamente punteros a objetos ADO con ( IDispatch * )
El siguiente ejemplo de Visual C++ muestra el uso de ( IDispatch * ) para convertir explícitamente punteros a objetos ADO.
Nota:
[!NOTA] Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
Especifique un objeto Connection abierto en un Variant codificado explícitamente. Conviértalo explícitamente con (IDispatch *) para que se realice la llamada al constructor correcto. Además, establezca explícitamente el segundo parámetro _variant_t con el valor predeterminado true, de modo que el contador de referencias de objetos sea correcto cuando la operación Recordset::Open finalice.
La expresión (_bstr_t) no es una conversión, sino un operador de _variant_t que extrae una cadena de _bstr_t de la variant devuelta por Value. La expresión (char*), no es una conversión, sino un operador de _bstr_t que extrae un puntero a la cadena encapsulada en un objeto _bstr_t . En esta sección de código, se muestran algunos de los comportamientos útiles de los operadores _variant_t y _bstr_t.
#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile") #include <stdio.h> void main(void) { CoInitialize(NULL); try { _ConnectionPtr pConn("ADODB.Connection"); _RecordsetPtr pRst("ADODB.Recordset"); pConn->Open("Provider=sqloledb;Data Source=MyServer;" "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(); }