//--------------------------------------------------------------------
// Microsoft OLE DB ISAPI Sample
// Copyight(c) 1996 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module DOclient.CPP | OLE DB DO client, it connects to the provider,
// runs SQL SELECT statement, prints data onto a webpage
//
// @rev 1 | 06-11-96 | Created
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <afxole.h>
#define DBINITCONSTANTS
#include <iostream.h>
#include <assert.h>
#include <oledb.h>
#include <msdasql.h>
#include <oledberr.h>
#include "DOclient.h" //Data Objects Client header file
#define NUMELEM(p1) (sizeof(p1) / sizeof(p1[0]))
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
IMalloc* g_pIMalloc = NULL; //Memory allocator
//-----------------------------------------------------------------------------------
// ConnectDB
//
// @func HRESULT| ConnectDB | Instantiates Kagera, Initialize OLE DB, Create Session
//
// @rdesc HRESULT
// @flag E_FAIL | Failed
// @flag E_NOERROR | Success
//-----------------------------------------------------------------------------------
HRESULT ConnectDB
(
IDBCreateCommand **ppIDBCreateCommand_out,//@param OUT | Pointer to Create Command
LPCSTR pstrDNS, //@param IN | Login Inforamtion
LPCSTR pstrUserName, //@param IN | Login Inforamtion
LPCSTR pstrPassword, //@param IN | Login Inforamtion
CHttpServerContext* pCtxt//@param IN | HTML page context
)
{
ULONGcVar; //Utility Variables
HRESULThr = ResultFromScode(S_OK);
IDBProperties * pIDBProps = NULL; // IDBInitialize Object
IDBInitialize * pIDBInit = NULL; // IDBInitialize Object
IDBCreateSession *pIDBCreateSession= NULL;// IDBCreateSession
IDBCreateCommand *pIDBCreateCommand = NULL;// IDBCreateCommand
DBPROPSETrgPropertySet[1];// Array of property sets
DBPROPrgProperties[3];// Array of property values
// Strings for OLE DB DO (CHAR & WCHAR)
*ppIDBCreateCommand_out=NULL;
// Set up the Property Buffer
rgPropertySet[0].guidPropertySet=DBPROPSET_DBINIT;
rgPropertySet[0].rgProperties=rgProperties;
rgPropertySet[0].cProperties=NUMELEM(rgProperties);
if( FAILED(hr = SetInitializationData(pstrDNS, pstrUserName, pstrPassword,
rgPropertySet, pCtxt)) )
goto error;
// Initialize OLE
hr = CoInitialize( NULL );
if (FAILED(hr))
{
*pCtxt << "<p>Ole Failed</p>";
goto error;
}
// Retrieve the task memory allocator
hr = CoGetMalloc( MEMCTX_TASK, &g_pIMalloc );
if (FAILED(hr))
{
*pCtxt << "<p>CoGetMalloc Failed</p>";
goto error;
}
GUID ProviderClsid = CLSID_MSDASQL;
// Get IDBProperties Pointer
hr = CoCreateInstance( ProviderClsid, NULL,
CLSCTX_INPROC_SERVER, IID_IDBProperties, (LPVOID*)&pIDBProps );
if (FAILED(hr))
{
*pCtxt << "<p>CoCreateInstance Failed</p>";
*pCtxt << "<p>"<<hr<<"</p>";
goto error;
}
// Set DSO init properties.
hr = pIDBProps->SetProperties(NUMELEM(rgPropertySet), rgPropertySet);
if (FAILED(hr))
{
*pCtxt << "<p>Set properties.</p>";
*pCtxt << "<p>"<<hr<<"</p>";
goto error;
}
//Get IDBInitialize pointer.
hr = pIDBProps->QueryInterface (IID_IDBInitialize,(LPVOID*)&pIDBInit);
if (FAILED(hr))
{
*pCtxt << "<p>QI for IDBInit failed.</p>";
*pCtxt << "<p>"<<hr<<"</p>";
goto error;
}
//Initialize DSO.
hr = pIDBInit->Initialize();
if (FAILED(hr))
{
PrintErrorInfo (pIDBInit,IID_IDBInitialize,pCtxt);
*pCtxt<<"<p>Initialize Failed</p>";
*pCtxt<<"<h3>Check your login parameters</h3>";
goto error;
}
// from the DataSource Object get the Session Object
hr = pIDBInit->QueryInterface(IID_IDBCreateSession,
(void**)&pIDBCreateSession );
if (FAILED(hr))
{
PrintErrorInfo (pIDBInit,IID_IUnknown,pCtxt);
*pCtxt<<"<p>QI for Session Object failed </p>";
goto error;
}
// From the Session object, get a Command Object
hr = pIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**) ppIDBCreateCommand_out);
if (FAILED(hr))
{
PrintErrorInfo (pIDBCreateSession,IID_IDBCreateCommand,pCtxt);
*pCtxt<<"<p>Create Session failed !</p>";
goto error;
}
error :
//Release resources that are not essential anymore.
for (cVar=0; cVar<rgPropertySet[0].cProperties; cVar++)
VariantClear(&rgPropertySet[0].rgProperties[cVar].vValue);
if( pIDBCreateSession )
pIDBCreateSession->Release();
if( pIDBProps )
pIDBProps->Release();
if( pIDBInit )
pIDBInit->Release();
return hr;
} //ConnectDB
//-----------------------------------------------------------------------------------
// SetAndExecute
//
// @func HRESULT| SetAndExecute | Sets the query, executes and sets up the ground
// for data retrieval
//
// @rdesc HRESULT
// @flag E_FAIL | Failed
// @flag E_NOERROR | Success
//-----------------------------------------------------------------------------------
HRESULT SetAndExecute
(
WCHAR *wszSQLCommand,
IDBCreateCommand *pIDBCreateCommand,
IRowset**ppIRowset_out,
DBCOLUMNINFO **ppColumnInfo_out,
WCHAR **ppStringBuffer_out,
ULONG *pcCol,
DBBINDING **pprgBind,
ULONG *pcBind,
HACCESSOR *phAccessor,
ULONG *pcbMaxRowSize,
CHttpServerContext*pCtxt
)
{
HRESULThr = S_OK;
//Column Info Variables
ULONGcCol;
DBCOLUMNINFO *pColumnInfo;
WCHAR*pStringBuffer; //It is needed for printing column names
ULONG cBind;
HACCESSOR hAccessor= NULL;
IAccessor*pIAccessor= NULL;
IColumnsInfo*pIColumnsInfo= NULL;
ICommandText * pICommandText = NULL; //
IRowset * pIRowset = NULL; //
ULONG cbMaxRowSize;
hr = pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText);
if (FAILED(hr))
{
PrintErrorInfo (pIDBCreateCommand,IID_ICommand,pCtxt); //?????
*pCtxt << "<h3>ERROR : Create Command Text Failed</h3>";
goto error;
}
else
{
hr = pICommandText->SetCommandText (DBGUID_DBSQL,wszSQLCommand);
if (FAILED (hr))
{
PrintErrorInfo (pIDBCreateCommand,IID_ICommandText,pCtxt);
*pCtxt <<"<h3> ERROR : Could not set command </h3>";
goto error;
}
}
//Execute Query
hr = pICommandText->Execute (
NULL,
IID_IRowset,
NULL,
NULL,
(IUnknown**)&pIRowset);
if (FAILED(hr))
{
PrintErrorInfo (pICommandText,IID_ICommandText,pCtxt);
*pCtxt<<"<h3>ERROR : Execution failed, Check your SQL statement.</h3>";
goto error;
}
//Get column Info
hr = pIRowset->QueryInterface(IID_IColumnsInfo,(void **) &pIColumnsInfo);
if (FAILED(hr))
{
PrintErrorInfo (pIRowset,IID_IRowset,pCtxt);
goto error;
}
hr = pIColumnsInfo->GetColumnInfo(&cCol,&pColumnInfo,&pStringBuffer);
if (FAILED(hr))
{
PrintErrorInfo (pIColumnsInfo,IID_IRowset,pCtxt);
goto error;
}
//Allocate array of Bindings
(*pprgBind) = new DBBINDING [cCol];
if (*pprgBind==NULL)
{
*pCtxt << "<p>Could not allocate required number of columns.\n<p>";
*pCtxt << "<p>Out of memory.\n<p>";
goto error;
}
if (cCol==0)
{
*pCtxt << "<p>No Data (no columns found). \n<p>";
goto error;
}
hr = SetupBindings(cCol,pColumnInfo,*pprgBind,&cBind,&cbMaxRowSize);
if (FAILED(hr))
{
*pCtxt<<"<h3>ERROR : Could not setup bindings</h3>";
goto error;
}
// Get an accessor for our bindings from the rowset, via IAccessor
hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor );
if (FAILED(hr))
{
PrintErrorInfo (pIRowset,IID_IRowset,pCtxt);
goto error;
}
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
cBind,
*pprgBind,
0,
&hAccessor,
NULL);
if (FAILED(hr))
{
PrintErrorInfo (pIAccessor,IID_IAccessor,pCtxt);
goto error;
}
//Assign out parameters
error :
if( SUCCEEDED(hr) )
{
*ppIRowset_out = pIRowset;
pIRowset = NULL;
*ppColumnInfo_out = pColumnInfo;
pColumnInfo = NULL;
*ppStringBuffer_out = pStringBuffer;
pStringBuffer = NULL;
*pcCol = cCol;
*pcBind = cBind;
*phAccessor = hAccessor;
*pcbMaxRowSize = cbMaxRowSize;
}
else
{
*ppIRowset_out = NULL;
*ppColumnInfo_out = NULL;
*ppStringBuffer_out = NULL;
*pcCol = 0;
*pcBind = 0;
*phAccessor = NULL;
*pcbMaxRowSize = 0;
}
if( pStringBuffer )
g_pIMalloc->Free(pStringBuffer);
if( pIRowset )
pIRowset->Release();
if( pIColumnsInfo )
pIColumnsInfo->Release();
if( pIAccessor )
pIAccessor->Release();
if( pICommandText )
pICommandText->Release();
if( pIDBCreateCommand )
pIDBCreateCommand->Release();
return hr;
} //Set And Execute
//-----------------------------------------------------------------------------------
// GetAndWrite
//
// @func HRESULT| GetAndWrite | Gets data from the rowset.
//
// @rdesc HRESULT
// @flag E_FAIL | Failed
// @flag E_NOERROR | Success
//-----------------------------------------------------------------------------------
HRESULT GetAndWrite
(
IRowset*pIRowset, //@param IN | Pointer to set of rows
ULONG cMaxRowSize,//@param IN | MaxRowSize
HACCESSOR hAccessor,//@param IN | Accessor Handle
DBBINDING*rgBind, //@param IN | Array of bindings
ULONGcBind, //@param IN | Number of bindings
DBCOLUMNINFO*pColumnInfo,//@param IN | Points to an array of DBCOLUMNIFO structures
ULONGcCol,//@param IN | Number of columns
CHttpServerContext* pCtxt//@param IN | Output place
)
{
ULONG cRowsObtained; // Number of rows obtained
ULONGiRow; // Row Count
BYTE*pRowData = NULL; // Memory for Data
HROW rghRows[NUMROWS_CHUNK]; // Row Handles
HROW*pRows = &rghRows[0]; // Pointer to the Row Handles
HRESULT hr=S_OK; // HRESULT
ULONG ulCount; //Counter
CHAR szBuffer[MAXBUFLEN+1];
// Asserts
assert(pIRowset != NULL);
assert(rgBind != NULL);
assert(pColumnInfo != NULL);
// Create a buffer for row data, big enough to hold the biggest row
pRowData = (BYTE *) malloc( cMaxRowSize );
if (!pRowData)
goto error;
//Initialize table output
*pCtxt << "<CENTER>\n";
*pCtxt << "<table>\n";
*pCtxt << "<TABLE BORDER>\n";
*pCtxt << "<caption> <h3> The data you requested: <h3> </caption>\n";
//Print Column Names
*pCtxt << "<TR>";
for (ulCount=0;ulCount<cCol;ulCount++)
{
WideCharToMultiByte(CP_ACP, 0, pColumnInfo[ulCount].pwszName, -1, szBuffer, MAXBUFLEN+1, NULL, NULL);
*pCtxt << "<TH><B>"<<szBuffer<<"</B></TH>";
}
*pCtxt << "</TR>";
// Process all the rows, NUMROWS_CHUNK rows at a time
while (1)
{
hr = pIRowset->GetNextRows(
0,// cbChapter
0,// cRowsToSkip
NUMROWS_CHUNK,// cRowsDesired
&cRowsObtained,// cRowsObtained
&pRows );// filled in w/ row handles
if (FAILED(hr))
{
PrintErrorInfo (pIRowset,IID_IRowset,pCtxt);
goto error;
}
// All done, no more rows left to get
if ( cRowsObtained == 0 )
break;
// Loop over rows obtained, getting data for each
for ( iRow=0; iRow < cRowsObtained; iRow++ )
{
hr = pIRowset->GetData(
rghRows[iRow],
hAccessor,
pRowData );
if (FAILED(hr))
{
PrintErrorInfo (pIRowset,IID_IRowset,pCtxt);
goto error;
}
// Print to web page
*pCtxt <<"<tr>\n";
DumpRow( rgBind, cBind,pRowData,pCtxt);
*pCtxt <<"</tr>\n";
} //for
// Release row handles
hr = pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL );
if (FAILED(hr))
{
PrintErrorInfo (pIRowset,IID_IRowset,pCtxt);
goto error;
}
}// end while
*pCtxt << "</table>"; //End of table (no more data)
error:
if( pRowData )
free( pRowData );
return hr;
} //GetAndWrite
//-----------------------------------------------------------------------------------
// FreeEnvironment
//
// @func void| FreeEnvironment | Deallocates resources
//
// @rdesc NONE
//-----------------------------------------------------------------------------------
void FreeEnvironment
(
IRowset*pIRowset, //@param IN | Pointer to set of rows
HACCESSOR hAccessor,//@param IN | Accessor Handle
DBCOLUMNINFO*pColumnInfo, //@param IN | DBCOLUMNINFO array pointer
WCHAR * pStringBuffer //@param IN | String Buffer contining the info about columns
)
{
HRESULT hr;
IAccessor*pIAccessor = NULL;// Pointer to an Accessor
// Tell the rowset object it can release the accessor, via IAccessor
if (pIRowset)
hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor );
else
goto error;
if (FAILED(hr))
goto error;
hr = pIAccessor->ReleaseAccessor( hAccessor,NULL );
if (FAILED(hr))
goto error;
error :
if( pIAccessor )
pIAccessor->Release();
if( pIRowset )
pIRowset->Release();
if (pStringBuffer!=NULL)
{
g_pIMalloc->Free(pStringBuffer);
pStringBuffer = NULL;
}
if (pColumnInfo!=NULL)
{
g_pIMalloc->Free(pColumnInfo);
pColumnInfo = NULL;
}
if (g_pIMalloc)
g_pIMalloc->Release();
SetErrorInfo(0, NULL);
CoUninitialize();
} //Free Environment
//-----------------------------------------------------------------------------------
//Functions that are not called directly by MainFunction but are used by
//functions described above.
//-----------------------------------------------------------------------------------
HRESULT SetInitializationData
(
LPCSTR pstrDNS,//@param IN | DNS Name
LPCSTR pstrUserName,//@param IN | User Name
LPCSTR pstrPassword,//@param IN | Passwd
DBPROPSET rgPropertySet[],//@param OUT | Array of propery sets (only one)
CHttpServerContext* pCtxt//@param IN | Web page context
)
{
HRESULT hr = ResultFromScode(S_OK);
CHARszDBName[MAXBUFLEN+1];// DSN
CHARszUserName[MAXBUFLEN+1]; // User Name
CHARszPassword[MAXBUFLEN+1]; // Password
WCHARwszDBName[MAXBUFLEN+1];// DSN String (WCHAR)
WCHARwszUserName[MAXBUFLEN+1];// User Name (WCHAR)
WCHARwszPassword[MAXBUFLEN+1];// Password (WCHAR)
strcpy (szDBName,pstrDNS);
strcpy (szUserName,pstrUserName);
strcpy (szPassword,pstrPassword);
//Reset the out parameter(s)
//*****************************************************************
// Identify Property Set
// Initialize property values
for(ULONG ul=0; ul<rgPropertySet[0].cProperties; ul++)
{
VariantInit(&rgPropertySet[0].rgProperties[ul].vValue);
// Set Common structure values
rgPropertySet[0].rgProperties[ul].dwOptions=DBPROPOPTIONS_REQUIRED;
rgPropertySet[0].rgProperties[ul].colid=DB_NULLID;
rgPropertySet[0].rgProperties[ul].vValue.vt=VT_BSTR;
}
// Fill in Data Source
rgPropertySet[0].rgProperties[0].dwPropertyID=DBPROP_INIT_DATASOURCE;
if (0==MultiByteToWideChar(CP_ACP, 0, szDBName, -1, wszDBName, MAXBUFLEN+1))
{
*pCtxt << "MultiByteToWideChar szDBName, wszDBName FAILED";
hr = E_FAIL;
goto error;
}
rgPropertySet[0].rgProperties[0].vValue.bstrVal=SysAllocString(wszDBName);
if (rgPropertySet[0].rgProperties[0].vValue.bstrVal==NULL)
{
*pCtxt << "Error during string allocation #0 (ConnectDB)\n";
hr = E_OUTOFMEMORY;
goto error;
}
// Fill in User Name
rgPropertySet[0].rgProperties[1].dwPropertyID=DBPROP_AUTH_USERID;
if (0==MultiByteToWideChar(CP_ACP, 0, szUserName, -1, wszUserName, MAXBUFLEN+1))
{
*pCtxt << "MultiByteToWideChar szDBName, wszDBName FAILED";
hr = E_FAIL;
goto error;
}
rgPropertySet[0].rgProperties[1].vValue.bstrVal=SysAllocString(wszUserName);
if (rgPropertySet[0].rgProperties[1].vValue.bstrVal==NULL)
{
*pCtxt << "Error during string allocation #1 (ConnectDB)\n";
hr = E_OUTOFMEMORY;
goto error;
}
// Fill in Password
rgPropertySet[0].rgProperties[2].dwPropertyID=DBPROP_AUTH_PASSWORD;
if (0==MultiByteToWideChar(CP_ACP, 0, szPassword, -1, wszPassword, MAXBUFLEN+1))
{
*pCtxt << "MultiByteToWideChar szDBName, wszDBName FAILED";
hr = E_FAIL;
goto error;
}
rgPropertySet[0].rgProperties[2].vValue.bstrVal=SysAllocString(wszPassword);
if (rgPropertySet[0].rgProperties[2].vValue.bstrVal==NULL)
{
*pCtxt << "Error during string allocation #2(ConnectDB)\n";
hr = E_OUTOFMEMORY;
goto error;
}
error :
return hr;
} //SetInitializationData
//-----------------------------------------------------------------------------------
// PrintErrorInfo
//
// @func void| PrintErrorInfo | Uses error collection data to issue an error.
//
// @rdesc HRESULT
//-----------------------------------------------------------------------------------
void PrintErrorInfo
(
IUnknown * pBadObject, //@param IN | Pointer to the object where error happened
REFIID IID_BadIntereface, //@param IN | Interface that caused the error
CHttpServerContext* pCtxt//@param IN | Output place
)
{
HRESULT hr = S_OK;
IErrorInfo * pErrorInfo= NULL;
IErrorInfo * pErrorInfoRec= NULL;
IErrorRecords * pErrorRecords= NULL;
ISupportErrorInfo * pSupportErrorInfo= NULL;
ULONG i,ulNumErrorRecs;
ERRORINFO ErrorInfo;
BSTRbstrDescriptionOfError = NULL;
BSTRbstrSourceOfError = NULL;
CHAR szBuffer [MAXBUFLEN+1]; //Error Info Buffer
DWORD MYLOCALEID;
MYLOCALEID = GetSystemDefaultLCID();
hr = pBadObject->QueryInterface (IID_ISupportErrorInfo,
(LPVOID FAR*)&pSupportErrorInfo);
if (SUCCEEDED(hr))
{
hr = pSupportErrorInfo->InterfaceSupportsErrorInfo(IID_BadIntereface);
if( hr == S_OK )
{
//Get Error Object. Return if no object Exists
GetErrorInfo (0,&pErrorInfo);
if( !pErrorInfo )
goto error;
//Get the IErrorRecord interface and get the count of error recs.
pErrorInfo->QueryInterface (IID_IErrorRecords,(LPVOID FAR*)&pErrorRecords);
pErrorRecords->GetRecordCount (&ulNumErrorRecs);
//Go through and print messages
for (i=0;i<ulNumErrorRecs;i++)
{
pErrorRecords->GetBasicErrorInfo(i,&ErrorInfo);
pErrorRecords->GetErrorInfo (i,MYLOCALEID,&pErrorInfoRec);
hr = pErrorInfoRec->GetDescription (&bstrDescriptionOfError);
if (FAILED(hr))
{
*pCtxt << "pErrorInfoRec->GetDescription FAILED!!! \n";
goto error;
}
hr = pErrorInfoRec->GetSource (&bstrSourceOfError);
if (FAILED(hr))
{
*pCtxt << "pErrorInfoRec->GetSource FAILED!!! \n";
goto error;
}
if (0==WideCharToMultiByte(CP_ACP, 0, bstrDescriptionOfError, -1, szBuffer, MAXBUFLEN+1, NULL, NULL))
{
*pCtxt << "WideChar -> Multi Conversion #1 failed. ERROR in PrintErrorInfo. \n";
goto error;
}
*pCtxt << "<p> Error Description : </p>";
*pCtxt <<"<p>" << szBuffer<< "</p>\n";
if (0==WideCharToMultiByte(CP_ACP, 0, bstrSourceOfError, -1, szBuffer, MAXBUFLEN+1, NULL, NULL))
{
*pCtxt << "WideChar -> Multi Conversion #2 failed. ERROR in PrintErrorInfo. \n";
goto error;
}
*pCtxt << "<p> Error Source : </p>";
*pCtxt <<"<p>" << szBuffer<< "</p>\n";
if( bstrDescriptionOfError )
{
SysFreeString (bstrDescriptionOfError);
bstrDescriptionOfError = NULL;
}
if( bstrSourceOfError )
{
SysFreeString (bstrSourceOfError);
bstrSourceOfError = NULL;
}
pErrorInfoRec->Release();
pErrorInfoRec = NULL;
}
pErrorInfo->Release();
pErrorInfo = NULL;
pErrorRecords->Release();
pErrorRecords = NULL;
} //S_OK
} //if (SUCCEEDED)
error :
if( bstrDescriptionOfError )
SysFreeString (bstrDescriptionOfError);
if( bstrSourceOfError )
SysFreeString (bstrSourceOfError);
if( pErrorInfo )
pErrorInfo->Release();
if( pErrorRecords )
pErrorRecords->Release();
if( pErrorInfoRec )
pErrorInfoRec->Release();
if( pSupportErrorInfo )
pSupportErrorInfo->Release();
} //PrintErrorInfo
//-----------------------------------------------------------------------------------
// SetupBindings
//
// @func HRESULT| SetupBindings | Recycle
//
// @rdesc HRESULT
// @flag E_FAIL | Failed
// @flag E_NOERROR | Success
//-----------------------------------------------------------------------------------
HRESULT SetupBindings
(
ULONG cCol,
DBCOLUMNINFO*pColumnInfo,
DBBINDING*rgBind_out,
ULONG*pcBind_out,
ULONG*pcMaxRowSize_out
)
{
ULONG dwOffset;// Length of a Row
ULONG iCol;// Column Count
ULONG iBind;// Binding Index
// Asserts
assert(pColumnInfo!= NULL);
assert(rgBind_out != NULL);
assert(pcBind_out != NULL);
assert(pcMaxRowSize_out != NULL);
// Create bindings.
// Bind everything as a string just to keep things simple.
dwOffset = 0;
iBind=0;
for (iCol=0; iCol < cCol; iCol++)
{
// Binding Structure
rgBind_out[iBind].dwPart = DBPART_VALUE | DBPART_LENGTH |
DBPART_STATUS;
rgBind_out[iBind].eParamIO = DBPARAMIO_OUTPUT;
rgBind_out[iBind].iOrdinal = pColumnInfo[iCol].iOrdinal;
rgBind_out[iBind].wType = DBTYPE_STR;
rgBind_out[iBind].pTypeInfo = NULL;
rgBind_out[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
rgBind_out[iBind].obValue = dwOffset + offsetof(COLUMNDATA,bData);
rgBind_out[iBind].obLength = dwOffset + offsetof(COLUMNDATA,dwLength);
rgBind_out[iBind].obStatus = dwOffset + offsetof(COLUMNDATA,wStatus);
rgBind_out[iBind].cbMaxLen = pColumnInfo[iCol].wType == DBTYPE_STR ?
pColumnInfo[iCol].ulColumnSize + 1 : DEFAULT_CBMAXLENGTH;
// LONG DATA hack
if(rgBind_out[iBind].cbMaxLen > MAX_ROW_SIZE)
rgBind_out[iBind].cbMaxLen = MAX_ROW_SIZE;
dwOffset += rgBind_out[iBind].cbMaxLen + offsetof( COLUMNDATA, bData );
dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
iBind++;
}
// Return Values
*pcBind_out = iBind;
*pcMaxRowSize_out = dwOffset;
return S_OK;
}
//-----------------------------------------------------------------------------------
// DumpRow
//
// @func void | DumpRow | Puts data onto the webpage
//
//-----------------------------------------------------------------------------------
void DumpRow
(
DBBINDING* rgBind, //@param IN | Column bindings
ULONGcBind, //@param IN | Count of bindings
BYTE* pData, //@param IN | Data Pointer
CHttpServerContext* pCtxt //@param IN | Web Server context
)
{
ULONG iBind;// Binding Count
COLUMNDATA*pColumn;// Data Structure
CHARszDispBuffer[MAXBUFLEN+1];//Display Buffer
// Print each column we're bound to.
szDispBuffer[0] = '\0';
for (iBind=0; iBind < cBind; iBind++)
{
pColumn = (COLUMNDATA *) (pData + rgBind[iBind].obLength);
// Check Status for NULL / OK / CANTCONVERT.
switch (pColumn->wStatus)
{
case DBSTATUS_S_ISNULL:
strcpy(szDispBuffer, (LPSTR)"<b>NULL</b>\n");
break;
case DBSTATUS_S_OK:
pColumn->bData[MAXBUFLEN] = '\0'; //Long data problem solved??!
if (NULL==lstrcpy(szDispBuffer, (LPSTR)pColumn->bData))
*pCtxt << "lstrcpy ERROR. ";
break;
case DBSTATUS_E_CANTCONVERTVALUE:
strcpy(szDispBuffer,(LPSTR)"<b>can't convert</b>\n");
break;
default:
strcpy(szDispBuffer,(LPSTR)"<b>unknown status</b>\n");
break;
}
*pCtxt<<"<td>"<<szDispBuffer<<"</td>\n";
}
}//DumpRow