Pages

Monday 9 April 2018

Accessing ActiveX Data Objects (ADO) with Visual C++

Visual C++ is a much more difficult language and environment with which to develop applications for ActiveX Data Objects. Because it is so difficult, Microsoft is constantly trying to provide developers with easier ways to access ADO components.

By far the easiest method (and the only method described here) is one that takes advantage of the #import keyword. This approach offers not only the most control to the developer, but it also allows the developer to code in a Visual Basic programming style.

Referencing ActiveX Data Objects:-
The #import keyword is used in Visual C++ applications to import information from a type library. To make ADO.ACcessible to your C++ code, use the following #import directive:

#import <msado15.dll> no_namespace rename("EOF", "EOFile")

This statement assumes that the path to msado15.dll (usually C:\Program Files\Common Files\System\ADO) is already set within the Visual C++ environment; if not, select the Directories tab of the Options dialog box (Tools Options), and add it.

The #import statement does a couple of things. First, at compile time it creates a header file with a .tlh extension, which stands for Type Library Header. This header file is comprised of enumerated types and definitions for the objects contained in the type library for msado15.dll.

Secondly, it creates a file with a .tli (Type Library Implementation) extension that contains the wrappers for each function in the object model defined by the msado15.dll type library.

Finally, the rename attribute in the statement:

rename("EOF", "EOFile")

renames the EOF keyword from the type library and calls it EOFile so that it does not conflict with Visual C++'s definition of the EOF property.

Creating ActiveX Data Objects:-
In order to invoke an ActiveX Data Object, we must first start OLE so that we can use OLE DB. We do this with the following piece of code:

struct StartOLEProcess{
          StartOLEProcess( ) {
                  ::CoInitialize(NULL);
         }
         ~StartOLEProcess( ) {
                 ::CoUninitialize( );
         }
} _start_StartOLEProcess;

Placing this structure definition anywhere in our application forces the application to call the _start_StartOLEProcess constructor once it has started. This constructor simply calls CoInitialize to initialize OLE. Once our application is complete, the destructor of _start_StartOLEProcess will be called. This in turn will call CoUninitialize, which will shut down OLE.

The next thing we must do to create an ActiveX Data Object is to declare a pointer to the object we wish to create, as follows:

// define a variable that will be used as a reference to the
// Connection object and set it to NULL
ADODB::_ConnectionPtr con = NULL;

// define a variable that will be used as a reference to the
// Recordset object and set it to NULL
ADODB::_RecordsetPtr rst = NULL;

We then can create an ActiveX Data Object by calling the CreateInstance function of our ADO pointer. This function returns a result of type HRESULT to inform us whether the creation of the object was successful. This is illustrated in the following code fragment:

' create a new instance of an ADO Connection object
hr = con.CreateInstance(_ _uuidof(ADODB::Connection));

' create a new instance of an ADO Recordset object
hr = rst.CreateInstance(_ _uuidof(ADODB::Recordset));

Finally, just as in Visual Basic, it is always a good idea to release objects once they are no longer needed. In Visual C++, we accomplish this with a couple of lines of code that look like the following:

' remove the objects
con = Null;
rst = Null;

Using ADO with Visual C++: An Example:-
Now let's take a look at a fully functional example of a Visual C++ application that utilizes ActiveX Data Objects. To try the following code, create a new Win32 Console Application from within Visual C++, choosing the Simple option from the wizard, and replace the contents of the main .cpp file with the code shown in Example 3-2.

Remember, just as with the Visual Basic example, make sure that a copy of Biblio.mdb is in the C:\Program Files\Microsoft Visual Studio\VB98 directory, or that you change the directory in the following source code to reflect the proper path of the Access database. In addition, if you are having trouble with this code, make sure that you have the MSADO15.DLL file in the C:\Program Files\Common Files\System\ado directory or that you have the proper directory entered in the source code.

Example 3-2. A Simple Visual C++ Example

#include "stdafx.h"
#include <stdio.h>

#import "C:\Program Files\Common Files\System\ado\MSADO15.dll" _
         rename("EOF", "EOFile")

struct StartOLEProcess{
         StartOLEProcess( ) {
                 ::CoInitialize(NULL);
         }
         ~StartOLEProcess( ) {
                 ::CoUninitialize( );
         }
} _start_StartOLEProcess;

void main(void)
{
               // define our variables which will be used as references to the
              // Connection and Recordset objects

             ADODB::_ConnectionPtr con = NULL;
             ADODB::_RecordsetPtr rec = NULL;

// define variables to read the Author field from the recordset

ADODB::FieldPtr                 pAuthor;
_variant_t                              vAuthor;
char                                       sAuthor[40];

// create two strings for use with the creation of a Connection
// and a Recordset object

bstr_t                                    sConString;
bstr_t                                    sSQLString;

// create a variable to hold the result to function calls

HRESULT                hr                       = S_OK;

// long variable needed for Execute method of Connection object

VARIANT               *vRecordsAffected              = NULL;

// create a new instance of an ADO Connection object

hr = con.CreateInstance(_ _uuidof(ADODB::Connection));

printf("Connection object created.\n");

// open the BiblioDSN data source with the Connection object

sConString = L"Provider=Microsoft.Jet.OLEDB.4.0; "
                      L"Data Source=C:\\Program Files\\"
                                                 L"Microsoft Visual Studio\\"
                                                 L"VB98\\Biblio.mdb";

con->Open(sConString, L"", L"", -1);

printf("Connection opened.\n");

// create a Recordset object from a SQL string

sSQLString = L"SELECT TOP 10 Author FROM Authors;";

rec = con->Execute(sSQLString,
                                vRecordsAffected,
                                1);

printf("SQL statement processed.\n");

// point to the Author field in the recordset

pAuthor = rec->Fields->GetItem("Author");

// retrieve all the data within the Recordset object

printf("Getting data now...\n\n");

while(!rec->EOFile) {

// get the Author field's value and change it
// to a multibyte type
vAuthor.Clear( );

vAuthor = pAuthor->Value;

WideCharToMultiByte(CP_ACP,
                                      0,
                                      vAuthor.bstrVal,
                                      -1,
                                      sAuthor,
                                      sizeof(sAuthor),
                                      NULL,
                                      NULL);
printf("%s\n", sAuthor);

rec->MoveNext( );

}

printf("\nEnd of data.\n");

// close and remove the Recordset object from memory

rec->Close( );
rec = NULL;

printf("Closed an removed the "
          "Recordset object from memory.\n");

// close and remove the Connection object from memory

con->Close( );
con = NULL;

printf("Closed and removed the "
          "Connection object from memory.\n");
}
 
Although much of the previous example will be very foreign to you until you have a thorough understanding of how to develop applications with ActiveX Data Objects, it is particularly important to notice how Visual C++ applications must convert datatypes returned by a field's value. In Example 3-2, a function called WideCharToMultiByte is used to convert a Variant datatype to a normal char string datatype (ASCII) so that it can in turn be passed to the printf function.

No comments:

Post a Comment