Compartilhar via


Programação ADO do Visual C++

A Referência da API ADO descreve a funcionalidade da API (interface de programação de aplicativo) ADO usando uma sintaxe semelhante ao Microsoft Visual Basic. Embora o público-alvo pretendido seja todos os usuários, os programadores de 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).

Observação

A Microsoft encerrou o suporte a Visual J++ em 2004.

Para acomodar essa diversidade, os Índices de Sintaxe do ADO para Visual C++ fornecem sintaxe específica de linguagem do Visual C++ com links para descrições comuns de funcionalidade, parâmetros, comportamentos excepcionais e outros 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 do COM são tratados implicitamente para programadores de Visual Basic; já os programadores de Visual C++ precisam lidar com esses detalhes por conta própria.

As seções a seguir resumem os detalhes para programadores de C e C++ que usam ADO e a diretiva #import. Elas se concentram em tipos de dados específicos de COM (Variant, BSTR e SafeArray) e tratamento de erros (_com_error).

Usando a diretiva do compilador #import

A diretiva do compilador de Visual C++#import simplifica o trabalho com os métodos e as propriedades de ADO. A diretiva usa o nome de um arquivo que contém uma biblioteca de tipos, por exemplo, ADO.dll (Msado15.dll) e gera arquivos de cabeçalho que contém declarações typedef, ponteiros inteligentes para interfaces e constantes enumeradas. Cada interface é encapsulada em uma classe.

Para cada operação em 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 quando a operação não é executada com êxito. Se a operação for uma propriedade, geralmente haverá uma diretiva do compilador a fim de criar uma sintaxe alternativa para a operação que tem sintaxe como o Visual Basic.

As operações que recuperam o valor de uma propriedade têm nomes do formulário GetProperty. As operações que definem o valor de uma propriedade têm nomes do formulário PutProperty. 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 destes formulários:

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 desta 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 apropriada com base em qual sintaxe alternativa é declarada e se a propriedade está sendo lida ou gravada.

A diretiva do compilador __declspec(property...) só pode declarar a sintaxe alternativa get, put ou get e put para uma função. As operações somente leitura têm apenas uma declaração get; as operações somente gravação têm apenas uma declaração put; as operações que são leitura e gravação têm declarações get e put.

Somente duas declarações são possíveis com essa diretiva; no entanto, cada propriedade pode ter três funções de propriedade: GetProperty, PutProperty e PutRefProperty. Nesse caso, apenas duas formas da propriedade têm a sintaxe alternativa.

Por exemplo, a propriedade ActiveConnection do objeto Command é declarada com uma sintaxe alternativa para GetActiveConnection e PutRefActiveConnection. A sintaxe PutRef– é uma boa opção porque, na prática, você normalmente quer colocar um objeto Connection aberto (ou seja, um ponteiro do objeto Connection) nessa propriedade. Por outro lado, o objeto Recordset tem operações Get-, Put- e PutRefActiveConnection, mas nenhuma sintaxe alternativa.

Coleções, o método GetItem e a propriedade Item

O ADO define várias coleções, incluindo Campos, Parâmetros, Propriedades e Erros. No Visual C++, o método GetItem(index) retorna um membro da coleção. Index é uma Variant, que é um índice numérico do membro na coleção ou uma cadeia de caracteres que contém o nome do membro.

