The following is a complete source code listing for the example presented in "Basic OLE DB." The example selects the CompanyName, City, Phone and FAX columns from the Customers table of the Access Northwind sample database. The database is shipped with the OLE DB SDK and is installed as the ODBC data source OLE_DB_NWind_Jet.
To build the file using Microsoft Visual C++ ® 4.0 or later:
/********************************************************************
* OLE DB
********************************************************************/
#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS // Initialize OLE constants...
#define INITGUID // ...once in each app
#include <windows.h>
#include <stdio.h>
#include <oledb.h> // OLE DB include files
#include <oledberr.h>
#include <msdaguid.h> // ODBC provider include files
#include <msdasql.h>
// Macros--number of row identifiers to retrieve
#define NUMROWS_CHUNK 35
// Prototypes
HRESULT myInitDSO(IDBInitialize** ppIDBI);
HRESULT mySetInitProps(IDBInitialize* pIDBInitialize);
HRESULT myCommand(IDBInitialize* pIDBI, IRowset** ppIRowset);
void myGetData(IRowset* pIRowset);
void DumpError(LPSTR lpStr);
HRESULT myGetColumnsInfo(IRowset* pIRowset, ULONG* pnCols,
DBCOLUMNINFO** ppColumnsInfo, OLECHAR** ppColumnStrings);
void myCreateDBBindings(ULONG nCols, DBCOLUMNINFO* pColumnsInfo,
DBBINDING** ppDBBindings, char** ppRowValues);
// Global task memory allocator
IMalloc* g_pIMalloc = NULL;
/********************************************************************
* General OLE DB application main()
********************************************************************/
int main()
{
IDBInitialize* pIDBInitialize = NULL;
IRowset* pIRowset = NULL;
// Init OLE and set up the DLLs
CoInitialize(NULL);
// Get the task memory allocator.
if (FAILED(CoGetMalloc(MEMCTX_TASK, &g_pIMalloc)))
goto EXIT;
// Connect to the data source.
if (FAILED(myInitDSO(&pIDBInitialize)))
goto EXIT;
// Get a session, set and execute a command.
if (FAILED(myCommand(pIDBInitialize, &pIRowset)))
goto EXIT;
// Retrieve data from rowset.
myGetData(pIRowset);
EXIT:
// Clean up and disconnect.
if (pIRowset != NULL)
pIRowset->Release();
if (pIDBInitialize != NULL)
{
if (FAILED(pIDBInitialize->Uninitialize()))
{
// Uninitialize is not required, but it will fail if an
// interface has not been released; we can use it for
// debugging.
DumpError("Someone forgot to release something!");
}
pIDBInitialize->Release();
}
if (g_pIMalloc != NULL)
g_pIMalloc->Release();
CoUninitialize();
return (0);
}
/********************************************************************
* Initialize the data source.
********************************************************************/
HRESULT myInitDSO
(
IDBInitialize** ppIDBInitialize // [out]
)
{
// Create an instance of the MSDASQL (ODBC) provider.
CoCreateInstance(CLSID_MSDASQL, NULL, CLSCTX_INPROC_SERVER,
IID_IDBInitialize, (void**)ppIDBInitialize);
if (*ppIDBInitialize == NULL)
{
return (E_FAIL);
}
if (FAILED(mySetInitProps(*ppIDBInitialize)))
{
return (E_FAIL);
}
if (FAILED((*ppIDBInitialize)->Initialize()))
{
DumpError("IDBInitialze->Initialize failed.");
return (E_FAIL);
}
return (NOERROR);
}
/********************************************************************
* Set initialization properties on a data source.
********************************************************************/
HRESULT mySetInitProps
(
IDBInitialize* pIDBInitialize // [in]
)
{
const ULONG nProps = 4;
IDBProperties* pIDBProperties;
DBPROP InitProperties[nProps];
DBPROPSET rgInitPropSet;
HRESULT hr;
// Initialize common property options.
for (ULONG i = 0; i < nProps; i++ )
{
VariantInit(&InitProperties[i].vValue);
InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[i].colid = DB_NULLID;
}
// Level of prompting that will be done to complete the
// connection process
InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;
InitProperties[0].vValue.vt = VT_I2;
InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;
// Data source name--see the sample source included with the OLE
// DB SDK.
InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;
InitProperties[1].vValue.vt = VT_BSTR;
InitProperties[1].vValue.bstrVal =
SysAllocString(OLESTR("OLE_DB_NWind_Jet"));
// User ID
InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
InitProperties[2].vValue.vt = VT_BSTR;
InitProperties[2].vValue.bstrVal = SysAllocString(OLESTR(""));
// Password
InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
InitProperties[3].vValue.vt = VT_BSTR;
InitProperties[3].vValue.bstrVal = SysAllocString(OLESTR(""));
rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;
rgInitPropSet.cProperties = nProps;
rgInitPropSet.rgProperties = InitProperties;
// Set initialization properties.
pIDBInitialize->QueryInterface(IID_IDBProperties, (void**)
&pIDBProperties);
hr = pIDBProperties->SetProperties(1, &rgInitPropSet);
SysFreeString(InitProperties[1].vValue.bstrVal);
SysFreeString(InitProperties[2].vValue.bstrVal);
SysFreeString(InitProperties[3].vValue.bstrVal);
pIDBProperties->Release();
if (FAILED(hr))
{
DumpError("Set properties failed.");
}
return (hr);
}
/********************************************************************
* Execute a command, retrieve a rowset interface pointer.
********************************************************************/
HRESULT myCommand
(
IDBInitialize* pIDBInitialize, // [in]
IRowset** ppIRowset // [out]
)
{
IDBCreateSession* pIDBCreateSession;
IDBCreateCommand* pIDBCreateCommand;
IRowset* pIRowset;
ICommandText* pICommandText;
LPCTSTR wSQLString = OLESTR("SELECT CompanyName,
City, Phone, Fax")
OLESTR(" FROM Customers")
OLESTR(" ORDER BY CompanyName,
City");
LONG cRowsAffected;
HRESULT hr;
// Get the DB session object.
if (FAILED(pIDBInitialize->QueryInterface(IID_IDBCreateSession,
(void**) &pIDBCreateSession)))
{
DumpError("Session initialization failed.");
return (E_FAIL);
}
// Create the session, getting an interface for command creation.
hr = pIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand,
(IUnknown**) &pIDBCreateCommand);
pIDBCreateSession->Release();
if (FAILED(hr))
{
DumpError("Create session failed.");
return (hr);
}
// Create the command object.
hr = pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText,
(IUnknown**) &pICommandText);
if (FAILED(hr))
{
DumpError("Create command failed.");
return (hr);
}
pIDBCreateCommand->Release();
// The command requires the actual text as well as an indicator
// of its language and dialect.
pICommandText->SetCommandText(DBGUID_DBSQL, wSQLString);
// Execute the command.
hr = pICommandText->Execute(NULL, IID_IRowset, NULL,
&cRowsAffected, (IUnknown**) &pIRowset);
if (FAILED(hr))
{
DumpError("Command execution failed.");
}
pICommandText->Release();
*ppIRowset = pIRowset;
return (hr);
}
/********************************************************************
* Get the characteristics of the rowset (the ColumnsInfo interface).
********************************************************************/
HRESULT myGetColumnsInfo
(
IRowset* pIRowset, // [in]
ULONG* pnCols, // [out]
DBCOLUMNINFO** ppColumnsInfo, // [out]
OLECHAR** ppColumnStrings // [out]
)
{
IColumnsInfo* pIColumnsInfo;
HRESULT hr;
if (FAILED(pIRowset->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo)))
{
DumpError("Query rowset interface for IColumnsInfo failed");
return (E_FAIL);
}
hr = pIColumnsInfo->GetColumnInfo(pnCols, ppColumnsInfo, ppColumnStrings);
if (FAILED(hr))
{
DumpError("GetColumnInfo failed.");
*pnCols = 0;
}
pIColumnsInfo->Release();
return (hr);
}
/********************************************************************
* Create binding structures from column information. Binding
* structures will be used to create an accessor that allows row value
* retrieval.
********************************************************************/
void myCreateDBBindings
(
ULONG nCols, // [in]
DBCOLUMNINFO* pColumnsInfo, // [in]
DBBINDING** ppDBBindings, // [out]
char** ppRowValues // [out]
)
{
ULONG nCol;
ULONG cbRow = 0;
DBBINDING* pDBBindings;
char* pRowValues;
pDBBindings = new DBBINDING[nCols];
for (nCol = 0; nCol < nCols; nCol++)
{
pDBBindings[nCol].iOrdinal = nCol+1;
pDBBindings[nCol].obValue = cbRow;
pDBBindings[nCol].obLength = 0;
pDBBindings[nCol].obStatus = 0;
pDBBindings[nCol].pTypeInfo = NULL;
pDBBindings[nCol].pObject = NULL;
pDBBindings[nCol].pBindExt = NULL;
pDBBindings[nCol].dwPart = DBPART_VALUE;
pDBBindings[nCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pDBBindings[nCol].eParamIO = DBPARAMIO_NOTPARAM;
pDBBindings[nCol].cbMaxLen = pColumnsInfo[nCol].ulColumnSize;
pDBBindings[nCol].dwFlags = 0;
pDBBindings[nCol].wType = pColumnsInfo[nCol].wType;
pDBBindings[nCol].bPrecision = pColumnsInfo[nCol].bPrecision;
pDBBindings[nCol].bScale = pColumnsInfo[nCol].bScale;
cbRow += pDBBindings[nCol].cbMaxLen;
}
pRowValues = new char[cbRow];
*ppDBBindings = pDBBindings;
*ppRowValues = pRowValues;
return;
}
/********************************************************************
* Retrieve data from a rowset.
********************************************************************/
void myGetData
(
IRowset* pIRowset // [in]
)
{
ULONG nCols;
DBCOLUMNINFO* pColumnsInfo = NULL;
OLECHAR* pColumnStrings = NULL;
ULONG nCol;
ULONG cRowsObtained; // Number of rows obtained
ULONG iRow; // Row count
HROW rghRows[NUMROWS_CHUNK];// Row handles
HROW* pRows = &rghRows[0]; // Pointer to the row
// handles
IAccessor* pIAccessor; // Pointer to the accessor
HACCESSOR hAccessor; // Accessor handle
DBBINDSTATUS* pDBBindStatus = NULL;
DBBINDING* pDBBindings = NULL;
char* pRowValues;
// Get the description of the rowset for use in binding structure
// creation.
if (FAILED(myGetColumnsInfo(pIRowset, &nCols, &pColumnsInfo,
&pColumnStrings)))
{
return;
}
// Create the binding structures.
myCreateDBBindings(nCols, pColumnsInfo, &pDBBindings,
&pRowValues);
pDBBindStatus = new DBBINDSTATUS[nCols];
// Create the accessor.
pIRowset->QueryInterface(IID_IAccessor, (void**) &pIAccessor);
pIAccessor->CreateAccessor(
DBACCESSOR_ROWDATA, // Accessor will be used to retrieve row
// data.
nCols, // Number of columns being bound
pDBBindings, // Structure containing bind info
0, // Not used for row accessors
&hAccessor, // Returned accessor handle
pDBBindStatus // Information about binding validity
);
// Process all the rows, NUMROWS_CHUNK rows at a time
while (TRUE)
{
pIRowset->GetNextRows(
0, // Reserved
0, // cRowsToSkip
NUMROWS_CHUNK, // cRowsDesired
&cRowsObtained, // cRowsObtained
&pRows ); // Filled in w/ row handles.
// All done; there is no more rows left to get.
if (cRowsObtained == 0)
break;
// Loop over rows obtained, getting data for each.
for (iRow=0; iRow < cRowsObtained; iRow++)
{
pIRowset->GetData(rghRows[iRow], hAccessor, pRowValues);
for (nCol = 0; nCol < nCols; nCol++)
{
wprintf(OLESTR("%s%s:"), pColumnsInfo[nCol].pwszName,
wcslen(pColumnsInfo[nCol].pwszName) > 10 ?
OLESTR("\t") :
OLESTR("\t\t"));
printf("\t%s\n",
&pRowValues[pDBBindings[nCol].obValue]);
}
printf("\n");
}
// Release row handles.
pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL,
NULL);
} // End while
// Release the accessor.
pIAccessor->ReleaseAccessor(hAccessor, NULL);
pIAccessor->Release();
delete [] pDBBindings;
delete [] pDBBindStatus;
g_pIMalloc->Free( pColumnsInfo );
g_pIMalloc->Free( pColumnStrings );
return;
}
/********************************************************************
* Dump an error to the console.
********************************************************************/
void DumpError(LPSTR lpStr)
{
printf(lpStr);
printf("\n");
}