ADO Tutorial (Visual C++)

Microsoft ActiveX Data Objects (ADO)

ADO Tutorial (Visual C++)

This is the ADO tutorial, written in Microsoft Visual C++, along with the #import directive. See the ADO Tutorial for a description of the purpose of this tutorial.

The #import directive generates functions from the ADO type library into a header file which provides ADO and Visual C++ with some of the ease-of-use of Microsoft Visual Basic.

This tutorial also features the Visual C++ Extensions for ADO. The Visual C++ Extensions automatically convert and populate local instance variables with the value of fields in a specified Recordset. The Visual C++ Extensions also support versions of the AddNew and Update methods.

The #import directive generates an error handling routine for each ADO property and method. The function, TESTHR(), is provided in this tutorial as a convenient way to invoke the same error handling mechanism for non-ADO functions.

#import "c:\Program Files\Common Files\System\ADO\msado15.dll" \
   no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
#include <icrsint.h>   //Include support for VC++ Extensions

void dump_com_error(_com_error &e)
   {
   printf("Error:\n");
   printf("Code = %08lx\n", e.Error());
   printf("Code meaning = %s\n", e.ErrorMessage());
   printf("Source = %s\n", (LPCSTR) e.Source());
   printf("Description = %s\n", (LPCSTR) e.Description());
   }

inline void TESTHR( HRESULT _hr ) 
   { if FAILED(_hr) _com_issue_error(_hr); }

class CCustomRs : 
   public CADORecordBinding
{
BEGIN_ADO_BINDING(CCustomRs)
   ADO_VARIABLE_LENGTH_ENTRY2(3, adVarChar, m_szau_fname, 
         sizeof(m_szau_fname), lau_fnameStatus, false)
   ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_szau_lname, 
         sizeof(m_szau_lname), lau_lnameStatus, false)
   ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_szphone,    
         sizeof(m_szphone),    lphoneStatus,    true)
END_ADO_BINDING()

public:
   CHAR   m_szau_fname[22];
   ULONG   lau_fnameStatus;
   CHAR   m_szau_lname[42];
   ULONG   lau_lnameStatus;
   CHAR   m_szphone[14];
   ULONG   lphoneStatus;
};

VOID   main()         // Tutorial in VC
   {
   IADORecordBinding   *picRs = NULL;
   
   ::CoInitialize(NULL);

   try 
      {
      _ConnectionPtr pConn("ADODB.Connection");
      _RecordsetPtr pRs("ADODB.Recordset");
      _CommandPtr pCmd("ADODB.Command");
      CCustomRs rs;

// Step 1: Open a connection
      pConn->Open("dsn=Pubs;", "sa", "", adConnectUnspecified);

// Step 2: Create a command
      pCmd->CommandText = "select * from Authors";
      pCmd->ActiveConnection = pConn;

// Step 3: Execute the command
      pRs->CursorLocation = adUseClient;
      pRs->Open((IDispatch *) pCmd, vtMissing,
         adOpenStatic, adLockBatchOptimistic, adCmdUnspecified);

      TESTHR(pRs->QueryInterface(__uuidof(IADORecordBinding), 
               (LPVOID*)&picRs));
      TESTHR(picRs->BindToRecordset(&rs));

// Step 4: Manipulate the data
      pRs->Fields->GetItem("au_lname")->Properties->GetItem("Optimize")->Value = true; 
      pRs->Sort = "au_lname ASC";
      pRs->Filter = "phone LIKE '415 5*'";

      pRs->MoveFirst();
      while (VARIANT_FALSE == pRs->EndOfFile)
         {
         printf("Name: %s\t %s\tPhone: %s\n",  
            (rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : ""), 
            (rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : ""),
            (rs.lphoneStatus == adFldOK ? rs.m_szphone   : ""));

         if (rs.lphoneStatus == adFldOK)
            memcpy(rs.m_szphone, "777", 3);
            
         TESTHR(picRs->Update(&rs));   // Add change to the batch

      // Change the current row of the Recordset. 
      // Recordset data for the new current row will automatically be 
      // extracted and placed in the CCustomRs C++ instance variables.

         pRs->MoveNext();
         }

      pRs->Filter = (long) adFilterNone;

// Step 5: Update the data
      pConn->BeginTrans();
      try 
         {
         pRs->UpdateBatch(adAffectAll);

// Step 6, part A: Conclude the update - Accept changes
         pConn->CommitTrans();
         }

// Step 6, part B: Conclude the update - Reject changes
      catch (_com_error &e)
         {
         dump_com_error(e);
         pRs->Filter = (long) adFilterConflictingRecords;
         pRs->MoveFirst();
         while (VARIANT_FALSE == pRs->EndOfFile)
            {
            printf("Conflict: Name = %s\t %s\n", 
               (rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : ""), 
               (rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : ""));
            pRs->MoveNext();
            }
         pConn->RollbackTrans();
         }

      if (picRs) picRs->Release();
      pRs->Close();
      pConn->Close();
      }

   catch (_com_error &e)
      {
      dump_com_error(e);
      }

   CoUninitialize();
   }

This is the end of the Visual C++ tutorial.