Figure 2  
Cotype TSession


 cotype TSession {
   [mandatory] interface IGetDataSource;
   [mandatory] interface IOpenRowset;
   [mandatory] interface ISessionProperties;
   [optional]  interface IAlterIndex;
   [optional]  interface IAlterTable;
   [optional]  interface IBindResource;
   [optional]  interface ICreateRow;          
   [optional]  interface IDBCreateCommand;
   [optional]  interface IDBSchemaRowset;
   [optional]  interface IIndexDefinition;
   [optional]  interface ISupportErrorInfo;
   [optional]  interface ITableDefinition;
   [optional]  interface ITransactionJoin;
   [optional]  interface ITransactionLocal;
   [optional]  interface ITransaction;
   [optional]  interface ITransactionObject;
 }

Figure 3   Establishing a Connection


 #include <oledb.h>    // oledb headers
 #include <sqloledb.h> // SQL Server headers
 void GetConnection(IUnknown **ppUnkSession,
                    DBPROPSET *pProperties) {
 // load the provider
   IDBInitialize *pdbInit;
   CoCreateInstance(CLSID_SQLOLEDB, 0, CLSCTX_ALL,
                     __uuidof(pdbInit), (void**)&pdbInit);
 // set the initial properties
   IDBProperties *pdbProps;
   pdbInit->QueryInterface(&pdbProps);
   pdbProps->SetProperties(1, pProperties);
 // tell the provider to connect to data source
   pdbInit->Initialize();
 // create a new session object
   IDBCreateSession *pdbcs = 0;
   pdbcs->CreateSession(0,
                        __uuidof(**ppUnkSession),
                        (IUnknown**)ppUnkSession);
 // release intermediate references
   pdbInit->Release();
   pdbProps->Release();
   pdbcs->Release();
 }

Figure 4   Sending SQL Commands and OLE DB


 void SendSQL(IUnknown *pUnkSession,
              const OLECHAR *pwszSQL) {
 // ask session to create a new commmand
   IDBCreateCommand *pdbcc;
   pUnkSession->QueryInterface(&pdbcc);
   ICommandText *pCmdTxt;
   pdbcc->CreateCommand(0, __uuidof(pCmdText),
                        (IUnknown**)&pCmdText);
 // store SQL statement in command object
   pCmdText->SetCommandText(DBGUID_DEFAULT, 
                            pwszSQL);
 // ship SQL down to database
   pCmdText->Execute(0, GUID_NULL, 0, 0, 0);
 // release all resources
   pCmdText->Release();                  
   pdbcc->Release();
 }

Figure 5   OLE DB Property Sets

Property Set
Set Via
Read Via
DBINIT
IDBProperties::SetProperties
IDBDataSourceAdmin::CreateDataSource
IDBDataSourceAdmin::ModifyDataSource
IDBProperties::GetProperties
DATASOURCE
IDBProperties::SetProperties
IDBProperties::GetProperties
DATASOURCEINFO
N/A
IDBProperties::GetProperties
TABLE
ITableDefinition::CreateTable
IAlterTable::AlterTable
ITableCreation::GetTableDefinition
COLUMN
ITableDefinition::CreateTable
ITableDefinition::AddColumn
IAlterTable::AlterColumn
ITableCreation::GetTableDefinition
INDEX
IIndexDefinition::CreateIndex
IAlterIndex::AlterIndex
IRowsetIndex::GetIndexInfo
SESSION
ISessionProperties::SetProperties
ISessionProperties::GetProperties
ROWSET
IOpenRowset::OpenRowset
ICommandProperties::SetProperties
IColumnsRowset::GetColumnsRowset
ISourcesRowset::GetSourcesRowset
IDBSchemaRowset::GetRowset
IRowsetInfo::GetProperties
ICommandProperties::GetProperties


