Figure 2  
Basic OLE DB COM Interfaces

Interface
Description
IDBInitialize
Used to initialize and uninitialize data source objects and enumerators. An enumerator is an object used to enumerate the data sources available as well as other enumerators. A consumer should rely on enumerators instead of snooping in the registry when it comes to looking for data sources.
IDBProperties
Used to set and get the properties on the data source object and to get information about all the properties of the provider.
IDBCreateSession
Used to create a new session.
IPersist
Supplies the CLSID of a COM object that can be stored persistently in the system.
IGetDataSource
Used to provide a Session object with the pointer to its DataSource object.
IOpenRowset
Used by the session to generate a rowset, a collection of all the rows in the data store. (If commands were supported, a rowset would be the collection of all the rows that satisfy the query.)
ISessionProperties
Used to get information about the properties a session supports and their settings.
IAccessor
Manages accessors, the data structures the consumer will use to buffer each row coming from the data store.
IConvertType
Used to know about the possibility of converting a type into another one within rowsets.
IColumnsInfo
Exposes information about the columns of a rowset.
IRowset
Used to fetch rows and fill in the accessors.
IRowsetIdentity
Used to allow consumers to compare two rows for identity.
IRowsetInfo
Provides information about a rowset.
IRowsetChange
Used to update/insert/delete the single fields of a rowset. This interface is strictly required only if you want to support updateability.


Figure 5  
Current OLE DB Providers

OLE DB Providers
Description
MSDASQL
OLE DB provider used to access data through ODBC. It’s the default provider for ADO 2.x.
Microsoft.Jet.OLEDB.3.51, or Microsoft.Jet.OLEDB.4.0
Lets consumers treat Microsoft Access archives based either on Jet 3.51 or Jet 4.0.
MS Remote
The OLE DB Remoting Provider enables consumers to get data from remote OLE DB data providers. A remote provider may run in a different process as well as on a different machine. It can make use of either HTTP or DCOM to communicate.
MSDataShape
The Data Shaping Service for OLE DB allows applications to create hierarchical relation-ships between keys, fields, and rowsets. The provider supports the Shape language.
SQLOLEDB
It’s the OLE DB provider that retrieves data from SQL Server 7.0.
SQL65Prv
Retrieves data from SQL Server 6.5. Know-ledge Base article Q181890 illustrates some problems you can run into along the way.
MSDAORA
The OLE DB Provider for Oracle makes available whatever Oracle can expose through the Oracle Call Interface API.
MSIDXS
The OLE DB Provider for Microsoft Index Server provides read-only access to nondatabase, file system, and Web data indexed by Index Server 2.0.
SNA Server
The SNA Server OLE DB provider is an OLE DB provider for IBM’s Distributed Data Management (DDM) architecture. It provides access to many different mainframe file types including AS/400, VSAM, and DB2.
ADSDSOObject
It’s the OLE DB provider through which you can access Windows NT, Novell or LDAP directory services via Active Directory Service Interface (ADSI).
OLEDB for OLAP
OLE DB for OLAP lets you access OLAP data through the standard OLE DB interface. OLAP data are multidimensional data subject to complex relations on which to perform sophisticated data analysis.
MSPersist
The Microsoft OLE DB Persistence provider lets you save a recordset object into a file and later restore that Recordset object from the file. Schema information, data, and pending changes are also stored.


Figure 6  
Creating an Email Recordset


'--------------------------------------------------------
' Creates the recordset
'--------------------------------------------------------
Private Function CreateRecordset(ByVal oMsgs As Outlook.Items) As  \
ADODB.Recordset
    Dim rs As ADODB.Recordset
    Dim msg As Outlook.MailItem
    Dim i As Integer

    ' Creates a recordset schema with 3 fields:
    ' "Sender, Subject, Received"
    Set rs = New ADODB.Recordset
    rs.CursorLocation = adUseClient
    rs.CursorType = adOpenStatic
    rs.LockType = adLockOptimistic
    rs.Fields.Append "Sender", adBSTR
    rs.Fields.Append "Subject", adBSTR
    rs.Fields.Append "Received", adBSTR
    rs.Open
    
    ' Scan the message collection
    i = 1
    Set msg = oMsgs.GetFirst
    
    For Each msg In oMsgs
        rs.AddNew
        rs.Fields("Sender") = msg.SenderName
        rs.Fields("Subject") = msg.Subject
        rs.Fields("Received") = msg.ReceivedTime
    Next
    
    Set CreateRecordset = rs
