Programação ADO em Visual C++
A Referência da API do ADO descreve a funcionalidade da API (interface de programação de aplicativos) do ADO usando uma sintaxe semelhante ao Microsoft Visual Basic. Embora o público-alvo pretendido seja de todos os usuários, os programadores do ADO empregam linguagens diversas, como Visual Basic, Visual C++ (com e sem a diretiva #import) e Visual J++ (com o pacote de classes ADO/WFC).
Nota
A Microsoft encerrou o suporte para Visual J++ em 2004.
Para acomodar essa diversidade, o índices de sintaxe do ADO para Visual C++ fornecem sintaxe específica da linguagem do Visual C++ com links para descrições comuns de funcionalidade, parâmetros, comportamentos excepcionais e assim por diante, na Referência de API.
O ADO é implementado com interfaces COM (Component Object Model). No entanto, é mais fácil para os programadores trabalhar com COM em determinadas linguagens de programação do que em outras. Por exemplo, quase todos os detalhes do uso de COM são tratados implicitamente para programadores do Visual Basic, enquanto os programadores do Visual C++ devem atender a esses próprios detalhes.
As seções a seguir resumem detalhes para programadores C e C++ usando o ADO e a diretiva #import. A ênfase está em tipos de dados específicos ao COM (Variant, BSTRe SafeArray), além do tratamento de erros (_com_error).
Usando a diretiva do compilador #import
A diretiva do compilador #import Visual C++ simplifica o trabalho com os métodos e as propriedades do ADO. A diretiva usa o nome de um arquivo que contém uma biblioteca de tipos, como a .dll do ADO (Msado15.dll) e gera arquivos de cabeçalho contendo declarações typedef, ponteiros inteligentes para interfaces e constantes enumeradas. Cada interface é encapsulada, ou seja, envolvida, em uma classe.
Para cada operação dentro de uma classe (ou seja, um método ou chamada de propriedade), há uma declaração para chamar a operação diretamente (ou seja, a forma "bruta" da operação) e uma declaração para chamar a operação bruta e gerar um erro COM se a operação não for executada com êxito. Se a operação for uma propriedade, geralmente haverá uma diretiva do compilador que cria uma sintaxe alternativa para a operação que tem sintaxe como o Visual Basic.
As operações que recuperam o valor de uma propriedade são nomeadas no formato GetProperty. As operações que definem o valor de uma propriedade têm nomes do formato DefinirPropriedade. As operações que definem o valor de uma propriedade com um ponteiro para um objeto ADO têm nomes do formulário, PutRefProperty.
Você pode obter ou definir uma propriedade com chamadas destas formas:
variable = objectPtr->GetProperty(); // get property value
objectPtr->PutProperty(value); // set property value
objectPtr->PutRefProperty(&value); // set property with object pointer
Usando diretivas de propriedade
A diretiva do compilador __declspec(property...) é uma extensão de linguagem C específica da Microsoft que declara uma função usada como uma propriedade para ter uma sintaxe alternativa. Como resultado, você pode definir ou obter valores de uma propriedade de forma semelhante ao Visual Basic. Por exemplo, você pode definir e obter uma propriedade dessa maneira:
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
Observe que você não precisa codificar:
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
O compilador gerará a chamada Get-, Put- ou PutRefProperty, com base na sintaxe alternativa declarada e se a propriedade está sendo lida ou gravada.
A diretiva do compilador __declspec(property...) só pode declarar obter, colocarou obter e colocar sintaxe alternativa para uma função. Operações somente de leitura têm apenas uma declaração obter; operações somente de gravação têm apenas uma declaração set; operações tanto de leitura quanto de gravação têm declarações obter e set.
Somente duas declarações são possíveis com essa diretiva; no entanto, cada propriedade pode ter três funções de propriedade: ObterPropriedade, ColocarPropriedade, e ColocarRefPropriedade. Nesse caso, apenas duas formas da propriedade têm a sintaxe alternativa.
Por exemplo, a propriedade do objeto Command ActiveConnection é declarada com uma sintaxe alternativa para GetActiveConnection e PutRefActiveConnection. A sintaxe PutRefé uma boa opção porque, na prática, você normalmente deseja colocar um objeto Conexão aberto (ou seja, um ponteiro de objeto Conexão) nesta propriedade. Por outro lado, o objeto Recordset possui as operações Get-, Put- e PutRefActiveConnection, mas sem sintaxe alternativa.
Coleções, o método GetItem e a propriedade Item
O ADO define várias coleções, incluindo Fields, Parameters, Propertiese Errors. No Visual C++, o método GetItem(index) retorna um membro da coleção. Index é um Variant, cujo valor é um índice numérico do membro na coleção ou uma string que contém o nome do membro.
A diretiva do compilador __declspec(property...) declara a propriedade Item como uma sintaxe alternativa ao método fundamental GetItem() de cada coleção. A sintaxe alternativa usa colchetes e é semelhante a uma referência de matriz. Em geral, os dois formulários são semelhantes aos seguintes:
collectionPtr->GetItem(index);
collectionPtr->Item[index];
Por exemplo, atribua um valor a um campo de um objeto Recordset, chamado rs, derivado da tabela autores do banco de dados pubs. Use a propriedade Item() para acessar o terceiro Campo do objeto Recordset na coleção de Campos (coleções são indexadas a partir de zero; suponha que o terceiro campo seja nomeado au_fname). Em seguida, chame o método Value() no objeto field para atribuir um valor de cadeia de caracteres.
Isso pode ser expresso no Visual Basic das quatro maneiras a seguir (os dois últimos formulários são exclusivos do Visual Basic; outras linguagens não têm equivalentes):
rs.Fields.Item(2).Value = "value"
rs.Fields.Item("au_fname").Value = "value"
rs(2) = "value"
rs!au_fname = "value"
O equivalente no Visual C++ às duas primeiras formas acima é:
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
-ou- (a sintaxe alternativa para a propriedade Value também é mostrada)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
Para obter exemplos de iteração por meio de uma coleção, consulte a seção "Coleções ADO" de "Referência do ADO".
COM-Specific tipos de dados
Em geral, qualquer tipo de dados do Visual Basic que você encontrar na Referência da API do ADO tem um equivalente do Visual C++. Eles incluem tipos de dados padrão, como caractere sem sinal para um Byte de Visual Basic , Short para Integer , e Long para Long . Examine os Índices de Sintaxe para ver exatamente o que é necessário para os operandos de um determinado método ou propriedade.
As exceções a essa regra são os tipos de dados específicos de COM: Variant, BSTR e SafeArray.
Variante
Um Variant é um tipo de dados estruturado que contém um membro de valor e um membro do tipo de dados. Um Variant pode conter uma ampla gama de outros tipos de dados, incluindo outro Variant, BSTR, Boolean, ponteiro IDispatch ou IUnknown, moeda, data e assim por diante. O COM também fornece métodos que facilitam a conversão de um tipo de dados em outro.
A classe _variant_t encapsula e gerencia o tipo de dados Variant.
Quando a Referência da API do ADO diz que um método ou operando de uma propriedade utiliza um valor, geralmente significa que o valor é passado em um _variant_t.
Essa regra é explicitamente verdadeira quando a seção Parâmetros nos tópicos da Referência da API do ADO diz que um operando é um Variant. Uma exceção é quando a documentação diz explicitamente que o operando usa um tipo de dados padrão, como Long ou Byte, ou uma enumeração. Outra exceção é quando o operando usa um String.
BSTR
Um BSTR (Basic STRing) é um tipo de dados estruturado que contém uma cadeia de caracteres e o comprimento da cadeia de caracteres. O COM fornece métodos para alocar, manipular e liberar um BSTR .
A classe _bstr_t encapsula e gerencia o tipo de dados BSTR.
Quando a Referência da API do ADO diz que um método ou propriedade usa um valor String, isso significa que o valor está na forma de um _bstr_t.
Conversão das Classes _variant_t e _bstr_t
Geralmente, não é necessário codificar explicitamente um _variant_t ou _bstr_t em um argumento para uma operação. Se a classe _variant_t ou _bstr_t tiver um construtor que corresponda ao tipo de dados do argumento, o compilador gerará o _variant_t ou _bstr_tapropriado.
No entanto, se o argumento for ambíguo, ou seja, o tipo de dados do argumento corresponderá a mais de um construtor, você deverá converter o argumento com o tipo de dados apropriado para invocar o construtor correto.
Por exemplo, a declaração do método Recordset::Open é:
HRESULT Open (
const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options );
O argumento ActiveConnection
faz referência a um _variant_t, que você pode codificar como uma cadeia de conexão ou um ponteiro para um objeto conexão aberto.
O _variant_t correto será construído implicitamente se você passar uma cadeia de caracteres como "DSN=pubs;uid=MyUserName;pwd=<password>;
", ou um ponteiro como "(IDispatch *) pConn
".
Nota
Se você estiver se conectando a um provedor de fonte de dados que dê suporte à autenticação do Windows, especifique Trusted_Connection=sim ou Segurança Integrada = SSPI em vez de informações de ID de usuário e senha na cadeia de conexão.
Ou você pode explicitamente codificar um _variant_t que contenha um ponteiro como "_variant_t((IDispatch *) pConn, true)
". A conversão, (IDispatch *)
, resolve a ambiguidade com outro construtor que recebe um ponteiro para uma interface IUnknown.
É um fato crucial, embora raramente mencionado, que o ADO é uma interface IDispatch. Sempre que um ponteiro para um objeto ADO deve ser passado como um Variant, esse ponteiro deve ser convertido como um ponteiro para uma interface IDispatch.
O último caso codifica explicitamente o segundo argumento booliano do construtor com seu valor padrão opcional de true
. Esse argumento faz com que o construtor Variant chame seu método AddRef(), que compensa o ADO ao chamar automaticamente o método _variant_t::Release() quando o método ADO ou a chamada de propriedade é concluída.
SafeArray
Um SafeArray é um tipo de dados estruturado que contém uma matriz de outros tipos de dados. Um SafeArray é chamado seguro porque contém informações sobre os limites de cada dimensão de matriz e limita o acesso a elementos de matriz dentro desses limites.
Quando a Referência da API do ADO diz que um método ou propriedade usa ou retorna uma matriz, significa que o método ou a propriedade usa ou retorna um SafeArray, não uma matriz C/C++ nativa.
Por exemplo, o segundo parâmetro do objeto Connectionmétodo OpenSchema requer uma matriz de valores Variant. Esses valores Variant devem ser passados como elementos de um SafeArray, e esse SafeArray deve ser definido como o valor de outro Variant. É essa outra Variante que é passada como o segundo argumento de OpenSchema.
Como exemplos adicionais, o primeiro argumento do método Find é um Variant cujo valor é um SafeArray unidimensional; cada um dos argumentos opcionais de AddNew é um SafeArray unidimensional; e o valor retornado do método GetRows é um Variant cujo valor é um SafeArray bidimensional.
Parâmetros ausentes e parâmetros padrão
O Visual Basic permite parâmetros ausentes em métodos. Por exemplo, o método Open do objeto Recordset tem cinco parâmetros, mas você pode pular parâmetros intermediários e omitir os parâmetros finais. Um BSTR padrão ou Variant padrão será substituído dependendo do tipo de dados do operando ausente.
Em C/C++, todos os operandos devem ser especificados. Se você quiser especificar um parâmetro ausente cujo tipo de dados é uma cadeia de caracteres, especifique um _bstr_t que contém uma cadeia de caracteres nula. Se desejar especificar um parâmetro ausente cujo tipo de dados é um Variant, especifique um _variant_t com o valor DISP_E_PARAMNOTFOUND e o tipo VT_ERROR. Como alternativa, especifique a constante _variant_t equivalente, vtMissing, que é fornecida pela diretiva #import.
Três métodos são exceções ao uso típico de vtMissing. Estes são os métodos Execute dos objetos Conexão e Command, e o método NextRecordset do objeto Recordset. Veja a seguir suas assinaturas:
_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
Os parâmetros RecordsAffected e Parameterssão ponteiros para um Variant. Parameters é um parâmetro de entrada que especifica o endereço de um Variant que contém um único parâmetro, ou matriz de parâmetros, que modificará o comando que está sendo executado. RecordsAffected é um parâmetro de saída que especifica o endereço de um Variant, em que o número de linhas afetadas pelo método é retornado.
No método Execute do objeto Command, indique que nenhum parâmetro é especificado definindo Parameters para &vtMissing
(o que é recomendado) ou para o ponteiro nulo, ou seja, NULL ou zero (0). Se Parâmetros for definido como o ponteiro nulo, o método substituirá internamente o equivalente de vtMissinge, em seguida, concluirá a operação.
Em todos os métodos, indique que o número de registros afetados não deve ser retornado definindo RecordsAffected para o ponteiro nulo. Nesse caso, o ponteiro nulo não é tanto um parâmetro ausente como uma indicação de que o método deve descartar o número de registros afetados.
Portanto, para esses três métodos, é válido codificar algo como:
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
Tratamento de erros
Em COM, a maioria das operações retorna um código de retorno HRESULT que indica se uma função foi concluída com êxito. A diretiva #import gera código de encapsulamento em torno de cada método ou propriedade "bruto" e verifica o HRESULT retornado. Se o HRESULT indicar falha, o código de wrapper gerará um erro COM chamando _com_issue_errorex() com o código de retorno HRESULT como um argumento. Objetos de erro COM podem ser capturados em uma tente-capturar bloco. (Para fins de eficiência, capture uma referência a um objeto _com_error.)
Lembre-se de que estes são erros do ADO: eles resultam da falha na operação do ADO. Os erros retornados pelo provedor subjacente aparecem como objetos Error no objeto ConnectionErrors collection.
A diretiva #import cria apenas rotinas de tratamento de erros para métodos e propriedades declaradas no .dlldo ADO. No entanto, você pode aproveitar esse mesmo mecanismo de tratamento de erros escrevendo sua própria macro de verificação de erros ou função embutida. Consulte o tópico Extensões do Visual C++ou o código nas seções seguintes para ver exemplos.
Equivalentes em Visual C++ para Convenções do Visual Basic
Veja a seguir um resumo de várias convenções na documentação do ADO, codificadas no Visual Basic, bem como seus equivalentes no Visual C++.
Declarando um objeto ADO
No Visual Basic, uma variável de objeto ADO (neste caso para um objeto Recordset) é declarada da seguinte maneira:
Dim rst As ADODB.Recordset
A cláusula "ADODB.Recordset
" é o ProgID do objeto Recordset , conforme definido no registro. Uma nova instância de um objeto Record é declarada da seguinte maneira:
Dim rst As New ADODB.Recordset
-ou-
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
No Visual C++, a diretiva #import gera declarações de tipo ponteiro inteligente para todos os objetos do ADO. Por exemplo, uma variável que aponta para um objeto _Recordset é do tipo _RecordsetPtre é declarada da seguinte maneira:
_RecordsetPtr rs;
Uma variável que aponta para uma nova instância de um objeto _Recordset é declarada da seguinte maneira:
_RecordsetPtr rs("ADODB.Recordset");
-ou-
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
-ou-
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
Depois que o método CreateInstance for chamado, a variável poderá ser usada da seguinte maneira:
rs->Open(...);
Observe que, em um caso, o operador ".
" é usado como se a variável fosse uma instância de uma classe (rs.CreateInstance
) e, em outro caso, o operador "->
" é usado como se a variável fosse um ponteiro para uma interface (rs->Open
).
Uma variável pode ser usada de duas maneiras porque o operador "->
" é sobrecarregado para permitir que uma instância de uma classe se comporte como um ponteiro para uma interface. Um membro de classe privada da variável de instância contém um ponteiro para a interface _Recordset; o operador "->
" retorna esse ponteiro; e o ponteiro retornado acessa os membros do objeto _Recordset.
Codificando um parâmetro ausente – cadeia de caracteres
Quando você precisa codificar um operando string ausente no Visual Basic, você simplesmente omite o operando. Você deve especificar o operando no Visual C++. Codificar um _bstr_t que tenha uma cadeia de caracteres vazia como um valor.
_bstr_t strMissing(L"");
Codificando um parâmetro ausente – Variante
Quando você precisa codificar um operando Variant ausente no Visual Basic, você simplesmente omite o operando. Você deve especificar todos os operandos no Visual C++. Codifique um parâmetro ausente Variant com um _variant_t definido para o valor especial DISP_E_PARAMNOTFOUND e o tipo VT_ERROR. Como alternativa, especifique vtMissing, que é uma constante predefinida equivalente fornecida pela diretiva #import.
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
-ou use -
...vtMissing...;
Declarando uma variante
No Visual Basic, um Variant é declarado com a instrução Dim da seguinte maneira:
Dim VariableName As Variant
No Visual C++, declare uma variável como tipo _variant_t. Algumas declarações esquemáticas de _variant_t são mostradas abaixo.
Nota
Essas declarações apenas dão uma ideia aproximada do que você codificaria em seu próprio programa. Para obter mais informações, consulte os exemplos abaixo e a documentação do 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);
Usando matrizes de variantes
No Visual Basic, matrizes de Variants podem ser codificadas com a instrução Dim ou você pode usar a função Array, conforme demonstrado no código de exemplo a seguir:
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
O exemplo a seguir de Visual C++ demonstra o uso de um SafeArray em combinação com um _variant_t.
Anotações
As anotações a seguir correspondem às seções comentadas no exemplo de código.
Mais uma vez, a função embutida TESTHR() é definida para aproveitar o mecanismo de tratamento de erros existente.
Você só precisa de uma matriz unidimensional, então pode usar SafeArrayCreateVector, em vez da declaração de uso geral SAFEARRAYBOUND e da função SafeArrayCreate. Veja a seguir a aparência desse código usando SafeArrayCreate:
SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);
O esquema identificado pela constante enumerada, adSchemaColumns, está associado a quatro colunas de restrição: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME e COLUMN_NAME. Portanto, uma matriz de valores Variant com quatro elementos é criada. Em seguida, um valor de restrição que corresponde à terceira coluna, TABLE_NAME, é especificado.
O conjunto de registros retornado consiste em várias colunas, um subconjunto das quais são as colunas de restrição. Os valores das colunas de restrição para cada linha retornada devem ser os mesmos que os valores de restrição correspondentes.
Aqueles familiarizados com SafeArrays podem se surpreender que SafeArrayDestroy () não seja chamado antes da saída. Na verdade, chamar SafeArrayDestroy () nesse caso causará uma exceção em tempo de execução. O motivo é que o destruidor do
vtCriteria
chamará VariantClear() quando o _variant_t sair do escopo, o que liberará o SafeArray . Chamar SafeArrayDestroy, sem limpar manualmente o _variant_t, faria com que o destruidor tentasse limpar um ponteiro SafeArray inválido.Se SafeArrayDestroy fosse chamado, o código teria esta aparência:
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
No entanto, é muito mais simples permitir que o _variant_t gerencie a 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();
}
Usando as funções Get/Put/PutRef
No Visual Basic, o nome de uma propriedade não é diferenciado por sua recuperação, atribuição ou atribuição de uma referência.
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
Este exemplo do Visual C++ demonstra a propriedade Get/Put/PutRef.
Anotações
As anotações a seguir correspondem às seções comentadas no exemplo de código.
Este exemplo usa duas formas de um argumento de cadeia de caracteres ausente: uma constante explícita, strMissing e uma cadeia de caracteres que o compilador usará para criar um _bstr_t temporário que existirá para o escopo do método Open.
Não é necessário converter o operando de
rs->PutRefActiveConnection(cn)
para(IDispatch *)
porque o tipo do operando 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();
}
Usando GetItem(x) e Item[x]
Este exemplo do Visual Basic demonstra a sintaxe padrão e 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
Este exemplo do Visual C++ demonstra o Item.
Nota
A observação a seguir corresponde às seções comentadas no exemplo de código: quando a coleção é acessada com Item, o índice 2deve ser convertido em long para que um construtor apropriado seja invocado.
// 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();
}
Conversão de ponteiros de objetos ADO com (IDispatch *)
O exemplo do Visual C++ a seguir demonstra o uso (IDispatch *) para converter ponteiros de objeto do ADO.
Anotações
As anotações a seguir correspondem às seções comentadas no exemplo de código.
Especifique um objeto Connection aberto em uma Variantecodificada explicitamente. Converta-o com (IDispatch *) para que o construtor correto seja invocado. Além disso, defina explicitamente o segundo parâmetro _variant_t como o valor padrão de verdadeiro, portanto, a contagem de referência de objeto estará correta quando a operação Recordset::Open terminar.
A expressão,
(_bstr_t)
, não é um cast, mas um operador _variant_t que extrai uma string _bstr_t do Variant retornado por Value.
A expressão, (char*)
, não é uma conversão, mas sim um operador _bstr_t que extrai um ponteiro para a string encapsulada em um objeto _bstr_t.
Esta seção de código demonstra alguns dos comportamentos úteis dos operadores _variant_t e _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();
}