MarshalOptions Property Example (VC++)

Microsoft ActiveX Data Objects (ADO)

MarshalOptions Property Example (VC++)

This example uses the MarshalOptions property to specify what rows are sent back to the server—All Rows or only Modified Rows.

#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
    no_namespace rename("EOF", "EndOfFile")

#include <stdio.h>
#include <ole2.h>
#include <conio.h>
#include <malloc.h>
#include "MarshalOptionsX.h"

// Function declarations
inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
void MarshalOptionsX(void);
void PrintProviderError(_ConnectionPtr pConnection);
void PrintComError(_com_error &e);

///////////////////////////////////////////////////////////
//                                                       //
//               Main Function                           //
//                                                       //
///////////////////////////////////////////////////////////

void main()
{
    if(FAILED(::CoInitialize(NULL)))
        return;

    MarshalOptionsX();

    ::CoUninitialize();
}

///////////////////////////////////////////////////////////
//                                                       //
//      Marshal Options Function                         //
//                                                       //
///////////////////////////////////////////////////////////

void   MarshalOptionsX(void)
{

    // Define string variables
    _bstr_t strCnn("Provider=sqloledb;Data Source=srv;"
            "Initial Catalog=Pubs;User Id=sa;Password=;");

    // Define ADO object pointers.
    // Initialize pointers on define.
    // These are in the ADODB::  namespace
    _RecordsetPtr pRstEmployees = NULL;

    // Define Other Variables
    IADORecordBinding   *picRs  = NULL;  //Interface Pointer declared
    CEmployeesRs emprs;               //C++ Class Object
    HRESULT hr = S_OK;

    try 
    {                
        // Open recordset with names from Employees table.
        TESTHR(pRstEmployees.CreateInstance(__uuidof(Recordset)));
        pRstEmployees->CursorType = adOpenKeyset;
        pRstEmployees->LockType = adLockOptimistic;
        pRstEmployees->CursorLocation = adUseClient;
        pRstEmployees->Open("SELECT fname, lname FROM Employees "
            "ORDER BY lname",strCnn, 
            adOpenKeyset, adLockOptimistic,adCmdText);

        // Open an IADORecordBinding interface pointer which 
        // we'll use for Binding Recordset to a class.
        TESTHR(pRstEmployees->QueryInterface(
            __uuidof(IADORecordBinding),(LPVOID*)&picRs));

        // Bind the Recordset to a C++ Class here.
        TESTHR(picRs->BindToRecordset(&emprs));

        // Store Original Data
        LPSTR strOldFirst = (LPSTR) malloc(sizeof(emprs.m_szemp_fname));
        LPSTR strOldLast  = (LPSTR) malloc(sizeof(emprs.m_szemp_lname));
        strcpy(strOldFirst,strtok(emprs.m_szemp_fname," "));
        strcpy(strOldLast,strtok(emprs.m_szemp_lname," ")); 

        //Change Data in Edit Buffer
        strcpy(emprs.m_szemp_fname,"Linda");
        strcpy(emprs.m_szemp_lname,"Kobara");

        // Show contents of buffer and get user input
        printf("Edit in Progress:\n");
        printf("Original Data = %s  %s \n",strOldFirst,strOldLast);
        printf("Data in buffer = %s  %s \n", emprs.lemp_fnameStatus == 
            adFldOK ? emprs.m_szemp_fname : "<NULL>",
            emprs.lemp_lnameStatus == adFldOK ? 
            emprs.m_szemp_lname : "<NULL>");
        printf("Use Update to replace the original data with the "
            "buffered data in the Recordset?\nEnter (y/n) :?");
        char opt1=getch();

        if(toupper(opt1)=='Y')
        {
                printf("\nWould you like to send all the rows in "
                    "the recordset back to the server?\nEnter (y/n):");
                char opt2 = getch();
                if(toupper(opt2) == 'Y')
                {
                    {
                        pRstEmployees->MarshalOptions = adMarshalAll;
                        picRs->Update(&emprs);
                    }
                }
                else 
                {
                    printf("\nWould you like to send only modified "
                        "rows back to the server?\nEnter (y/n):");
                    char opt3=getch();
                    if(toupper(opt3) == 'Y')
                        {
                            pRstEmployees->MarshalOptions = 
                                adMarshalModifiedOnly;
                            picRs->Update(&emprs);
                        }
                }
        }
        // Show the resulting data
        printf("\nData In the Recordset = %s  %s\n",
            emprs.lemp_fnameStatus == adFldOK ? 
            emprs.m_szemp_fname : "<NULL>",
            emprs.lemp_lnameStatus == adFldOK ? 
            emprs.m_szemp_lname : "<NULL>");

        // Restore original data because this is a demonstration
        if((strcmp(strOldFirst,emprs.m_szemp_fname)) && 
           (strcmp(strOldLast,emprs.m_szemp_lname)))
        {
            strcpy(emprs.m_szemp_fname,strOldFirst); 
            strcpy(emprs.m_szemp_lname,strOldLast);
            picRs->Update(&emprs);
        }
        // Deallocate memory
        free(strOldFirst);
        free(strOldLast);

        // Release IADORecordset Interface
        if (picRs)
            picRs->Release();

        // Clean up objects before exit.
        pRstEmployees->Close();
    }

    catch(_com_error &e)
    {
       // Notify the user of errors if any.
       // Pass a connection pointer accessed from the Recordset.
        _variant_t vtConnect = pRstEmployees->GetActiveConnection();

        // GetActiveConnection returns connect string if connection
        // is not open, else returns Connection object.
        switch(vtConnect.vt)
        {
            case VT_BSTR:
                PrintComError(e);
                break;
            case VT_DISPATCH:
                PrintProviderError(vtConnect);
                break;
            default:
                printf("Errors occured.");
                break;
        }
    }
}