Figure 6   Using Properties


 // build a vector of three properties
   DBPROP rgp[3] = { 0 };
   rgp[0].dwPropertyID = DBPROP_AUTH_USERID;
   rgp[0].vValue.vt = VT_BSTR;
   rgp[0].vValue.bstrVal = SysAllocString(L"sa"); 
   rgp[1].dwPropertyID = DBPROP_AUTH_PASSWORD;
   rgp[1].vValue.vt = VT_BSTR;
   rgp[1].vValue.bstrVal = SysAllocString(L"");
   rgp[2].dwPropertyID = DBPROP_INIT_CATALOG;
   rgp[2].vValue.vt = VT_BSTR;
   rgp[2].vValue.bstrVal = SysAllocString(L"pubs");
 // scope/bind vector with property set GUID
   DBPROPSET rgdbpropset[1] = { 0 };
   rgdbpropset[0].cProperties = 3;
   rgdbpropset[0].rgProperties = rgp;
   rgdbpropset[0].guidPropertySet=DBPROPSET_DBINIT;
 // pass PROPSET to previous code to init provider
   IUnknown *pUnkSession;
   GetConnection(&pUnkSession, rgdbpropset);
 // clean up
   VariantClear(&rgp[0].vValue);     
   VariantClear(&rgp[1].vValue);   
   VariantClear(&rgp[2].vValue);

Figure 7   MSDASC.IDL


 ////////////////////////////////////////////////
 // MSDASC.IDL (excerpt)
 //
 
 interface IDataInitialize : IUnknown {
 // parse initialization string into propset and load datasource
     HRESULT GetDataSource( 
         [in] IUnknown *pUnkOuter,
         [in] DWORD dwClsCtx,
         [in,unique] LPCOLESTR pwszInitializationString,
         [in] REFIID riid,
         [in,out,iid_is(riid)] IUnknown **ppDataSource);
 
 // reverse engineer initialization string 
     HRESULT GetInitializationString( 
         [in] IUnknown *pDataSource,
         [in] boolean fIncludePassword,
         [out] LPOLESTR *ppwszInitString);
 
 // create  provider using service components
     HRESULT CreateDBInstance( 
         [in] REFCLSID clsidProvider,
         [in] IUnknown *pUnkOuter,
         [in] DWORD dwClsCtx,
         [in,unique] LPOLESTR pwszReserved,
         [in] REFIID riid,
         [out,iid_is(riid)] IUnknown **ppDataSource);
     
 // create  provider using service components
     HRESULT CreateDBInstanceEx( 
         [in] REFCLSID clsidProvider,
         [in] IUnknown *pUnkOuter,
         [in] DWORD dwClsCtx,
         [in,unique] LPOLESTR pwszReserved,
         [in,unique] COSERVERINFO *pServerInfo,
         [in] ULONG cmq,
         [in,out,size_is(cmq)] MULTI_QI *rgmqResults);
     
 // read initialization string from a UDL file
     HRESULT LoadStringFromStorage( 
         [in,unique] LPCOLESTR pwszFileName,
         [out] LPOLESTR *ppwszInitializationString);
     
 // write initialization string to a UDL file
     HRESULT WriteStringToStorage( 
         [in,unique] LPCOLESTR pwszFileName,
         [in,unique] LPCOLESTR pwszInitializationString,
         [in] DWORD dwCreationDisposition);
     
 };
 
 coclass MSDAINITIALIZE {
   interface IDataInitialize;
 }

Figure 8   Using MSDAINITIALIZE


 void GetConnection(IUnknown **ppUnkDataSource) {
 // load MSDAINITIALIZE
   IDataInitialize *pdi;
   CoCreateInstance(CLSID_MSDAINITIALIZE, 0,
          CLSCTX_ALL, __uuidof(pdi), (void**)&pdi);
 // parse the init string and load provider
   IDBInitialize *pdbInit;
   pdi->GetDataSource(0, CLSCTX_ALL, 
    L"PROVIDER=SQLOLEDB;DATABASE=pubs;UID=sa;PWD=",
          __uuidof(pdbInit), (IUnknown**)&pdbInit);
 // initialize the provider based on parsed props
   pdbInit->Initialize();
 // clean up
   pdi->Release();
   (*ppUnkDataSource = pdbInit)->AddRef();
   pdbInit->Release();
 }