End Function



Figure 7  
A Word Document Recordset



Option Explicit
Private g_rsWordDoc As ADODB.Recordset
Private g_objWordApp As Word.Application


Private Sub Class_GetDataMember(DataMember As String, Data As Object)
    Dim doc As Word.Document
    Dim par As Word.Paragraph
    
    ' Prepare the recordset using DataMember as the file name
    Set doc = g_objWordApp.Documents.Open(DataMember, True)

    For Each par In doc.Paragraphs
        Dim text As String
        text = par.Range.text
        g_rsWordDoc.AddNew
        g_rsWordDoc.Fields("Paragraph").Value = Left(text, Len(text) - 1)
    Next
    
    doc.Close
    g_rsWordDoc.MoveFirst
    Set Data = g_rsWordDoc
End Sub

Private Sub Class_Initialize()
    ' Initializes the data member
    Set g_rsWordDoc = New ADODB.Recordset
    g_rsWordDoc.Fields.Append "Paragraph", adBSTR
    g_rsWordDoc.Open
    
    ' Add the a new data member
    DataMembers.Add "Paragraphs"
    
    ' Initializes Word
    Set g_objWordApp = New Word.Application
End Sub

Private Sub Class_Terminate()
    g_rsWordDoc.Close
    Set g_rsWordDoc = Nothing
    Set g_objWordApp = Nothing
End Sub


Figure 10  
ATL COM Wizard-created Classes

Class Name
Project File
Description
CXxxSource
XxxDS.h
The OLE DB DataSource object. It defines all the properties supported by the provider. Properties are grouped into categories. Feel free to remove from the class declaration the properties you don’t want to expose.
CXxxSession
XxxSess.h
The OLE DB Session object meant to represent a dialog between


providers and consumers. Any data source can support multiple sessions at the same time. Instances of this class are created by CXxxSource. This object handles session properties, creates commands, and governs the preparation of the rowset to return.
CXxxSessionColSchema
XxxSess.h
A schema rowset class meant to return metadata information about the columns of the rowset.
CXxxSessionPTSchema
XxxSess.h
A schema rowset class meant to return metadata information about the data types the provider supports.
CXxxSessionTRSchema
XxxSess.h
A schema rowset class meant to return metadata information about the tables exposed by the data source.
CXxxCommand
XxxRS.h
The OLE DB Command object thatlets you specify command strings to pass down to the data source. The association between formal and actual parameters is done through accessors.
CXxxRowset
XxxRS.h
The OLE DB Rowset object that renders a set of rows with data. It allows data retrieval, type conversion, and row comparison.Accessors are used to bind the structure of the columns to a consumer's defined data structure.
CXxxWindowsFile
XxxRS.h
This class represents the row of data. It is the structure where the Rowset accessor will store the data just read from the table. Its members bind to the columns exposed by the data source. The suffix is WindowsFile just because the ATL wizard creates a provider that handles Windows files.
Xxx is the name of the project (that is, FileSystem). WindowsFile is a suffix that reflects what the wizard generates but not necessarily what the class will do in your own projects. You might want to rename it.


Figure 12  
COutlookRowset::Execute


