Programación de ADO de Visual C++
La referencia de 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 el público previsto es todos los usuarios, los programadores de ADO emplean diversos lenguajes como Visual Basic, Visual C++ (con y sin la directiva #import) y Visual J++ (con el paquete de clase ADO/WFC).
Nota
Microsoft finalizó la compatibilidad con Visual J++ en 2004.
Para dar cabida a esta diversidad, los ADO para los índices de sintaxis de Visual C++ proporcionan sintaxis específica del lenguaje Visual C++ con vínculos a descripciones comunes de funcionalidad, parámetros, comportamientos excepcionales, etc., en la referencia de API.
ADO se implementa con interfaces COM (Modelo de objetos componentes). Sin embargo, es más fácil que los programadores trabajen con COM en determinados lenguajes de programación que otros. Por ejemplo, casi todos los detalles del uso de COM se controlan implícitamente para los programadores de Visual Basic, mientras que los programadores de Visual C++ deben encargarse de esos detalles.
En las secciones siguientes se resumen los detalles de los programadores de C y C++ que usan ADO y la directiva #import. Se centra en los tipos de datos específicos de COM (Variant, BSTRy SafeArray) y el control de errores (_com_error).
Uso de la directiva del compilador #import
La #import directiva 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, como el .dll de ADO (Msado15.dll), y genera archivos de encabezado que contienen declaraciones de definición de tipo, punteros inteligentes para interfaces y constantes enumeradas. Cada interfaz está encapsulada o envuelta en una clase.
Para cada operación dentro de una clase (es decir, una llamada a método o propiedad), hay una declaración para llamar a la operación directamente (es decir, la forma "sin procesar" de la operación) y una declaración para llamar a la operación sin procesar y producir un error COM si la operación no se ejecuta correctamente. Si la operación es una propiedad, normalmente hay una directiva del compilador que crea una sintaxis alternativa para la operación que tiene sintaxis como Visual Basic.
Las operaciones que recuperan el valor de una propiedad tienen nombres del formato GetProperty. Las operaciones que establecen el valor de una propiedad tienen nombres de la forma PutProperty. Las operaciones que establecen el valor de una propiedad con un puntero a un objeto ADO tienen nombres del formulario, PutRefProperty.
Puede obtener o establecer una propiedad con llamadas de estas formas:
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(propiedad...) es una extensión del lenguaje C específica de Microsoft que declara una función que se usa como propiedad para tener una sintaxis alternativa. Como resultado, puede establecer o obtener valores de una propiedad de forma similar a Visual Basic. Por ejemplo, puede establecer y obtener una propiedad de esta manera:
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
Tenga en cuenta que no tiene que codificar:
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
El compilador generará la llamada adecuada Get-, Put-, o PutRefProperty, en función de la sintaxis alternativa que se declare y de si la propiedad se está leyendo o escribiendo.
La directiva del compilador __declspec(property...) solo puede declarar get, put, o get y put como sintaxis alternativa para una función. Las operaciones de solo lectura solo tienen una declaración get; las operaciones de solo escritura solo tienen una declaración put; las operaciones que son tanto de lectura como de escritura tienen declaraciones get y put.
Solo se pueden realizar dos declaraciones con esta directiva; sin embargo, cada propiedad puede tener tres funciones de propiedad: GetProperty, PutPropertyy PutRefProperty. En ese caso, solo dos formas de la propiedad tienen la sintaxis alternativa.
Por ejemplo, el objeto Command propiedad ActiveConnection se declara con un sintaxis alternativa para GetActiveConnection y PutRefActiveConnection. La PutRef- la sintaxis es una buena opción porque, en la práctica, normalmente querrá colocar un objeto Connection abierto (es decir, un puntero de objeto Connection ) en esta propiedad. Por otro lado, el objeto Recordset tiene Get-, Put-, y PutRefoperaciones de ActiveConnection, pero sintaxis alternativa.
Colecciones, el método GetItem y la propiedad Item
ADO define varias colecciones, incluidas Fields, Parameters, Propertiesy Errors. En Visual C++, el método GetItem(index) devuelve un miembro de la colección. Index es un Variant, cuyo valor es un í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 alternativa sintáctica al método fundamental GetItem() de cada colección. La sintaxis alternativa usa corchetes y tiene un aspecto similar a una referencia de matriz. En general, las dos formas tienen un aspecto similar al siguiente:
collectionPtr->GetItem(index);
collectionPtr->Item[index];
Por ejemplo, asigne un valor a un campo de un objeto Recordset de, denominado rs, derivado de la tabla autores de la base de datos pubs. Utilice la propiedad Item() para acceder al tercer Field de la colección de Fields del objeto Recordset (las colecciones se indexan desde cero; supongamos que el tercer campo se denomina au_fname). A continuación, llame al método Value() en el objeto field para asignar un valor de cadena.
Esto se puede expresar en Visual Basic de las cuatro maneras siguientes (los dos últimos formularios son únicos para 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 de Visual C++ a los dos primeros formularios anteriores es:
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
-o- (también se muestra la sintaxis alternativa para la propiedad Value)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
Para obtener ejemplos de iteración a través de una colección, vea la sección "Colecciones de ADO" de "Referencia de ADO".
COM-Specific Tipos de Datos
En general, cualquier tipo de datos de Visual Basic que encuentre en la referencia de API de ADO tiene un equivalente de Visual C++. Estos incluyen tipos de datos estándar, como de caracteres sin signo para un byte de Visual Basic, corto para entero y largos para Long. Busque en Los índices de sintaxis para ver exactamente lo que es necesario para los operandos de un método o propiedad determinado.
Las excepciones a esta regla son los tipos de datos específicos de COM: Variant, BSTRy SafeArray.
Variante
Un Variant es un tipo de datos estructurado que contiene un miembro de valor y un miembro de tipo de datos. Un Variant puede contener una amplia gama de otros tipos de datos, como otro variant, BSTR, booleano, puntero IDispatch o IUnknown, moneda, fecha, etc. COM también proporciona métodos que facilitan la conversión de un tipo de datos a otro.
La clase _variant_t encapsula y administra el tipo de datos Variant.
Cuando la referencia de api de ADO indica que un método o operando de propiedad toma un valor, normalmente significa que el valor se pasa en un _variant_t.
Esta regla se cumple explícitamente cuando la sección Parámetros de de los temas de la Referencia de API de ADO indica que un operando es un Variant. Una excepción es cuando la documentación indica explícitamente que el operando toma un tipo de datos estándar, como Long o Byteo una enumeración. Otra excepción es cuando el operando toma un string.
BSTR
Un BSTR (Basic STRing) es un tipo de datos estructurado que contiene una cadena de caracteres y la longitud de esa 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 propiedad recibe un valor de tipo String, significa que el valor está en la forma de un _bstr_t.
Conversión de clases _variant_t y _bstr_t
A menudo no es necesario codificar explícitamente un _variant_t o _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, el compilador generará el _variant_t o _bstr_tadecuado.
Sin embargo, si el argumento es ambiguo, es decir, el tipo de datos del argumento coincide con más de un constructor, debe convertir el argumento con el tipo de datos adecuado para invocar el constructor correcto.
Por ejemplo, la declaración del 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
toma una referencia a un _variant_t, que 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=MyUserName;pwd=<password>;
", o un puntero como "(IDispatch *) pConn
".
Nota
Si se conecta a un proveedor de origen de datos que admite la autenticación de Windows, debe especificar Trusted_Connection=sí o Integrated Security = SSPI en lugar del identificador de usuario y la información de contraseña en la cadena de conexión.
O bien, puede codificar explícitamente un _variant_t que contenga un puntero como "_variant_t((IDispatch *) pConn, true)
". El elenco, (IDispatch *)
, resuelve la ambigüedad con otro constructor que toma un puntero a una interfaz IUnknown.
Es un hecho crucial, aunque rara vez mencionado, que ADO es una interfaz IDispatch. Cada vez que se debe pasar un puntero a un objeto ADO como Variant, ese puntero debe ser convertido a un puntero a una interfaz IDispatch.
El último caso codifica explícitamente el segundo argumento booleano del constructor con su valor predeterminado opcional de true
. Este argumento hace que el constructor Variant llame a su método AddRef(), lo que compensa que ADO llame automáticamente al método _variant_t::Release() cuando se completa la llamada al método o la propiedad de ADO.
SafeArray
Un SafeArray es un tipo de datos estructurado que contiene una matriz de otros tipos de datos. Un safeArray se denomina seguro porque contiene información sobre los límites de cada dimensión de matriz y limita el acceso a los elementos de matriz dentro de esos límites.
Cuando la referencia de API de ADO indica que un método o propiedad toma o devuelve una matriz, significa que el método o la propiedad toma o devuelve una SafeArray, no una matriz nativa de C/C++.
Por ejemplo, el segundo parámetro del objeto connection openSchema método requiere una matriz de valores de Variant de. Esos valores Variant deben pasarse como elementos de un SafeArray, y SafeArray debe establecerse como el valor de otro Variant. Esa otra Variante que se pasa como segundo argumento de OpenSchema.
Como ejemplos adicionales, el primer argumento del método Find es un Variant cuyo valor es una SafeArray unidimensional; cada uno de los primeros y segundos argumentos opcionales de AddNew es una SafeArray unidimensional; y el valor devuelto del método GetRows es un Variant cuyo valor es una SafeArray bidimensional.
Parámetros ausentes y predeterminados
Visual Basic permite parámetros ausentes en los métodos. Por ejemplo, el objeto Recordset con el método Open tiene cinco parámetros, pero puede omitir los parámetros intermedios y dejar sin especificar los parámetros finales. En función del tipo de datos que falte en el operando, se sustituirá por un BSTR predeterminado o un Variante.
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 sea un Variant, especifique un _variant_t con un valor de DISP_E_PARAMNOTFOUND y un tipo de VT_ERROR. Como alternativa, especifique la constante _variant_t equivalente, vtMissing, que proporciona la directiva #import.
Tres métodos son excepciones al uso típico de vtMissing. Estos son los métodos Execute de los objetos Connection y Command, y el método NextRecordset del objeto Recordset. Estas son sus firmas:
_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
Los parámetros, RecordsAffected y Parameters, son punteros a un Variant. Parameters es un parámetro de entrada que especifica la dirección de un Variant que contiene un único parámetro o matriz de parámetros, que modificará el comando que se está ejecutando. 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 hay parámetros especificados configurando Parameters a &vtMissing
(lo cual se recomienda) o al puntero nulo (es decir, NULL o cero (0)). Si Parámetros se establece en el puntero nulo, el método sustituye internamente el equivalente de vtMissingy, a continuación, completa la operación.
En todos los métodos, indique que no se debe devolver el número de registros afectados estableciendo RecordsAffected en el 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 debe descartar el número de registros afectados.
Por lo tanto, para estos tres métodos, es válido codificar algo como:
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
Control de errores
En COM, la mayoría de las operaciones devuelven un código de retorno HRESULT que indica si una función se completó correctamente. La directiva #import genera código envoltorio alrededor de cada método o propiedad "sin procesar" y verifica el HRESULT devuelto. Si el HRESULT indica un fallo, el código de empaquetado lanza un error COM llamando a _com_issue_errorex() con el código de retorno HRESULT como argumento. Los objetos de error COM se pueden detectar en un probar-detectar bloque. (Por motivos de eficacia, capture una referencia a un objeto _com_error).
Recuerde que se trata de errores de ADO: se producen errores en la operación de ADO. Los errores devueltos por el proveedor subyacente aparecen como objetos de error en el objeto de conexión dentro de la colección de errores .
La directiva #import crea solo rutinas de control de errores para métodos y propiedades declarados en el .dllde ADO . Sin embargo, puede aprovechar este mismo mecanismo de control de errores escribiendo su propia macro de comprobación de errores o función en línea. Vea el tema extensiones de Visual C++o el código de las secciones siguientes para obtener ejemplos.
Equivalentes de las convenciones de Visual Basic en Visual C++
A continuación se muestra un resumen de varias convenciones de la documentación de ADO, codificadas en Visual Basic, así como sus equivalentes en Visual C++.
Declarar un objeto ADO
En Visual Basic, una variable de objeto de ADO (en este caso para un objeto Recordset ) se declara de la siguiente manera:
Dim rst As ADODB.Recordset
La cláusula "ADODB.Recordset
", es el ProgID del objeto Recordset tal como se define en el Registro. Una nueva instancia de un objeto record se declara de la siguiente manera:
Dim rst As New ADODB.Recordset
-o-
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
En Visual C++, la directiva #import genera declaraciones de tipo de puntero inteligente para todos los objetos ADO. Por ejemplo, una variable que apunta a un objeto _Recordset es de tipo _RecordsetPtry se declara de la siguiente manera:
_RecordsetPtr rs;
Una variable que apunta a una nueva instancia de un objeto _Recordset se declara de la siguiente manera:
_RecordsetPtr rs("ADODB.Recordset");
-o-
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
-o-
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
Después de llamar al método CreateInstance, la variable se puede usar de la siguiente manera:
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 un string que falta operando en Visual Basic, simplemente se omite el operando. Debe especificar el operando en Visual C++. Codigo un _bstr_t que tiene una cadena vacía como valor.
_bstr_t strMissing(L"");
Codificación de un parámetro que falta: variant
Cuando necesites codificar un operando de variante en Visual Basic, basta con omitir el operando. Debe especificar todos los operandos en Visual C++. Codifica un parámetro de Variante faltante con un _variant_t configurado al valor especial, DISP_E_PARAMNOTFOUND, y tipo, VT_ERROR. Como alternativa, especifique vtMissing, que es una constante predefinida equivalente proporcionada por la directiva #import.
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
-o usa-
...vtMissing...;
Declarar un Variant
En Visual Basic, un Variant se declara con la instrucción Dim de la siguiente manera:
Dim VariableName As Variant
En Visual C++, declare una variable como tipo _variant_t. A continuación, se muestran algunas declaraciones esquemáticas de _variant_t.
Nota
Estas declaraciones simplemente dan una idea aproximada de lo que codificaría en 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 bien puede usar la función Array de, 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"
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 siguiente ejemplo de Visual C++ se muestra el uso de un SafeArray usado con un _variant_t.
Notas
Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
Una vez más, se define la función insertada TESTHR() para aprovechar el mecanismo de control de errores existente.
Solo necesita una matriz unidimensional, por lo que puede usar SafeArrayCreateVectoren lugar de la declaración general SAFEARRAYBOUND y la función SafeArrayCreate. A continuación se muestra el aspecto que tendría ese código mediante SafeArrayCreate:
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, está asociado a cuatro columnas de restricción: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME y COLUMN_NAME. Por lo tanto, se crea una matriz de valores de variante con cuatro elementos. A continuación, se especifica un valor de restricción que corresponde a la tercera columna, TABLE_NAME.
El recordset que se devuelve consta de varias columnas, un subconjunto de las cuales son 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.
Los familiarizados con SafeArrays pueden sorprenderse de que no se llame a SafeArrayDestroy() antes de la salida. De hecho, llamar a SafeArrayDestroy() en este caso provocará una excepción en tiempo de ejecución. El motivo es que el destructor de
vtCriteria
llamará a VariantClear() cuando el _variant_t salga del alcance, lo que liberará el SafeArray. Llamar a SafeArrayDestroy, sin borrar manualmente el _variant_t, provocaría que el destructor intente borrar un puntero SafeArray no válido.Si se llamara a SafeArrayDestroy, el código tendría este aspecto:
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
Sin embargo, es mucho más sencillo permitir que el _variant_t administre el 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();
}
Uso de la propiedad Get/Put/PutRef
En Visual Basic, el nombre de una propiedad no está determinado por si se recupera, se asigna o se le asigna 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 demuestra el uso de Get/Put/PutRefProperty.
Notas
Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
En este ejemplo se usan dos formas de un argumento de cadena perdido: una constante explícita, strMissing, y una cadena que el compilador usará para crear un _bstr_t temporal que existirá para el ámbito del método Open .
No es necesario convertir el operando de
rs->PutRefActiveConnection(cn)
a(IDispatch *)
porque el operando ya es de tipo(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();
}
Uso de GetItem(x) y Item[x]
En este ejemplo de Visual Basic se 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 Elemento.
Nota
La nota siguiente corresponde a las secciones comentadas del ejemplo de código: cuando se accede a la colección con Item, el índice, 2, debe convertirse en long para que se invoque un constructor adecuado.
// 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();
}
Convertir punteros de objeto de ADO utilizando (IDispatch *)
En el siguiente ejemplo de Visual C++ se demuestra cómo usar (IDispatch *) para convertir punteros de objetos ADO.
Notas
Las notas siguientes corresponden a secciones comentadas en el ejemplo de código.
Especifique un objeto abierto Connection en un Variantexplícitamente codificado. Castearlo con (IDispatch *) para que se invoque el constructor correcto. Además, establezca explícitamente el segundo parámetro _variant_t en el valor predeterminado de true, por lo que el recuento de referencias de objetos será correcto cuando finalice la operación recordset::Open .
La expresión,
(_bstr_t)
, no es una conversión, sino un operador _variant_t que extrae una cadena de _bstr_t de la Variant de devuelta por Value.
La expresión, (char*)
, no es una conversión, sino un operador _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 de _variant_t y _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();
}