///////////////////////////////////////////////////////////
//                                                       //
//      PrintProviderError Function                      //
//                                                       //
///////////////////////////////////////////////////////////

void PrintProviderError(_ConnectionPtr pConnection)
{
    // Print Provider Errors from Connection object.
    // pErr is a record object in the Connection's Error collection.
    ErrorPtr     pErr   = NULL;

    if( (pConnection->Errors->Count) > 0)
    {
        long nCount = pConnection->Errors->Count;
        // Collection ranges from 0 to nCount -1.
        for(long i = 0; i < nCount; i++)
        {
            pErr = pConnection->Errors->GetItem(i);
            printf("\t Error number: %x\t%s", pErr->Number,
                (LPCSTR) pErr->Description);
        }
    }
}

///////////////////////////////////////////////////////////
//                                                       //
//      PrintComError Function                           //
//                                                       //
///////////////////////////////////////////////////////////

void PrintComError(_com_error &e)
{
    _bstr_t bstrSource(e.Source());
    _bstr_t bstrDescription(e.Description());

     // Print Com errors.
    printf("Error\n");
    printf("\tCode = %08lx\n", e.Error());
    printf("\tCode meaning = %s\n", e.ErrorMessage());
    printf("\tSource = %s\n", (LPCSTR) bstrSource);
    printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
}

MarshalOptionsX.h:

// MarshalOptionsX.h

#include "icrsint.h"

//This Class extracts only fname,lname from employees table  
class CEmployeesRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CEmployeesRs)
    //Column fname is the 1st field in the recordset
    ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_szemp_fname, 
         sizeof(m_szemp_fname), lemp_fnameStatus, TRUE)
   
     //Column lname is the 2nd field in the recordset
    ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_szemp_lname, 
         sizeof(m_szemp_lname), lemp_lnameStatus, TRUE)

END_ADO_BINDING()

public:
   CHAR   m_szemp_fname[21];
   ULONG   lemp_fnameStatus;
   CHAR   m_szemp_lname[31];
   ULONG   lemp_lnameStatus;
};