Figure 12   OLEDB.IDL


 ////////////////////////////////////////////////
 // OLEDB.IDL (excerpt)
 //
 
 typedef struct tagDBBINDING {
     DBORDINAL iOrdinal;    // column #
     DBBYTEOFFSET obValue;  // offset into buffer
     DBBYTEOFFSET obLength; // offset into buffer for length
     DBBYTEOFFSET obStatus; // error/status code
     ITypeInfo *pTypeInfo;  // desc of COM object
     DBOBJECT *pObject;     // IID of COM object ref
     DBBINDEXT *pBindExt;   // extensions
     DBPART dwPart;         // value and/or length?
     DBMEMOWNER dwMemOwner; // client vs. provider owned
     DBPARAMIO eParamIO;    // in/out for command parameters
     DBLENGTH cbMaxLen;     // sub-buffer size
     DWORD dwFlags;         // HTML?
     DBTYPE wType;          // Data type (extended VARTYPE)
     BYTE bPrecision;       // precision for numerics
     BYTE bScale;           // scale for numerics
 } DBBINDING;
 
 interface IAccessor : IUnknown {
 
   HRESULT AddRefAccessor([in] HACCESSOR hAccessor,
               [in,out,unique] DBREFCOUNT *pcRefCount) ;
 
   HRESULT CreateAccessor( 
         [in] DBACCESSORFLAGS dwAccessorFlags,
         [in] DBCOUNTITEM cBindings,
         [in, size_is(cBindings)] const DBBINDING rgBindings[  ],
         [in] DBLENGTH cbRowSize,
         [out] HACCESSOR *phAccessor,
         [out,size_is(cBindings)] DBBINDSTATUS rgStatus[  ]) ;
     
   HRESULT GetBindings( 
         [in] HACCESSOR hAccessor,
         [out] DBACCESSORFLAGS *pdwAccessorFlags,
         [in,out] DBCOUNTITEM *pcBindings,
         [out, size_is(*pcBindings)] DBBINDING **prgBindings) ;
     
   HRESULT ReleaseAccessor([in] HACCESSOR hAccessor,
                [in,out,unique] DBREFCOUNT *pcRefCount) ;
     
 }
 
 interface IRowset : IUnknown {
 
   HRESULT AddRefRows( 
             [in] DBCOUNTITEM cRows,
             [in,size_is(cRows) ] const HROW rghRows[  ],
             [out,size_is(cRows)] DBREFCOUNT rgRefCounts[  ],
             [out,size_is(cRows)] DBROWSTATUS rgRowStatus[  ]) ;
         
   HRESULT GetData([in] HROW hRow, [in] HACCESSOR hAccessor,
                   [out] void *pData) ;
         
   HRESULT GetNextRows( 
             [in] HCHAPTER hReserved,
             [in] DBROWOFFSET lRowsOffset,
             [in] DBROWCOUNT cRows,
             [out] DBCOUNTITEM *pcRowsObtained,
             [size_is][size_is][out] HROW **prghRows) ;
         
   HRESULT ReleaseRows( 
             [in] DBCOUNTITEM cRows,
             [size_is][in] const HROW rghRows[  ],
             [size_is][in] DBROWOPTIONS rgRowOptions[  ],
             [size_is][out] DBREFCOUNT rgRefCounts[  ],
             [size_is][out] DBROWSTATUS rgRowStatus[  ]) ;
         
   HRESULT RestartPosition([in] HCHAPTER hReserved) ;
 };