class COutlookRowset : public CRowsetImpl< COutlookRowset, COutlookMessageList, 
    COutlookCommand>
{
public:
  HRESULT Execute(DBPARAMS* pParams, LONG* pcRowsAffected)
  {
    COutlookMessageList oml;
    FILTERMESSAGE fm;
    ZeroMemory(&fm, sizeof(FILTERMESSAGE));
        
    // Parse the command text
    if (!ParseCommandText(m_strCommandText, &fm))
        return DB_E_ERRORSINCOMMAND;

    // Read messages using Simple MAPI
    LONG cMessages = 1;
    MyMapi_GotoFirstMessage();

    while(true) {
        BOOL bResult;
        bResult = MyMapi_GetNextMessage(g_hMAPISession, 
            oml.szSenderName, oml.szAddress, oml.szSubject, 
                  oml.szReceivedTime);
        if (!bResult)
            break;

        // Check the message against the filter
        lstrcpy(fm.pszMsgReceived, oml.szReceivedTime);
        lstrcpy(fm.pszMsgSubject, oml.szSubject);
        lstrcpy(fm.pszMsgSender, oml.szSenderName);
        lstrcpy(fm.pszMsgAddress, oml.szAddress);

        if (FilterMessage(&fm))
        {
                  // This line will add the row to the recordset 
            if (!m_rgRowData.Add(oml))
                return E_OUTOFMEMORY;
            cMessages ++;

            // Did we reach the max number of records?
            if (fm.iMaxNumOfRecords >0)
            if (cMessages >fm.iMaxNumOfRecords)
                break;
        }
    }

      // Stores how many records have been involved
    if (pcRowsAffected != NULL)
        *pcRowsAffected = cMessages;

    return S_OK;
  }
};


Figure 13  
Outlook Email Provider Syntax

Keyword
Usage
Description
Select
Select=string;
Filters the messages on the sender’s name. A message is selected if the specified string is part of the sender’s name.
By Address
By Address
If this clause is specified then select works on the email address (not the display name) of the sender. Sometimes, display name and address coincide, but not always. This clause lets you do searching via email and is useful to join with other tables (see later).
Case
Case=no;
If set to no, then the comparisons won’t be case-sensitive.
About
About=string;
Filters the messages on the subject. A message is selected if the specified string is part of the subject line.
Max
Max=number;
Sets the maximum number of messages to retrieve.
From
From=[datestring] [,datestring]
Fixes a time interval for the messages to [,datestring] select. The date has the MAPI format yyyy/mm/dd.


Figure 15  
Messages.H



// Messages.H : Declaration of the CMessages class

#ifndef __MESSAGES_H_
#define __MESSAGES_H_

class CMessagesAccessor
{
public:
    TCHAR m_sender[52];
    TCHAR m_address[52];
    TCHAR m_subject[52];
    TCHAR m_received[32];

BEGIN_COLUMN_MAP(CMessagesAccessor)
    COLUMN_ENTRY(1, m_sender)
    COLUMN_ENTRY(2, m_address)
    COLUMN_ENTRY(3, m_subject)
    COLUMN_ENTRY(4, m_received)
END_COLUMN_MAP()

DEFINE_COMMAND(CMessagesAccessor, _T("Messages"))

    void ClearRecord()
    {
        memset(this, 0, sizeof(*this));
    }
};

class CMessages : public CCommand<CAccessor<CMessagesAccessor> >
{
public:
    HRESULT Open()
    {
    // You could add here an argument being the command text to execute
    // and pass it to OpenRowset().
        HRESULT hr;
        hr = OpenDataSource();
        if (FAILED(hr))
            return hr;

        return OpenRowset();
    }


    HRESULT OpenDataSource()
    {
        HRESULT        hr;
        CDataSource db;
        CDBPropSet    dbinit(DBPROPSET_DBINIT);
        hr = db.Open(_T("MailProvider.Outlook.1"), &dbinit);
        if (FAILED(hr))
            return hr;

        return m_session.Open(db);
    }


    HRESULT OpenRowset()
    {
        // CCommand::Open can accept a 2nd argument being the command text
        return CCommand<CAccessor<CMessagesAccessor> >::Open(m_session);
    }
    CSession    m_session;
};

#endif // __MESSAGES_H_