A diretiva do compilador __declspec(property...) declara a propriedade Item como uma sintaxe alternativa do método GetItem() fundamental de cada coleção. A sintaxe alternativa usa colchetes e é semelhante a uma referência de matriz. Em geral, as duas formas se parecem com as 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 da coleção Campos do objeto Recordset (as coleções são indexadas do zero; assuma que o terceiro campo tem o nome 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 abaixo (as duas últimas formas são exclusivas 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++ das 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, confira a seção "Coleções ADO" de "Referência do ADO".

Tipos de dados específicos de COM

Em geral, todo tipo de dados do Visual Basic encontrado na Referência de API do ADO tem um equivalente de Visual C++. Eles incluem tipos de dados padrão, como char não assinado para um Byte do Visual Basic, curto para Integer e longo para Long. Examine os Índices de Sintaxe para ver exatamente o que é exigido para os operandos de 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

Uma Variant é um tipo de dados estruturado que contém um membro de valor e um membro de tipo de dados. Uma Variant pode conter uma ampla variedade de outros tipos de dados, incluindo outro ponteiro Variant, BSTR, Boolean, 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 de API do ADO diz que um método ou operando de propriedade usa um valor, geralmente significa que o valor é transmitido em uma _variant_t.

Essa regra é expressamente verdadeira quando a seção Parâmetros nos tópicos da Referência de API do ADO diz que um operando é uma 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 uma String.

BSTR

Um BSTR (Basic STRing) é um tipo de dados estruturado que contém uma cadeia de caracteres e o tamanho 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 de 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.

Convertendo classes de _variant_t e _bstr_t

Muitas vezes, não é necessário codificar explicitamente uma _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á a _variant_t ou _bstr_tapropriada.

No entanto, se o argumento for ambíguo, ou seja, o tipo de dados do argumento corresponde a mais de um construtor, você precisará 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 usa uma referência a uma _variant_t, que você pode codificar como uma cadeia de conexão ou um ponteiro para um objeto Connection aberto.

A _variant_t correta será construída implicitamente se você transmitir uma cadeia de caracteres como "DSN=pubs;uid=MyUserName;pwd=MyPassword;", ou um ponteiro como "(IDispatch *) pConn".

Observação

Se você estiver se conectando a um provedor de fonte de dados que dá suporte a autenticação do Windows, especifique Trusted_Connection=yes ou Segurança Integrada = SSPI em vez das informações de ID de usuário e de senha na cadeia de conexão.

Ou você pode codificar explicitamente uma _variant_t contendo um ponteiro como "_variant_t((IDispatch *) pConn, true)". A conversão, (IDispatch *), resolve a ambiguidade com outro construtor que usa 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 precisar ser transmitido como Variant, esse ponteiro precisará 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(), o que compensa o ADO chamar automaticamente o método _variant_t::Release() quando o método ADO ou a chamada de propriedade são concluídos.

SafeArray

Um SafeArray é um tipo de dados estruturado que contém uma matriz de outros tipos de dados. Um SafeArray é considerado 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 de API do ADO diz que um método ou uma propriedade usa ou retorna uma matriz, isso 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 método OpenSchema do objeto Connection requer uma matriz de valores Variant. Esses valores Variant precisam ser transmitidos como elementos de um SafeArraye essa SafeArray deve ser definida como o valor de outra Variant. É a outra Variant que é transmitida como o segundo argumento do OpenSchema.

Como exemplos adicionais, o primeiro argumento do método Find é uma Variant cujo valor é uma SafeArray unidimensional; cada um dos argumentos opcionais de AddNew é uma SafeArrayunidimensional; e o valor retornado do método GetRows é uma Variant cujo valor é uma SafeArray bidimensional.

Parâmetros padrão e ausentes

O Visual Basic permite parâmetros ausentes nos métodos. Por exemplo, o método Open do objeto Recordset tem cinco parâmetros, mas você pode ignorar parâmetros intermediários e deixar de fora os parâmetros à direita. Uma BSTR ou Variant padrão será substituída dependendo do tipo de dados do operando ausente.

Em C/C++, todos os operandos precisam ser especificados. Se você quiser especificar um parâmetro ausente cujo tipo de dados seja uma cadeia de caracteres, especifique uma _bstr_t que contém uma cadeia de caracteres nula. Se você quiser especificar um parâmetro ausente cujo tipo de dados seja uma Variant, especifique uma um _variant_t com um valor de DISP_E_PARAMNOTFOUND e um tipo de 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. São os métodos Execute dos objetos Connection e Command e o método NextRecordset do objeto Recordset. Estas são 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 Parameters são ponteiros para uma Variant. Parameters é um parâmetro de entrada que especifica o endereço de uma Variant que contém um único parâmetro, ou uma 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 uma Variant, na qual 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 como &vtMissing (o que é recomendado) ou como o ponteiro nulo (ou seja, NULL ou zero (0)). Se Parameters for definido como o ponteiro nulo, o método substituirá internamente o equivalente de vtMissing e concluirá a operação.

Em todos os métodos, indique que o número de registros afetados não deve ser retornado definindo RecordsAffected como o ponteiro nulo. Nesse caso, o ponteiro nulo não é tanto um parâmetro ausente; é mais uma indicação de que o método deve descartar o número de registros afetados.

Assim, 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

No 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 wrapper em torno de cada método ou propriedade "bruto" e verifica o HRESULT retornado. Se o HRESULT indicar falha, o código 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 um bloco try-catch. (Para fins de eficiência, capture uma referência a um objeto _com_error.)

Lembre-se de que são erros do ADO: eles resultam da falha na operação do ADO. Os erros retornados pelo provedor subjacente aparecem como objetos Error na coleção Errors do objeto Connection.

A diretiva #import cria apenas rotinas de tratamento de erros para métodos e propriedades declaradas no .dll do 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. Confira o tópico Extensões do Visual C++ ou o código nas seções a seguir para obter exemplos.

Equivalentes Visual C++ das Convenções do Visual Basic

Veja a seguir um resumo de várias convenções na documentação do ADO, codificadas em 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" é a 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 ADO. Por exemplo, uma variável que aponta para um objeto _Recordset é do tipo _RecordsetPtr e é 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 dos casos, o operador "." é usado como se a variável fosse uma instância de uma classe (rs.CreateInstance) e, em outro, 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 "->" está 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 – String

Quando você precisa codificar um operando String ausente no Visual Basic, simplesmente omite o operando. Você precisa especificar o operando no Visual C++. Codifique um _bstr_t que tenha uma cadeia de caracteres vazia como um valor.

_bstr_t strMissing(L"");  

Codificando um parâmetro ausente – Variant

Quando você precisa codificar um operando Variant ausente no Visual Basic, simplesmente omite o operando. Você precisa especificar todos os operandos no Visual C++. Codifique um parâmetro Variant ausente com uma _variant_t definida como 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 Variant

No Visual Basic, uma Variant é declarada 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 _variant_t esquemáticas são mostradas abaixo.

Observação

Essas declarações apenas dão uma ideia aproximada do que você codificaria em seu próprio programa. Para saber mais, confira 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 Variants

No Visual Basic, as matrizes de Variants podem ser codificadas com a instrução Dim, ou você pode usar a função Matriz, conforme demonstrado no seguinte código de exemplo:

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 do Visual C++ a seguir demonstra o uso de um SafeArray usado com uma _variant_t.

Observações

As anotações a seguir correspondem às seções comentadas no exemplo de código.

  1. Mais uma vez, a função embutida TESTHR() é definida para aproveitar o mecanismo de tratamento de erros existente.

  2. Você só precisa de uma matriz unidimensional para poder usar SafeArrayCreateVector em vez da declaração SAFEARRAYBOUND de uso geral e da função SafeArrayCreate. Veja abaixo como seria esse código usando SafeArrayCreate:

       SAFEARRAYBOUND   sabound[1];  
       sabound[0].lLbound = 0;  
       sabound[0].cElements = 4;  
       pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);  
    
  3. 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 Recordset retornado consiste em várias colunas, um subconjunto dos quais são as colunas de restrição. Os valores das colunas de restrição para cada linha retornada precisam ser os mesmos que os valores de restrição correspondentes.

  4. 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 de vtCriteria chamará VariantClear() quando a _variant_t sair do escopo, o que liberará a SafeArray. Chamar SafeArrayDestroy sem limpar manualmente a _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 a _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 a propriedade Get/Put/PutRef

No Visual Basic, o nome de uma propriedade não é qualificado se ela é recuperada, atribuída ou recebe 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 Get/Put/PutRefProperty.

Observações

As anotações a seguir correspondem às seções comentadas no exemplo de código.

  1. 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 uma _bstr_t temporária que existirá para o escopo do método Open.

  2. Não é necessário converter o operando de rs->PutRefActiveConnection(cn) em (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 as sintaxes 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 Item.

Observação

A observação a seguir corresponde às seções comentadas no exemplo de código: quando a coleção é acessada com Item, o índice 2 precisa 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();  
}  

Convertendo ponteiros de objeto ADO com (IDispatch *)

O exemplo do Visual C++ a seguir demonstra o uso de (IDispatch *) para converter ponteiros de objeto ADO.

Observações

As anotações a seguir correspondem às seções comentadas no exemplo de código.

  1. Especifique um objeto Connection aberto em uma Variant codificado 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 true para que a contagem de referência de objeto esteja correta quando a operação Recordset::Open terminar.

  2. A expressão (_bstr_t) não é uma conversão, mas um operador _variant_t que extrai uma cadeia de caracteres _bstr_t da Variant retornada por Value.

A expressão (char*)é não é uma conversão, mas um operador _bstr_t que extrai um ponteiro para a cadeia de caracteres 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();  
}