Creating an OLE DB consumer is pretty straightforwardmost of the support comes through the ATL Object Wizard. You can see an example of a consumer in the x33a folder on the companion CD. Here are the steps for creating a consumer using the ATL Object Wizard.
Figure 33-1. The ATL Object Wizard Properties.
As an example, we took the BIBLIO.MDB database (a Microsoft Access database) that comes in the Visual Studio VB98 directory and made a data consumer out of it. The BIBLIO database includes the titles and the authors of various programming texts. Using the ATL Object Wizard to create the OLE DB Consumer template for the authors in the database yielded these classes:
// Authors.H : Declaration of the CAuthors class #ifndef __AUTHORS_H_ #define __AUTHORS_H_ class CAuthorsAccessor { public: LONG m_AuID; TCHAR m_Author[51]; SHORT m_YearBorn; BEGIN_COLUMN_MAP(CAuthorsAccessor) COLUMN_ENTRY(1, m_AuID) COLUMN_ENTRY(2, m_Author) COLUMN_ENTRY(3, m_YearBorn) END_COLUMN_MAP() DEFINE_COMMAND(CAuthorsAccessor, _T("SELECT * FROM Authors")) }; class CAuthors : public CCommand<CAccessor<CAuthorsAccessor> > { public: HRESULT Open() { HRESULT hr; hr = OpenDataSource(); if (FAILED(hr)) return hr; return OpenRowset(); } HRESULT OpenDataSource() { HRESULT hr; CDataSource db; CDBPropSet dbinit(DBPROPSET_DBINIT); dbinit.AddProperty(DBPROP_AUTH_CACHE_AUTHINFO, true); dbinit.AddProperty(DBPROP_AUTH_ENCRYPT_PASSWORD, false); dbinit.AddProperty(DBPROP_AUTH_MASK_PASSWORD, false); dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR("")); dbinit.AddProperty(DBPROP_AUTH_PERSIST_ENCRYPTED, false); dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false); dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("Admin")); dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("c:\\biblio.mdb")); dbinit.AddProperty(DBPROP_INIT_MODE, (long)16); dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4); dbinit.AddProperty(DBPROP_INIT_PROVIDERSTRING, OLESTR (";COUNTRY=0;CP=1252;LANGID=0x0409")); dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033); hr = db.Open(_T("Microsoft.Jet.OLEDB.3.51"), &dbinit); if (FAILED(hr)) return hr; return m_session.Open(db); } HRESULT OpenRowset() { return CCommand<CAccessor<CAuthorsAccessor> >::Open(m_session, _T("Authors")); } Csession m_session; }; #endif // __AUTHORS_H_
The CAuthorsAccessor class defines the structure of the author record. Notice that the class includes an author ID field, a name field, and a field indicating when the author was born.
The CAuthors class represents the actual data consumer class that connects to the database. Notice that it's derived from CCommand. Remember that command objects represent a command (such as a SQL statement) and generate rowsets. The COLUMN_MAP represents data returned in the rowset. The PARAM_MAP represents parameter data for a command.
The column maps and the parameter maps represent the user's view of the accessor. As with many data structures in ATL and MFC, these maps are built up with macros. Here's how the maps work: when running against a database, the data that comes back is contained in a contiguous block of memory. OLE DB templates work with this block of memory to extract the data. The data members in the entries represent offsets into that block of memory. The entries in the maps filter out the data from the database. That way, you as a developer do not have to worry about doing anything funky like performing pointer arithmetic on the block to get information.