Figure 13   PrintAll.cpp


 ///////////////////////////////////////////
 // Printall.cpp - a simple client that prints
 // the result of a select statement
 //
 
 #define OLEDBVER 0x0250 
 #define _WIN32_DCOM
 #include <windows.h>
 #include <stdio.h>
 #include <oledb.h>
 #include <msdasc.h>
 
 #include <atlbase.h>
 CComModule _Module;
 #include <atlcom.h>
 
 // some helper macros
 #define CELEMS(rg) (sizeof(rg)/sizeof(*(rg)))
 #define sizeofmember(T, m) sizeof( (((T*)16)->m) )
 
 // client representation of a row
 struct CUSTOMER
 {
     CUSTOMER() { *id = *lname = *fname = 0; }
     TCHAR id[9];
     TCHAR lname[33];
     TCHAR fname[33];
 };
 
 // description of CUSTOMER representation
 DBBINDING rgBindings[] =
 {
     { 1, offsetof(CUSTOMER, id), 0, 0, 0, 0, 0, DBPART_VALUE, 
         DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, id), 
         0, DBTYPE_STR, 0, 0 },
     { 2, offsetof(CUSTOMER, fname), 0, 0, 0, 0, 0, DBPART_VALUE, 
         DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, fname), 
         0, DBTYPE_STR, 0, 0 },
     { 3, offsetof(CUSTOMER, lname), 0, 0, 0, 0, 0, DBPART_VALUE, 
         DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, lname), 
         0, DBTYPE_STR, 0, 0 },
 };
 
 #define HR(exp) { HRESULT _hr = (exp); if (FAILED(_hr)) return _hr; }
 
 HRESULT PrintAll(const OLECHAR *pwszInitString)
 {
 // load and initialize the provider
     CComPtr<IDataInitialize> pdi;
     HR(CoCreateInstance(__uuidof(MSDAINITIALIZE), 0, CLSCTX_ALL, __uuidof(pdi), 
         (void**)&pdi));
 
     CComPtr<IDBInitialize> dbInit;
     HR(pdi->GetDataSource(0, CLSCTX_ALL, pwszInitString, 
                           __uuidof(dbInit), (IUnknown**)&dbInit));
     HR(dbInit->Initialize());
 
 // create a new command with our select statement
     CComPtr<IDBCreateSession> cs;
     HR(dbInit->QueryInterface(&cs));
 
     CComPtr<IDBCreateCommand> cc;
     HR(cs->CreateSession(0, __uuidof(cc), (IUnknown**)&cc));
     
     CComPtr<ICommandText> cmd;
     HR(cc->CreateCommand(0, __uuidof(cmd), (IUnknown**)&cmd));
     HR(cmd->SetCommandText(DBGUID_DEFAULT, L"select * from customers"));
 
 // squirt the SQL down to the database and get back a rowset object
     CComPtr<IRowset> rs;
     HR(cmd->Execute(0, __uuidof(rs), 0, 0, (IUnknown**)&rs));
 
 // create an accessor for CUSTOMER
     CComPtr<IAccessor> acc;
     HR(rs->QueryInterface(&acc));
 
     DBSTATUS rgStatus[CELEMS(rgBindings)];
     HACCESSOR hAccessor;
     HR(acc->CreateAccessor(DBACCESSOR_ROWDATA, CELEMS(rgBindings), 
                            rgBindings, sizeof(CUSTOMER), 
                            &hAccessor, rgStatus));
 
 // walk through the rowset and print each row
     bool bDone = false;
     HRESULT hr = S_OK;
     while (!bDone)
     {
         const int CHUNKSIZE = 5;
         HROW *prgRows = 0;
         ULONG cRows;
 // fetch CHUNKSIZE rows into provider's buffer
         hr = rs->GetNextRows(0, 0, CHUNKSIZE, &cRows, &prgRows);
         if (hr != S_OK)
             bDone = true;
         if (SUCCEEDED(hr))
         {
             for (ULONG i = 0; SUCCEEDED(hr) && i < cRows; i++)
             {
 // copy row into client buffer (record) and print
                 CUSTOMER record;
                 hr = rs->GetData(prgRows[i], hAccessor, &record);
                 if (FAILED(hr))
                     bDone = true;
                 else
                     printf("%s: %s %s\n", record.id, 
                            record.fname, record.lname);
             }
 // clean up
             rs->ReleaseRows(cRows, prgRows, 0, 0, 0);
             CoTaskMemFree(prgRows);
         }
     }
     acc->ReleaseAccessor(hAccessor, 0);
     return hr;
 }
 
 int main(int argc, char **argv)
 {
     HRESULT hr = CoInitializeEx(0, 0);
     if (SUCCEEDED(hr))
     {
         hr = PrintAll(L""PROVIDER=SQLOLEDB;DATABASE=bob;UID=sa;PWD=");
         CoUninitialize();
     }
     return hr;
 }