QUERY.CPP
//----------------------------------------------------------------------------- 
// Microsoft OLE DB QURYDEMO Sample 
// Copyright (C) 1994 - 1996 By Microsoft Corporation. 
// 
// @doc 
// 
// @module QURYDEMO.CPP 
// 
//----------------------------------------------------------------------------------- 
/* 
PROGRAM: QURYDEMO 
======== 
 
PURPOSE: 
======== 
demonstrates a simple MDI (Multiple Document Interface)application 
that allows a user to simultaneously connect to multiple 
hetrogeneous databases and perform SQL queries to get results. 
 
FUNCTIONS: 
========== 
InitEnvironment() - Initialize OLE 
DisplayProviders() - Display available Providers 
ConnectDatabase() - Connect to a specific data source 
DisplayConnections() - Display List of made connections 
DisplayICommands() - Display list of ICommands 
NewICommandWindow() - Open a new ICommand and update displays 
ChangeCurrentCursor() - Change current cursor display 
ChangeCurrentICommand() - Change current ICommand display 
DisplayNewCrsrAndICommand() - update cusor & ICommand displays 
FreeConnect() - free a IDBCreateCommand 
FreeICommand() - free a ICommand 
CloseICommandWindow() - close a ICommand window 
ExecuteQuery() - execute a user specified query 
CloseIDBCreateCommand() - check if all connections are closed 
FreeEnvironment() - free OLE 
ExecuteCommand() - Execute the ICommand and return an IRowset  
GetDataFromRowset() - Get the Data from the IRowset 
SetupBindings() - Set the binding structure 
CreateAccessor() - Create Accessor to store the Data 
GetData() - Get the Data out of the rowset 
  
 
COMMENTS: 
========= 
Created by Microsoft Corporation. 
 
The application uses MDI Child Window Titles to store values of 
PROVIDER's and Command Objects. These values are also stored in the 
comboboxes that are displayed on the toolbar. 
 
*/ 
#define DBINITCONSTANTS 
#define INITGUID 
 
#include <stdio.h> 
#include <string.h> 
#include <windows.h> 
#include <stddef.h>// offsetof 
#include <assert.h>// assert 
 
#include "oledb.h" 
#include "oledberr.h" 
#include "msdaguid.h" 
 
#include "qurydemo.h"   
 
// Globals 
extern HWNDhWndFrame; // Main Frame Window handle 
extern HWNDhWndCrsrList;// hdbc(s) combobox on the tool bar 
extern HWNDhWndStmtList;// hstmt(s) combobox on the tool bar 
extern HWNDhWndMDIClient;// MDI Client window handle 
extern HWNDhWndActiveChild;// Current active MDI Child window 
extern HINSTANCEhAppInstance;// Application instance 
 
IMalloc* g_pIMalloc = NULL; 
 
intnChildCount;// Number of child windows currently open 
charszDispBuffer[MAXDISPLAYSIZE+1];// Display Buffer 
unsigned charrgbData[MAX_COL][MAXDATALEN];// Results Data Array 
long dwDataLen[MAX_COL];// Results Data Length Array 
 
//charszErrorDescription [MAXDISPLAYSIZE+1]; 
//charszErrorSource      [MAXDISPLAYSIZE+1]; 
 
//Variables and constants used for provider enumeration 
//#define   MAX_VALUE_NAME          300 
//#define   MAX_PROVIDER_NUM        10 
#define NUMELEM(p1) (sizeof(p1) / sizeof(p1[0])) 
#define COLUMN_ALIGNVAL 8 
#define ROUND_UP( Size, Amount ) (((DWORD)(Size) +  ((Amount) - 1)) & ~((Amount) - 1)) 
 
const ULONGDEF_SOURCES_CBMAXLEN= 64; 
const ULONG MAX_NUM_PROVIDERS= 16; 
 
IParseDisplayName*g_pIParse = NULL; 
ULONGg_cProvNames; 
CHARg_rgszProvName[MAX_NUM_PROVIDERS][DEF_SOURCES_CBMAXLEN]; 
WCHARg_rgwszParseName[MAX_NUM_PROVIDERS][DEF_SOURCES_CBMAXLEN]; 
 
/* 
FUNCTION: InitEnvironment() 
COMMENTS: Allocate an environment handle for OLE function calls. 
*/ 
FAR PASCAL InitEnvironment() 
{ 
HRESULThr; 
 
// Initialize OLE 
hr = CoInitialize( NULL ); 
 
if (FAILED(hr)) 
{ 
DumpErrorHResult( hr, (LPSTR)"CoInitialize FAILED!!" ); 
return FALSE; 
} 
 
    // Retrieve the task memory allocator 
    hr = CoGetMalloc( MEMCTX_TASK, &g_pIMalloc ); 
 
if (FAILED(hr)) 
{ 
DumpErrorHResult( hr, (LPSTR)"CoGetMalloc FAILED!!" ); 
return FALSE; 
} 
 
// reset child window count 
nChildCount = 0; 
 
// Return TRUE 
return TRUE; 
} 
 
/* 
FUNCTION: DisplayProviders(HWND hWnd) 
COMMENTS: Display a list of available Providers. 
*/ 
void FAR PASCAL DisplayProviders(HWND hWnd) 
{ 
    ULONGiProv; 
HRESULThr; 
 
// Initialize count of provider names 
g_cProvNames = 0; 
 
//Go to registry and get me the provider names 
hr = EnumerateProviders();   
if (FAILED (hr)) 
{ 
  MessageBox(hWndFrame,  
             "There was an error retrieve providers from the OLE DB Enumerator",  
             "Enumeration Error",  
 MB_OK | MB_ICONERROR); 
  return; 
} 
 
//All returned Providerss in the provided combo box for display. 
SendMessage(hWnd, CB_RESETCONTENT, 0, 0); 
for (iProv=0; iProv<g_cProvNames; iProv++) 
   SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)(LPSTR)g_rgszProvName[iProv]); 
 
SendMessage(hWnd, CB_SETCURSEL, 0, 0); 
} 
 
/* 
FUNCTION: EnumerateProviders 
COMMENTS: Display a list of available providers 
*/ 
HRESULT EnumerateProviders 
( 
) 
{ 
HRESULThr; 
ULONGul, cRows = 0; 
ISourcesRowset*pISrcRowset = NULL; 
IRowset*pIRowset = NULL; 
IAccessor*pIAccessor = NULL; 
BYTE*pData = NULL; 
DWORDdwOffset; 
HACCESSORhAccessor = NULL; 
DBBINDINGrgBind[3]; 
HROWrghRows[MAX_NUM_PROVIDERS]; 
HROW*pRows = &rghRows[0]; 
 
enum enumSOURCES_COLUMNS { 
eid_SOURCES_NAME = 1, 
eid_SOURCES_PARSENAME, 
eid_SOURCES_DESCRIPTION, 
eid_SOURCES_TYPE, 
eid_SOURCES_ISPARENT, 
eid_SOURCES_CLSID, 
}; 
 
static struct tagSOURCES 
{ 
ULONGiOrdinal; 
DBTYPEwType; 
ULONGcbMaxLen; 
} s_rgSources[] = { 
eid_SOURCES_NAME,DBTYPE_STR,DEF_SOURCES_CBMAXLEN, 
eid_SOURCES_PARSENAME,DBTYPE_WSTR,DEF_SOURCES_CBMAXLEN * sizeof(WCHAR), 
eid_SOURCES_TYPE,DBTYPE_UI4,sizeof(ULONG), 
}; 
 
memset(rghRows, 0, sizeof(rghRows)); 
 
// Initialize the OLE DB Enumerator 
if( FAILED(hr = CoCreateInstance(CLSID_OLEDB_ENUMERATOR, NULL,  
CLSCTX_INPROC_SERVER, IID_ISourcesRowset, (LPVOID*)&pISrcRowset)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"CoCreateInstance FAILED!!" ); 
goto EXIT; 
} 
 
// Retrieve the Rowset 
if( FAILED(hr = pISrcRowset->GetSourcesRowset(NULL, IID_IRowset, 0, NULL,  
(IUnknown**)&pIRowset)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"GetSourcesRowset FAILED!!" ); 
goto EXIT; 
} 
 
memset(rgBind, 0, sizeof(rgBind)); 
 
if( FAILED(hr = pIRowset->QueryInterface(IID_IAccessor, (LPVOID*)&pIAccessor)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"QI of IID_IAccessor from pIRowset failed" ); 
goto EXIT; 
} 
 
dwOffset = 0; 
for(ul=0; ul< NUMELEM(s_rgSources); ul++) 
{ 
rgBind[ul].dwPart= DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; 
rgBind[ul].eParamIO= DBPARAMIO_NOTPARAM; 
rgBind[ul].iOrdinal= s_rgSources[ul].iOrdinal; 
rgBind[ul].wType= s_rgSources[ul].wType; 
rgBind[ul].obValue= dwOffset + offsetof(COLUMNDATA,bData); 
rgBind[ul].obLength= dwOffset + offsetof(COLUMNDATA,dwLength); 
rgBind[ul].obStatus= dwOffset + offsetof(COLUMNDATA,wStatus); 
rgBind[ul].cbMaxLen= s_rgSources[ul].cbMaxLen; 
rgBind[ul].dwMemOwner= DBMEMOWNER_CLIENTOWNED; 
dwOffset += rgBind[ul].cbMaxLen + offsetof( COLUMNDATA, bData ); 
dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL ); 
} 
 
if( FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, NUMELEM(s_rgSources),  
rgBind, dwOffset, &hAccessor, NULL)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"Accessor Creation failed!!" ); 
goto EXIT; 
} 
 
// Retrieve the providers 
if( SUCCEEDED(hr = pIRowset->GetNextRows(NULL, 0, MAX_NUM_PROVIDERS, &cRows, &pRows)) ) 
{ 
// Allocate block of memory to retrieve the row data into. 
pData = new BYTE[dwOffset]; 
if( pData == NULL ) 
{ 
DumpErrorHResult( E_OUTOFMEMORY, (LPSTR)"Unable to allocate memory for buffer"); 
goto EXIT; 
} 
 
// Loop over the rows of data, collecting providers and discarding  
// enumerators.. 
for(ul=0; (ul<cRows) && (ul<MAX_NUM_PROVIDERS); ul++) 
{ 
memset(pData, 0, dwOffset); 
 
if( SUCCEEDED(hr = pIRowset->GetData(rghRows[ul], hAccessor, pData)) ) 
{ 
if( *((ULONG*)(pData + rgBind[2].obValue)) == DBSOURCETYPE_DATASOURCE ) 
{ 
// Store Provider Name 
strcpy(g_rgszProvName[g_cProvNames], (CHAR*)(pData + rgBind[0].obValue)); 
 
// Store Parse Name 
wcscpy(g_rgwszParseName[g_cProvNames], (WCHAR*)(pData + rgBind[1].obValue)); 
 
g_cProvNames++; 
} 
} 
} 
} 
else 
{ 
DumpErrorHResult( hr, (LPSTR)"GetNextRows failed to retrieve Providers" ); 
goto EXIT; 
} 
 
// Retrieve the IID_IParseDisplayName interface before returning 
if( FAILED(hr = pISrcRowset->QueryInterface(IID_IParseDisplayName, (LPVOID*)&g_pIParse)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"QI for IParseDisplayName failed"); 
goto EXIT; 
} 
 
EXIT: 
if( pData ) 
delete[] pData; 
 
if( pIAccessor ) 
{ 
if( hAccessor ) 
{ 
if( FAILED(hr = pIAccessor->ReleaseAccessor(hAccessor, NULL)) ) 
DumpErrorHResult( hr, (LPSTR)"Release Accessor failed!!" ); 
} 
pIAccessor->Release(); 
} 
 
if( pIRowset ) 
{ 
if( cRows ) 
{ 
if( FAILED(hr = pIRowset->ReleaseRows(cRows, rghRows, NULL, NULL, NULL)) ) 
DumpErrorHResult( hr, (LPSTR)"Release of Row handles failed"); 
} 
pIRowset->Release(); 
} 
 
if( pISrcRowset ) 
pISrcRowset->Release(); 
return hr; 
} 
 
 
//********************************************************************** 
//  
// ConnectDatabase 
//  
// Purpose: 
//  
//     Initializes the PROVIDER and creates a IDBCreateCommand Object. 
//      
// Parameters: 
// 
// HWND hWnd                - handle to the window 
//  
// Return Value: 
//     TRUE         - Success 
//     FALSE        - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//     IDBInitialize::Release      provider's Command object 
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
BOOL FAR PASCAL ConnectDatabase(HWND hWnd) 
{ 
// Global IDBInitialize Options 
IMoniker*pIMoniker= NULL;// Moniker 
IDBInitialize * pIDBInit= NULL;// IDBInitialize Object 
IDBCreateCommand *pIDBCreateCommand= NULL;// IDBCreateCommand 
IDBCreateSession *pIDBCreateSession= NULL; // IDBCreateSession 
IDBProperties*pIDBProperties= NULL; // IDBProperties 
IOpenRowset *pIOpenRowset= NULL;// IOpenRowset 
IUnknown *pIUnknown= NULL;// IUnknown 
HRESULThr;// HRESULT 
DBPROPSETrgPropertySet[1];// Array of property sets 
DBPROPrgProperties[5];// Array of property values 
BOOLbReturn = FALSE;// Return Value 
shortiPrompt;// DBPROP_INIT_PROMPT value. 
ULONGiProp, iPDex; 
ULONGchEaten; 
 
// Strings for MSDASQL (CHAR & WCHAR) 
CHARszProvName[MAXBUFLEN+1];// Provider String 
CHARszDBName[MAXBUFLEN+1];// DSN String 
WCHARwszBuff[MAXBUFLEN+1];// WCHAR buffer 
CHARszUserName[MAXBUFLEN+1];// User Name 
CHARszPassword[MAXBUFLEN+1];// Password 
CHARszBuffer[MAXBUFLEN+1];// String Buffer 
LRESULT nResult;// Return Code 
BOOLfCommandWindow=FALSE;// Flag to indicate Command support 
 
// Initialize Property Buffers 
for(iProp=0; iProp<NUMELEM(rgProperties); iProp++) 
VariantInit(&(rgProperties[iProp].vValue)); 
 
// check if enough windows are already open, refuse connection 
if (nChildCount >= MAXCHILDWNDS) 
{ 
MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND); 
return (FALSE); 
} 
 
// Retrieve Provider values from the connect dialog box 
GetDlgItemText(hWnd, IDCOMBO_PROVIDER, szProvName, MAXBUFLEN); 
GetDlgItemText(hWnd, IDCOMBO_NAME,    szDBName,   MAXBUFLEN); 
GetDlgItemText(hWnd, IDTEXT_USERID,    szUserName, MAXBUFLEN); 
GetDlgItemText(hWnd, IDTEXT_PASSWORD,  szPassword, MAXBUFLEN); 
if ((iPrompt = (short) SendMessage(GetDlgItem(hWnd, IDCOMBO_PROMPT), CB_GETCURSEL, 0, 0)) == CB_ERR) 
iPrompt = -1; 
else 
++iPrompt; 
 
    //Determine the ParseDisplayName 
for(iPDex=0; iPDex<g_cProvNames; iPDex++) 
    { 
if( strcmp((const char *)szProvName, (const char *) g_rgszProvName[iPDex])==0 ) 
break; 
} 
 
if( iPDex >= g_cProvNames ) 
{ 
DumpErrorHResult( E_FAIL, (LPSTR)"Unknown Provider, Please Select Valid Provider" ); 
goto error; 
} 
 
if( FAILED(hr = g_pIParse->ParseDisplayName(NULL, g_rgwszParseName[iPDex], &chEaten, &pIMoniker)) )  
{ 
DumpErrorHResult( hr, (LPSTR)"ParseDisplayName failed"); 
goto error; 
} 
 
if( FAILED(hr = BindMoniker(pIMoniker, 0, IID_IDBInitialize, (LPVOID*)&pIDBInit)) ) 
{ 
DumpErrorHResult( hr, (LPSTR)"BindMoniker failed"); 
goto error; 
} 
 
iProp = 0; 
// If DataSource name specified, then create property node 
if( *szDBName != '\0' ) 
{ 
// Fill in Data Source 
rgProperties[iProp].dwPropertyID=DBPROP_INIT_DATASOURCE; 
rgProperties[iProp].dwOptions=DBPROPOPTIONS_REQUIRED; 
rgProperties[iProp].colid=DB_NULLID; 
MultiByteToWideChar(CP_ACP, 0, szDBName, -1, wszBuff, MAXBUFLEN+1); 
V_VT(&(rgProperties[iProp].vValue))=VT_BSTR; 
V_BSTR(&(rgProperties[iProp].vValue))=SysAllocString(wszBuff); 
iProp++; 
} 
 
// If User Name specified, then create property node 
if( *szUserName != '\0' ) 
{ 
rgProperties[iProp].dwPropertyID=DBPROP_AUTH_USERID; 
rgProperties[iProp].dwOptions=DBPROPOPTIONS_REQUIRED; 
rgProperties[iProp].colid=DB_NULLID; 
MultiByteToWideChar(CP_ACP, 0, szUserName, -1, wszBuff, MAXBUFLEN+1); 
V_VT(&(rgProperties[iProp].vValue))=VT_BSTR; 
V_BSTR(&(rgProperties[iProp].vValue))=SysAllocString(wszBuff); 
iProp++; 
} 
 
// If Password specified, then create property node 
if( *szPassword != '\0' ) 
{ 
rgProperties[iProp].dwPropertyID=DBPROP_AUTH_PASSWORD; 
rgProperties[iProp].dwOptions=DBPROPOPTIONS_REQUIRED; 
rgProperties[iProp].colid=DB_NULLID; 
MultiByteToWideChar(CP_ACP, 0, szPassword, -1, wszBuff, MAXBUFLEN+1); 
V_VT(&(rgProperties[iProp].vValue))=VT_BSTR; 
V_BSTR(&(rgProperties[iProp].vValue))=SysAllocString(wszBuff); 
iProp++; 
} 
 
// Set prompt level if one was given. 
if (iPrompt != -1) 
{ 
rgProperties[iProp].dwPropertyID=DBPROP_INIT_PROMPT; 
rgProperties[iProp].dwOptions=DBPROPOPTIONS_REQUIRED; 
rgProperties[iProp].colid=DB_NULLID; 
rgProperties[iProp].vValue.vt= VT_I2; 
rgProperties[iProp].vValue.iVal= iPrompt; 
iProp++; 
 
rgProperties[iProp].dwPropertyID=DBPROP_INIT_HWND; 
rgProperties[iProp].dwOptions=DBPROPOPTIONS_REQUIRED; 
rgProperties[iProp].colid=DB_NULLID; 
rgProperties[iProp].vValue.vt= VT_I4; 
rgProperties[iProp].vValue.lVal= (long) hWnd; 
iProp++; 
} 
 
if( iProp ) 
{ 
// Identify Property Set 
rgPropertySet[0].rgProperties=rgProperties; 
rgPropertySet[0].cProperties=iProp; 
rgPropertySet[0].guidPropertySet=DBPROPSET_DBINIT; 
 
// from the DataSource Object get the Session Object 
hr = pIDBInit->QueryInterface(  
IID_IDBProperties,  
(void**)&pIDBProperties ); 
if (FAILED(hr)) 
{ 
GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "QI for IDBProperties FAILED!!"); 
goto error; 
} 
 
// Set Connection Properties 
hr = pIDBProperties->SetProperties(1, rgPropertySet); 
if (FAILED(hr)) 
{ 
GetDetailedErrorInfo(hr, pIDBProperties, IID_IDBProperties, "IDBProperties->SetProperties FAILED!!"); 
goto error; 
} 
}  
 
 // Initialize the PROVIDER 
if( FAILED(hr = pIDBInit->Initialize()) ) 
{ 
        GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "IDBInit->Initialize FAILED!!"); 
goto error; 
} 
 
// from the DataSource Object get the Session Object 
if( FAILED(hr = pIDBInit->QueryInterface(  
IID_IDBCreateSession,  
(void**)&pIDBCreateSession)) ) 
{ 
GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "QI for IDBCreateSession FAILED!!"); 
goto error; 
} 
 
// from the Session object, attempt to get an IUnknown 
if( FAILED(hr = pIDBCreateSession->CreateSession(NULL, IID_IUnknown, (IUnknown**)&pIUnknown)) ) 
{ 
GetDetailedErrorInfo(hr, pIDBCreateSession, IID_IDBCreateSession, "IDBCreateSession->CreateSession FAILED!!"); 
goto error; 
} 
 
// from the Session object, attempt to get the IDBCreateCommand interface 
if( FAILED(hr = pIUnknown->QueryInterface( 
IID_IDBCreateCommand,  
(void**)&pIDBCreateCommand)) ) 
{ 
// if no Command object support, attempt to get the IOpenRowset interface 
hr = pIUnknown->QueryInterface( 
IID_IOpenRowset,  
(void**)&pIOpenRowset); 
if (FAILED(hr)) 
{ 
        GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!"); 
goto error; 
} 
} 
else 
{ 
fCommandWindow = TRUE; 
} 
 
// update the combo-box with IUnknown from Session object 
wsprintf( szBuffer, PROVIDER_SESSION_FORMAT, (LPSTR)szProvName, pIUnknown ); 
 
nResult = (UINT)SendMessage(hWndCrsrList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_SETCURSEL, (WPARAM)nResult, 0); 
SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
ChangeCurrentCursor(hWndCrsrList); 
 
if (fCommandWindow) 
{ 
// Create a Command Object and its associated window. 
NewICommandWindow(); 
} 
else 
{ 
NewIOpenRowsetWindow(); 
} 
 
bReturn = TRUE; 
 
error: 
if( pIMoniker ) 
pIMoniker->Release(); 
 
// Initialize Property Buffers 
for(iProp=0; iProp<NUMELEM(rgProperties); iProp++) 
VariantClear(&(rgProperties[iProp].vValue)); 
 
// If we are successully connected, and the IParse pointer 
// exists release it. 
if( bReturn && g_pIParse ) 
{ 
g_pIParse->Release(); 
g_pIParse = NULL; 
} 
 
// Release IUnknown (for Session) on error only. 
// The pointer value has been copied to the window. 
if( (!bReturn) && (pIUnknown) ) 
pIUnknown->Release(); 
 
if( (pIDBCreateCommand) ) 
pIDBCreateCommand->Release(); 
 
if( (pIDBProperties) ) 
pIDBProperties->Release(); 
 
if( (pIOpenRowset) ) 
pIOpenRowset->Release(); 
 
if( pIDBCreateSession ) 
pIDBCreateSession->Release(); 
 
if(pIDBInit) 
pIDBInit->Release(); 
 
return (bReturn); 
 
}  
 
//********************************************************************** 
//  
// DisplayConnections 
//  
// Purpose: 
//  
//     Display list of available hdbc(s) in the given list box. 
//      
// Parameters: 
// 
// HWND hWndhdbc               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL DisplayConnections(HWND hWndhdbc) 
{ 
ULONG nConnects;// # of Connections 
ULONG count;// Count 
charszBuffer[MAXBUFLEN+1];// String Buffer 
 
// Read the information from the  combo-box  
// on the tool bar and feed it in the given list box. 
SendMessage(hWndhdbc, LB_RESETCONTENT, 0, 0); 
nConnects = SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0); 
 
for (count = 0; count < nConnects; count++) 
{ 
SendMessage(hWndCrsrList, CB_GETLBTEXT, count, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndhdbc, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
 
SendMessage(hWndhdbc, LB_SETCURSEL, 0, 0); 
} 
 
//********************************************************************** 
//  
// DisplayICommands 
//  
// Purpose: 
//  
//     Initializes the PROVIDER and creates a ICommand Object. 
//     Display list of ICommand Objects for the currently selected PROVIDER. 
//      
// Parameters: 
// 
//  HWND hWndhdbc - handle to the PROVIDER 
// HWND hWndhstmt                - handle to the ICommand 
//int nCrsrIndex - Count 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL DisplayICommands(HWND hWndhstmt, HWND hWndhdbc, int nCrsrIndex) 
{ 
charszBuffer[MAXBUFLEN+1];// MDI child window title 
HWNDhWndChild;// MDI child window handle 
IDBCreateCommand * pIDBCreate1;// IDBCreateCommand Object #1 
IDBCreateCommand * pIDBCreate2;// IDBCreateCommand Object #2 
ICommand *pICommand;// ICommand Object 
 
// Reset the Command list box in the disconnect dialog box 
SendMessage(hWndhstmt, LB_RESETCONTENT, 0, 0); 
 
// Go through all available MDI child windows and check if the 
// PROVIDER in the title matches the one selected in the list box. 
// If they match, use the Command in the window title to create 
// a new entry in the Command list box. 
for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) 
{ 
// Class name check is necessary as some of MDI child 
// windows may be iconized by the user and MDIClient 
// in such cases create additional windows (such as icon titles). 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
 
if (strcmp(szBuffer, OLEDBMDICLASS)) 
continue; 
 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand); 
 
SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nCrsrIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2); 
 
if (pIDBCreate1 != pIDBCreate2) 
continue; 
 
wsprintf(szBuffer, ((hWndChild == hWndActiveChild) ?  CURQUERY_STRING:QUERY_STRING), pICommand); 
SendMessage(hWndhstmt, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
SendMessage(hWndhstmt, LB_SETSEL, TRUE, 0); 
} 
 
//********************************************************************** 
//  
// NewICommandWindow 
//  
// Purpose: 
//  
//     Create a new ICommand Object on the current IDBCreateCommand. 
//      
// Parameters: 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                         Location 
//  
//   IDBCreateCommand::CreateCommandprovider's Command object 
//     ICommand::Release                provider's Command object 
//     
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL NewICommandWindow() 
{ 
int nCurrenthdbc;// Current PROVIDER 
charszBuffer[MAXBUFLEN+1];// String in PROVIDER ComboBox on Toolbar 
charszProvName[MAXBUFLEN+1];// DSN String 
MDICREATESTRUCTmcs;// MDI Child Window Create Struc 
 
IDBCreateCommand * pIDBCreateCommand= NULL;// IDBCreateCommand Object 
IOpenRowset * pIOpenRowset= NULL;// IOpenRowset Object 
ICommand *pICommand= NULL;// ICommand Object 
ICommand *pIUnknown= NULL;// IUnknown for session Object 
HRESULThr;// HRESULT 
BOOLbReturn= FALSE;// Return Value 
 
         
// check if there is PROVIDER selected in the Combo-Box 
if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR) 
{ 
MessageBox(hWndFrame, MAKECONNECT, NOSESSIONERROR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// check if the number of windows exceeds MAXCHILDWNDS 
if (nChildCount >= MAXCHILDWNDS) 
{ 
MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// Scan PROVIDER string and IDBCreateCommand value from the combo-box 
SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer); 
 
sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIUnknown); 
 
// from the Session object, attempt to get the IDBCreateCommand interface 
hr = pIUnknown->QueryInterface( 
IID_IDBCreateCommand,  
(void**)&pIDBCreateCommand); 
if (FAILED(hr)) 
{ 
// if no Command object support, attempt to get the IOpenRowset interface 
hr = pIUnknown->QueryInterface( 
IID_IOpenRowset,  
(void**)&pIOpenRowset); 
if (FAILED(hr)) 
{ 
    GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!"); 
goto error; 
} 
} 
else 
{ 
// Create a command object  
hr = pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&pICommand); 
 
if (FAILED(hr)) 
{ 
       GetDetailedErrorInfo(hr, pIDBCreateCommand, IID_IDBCreateCommand, "pIDBCreateCommand->CreateCommand FAILED!!"); 
   goto error; 
} 
} 
 
 
// create a new MDI client window. maximized, if the previous is so. 
mcs.szClass = OLEDBMDICLASS; 
mcs.szTitle = UNTITLED; 
mcs.hOwner  = hAppInstance; 
mcs.style   = hWndActiveChild && IsZoomed(hWndActiveChild) ? WS_MAXIMIZE : 0; 
mcs.x = mcs.cx = mcs.y = mcs.cy = CW_USEDEFAULT; 
hWndActiveChild = (HWND)(UINT)SendMessage(hWndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mcs); 
         
    // check if it was created, if it wasn't free up resource and flag warning 
    if (!hWndActiveChild) 
    { 
MessageBox(hWndFrame, CREATECHILDERR, EXECERROR, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL); 
goto error; 
    } 
         
// Display the Provider string, PROVIDER and IDBCreateCommand/IOpenRowset in the title 
// of newly created window. Increment the child window counter 
 wsprintf(szBuffer, QUERY_STRING, pICommand); 
 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
 wsprintf(szBuffer, PROVIDER_SESSION_COMMAND_FORMAT, (LPSTR)szProvName, pIUnknown, pICommand); 
 
SetWindowText(hWndActiveChild, szBuffer); 
nChildCount++; 
 
// Update the Command Combo-Box on the tool bar. 
ChangeCurrentICommand(hWndStmtList); 
bReturn = TRUE; 
 
error: 
// Note that we obtained pIUnknown (Session ptr) from the window. 
// So we leave it alone. 
 
// Release ICommand on error only. 
// The pointer value has been copied to the window. 
if (pICommand && !bReturn) 
pICommand->Release(); 
 
if (pIDBCreateCommand) 
pIDBCreateCommand->Release(); 
 
if (pIOpenRowset) 
pIOpenRowset->Release(); 
} 
 
 
 
 
//********************************************************************** 
//  
// ChangeCurrentCursor 
//  
// Purpose: 
//  
//     Change the displayed PROVIDER in the PROVIDER(s) combobox. 
//     Also activate the appropriate MDI child window that 
//     has the same PROVIDER as the new PROVIDER in the combobox. 
// 
// Parameters: 
// 
// HWND hWndCrsrList               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL ChangeCurrentCursor(HWND hWndCrsrList) 
{ 
ULONGnNewhdbc;// New PROVIDER position 
ULONGnConnects;// # of connections 
ULONGnCount;// Counter 
charszBuffer[MAXBUFLEN+1];// String Buffer 
BOOLbChangedFocus;// Activate different MDI child 
HWNDhWndChild;// MDI Child window 
IDBCreateCommand* pIDBCreate1;// IDBCreateCommand #1 
IDBCreateCommand* pIDBCreate2;// IDBCreateCommand #2 
ICommand*pICommand;// ICommand Object 
 
// check to see if the current selection in the combo-box 
// differs from the previous selection, if it is the same then 
// simply return. Check is made by searching a marked string 
// in the PROVIDER combobox. 
nNewhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0); 
nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0); 
 
for(nCount = 0; nCount < nConnects; nCount++) 
{ 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer); 
if (strstr(szBuffer, CUR_MARK)) 
break; 
} 
 
if (nCount == nNewhdbc) 
return; 
 
// if there was a current marked hdbc in the combobox, remove the 
// mark from the string and replace it in the combobox. 
if (nCount != nConnects) 
{ 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer); 
szBuffer[strlen(szBuffer)-2] = '\0'; 
SendMessage(hWndCrsrList, CB_INSERTSTRING, nCount, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_DELETESTRING, nCount+1, 0); 
} 
 
// Create a new marked string with currently selected hdbc string in 
// the combobox and replace it with the original. 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nNewhdbc, (LPARAM)(LPSTR)szBuffer); 
strcat(szBuffer, CUR_MARK); 
SendMessage(hWndCrsrList, CB_INSERTSTRING, nNewhdbc, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_DELETESTRING, nNewhdbc+1, 0); 
SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
// Reset the ICommand combobox. Search through the MDI child windows 
// and collect all ICommands from window titles that have the same 
// PROVIDER value as the newly selected PROVIDER in the PROVIDER(s) combo-box above. 
SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0); 
for (bChangedFocus=FALSE, hWndChild=GetWindow(hWndMDIClient, GW_CHILD);hWndChild; hWndChild = GetWindow( 
hWndChild, GW_HWNDNEXT)) 
{ 
// Check class name to skip iconized titles or other 
// such non MDI Child windows 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if (strcmp(szBuffer, OLEDBMDICLASS)) 
continue; 
 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand); 
 
SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nNewhdbc, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2); 
 
if (pIDBCreate1 != pIDBCreate2) 
continue; 
                 
if (!bChangedFocus) 
{ 
            // If the first match is found, change the active window 
        // and update the ICommand(s) combobox with a new entry that 
        // has ICommand marked with current marker. 
bChangedFocus = TRUE; 
hWndActiveChild = hWndChild; 
SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0); 
wsprintf(szBuffer, CURQUERY_STRING, pICommand); 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
else 
{ 
// simply add the ICommand in the ICommand(s) combobox. 
wsprintf(szBuffer, QUERY_STRING, pICommand); 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
} 
} 
 
//********************************************************************** 
//  
// ChangeCurrentICommand 
//  
// Purpose: 
//  
//     Change the current selection in the ICommand(s) combobox. 
//     Update the current marker in the combobox and activate 
//     proper MDI Child window. 
// 
// Parameters: 
// 
// HWND hWndStmtList               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL ChangeCurrentICommand(HWND hWndStmtList) 
{ 
ULONGnNewICommand;// New Selection in Combo-Box 
ULONG nICommands;// # of ICommands 
ULONG nCount;// Counter 
charszBuffer[MAXBUFLEN+1];// String Buffer 
HWNDhWndChild;// MDI Child Window Handle 
IDBCreateCommand* pIDBCreate1;// IDBCreateCommand Object #1 
IDBCreateCommand* pIDBCreate2;// IDBCreateCommand Object #2 
ICommand*pICommand1;// ICommand Object #1 
ICommand*pICommand2;// ICommand Object #2 
 
// Find the index of new selection and total number of ICommand(s) 
nNewICommand = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0); 
nICommands  = (int)SendMessage(hWndStmtList, CB_GETCOUNT,  0, 0); 
 
// Check if the current selection is same as previous one, if 
// so simply return. Check for marker to determine previous selection 
for(nCount = 0; nCount < nICommands; nCount++) 
{ 
SendMessage(hWndStmtList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer); 
if (strstr(szBuffer, CUR_MARK)) 
break; 
} 
 
if (nCount == nNewICommand) 
return; 
 
// If a previous selection was found, remove current marker 
// and update it in the ICommand(s) combobox. 
if (nCount != nICommands) 
{ 
SendMessage(hWndStmtList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer); 
szBuffer[strlen(szBuffer)-2] = '\0'; 
SendMessage(hWndStmtList, CB_INSERTSTRING, nCount, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_DELETESTRING, nCount+1, 0); 
} 
 
// Mark the current selection and update it in the ICommand(s) combobox 
SendMessage(hWndStmtList, CB_GETLBTEXT, nNewICommand, (LPARAM)(LPSTR)szBuffer); 
strcat(szBuffer, CUR_MARK); 
SendMessage(hWndStmtList, CB_INSERTSTRING, nNewICommand, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_DELETESTRING, nNewICommand+1, 0); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
// Scan ICommand value and DSN value from current selection in 
// PROVIDER(s) and ICommand(s) comboboxes. 
sscanf(szBuffer, QUERY_STRING, &pICommand1); 
 
SendMessage( hWndCrsrList, CB_GETLBTEXT,  
(UINT)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0), 
(LPARAM)(LPSTR)szBuffer); 
 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1); 
 
// Go through list of MDI Child windows and match the ICommand and PROVIDER 
// values. If a match if found (must be), activate the window 
for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) 
{ 
// Ignore non MDI child windows 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if (strcmp(szBuffer, OLEDBMDICLASS)) 
continue; 
 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2); 
 
if (pIDBCreate1 == pIDBCreate2 && pICommand1 == pICommand2) 
{ 
hWndActiveChild = hWndChild; 
SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0); 
break; 
} 
} 
} 
 
//********************************************************************** 
//  
// DisplayNewCrsrAndICommand 
//  
// Purpose: 
//  
//     Change the current selection in the ICommand(s) combobox. 
//     Update the current marker in the combobox and activate 
//     proper MDI Child window. 
// 
// Parameters: 
// 
// HWND hWndStmtList               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL DisplayNewCrsrAndICommand() 
{ 
ULONG nConnects;// # of PROVIDER(s) 
ULONG nICommands;// # of ICommand(s) 
ULONG nOldPROVIDER;// Prev selected PROVIDER in combobox 
ULONGnOldICommand;// Prev selected ICommand in combobox 
ULONGnIndex;// Counter 
charszBuffer[MAXBUFLEN+1];// String Buffer 
HWNDhWndChild;// MDI Child Window 
IDBCreateCommand* pIDBCreate1;// IDBCreateCommand Object #1 
IDBCreateCommand* pIDBCreate2;// IDBCreateCommand Object #2 
ICommand*pICommand1;// ICommand Object #1 
ICommand*pICommand2;// ICommand Object #2 
 
// Scan PROVIDER and ICommand values from newly selected window 
GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand1); 
 
// Search through list of PROVIDER(s) in PROVIDER combobox and find 
// matching PROVIDER. remove marker from prev selection and add 
// marker to the new selection. Update combobox accordingly. 
nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT,  0, 0); 
nOldPROVIDER   = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0); 
 
for(pIDBCreate2 = (IDBCreateCommand*)(nIndex = 0); pIDBCreate1 != pIDBCreate2; nIndex++) 
{ 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2); 
} 
 
// Change in PROVIDER combobox required. 
if (--nIndex != nOldPROVIDER) 
{ 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nOldPROVIDER, (LPARAM)(LPSTR)szBuffer); 
szBuffer[strlen(szBuffer)-2] = '\0'; 
SendMessage(hWndCrsrList, CB_INSERTSTRING, nOldPROVIDER, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_DELETESTRING, nOldPROVIDER+1, 0); 
 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
strcat(szBuffer, CUR_MARK); 
SendMessage(hWndCrsrList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_DELETESTRING, nIndex+1, 0); 
SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
// Reset the ICommand(s) combobox, search through the list 
// of MDI child windows and find all hstmt(s) associated to 
// new PROVIDER. Build the new list of ICommand(s) for the ICommand 
// combobox. Mark the one ICommand that matches the currently 
// activated MDI child window. 
SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0); 
for (hWndChild=GetWindow(hWndMDIClient,GW_CHILD);hWndChild;hWndChild=GetWindow(hWndChild,GW_HWNDNEXT)) 
{ 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if (strcmp(szBuffer, OLEDBMDICLASS)) 
continue; 
 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2); 
 
if (pIDBCreate1 != pIDBCreate2) 
continue; 
 
if (hWndActiveChild == hWndChild) 
{ 
wsprintf(szBuffer, CURQUERY_STRING, pICommand2); 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
else 
{ 
wsprintf(szBuffer, QUERY_STRING, pICommand2); 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
} 
} 
// No change in PROVIDER combobox required 
else 
{ 
// Go through the list of ICommand(s) in ICommand combobox. 
// Find the one that matches the currently activated MDI child window. 
nOldICommand = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0); 
nICommands = (int)SendMessage(hWndStmtList, CB_GETCOUNT, 0, 0); 
 
for(pICommand2 = (ICommand*)(nIndex = 0); pICommand1 != pICommand2; nIndex++) 
{ 
SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, QUERY_STRING, &pICommand2); 
} 
 
// New index in ICommand differs from previous selection 
if (--nIndex != nOldICommand) 
{ 
// Remove the marker from previous selection. 
// Add it to the new string and update the combobox display 
SendMessage(hWndStmtList, CB_GETLBTEXT, nOldICommand, (LPARAM)(LPSTR)szBuffer); 
szBuffer[strlen(szBuffer)-2] = '\0'; 
SendMessage(hWndStmtList, CB_INSERTSTRING, nOldICommand, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_DELETESTRING, nOldICommand+1, 0); 
 
SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
strcat(szBuffer, CUR_MARK); 
SendMessage(hWndStmtList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_DELETESTRING, nIndex+1, 0); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
} 
} 
} 
 
//********************************************************************** 
//  
// FreeConnect 
//  
// Purpose: 
//  
//     Disconnect and Free the currently selected PROVIDER in 
//     the PROVIDER listbox in disconnect dialog. Call RELEASE 
//     to free the PROVIDER. Close all MDI 
//     child windows associated with this PROVIDER. That will 
//     automatically free associated ICommand(s). 
// 
// Parameters: 
// 
// HWND hWndhdbc               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//     IDBCreateCommand::Release   provider's Command object 
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL FreeConnect(HWND hWndhdbc) 
{ 
int nIndex;// Current Selection in the listbox of disconnect dlg 
intnCurrent;// Current Selected PROVIDER(s) combobox 
charszBuffer[MAXBUFLEN+1];// String Buffer 
charszSelect[MAXBUFLEN+1];// Original Selected PROVIDER(s) combobox 
charszProvName[MAXBUFLEN+1];// DSN string 
HWNDhWndChild;// MDI Child window 
IDBCreateCommand * pIDBCreate1;// IDBCreateCmmand Object #1 
IDBCreateCommand * pIDBCreate2;// IDBCreateCmmand Object #2 
IErrorInfo *pIErrorInfo;// IErrorInfo Object 
 
// Check current selection in the list box of disconnect dialog.  
// Scan PROVIDER value from the current selection. 
if ((nIndex = (int)SendMessage(hWndhdbc, LB_GETCURSEL, 0, 0)) == LB_ERR) 
return; 
 
SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIDBCreate1); 
 
// Go through the list of MDI child windows and find matching PROVIDER(s) 
// close all children who have the same PROVIDER value. Closing them 
// automatically frees associated ICommands. See CloseICommandWindow. 
for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; ) 
{ 
// Store next window handle before destroying the currentone 
HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT); 
 
// Ignore non MDI child windows 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if (!strcmp(szBuffer, OLEDBMDICLASS)) 
{ 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSION_TITLEFORMAT, &pIDBCreate2); 
if (pIDBCreate1 == pIDBCreate2) 
{ 
// Destroy the window and restart search 
SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
hWndTemp = GetWindow(hWndMDIClient, GW_CHILD); 
} 
} 
hWndChild = hWndTemp; 
} 
 
// Release the Command Object & return 
if( pIDBCreate1 ) 
pIDBCreate1->Release(); 
 
// Release any remaining error objects.  This is idempotent. 
// Otherwise the provider might have an outstanding global-object count. 
GetErrorInfo( 0, &pIErrorInfo ); 
if (pIErrorInfo) 
pIErrorInfo->Release(); 
 
// Unload any DLL's no longer being used 
CoFreeUnusedLibraries(); 
 
// Update the PROVIDER(s) combobox display by removing the deleted PROVIDER 
// from the list and reselecting the previous selection 
wsprintf(szBuffer, PROVIDER_SESSION_FORMAT, (LPSTR)szProvName, pIDBCreate1); 
nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0); 
SendMessage(hWndCrsrList, CB_GETLBTEXT, nCurrent, (LPARAM)(LPSTR)szSelect); 
nIndex = (int)SendMessage(hWndCrsrList, CB_FINDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndCrsrList, CB_DELETESTRING, (WPARAM)nIndex, 0); 
SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect); 
 
// If there is no query window open and the current selected PROVIDER 
// was deleted, make sure to make the next available PROVIDER as current 
if (SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) && 
!GetWindow(hWndMDIClient, GW_CHILD) && (nCurrent == nIndex)) 
{ 
if ((nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0))!=CB_ERR) 
return; 
SendMessage(hWndCrsrList, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)szSelect); 
strcat(szSelect, CUR_MARK); 
SendMessage(hWndCrsrList, CB_INSERTSTRING, 0, (LPARAM)(LPSTR)szSelect); 
SendMessage(hWndCrsrList, CB_DELETESTRING, 1, 0); 
SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect); 
} 
} 
 
//********************************************************************** 
//  
// FreeICommand 
//  
// Purpose: 
//  
//     Free a ICommand window based upon current selection in 
//     ICommand list box in the disconnect dialog. 
// 
// Parameters: 
// 
// HWND hWndhstmt               - handle to the window 
// HWND hWndhdbc                - handle to the window 
//  int             nIndex- Index 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL FreeICommand(HWND hWndhstmt, HWND hWndhdbc, int nIndex) 
{ 
charszBuffer[MAXBUFLEN+1];// display buffer 
HWNDhWndChild;// MDI child window 
IDBCreateCommand* pIDBCreate1;// IDBCreateCommand Object #1 
IDBCreateCommand* pIDBCreate2;// IDBCreateCommand Object #2 
ICommand*pICommand1;// ICommand Object #1 
ICommand*pICommand2;// ICommand Object #2 
 
// Scan the ICommand and PROVIDER values from the current selections in 
// respective listboxes of disconnect dialog box. 
SendMessage(hWndhstmt, LB_GETTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, QUERY_STRING, &pICommand1); 
SendMessage(hWndhdbc, LB_GETTEXT, (UINT)SendMessage(hWndhdbc, LB_GETCURSEL,0, 0), (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1); 
         
    // Go through the list of MDI child windows and find matching window 
    // that has same values for PROVIDER and ICommand. Destroy the matching window. 
    // That will call CloseICommandWindow and free up associated ICommand(s). 
for(hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) 
{ 
// Ignore non MDI child windows 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if( strcmp(szBuffer, OLEDBMDICLASS) ) 
continue; 
 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2); 
if (pIDBCreate1 == pIDBCreate2 && pICommand1 == pICommand2) 
break; 
} 
SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
} 
 
//********************************************************************** 
//  
// CloseICommandWindow 
//  
// Purpose: 
//  
//     Close a ICommand window.  
//     Call ICommand->Release() to free associated ICommand(s). 
// 
// Parameters: 
// 
// HWND hWnd               - handle to the window 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//     ICommand::Release           provider's Command object 
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL CloseICommandWindow(HWND hWnd) 
{ 
charszBuffer[MAXBUFLEN+1];// String buffer 
charszSelect[MAXBUFLEN+1];// Current Selected ICommand(s) 
ICommand*pICommand;// ICommand Object 
 
// Scan the ICommand value from the window title 
GetWindowText(hWnd, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANCOMMAND_TITLEFORMAT, &pICommand); 
 
// Release the Command Object & return 
if( pICommand ) 
pICommand->Release(); 
 
// Find the matching ICommand in the ICommand(s) combobox and remove it 
// from the list. Closure of a MDI child window will cause MDIClient 
// to automatically activate a different child window if available. 
// That will automatically refresh the ICommand and PROVIDER displays.  
// See DisplayNewCrsrAndICommand function. 
wsprintf( szBuffer, QUERY_STRING, pICommand ); 
 
SendMessage( hWndStmtList, CB_GETLBTEXT,  
(WPARAM)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0), 
(LPARAM)(LPSTR)szSelect ); 
 
SendMessage( hWndStmtList, CB_DELETESTRING,  
(WPARAM)SendMessage(hWndStmtList, CB_FINDSTRING, 0, 
(LPARAM)(LPSTR)szBuffer), 0 ); 
 
SendMessage( hWndStmtList, CB_SELECTSTRING, 
(WPARAM)-1,  
(LPARAM)(LPSTR)szSelect ); 
 
// Decrement the child window counter. 
nChildCount--; 
} 
 
//********************************************************************** 
//  
// ExecuteQuery 
//  
// Purpose: 
//  
//     Execute the user typed SQL Statements in the currently  
//     active MDI child window. If successful, then prepare 
//     the list of results and display it in the child listbox. 
//     Display errors in the OLE DB function(s) failed. 
// 
// Parameters: 
// 
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//     ExecuteCommand              query.cpp 
//     GetDataFromRowset           query.cpp 
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL ExecuteQuery() 
{ 
CHARszBuffer[MAXBUFLEN+1];// String Buffer 
WCHARwszBuffer[MAXBUFLEN+1];// String Buffer (WCHAR) 
signed short intswColLength = MAXDATALEN;// Column Data Length 
HCURSORhOldCursor;// Default Cursor Handle 
IUnknown*pIUnknown = NULL;// Session Object 
ICommand*pICommand = NULL;// ICommand Object 
IOpenRowset*pIOpenRowset= NULL;// IOpenRowset Object 
IRowset*pIRowset = NULL;// IRowset Object 
HRESULThr;// HRESULT 
 
// Check if there is an active window available 
if (!hWndActiveChild) 
{ 
MessageBox(hWndFrame, ((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ? 
MAKECONNECT : OPENWINDOW ), NOCOMMANDERROR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// Change cursor shape to hour glass 
hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); 
         
// Scan PROVIDER, session and ICommand values 
GetWindowText(hWndActiveChild, (char*)szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIUnknown, &pICommand); 
 
// Get the user typed SQL 
GetWindowText(GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDTEXT_SQL), szBuffer, MAXBUFLEN); 
 
// Convert ANSI String to WCHARString 
MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wszBuffer, MAXBUFLEN+1); 
 
// Execute the Command Object 
hr = ExecuteCommand( pIUnknown, pICommand, wszBuffer, &pIRowset );  
 
if (FAILED(hr)) 
return; 
 
// Empty IRowset 
if( hr == ResultFromScode(S_FALSE) ) 
{  
DumpErrorHResult( ResultFromScode(S_OK), (LPSTR)"ExecuteCommand returned No Rowset!!" ); 
return; 
} 
 
// Get Data from the IRowset Object 
GetDataFromRowset( pIRowset ); 
} 
 
 
//********************************************************************** 
//  
// CloseIDBCreateCommand 
//  
// Purpose: 
//  
//     Go through all open PROVIDER's (IDBCreateCommand(s) and ICommand(s))  
//     and close them one by one. 
// 
// Parameters: 
// 
// Return Value: 
//  
// Function Calls: 
//     Function                    Location 
//  
//     IDBCreateCommand::Release   provider's Command object 
//      
// Comments:       
//  
//  
//********************************************************************** 
BOOL FAR PASCAL CloseIDBCreateCommand() 
{ 
ULONG nIndex;// Index 
ULONGnCount;// # of PROVIDER(s) 
charszBuffer[MAXBUFLEN+1];// String Buffer 
HWNDhWndChild;// MDI Child Window 
IDBCreateCommand* pIDBCreate1;// IDBCreateCommand Object #1 
IDBCreateCommand* pIDBCreate2;// IDBCreateCommand Object #2 
 
// Get count of connected PROVIDER(s) from the PROVIDER(s) combobox on the toolbar 
if (!(nCount = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0))) 
return (TRUE); 
 
// Go through all available MDI child windows and for each PROVIDER, 
// find the matching MDI child window and ask it for closure, thereby 
// freeing the associated ICommand (see CloseICommandWindow). Once all 
// associated ICommand(s) are freed, free the PROVIDER 
for (nIndex = 0; nIndex < nCount; nIndex++) 
{        
// Scan current indexed PROVIDER from PROVIDER(s) combobox 
SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer); 
sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1); 
 
// Search through the list of MDI Child Windows 
for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; ) 
{ 
// Store the next child, before destroying the current 
HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT); 
 
// Ignore non MDI child windows 
GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
if (!strcmp(szBuffer, OLEDBMDICLASS)) 
{ 
GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSION_TITLEFORMAT, &pIDBCreate2); 
if (pIDBCreate1 == pIDBCreate2) 
{ 
// Destroy the window and restart search 
SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
hWndTemp = GetWindow(hWndMDIClient, GW_CHILD); 
} 
} 
hWndChild = hWndTemp; 
} 
 
// Call IDBCreateCommand->Release()  
// to free the current IDBCreateCommand resource 
if( pIDBCreate1 ) 
pIDBCreate1->Release(); 
} 
 
// Reset the PROVIDER(s) combobox display and display all connections 
// closed message. Return success to let application exit. 
SendMessage(hWndCrsrList, CB_RESETCONTENT, 0, 0); 
MessageBox(hWndFrame, CLOSEALLSESSION, LOGOUTINFO,MB_OK | MB_ICONINFORMATION); 
return (TRUE); 
} 
 
/* 
FUNCTION: FreeEnvironment() 
COMMENTS: Free the OLE environment. 
*/ 
HRESULT FreeEnvironment() 
{ 
    HRESULThr = S_OK;// HRESULT 
IErrorInfo*pIErrorInfo;//IErrorInfo 
 
    // Release the task memory allocator 
if( g_pIMalloc ) 
g_pIMalloc->Release(); 
 
// Release any remaining error objects.  This is idempotent. 
// Otherwise the provider might have an outstanding global-object count. 
GetErrorInfo( 0, &pIErrorInfo ); 
if (pIErrorInfo) 
pIErrorInfo->Release(); 
 
// Free the error queues 
SetErrorInfo(0,NULL); 
 
// Uninitialize OLE 
CoUninitialize(); 
 
return hr; 
} 
 
 
//********************************************************************** 
//  
// ExecuteCommand 
//  
// Purpose: 
//  
//    Executes the query command that was previously set on the Command object, 
//    and returns a first interface pointer on the resulting Rowset object. 
//  
// Parameters: 
//   IOpenRowset*pIOpenRowset- interface pointer to data provider's 
//  IOpenRowset 
//   ICommand*pICommand       - interface pointer on data provider's 
//              Command object 
//   LPWSTRwszBuffer- SQL-style query string to be sent 
//              to the Command object or table/file name to 
//  be sent to IOpenRowset 
//   IRowset**ppIRowset_out   - out pointer through which to return  
//              interface pointer on provider's 
//          Rowset object 
//  
// Return Value: 
//     S_OK        - Success 
//     E_*         - Failure 
//  
// Function Calls: 
//     Function                    Location 
//      
//     ICommand::Execute           provider's Command object 
//     IMalloc::Free               OLE task memory allocator 
//      
//  
//     assert                      c runtime 
//  
//  
//      
// Comments:       
//  
//     The interface pointer returned through ppIRowset_out has been AddRef'ed,  
//     it must be Release'd later by the caller. 
// 
//********************************************************************** 
HRESULT ExecuteCommand( 
IUnknown*pIUnknown,// Session object 
ICommand*pICommand,// Command object 
LPWSTR wszBuffer,// SQL String (WCHAR) or Table Name 
IRowset**ppIRowset_out 
) 
{ 
ICommandText*pICommandText = NULL;// ICommandText Object 
IOpenRowset*pIOpenRowset = NULL; 
DBIDTableID;// Table ID 
HRESULThr = S_OK;// HRESULT 
 
// Asserts 
assert(ppIRowset_out != NULL); 
    assert(wszBuffer != NULL); 
 
memset(&TableID, 0, sizeof(DBID)); 
 
// If no command object use IOpenRowset 
if (NULL == pICommand) 
{ 
// if no Command object support, attempt to get the IOpenRowset interface 
if( FAILED(hr = pIUnknown->QueryInterface(IID_IOpenRowset, (void**)&pIOpenRowset)) ) 
{ 
        GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!"); 
goto error; 
} 
// Pass in table/file name 
TableID.eKind = DBKIND_NAME; 
 
TableID.uName.pwszName = wszBuffer; 
 
// From IOpenRowset, get a rowset object 
if( FAILED(hr = pIOpenRowset->OpenRowset( 
NULL,// pUnkOuter 
&TableID,// pTableID 
NULL,// pIndexID 
IID_IRowset,// refiid 
0,// cProperties 
NULL,// rgProperties 
 (IUnknown**)ppIRowset_out)) )  // IRowset pointer 
{ 
     GetDetailedErrorInfo(hr, pIOpenRowset, IID_IOpenRowset, "IOpenRowset->OpenRowset FAILED!!"); 
goto error; 
} 
} 
else 
{ 
// QueryInterface for ICommandText::SetCommandText 
if( SUCCEEDED(hr = pICommand->QueryInterface(IID_ICommandText,(LPVOID*)&pICommandText)) ) 
{ 
// Tell the command object to copy this command text 
// The command object will then use this query when we call ICommand::Execute 
if( FAILED(hr = pICommandText->SetCommandText(DBGUID_DBSQL, wszBuffer)) ) 
{ 
        GetDetailedErrorInfo(hr, pICommandText, IID_ICommandText, "ICommandText->SetCommandText FAILED!!"); 
goto error; 
} 
} 
 
// From the command object, get a rowset object by executing command 
if( FAILED(hr = pICommand->Execute( 
NULL,// pUnkOuter 
IID_IRowset,// refiid 
NULL,// disp parms 
NULL,// rows affected 
 (IUnknown**)ppIRowset_out)) )  // IRowset pointer 
{ 
GetDetailedErrorInfo(hr, pICommand, IID_ICommand, "ICommand->Execute FAILED!!"); 
goto error; 
} 
} 
 
// NO Rowset Returning Statement 
    if( !*ppIRowset_out ) 
hr = ResultFromScode(S_FALSE); 
error: 
if( pICommandText ) 
pICommandText->Release(); 
if( pIOpenRowset ) 
pIOpenRowset->Release(); 
 
if( FAILED(hr) ) 
*ppIRowset_out = NULL; 
 
return hr;     
} 
 
//********************************************************************** 
//  
// GetDataFromRowset 
//  
// Purpose: 
//  
//     Pulls the data from a Rowset object. 
//      
// Parameters: 
//  
// IRowset*pIRowset    -  interface pointer on data provider's 
//                             Rowset object 
//  
// Return Value: 
//  
//     S_OK        - Success 
//     E_*         - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//   IRowset::QueryInterface   Clients Rowset pointer 
//     SetupBindings               query.cpp 
//     CreateAccessor              query.cpp 
//     GetData                     query.cpp 
//     CleanupRowset               query.cpp 
//  
//     IMalloc::Free               OLE task memory allocator 
//  
//     assert                      c runtime 
//  
// Comments:       
//  
//     At a high level, a consumer pulls the data from a Rowset object by: 
//      
//     1. getting metadata for the Rowset's columns 
//     2. using that metadata, along with the consumer's own knowledge of 
//        how it wants to recieve the data, to create bindings. Bindings 
//        represent how the actual data in the Rowset's columns is 
//        actually transferred to the consumer's buffer. 
//     3. pass the bindings to the Rowset, and get in return an accessor 
//        handle that represents that particular set of bindings    
//     4. get the actual data 
//     5. clean up the rowset (at a minumum, release the accessor)  
//      
//     GetDataFromRowset performs these steps by calling GetColumnsInfo, 
//     SetupBindings, CreateAccessor, GetData, and CleanupRowset 
//        
//********************************************************************** 
HRESULT GetDataFromRowset( 
IRowset*pIRowset 
) 
{ 
charszBuffer[MAXBUFLEN+1];// String Buffer 
HWNDhList;// Result Listbox Handle 
DWORD dwText;// Tab Stop for Listbox 
unsigned short intnCount;// Index 
signed short intswColLength = MAXDATALEN;// Column Data Length 
intcch;// Count of characters 
HCURSORhOldCursor;// Default Cursor Handle 
HRESULThr = S_OK;// HRESULTS 
    ULONGcCol;// # of Columns in Rowset 
    DBCOLUMNINFO*pColumnInfo;// Array of DBCOLUMNINFO 
    WCHAR*pStringsBuffer;// Storage for strings 
 
// BINDINGS 
ULONG cbMaxRowSize;// buffer size for 1 row's data 
ULONG cBind; 
DBBINDINGrgBind[MAX_COL]; 
 
// ACCESSORS 
HACCESSORhAccessor= NULL; 
 
// Asserts 
assert(pIRowset   != NULL); 
assert(g_pIMalloc != NULL); 
 
// Change cursor shape to hour glass 
hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); 
 
// Get the Columns Info 
GetColumnsInfo( pIRowset, &cCol, &pColumnInfo, &pStringsBuffer); 
 
// Call GetColumnsInfo to calculate the number of columns in 
// the result set, if more than the MAX_COL (the array boundary) 
// limit the number to MAX_COL and display truncation warning. 
// if it is 0, the statement probably was a non-SELECT simply return 
if (cCol >= MAX_COL) 
{ 
cCol = MAX_COL; 
wsprintf(szDispBuffer, COLTRUNC_WARNG, MAX_COL); 
MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION); 
} 
else if (cCol == 0) 
{ 
SetCursor(hOldCursor); 
goto error; 
} 
 
// Reset the display in the list box. Set tabstops to display 
// multiple columns in the list box separated by tabs. 
hList = GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDLIST_RSLT); 
 
SendMessage(hList, LB_RESETCONTENT, 0, 0); 
SendMessage(hList, WM_SETREDRAW, FALSE, 0); 
dwText = LISTTABSTOP; 
SendMessage(hList, LB_SETTABSTOPS, (WPARAM)1, (LPARAM)(LPINT)&dwText); 
 
// Display a description of each column in the result set.  
// Store the column name in the display buffer and make it 
// the first entry in the results list box of the MDI child window. 
for(nCount=0, szDispBuffer[0]='\0'; nCount < cCol; nCount++) 
{ 
if (pColumnInfo[nCount].pwszName) 
{ 
cch = WideCharToMultiByte(CP_ACP, 0, pColumnInfo[nCount].pwszName, -1, szBuffer, MAXBUFLEN+1, NULL, NULL); 
 
// Truncate if needed. 
// We should use GetTextExtents to determine width, but that's too complicated for now. 
szBuffer[MAXCOLNAMELEN] = '\0'; 
 
// Might be empty string for column name. 
if (cch) 
strcat(szDispBuffer, szBuffer); 
else 
strcat(szDispBuffer, "<EMPTY STRING>"); 
} 
else 
{ 
// Missing the column name; it is unknown. 
strcat(szDispBuffer, "<NULL STRING>"); 
} 
 
dwText = strlen(szDispBuffer); 
szDispBuffer[dwText++] = '\t'; 
szDispBuffer[dwText] = '\0'; 
} 
 
// NULL Terminate the Display Buffer 
if (*szDispBuffer) 
szDispBuffer[strlen(szDispBuffer)-1]='\0'; 
 
// ADD the Column Info to the Screen 
SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer); 
 
// SetUp Bindings 
if( FAILED(hr = SetupBindings( cCol, pColumnInfo, rgBind, &cBind, &cbMaxRowSize)) ) 
goto error; 
 
// Create the Accessor 
if( FAILED(hr = CreateAccessor( pIRowset, rgBind, cBind, &hAccessor)) ) 
goto error; 
 
// GetData 
if( FAILED(hr = GetData( pIRowset, cbMaxRowSize, hAccessor, rgBind, cBind, pColumnInfo,  
cCol, hList, dwText, LB_ADDSTRING)) ) 
goto error; 
 
// restore the cursor to default value 
SetCursor(hOldCursor); 
   
error:     
// Release the IColumnsInfo Object 
if( pColumnInfo ) 
g_pIMalloc->Free( pColumnInfo ); 
if( pStringsBuffer ) 
g_pIMalloc->Free( pStringsBuffer );     
     
// Clean-up the Rowset 
CleanupRowset( pIRowset, hAccessor ); 
 
    return hr;     
} 
 
 
//********************************************************************** 
//  
// GetColumnsInfo 
//  
// Purpose: 
//  
//     Get the Columns metadata back for the provider to setup the bundings.  
//      
// Parameters: 
// 
//IRowset*pIRowset- IRowset pointer to QI off of 
// ULONG cCol                - number of columns in metadata 
// DBCOLUMNINFO*pColumnInfo         - pointer to column metadata 
// WCHAR*pStringsBuffer      - pointer through which to return 
//                                        an array of string data, one 
//                                        structure per column bound 
//  
// Return Value: 
//     S_OK         - Success 
//     E_*          - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//     assert                      c runtime 
//     IRowset::QueryInterface     provider's Rowset object 
//     IColumnsInfo::GetColumnInfo provider's ColumnInfo object 
//     IColumnsInfo::Release       provider's ColumnInfo object 
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
HRESULT GetColumnsInfo 
( 
IRowset*pIRowset, 
ULONG* pcCol, 
DBCOLUMNINFO**ppColumnInfo, 
WCHAR**ppStringsBuffer 
) 
{ 
 
HRESULThr=NOERROR;// HRESULTS 
IColumnsInfo* pIColumnsInfo = NULL;// IColumnsInfo Object 
 
// QI for IColumnsInfo Object 
if( FAILED(hr = pIRowset->QueryInterface( IID_IColumnsInfo, (void **) &pIColumnsInfo)) ) 
{ 
GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IColumnsInfo FAILED!!"); 
goto error; 
} 
 
// Get column information from the command object via IColumnsInfo::GetColumnsInfo  
if( FAILED(hr = pIColumnsInfo->GetColumnInfo( pcCol, ppColumnInfo, ppStringsBuffer)) ) 
{ 
GetDetailedErrorInfo(hr, pIColumnsInfo, IID_IColumnsInfo, "IColumnsInfo->GetColumnsInfo FAILED!!"); 
goto error; 
} 
 
error: 
// Release the IColumnsInfo Object 
if( pIColumnsInfo ) 
pIColumnsInfo->Release(); 
return hr; 
 
} 
 
//********************************************************************** 
//  
// SetupBindings 
//  
// Purpose: 
//  
//     Creates bindings that map the data in the rowset's columns to  
//     slots in the consumer's data buffer. 
//      
// Parameters: 
// 
// ULONG cCol                - number of columns in rowset to bind 
// DBCOLUMNINFO*pColumnInfo         - pointer to column metadata 
// DBBINDING*rgBind_out          - out pointer through which to return 
//                                        an array of binding structures, one 
//                                        structure per column bound 
// ULONG*pcBind_out          - out pointer through which to return    
//                                        the number of columns bound (number 
//                                        of valid elements in rgBind_out)               
// ULONG*pcMaxRowSize_out    - out pointer through which to return 
//                                        the buffer size necessary to hold 
//                                        the largest row data 
//  
// Return Value: 
//     S_OK         - Success 
//     E_*          - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//     assert                      c runtime 
//  
//      
// Comments:       
//  
//  
//********************************************************************** 
HRESULT SetupBindings 
( 
ULONG cCol, 
DBCOLUMNINFO*pColumnInfo, 
DBBINDING*rgBind_out, 
ULONG*pcBind_out, 
ULONG*pcMaxRowSize_out 
) 
{ 
#define DEFAULT_CBMAXLENGTH 80// cbMaxLength for binding 
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_NOTPARAM; 
rgBind_out[iBind].iOrdinal= pColumnInfo[iCol].iOrdinal; 
rgBind_out[iBind].wType     = DBTYPE_WSTR; 
rgBind_out[iBind].pTypeInfo = NULL; 
rgBind_out[iBind].obValue   = dwOffset + offsetof(COLUMNDATA,bData); 
rgBind_out[iBind].obLength  = dwOffset + offsetof(COLUMNDATA,dwLength); 
rgBind_out[iBind].obStatus  = dwOffset + offsetof(COLUMNDATA,wStatus); 
 
// If columns information is a STR, double buffer and  
// add space for terminator 
if( ((pColumnInfo[iCol].wType == DBTYPE_STR) || 
 (pColumnInfo[iCol].wType == DBTYPE_WSTR)) &&  
(pColumnInfo[iCol].ulColumnSize != 0xffffffff) ) 
rgBind_out[iBind].cbMaxLen = (pColumnInfo[iCol].ulColumnSize + sizeof(CHAR)) * 2; 
else 
rgBind_out[iBind].cbMaxLen = DEFAULT_CBMAXLENGTH; 
rgBind_out[iBind].pObject= NULL; 
rgBind_out[iBind].pBindExt= NULL; 
rgBind_out[iBind].dwFlags= 0; 
rgBind_out[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED; 
rgBind_out[iBind].bPrecision = 0; 
rgBind_out[iBind].bScale= 0; 
 
// LONG DATA hack  
if(rgBind_out[iBind].cbMaxLen > 1000) 
rgBind_out[iBind].cbMaxLen = 1000; 
 
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; 
} 
 
 
 
//********************************************************************** 
//  
// CreateAccessor 
//  
// Purpose: 
// 
//     Passes a set of bindings to the data provider and recieves in return 
//     an accessor handle that represents those bindings.  
//       
// Parameters: 
// IRowset*pIRowset        - interface pointer on data provider's Rowset 
//                                object 
// DBBINDING*rgBind          - array of binding structures 
// ULONGcBind           - number of binding structures in rgBind 
// HACCESSOR*phAccessor_out  - out pointer through which to return an  
//                                accessor handle that represents all the bindings 
//                                in rgBind 
//  
// Return Value: 
//     S_OK        - Success 
//     E_*         - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//     IRowset::QueryInterface     provider's Rowset object 
//     IAccessor::CreateAccessor   provider's Rowset object 
//     IAccessor::Release          provider's Rowset object 
//  
//     assert                      c runtime 
//      
// Comments:       
//  
//  
//********************************************************************** 
HRESULT CreateAccessor 
( 
IRowset*pIRowset, 
DBBINDING*rgBind, 
ULONGcBind, 
HACCESSOR*phAccessor_out  
) 
{ 
IAccessor*pIAccessor = NULL; 
HRESULT hr; 
 
// Asserts 
assert(pIRowset   != NULL); 
    assert(rgBind   != NULL); 
    assert(phAccessor_out != NULL); 
 
  // Get an accessor for our bindings from the rowset, via IAccessor  
if( FAILED(hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor)) ) 
{ 
GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IAccessor FAILED!!"); 
goto error; 
} 
 
if( FAILED(hr = pIAccessor->CreateAccessor( 
DBACCESSOR_ROWDATA,  
cBind,  
rgBind,  
0,  
phAccessor_out, 
NULL)) ) 
{ 
GetDetailedErrorInfo(hr, pIAccessor, IID_IAccessor, "IAccessor->CreateAccessor FAILED!!"); 
goto error; 
} 
 
hr = S_OK; 
 
error: 
if (pIAccessor) 
    pIAccessor->Release(); 
 
if( FAILED(hr) ) 
*phAccessor_out = NULL; 
 
return hr; 
} 
 
 
//********************************************************************** 
//  
// GetData 
//  
// Purpose: 
//  
//     Reads the data from a rowset. 
//  
// Parameters: 
// 
//    IRowset* pIRowset           - interface pointer on data provider's 
//                                    Rowset object 
//    ULONG    cMaxRowSize        - size of buffer needed to hold the data 
//                                    for the largest row 
//     HACCESSOR hAccessor          - accessor handle representing the set 
//                                    of desired bindings 
//     DBBINDING*rgBind  - needed only for pretty printing 
//     ULONGcBind  - for pretty printing   
//     DBCOLUMNINFO*pColumnInfo - for pretty printing   
//     ULONGcCol- for pretty printing   
//  
//  
// Return Value: 
//     S_OK        - Success 
//     E_*         - Failure 
//  
// Function Calls: 
//     Function                    Location 
//  
//     IRowset::GetNextRows        provider's Rowset object 
//     IRowset::GetData            provider's Rowset object 
//     IRowset::ReleaseRows        provider's Rowset object 
//  
//  
//     malloc, free                c runtime 
//     assert                      c runtime 
//  
//  
//      
// Comments:       
// 
//     GetData reads all the rows in the rowset, sequentially. 
//   
//  
//********************************************************************** 
HRESULT GetData 
( 
IRowset*pIRowset, 
ULONG   cMaxRowSize, 
    HACCESSOR   hAccessor, 
    DBBINDING*rgBind,     
    ULONGcBind,     
    DBCOLUMNINFO*pColumnInfo,   
    ULONGcCol, 
HWNDhList, 
DWORDdwText, 
DWORDaddString 
) 
{ 
#define NUMROWS_CHUNK       20// Number of Rows to Grab at a Time 
 
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 
ULONGcMaxColWidth = MAXCOLNDATALENGTH; // Needed for Output 
HRESULT hr;// HRESULT 
 
// 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; 
 
    // Process all the rows, NUMROWS_CHUNK rows at a time 
while (1) 
{ 
if( FAILED(hr = pIRowset->GetNextRows( 
0,// cbChapter 
0,// cRowsToSkip 
NUMROWS_CHUNK,// cRowsDesired 
&cRowsObtained,// cRowsObtained 
&pRows)) )// filled in w/ row handles 
{ 
    GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->GetNextRows FAILED!!"); 
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++ ) 
{ 
if( FAILED(hr = pIRowset->GetData( 
rghRows[iRow], 
hAccessor, 
pRowData)) ) 
{ 
                GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->GetData FAILED!!"); 
goto error; 
} 
 
 
// Print to the Screen 
            DumpRow( rgBind, cBind, cMaxColWidth, pRowData, hList, dwText, addString ); 
 
// See if you are over the limit of rows 
if ((iRow + 1) == MAX_ROW) 
{ 
wsprintf(szDispBuffer, ROWTRUNC_WARNG, MAX_ROW); 
MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION); 
break; 
} 
 
} 
 
// Release row handles 
if( FAILED(hr = pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL)) ) 
{ 
           GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->ReleaseRows FAILED!!"); 
   goto error; 
} 
 
}// end while 
 
hr = S_OK; 
error: 
// Set the horizontal scroll extent in the list box and ask for repaint. 
SendMessage(hList, LB_SETHORIZONTALEXTENT, (WPARAM)(cBind*LISTHORZSCROLL+LISTHORZEXT), 0); 
SendMessage(hList, WM_SETREDRAW, TRUE, 0); 
 
if( cRowsObtained ) 
pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL); 
 
if( pRowData ) 
free( pRowData ); 
     
    return hr; 
} 
 
//********************************************************************** 
//  
// GetSchemaRowset 
//  
// Purpose: 
//  
//     Pulls the schema info out of the provider. 
//      
// Parameters: 
//  
// GUID  rguidSchema    -  SchemaRowset IID 
// 
// 
// Return Value: 
//  
// Function Calls: 
//     Function                      Location 
//  
//   IDBCreateCommand::QueryInterface   QI 
//   IDBSchemaRowset->GetRowset  Clients Rowset pointer 
//     GetDataFromRowset                 query.cpp 
//  
//     IMalloc::Free                 OLE task memory allocator 
//  
//     assert                        c runtime 
//  
// Comments:       
//  
//        
//********************************************************************** 
void FAR PASCAL GetSchemaRowset(GUID rguidSchema) 
{ 
charszBuffer[MAXBUFLEN+1];// String Buffer 
HCURSORhOldCursor;// Default Cursor Handle 
IDBCreateCommand* pIDBCreate  = NULL;// IDBCreateCommand Object 
IDBSchemaRowset*pIDBSchemaRowset = NULL;// SchemaRowset Object 
ICommand*pICommand = NULL;// Command Object 
IRowset*pIRowset = NULL;// Rowset Object 
HRESULThr;// HRESULT 
 
// Check if there is an active window available 
if( !hWndActiveChild ) 
{ 
MessageBox( hWndFrame,  
((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ? 
MAKECONNECT : OPENWINDOW ),  
NOCOMMANDERROR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// Change cursor shape to hour glass 
hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); 
         
// Scan hdbc, hstmt values 
GetWindowText(hWndActiveChild, (char*)szBuffer, MAXBUFLEN); 
sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate, &pICommand); 
 
// QueryInterface for IDBSession::IDBSchemaRowset 
hr = pIDBCreate->QueryInterface( IID_IDBSchemaRowset, 
(LPVOID*)&pIDBSchemaRowset ); 
 
if (FAILED(hr)) 
{ 
        GetDetailedErrorInfo(hr, pIDBCreate, IID_IDBCreateCommand, "QI for IDBScemaRowset FAILED!!"); 
goto error; 
} 
 
// Get a SchemaRowset back 
hr = pIDBSchemaRowset->GetRowset( 
NULL,// punkOuter 
rguidSchema,// schema IID 
0L,// # of restrictions 
NULL,// array of restrictions 
IID_IRowset,// rowset interface 
0L,// # of properties 
NULL,// properties 
(IUnknown**)&pIRowset);// rowset pointer 
 
if (FAILED(hr)) 
{ 
        GetDetailedErrorInfo(hr, pIDBSchemaRowset, IID_IDBSchemaRowset, "IDBSchemaRowset->GetRowset FAILED!!"); 
goto error; 
} 
 
// Get Data from the IRowset Object 
hr = GetDataFromRowset( pIRowset ); 
 
if (FAILED(hr)) 
{ 
//DumpErrorHResult( hr, (LPSTR)"GetDataFromRowset returned error!!" ); 
goto error; 
} 
 
// Release Object 
pIDBSchemaRowset->Release(); 
    pIDBSchemaRowset = NULL; 
 
return; 
 
error:     
if( pIDBSchemaRowset ) 
pIDBSchemaRowset->Release(); 
 
return; 
} 
 
 
//********************************************************************** 
//  
// CleanupRowset 
//  
// Purpose: 
// 
//     Allows the rowset to perform any necessary cleanup. 
//   
// Parameters: 
// 
// IRowset*pIRowset    - interface pointer on data provider's Rowset 
//                            object 
// HACCESSOR hAccessor   - accessor handle to release 
//  
// Return Value: 
// 
//     S_OK        - Success 
//     E_*         - Failure 
//      
// Function Calls: 
//     Function                    Location 
//  
//     IRowset::QueryInterface     provider's Rowset object 
//     IAccessor::ReleaseAccessor  provider's Rowset object 
//     IAccessor::Release          provider's Rowset object 
//  
//     assert                      c runtime 
//  
//      
// Comments:       
// 
//     In this sample, the only cleanup that the rowset needs to do is 
//     release the accessor handle.  
//  
//********************************************************************** 
HRESULT CleanupRowset 
( 
IRowset*pIRowset, 
HACCESSOR hAccessor 
) 
{ 
IAccessor*pIAccessor = NULL;// Pointer to an Accessor 
HRESULThr;// HRESULT 
 
// Assert     
    assert(pIRowset != NULL); 
     
if( hAccessor ) 
{ 
// Tell the rowset object it can release the accessor, via IAccessor 
hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor ); 
 
if (FAILED(hr)) 
{ 
GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IAccessor FAILED!!"); 
goto error; 
} 
 
hr = pIAccessor->ReleaseAccessor( hAccessor, NULL ); 
if (FAILED(hr)) 
{ 
GetDetailedErrorInfo(hr, pIAccessor, IID_IAccessor, "IAccessor->ReleaseAccessor FAILED!!"); 
goto error; 
} 
 
pIAccessor->Release(); 
pIAccessor = NULL; 
} 
 
pIRowset->Release(); 
pIRowset = NULL; 
 
return S_OK; 
     
error:     
if( pIAccessor ) 
    pIAccessor->Release(); 
if( pIRowset ) 
pIRowset->Release(); 
 
    return hr;     
} 
 
 
//********************************************************************** 
//  
// DumpRow 
//  
// Purpose: 
// 
//     Display the row to the screen. 
//   
// Parameters: 
// 
//  
// Return Value: 
// 
//      
// Function Calls: 
//     Function                    Location 
//  
//     assert                      c runtime 
//  
//      
// Comments:       
// 
//  
//********************************************************************** 
void DumpRow 
( 
    DBBINDING* rgBind, 
    ULONGcBind, 
    ULONGcMaxColWidth, 
    BYTE* pData, 
HWNDhList, 
DWORDdwText, 
DWORDaddString 
    ) 
{ 
ULONG iBind;// Binding Count 
    COLUMNDATA*pColumn;// Data Structure 
intcb; 
CHARszTempString[MAXDISPLAYSIZE+1];// Temporary Display Buffer, used to check data length 
 
// Asserts 
assert(rgBind); 
assert( offsetof(COLUMNDATA, wStatus) == 0); 
     
// Print each column we're bound to. 
for (iBind=0, szDispBuffer[0]='\0'; iBind < cBind; iBind++) 
{ 
// Columns are bound differently; not so easy. 
// Print out to at least DEFAULT_CBMAXLENGTH width (pretty), 
// Limit to first dwLength characters. 
pColumn = (COLUMNDATA *) (pData + rgBind[iBind].obStatus); 
 
// Check Status for NULL / OK / CANTCONVERT. 
switch (pColumn->wStatus) 
{ 
case DBSTATUS_S_ISNULL: 
strcat(szDispBuffer, (LPSTR)"<NULL>"); 
break; 
case DBSTATUS_S_OK: 
// Truncate if needed. 
// - calculate number of bytes needed 
cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1, 
NULL, 0, NULL, NULL); 
if( cb > MAXCOLNDATALENGTH ) 
{ 
cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1, 
szTempString, MAXCOLNDATALENGTH, NULL, NULL); 
 
szTempString[MAXCOLNDATALENGTH] = '\0';   
strcat(szTempString, "..."); 
} 
else 
{ 
cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1, 
szTempString, (MAXDISPLAYSIZE+1), NULL, NULL); 
} 
 
strcat(szDispBuffer,szTempString); 
        break; 
 
case DBSTATUS_E_CANTCONVERTVALUE: 
strcat(szDispBuffer, "<can't convert value>"); 
break; 
default: 
{ 
CHAR szChar[10] = ""; 
strcat(szDispBuffer, "<unknown status of "); 
strcat(szDispBuffer, itoa(pColumn->wStatus, szChar, 10)); 
strcat(szDispBuffer, ">"); 
} 
break; 
} 
 
dwText = strlen(szDispBuffer); 
szDispBuffer[dwText++] = '\t'; 
szDispBuffer[dwText] = '\0'; 
} 
// Take the last \t off the end 
szDispBuffer[--dwText] = '\0'; 
SendMessage(hList, addString, 0, (LPARAM)(LPSTR)szDispBuffer); 
 
}     
 
//********************************************************************** 
//  
// GetDetailedErrorInfo 
//  
// Purpose: 
// 
//    Reads error from the error collection and displays it in messageboxes 
//   
// Parameters: 
// 
// HRESULThr- OLE DB HRESULT 
// IUnknown*  pBadObject       - Object that caused an error 
//  GUIDIID_BadInterface    - Interface that contains method that caused the error 
// LPSTR lpStrBuffer- Title Bar text 
// 
// Return Value: 
//      
// Comments:       
// If any sort of failure is encountered the return values will be NULL 
//   strings. Therefore no extended error info will be printed. 
//********************************************************************** 
 
HRESULT GetDetailedErrorInfo  
    ( 
HRESULThresult,  
IUnknown*pBadObject,                   
GUIDIID_BadIntereface,                  
LPSTRlpStrBuffer 
) 
{ 
IErrorInfo *        pErrorInfo = NULL;  
IErrorInfo *    pErrorInfoRec = NULL; 
IErrorRecords *     pErrorRecords = NULL; 
ISupportErrorInfo * pSupportErrorInfo = NULL; 
HRESULT             hr = S_OK; 
ULONG               i,ulNumErrorRecs; 
BSTRbstrDescriptionOfError = NULL; 
BSTRbstrSourceOfError = NULL; 
CHAR                szBuffer [512];  //Error Info Buffer 
    
// Check to see if this interface posts error messages 
if( SUCCEEDED( pBadObject->QueryInterface(IID_ISupportErrorInfo,  
(LPVOID FAR*)&pSupportErrorInfo)) )  
{ 
if( pSupportErrorInfo->InterfaceSupportsErrorInfo(IID_BadIntereface) == S_OK ) 
{ 
//Get Error Object. Return if no object Exists 
if( !SUCCEEDED(hr = GetErrorInfo(0,&pErrorInfo)) ) 
   goto DisplayHResult; 
 
// If returned a NULL error Object, then just display HR 
if( pErrorInfo == NULL ) 
goto DisplayHResult; 
 
//Get the IErrorRecord interface and get the count of error recs. 
if( FAILED(hr = pErrorInfo->QueryInterface(IID_IErrorRecords,(LPVOID FAR*)&pErrorRecords)) ) 
   goto DisplayHResult; 
 
//Retrieve the number of Error Records 
if( FAILED(hr = pErrorRecords->GetRecordCount(&ulNumErrorRecs)) ) 
   goto DisplayHResult; 
 
//Go through and print messages 
for(i=0; i<ulNumErrorRecs; i++)  
{ 
if( FAILED(hr = pErrorRecords->GetErrorInfo(i, GetUserDefaultLCID(), &pErrorInfoRec)) ) 
goto Exit; 
if( FAILED(hr = pErrorInfoRec->GetDescription(&bstrDescriptionOfError)) ) 
goto Exit; 
if( FAILED(hr = pErrorInfoRec->GetSource(&bstrSourceOfError)) ) 
goto Exit; 
 
sprintf(szBuffer, "HResult of 0x%0x (%ld) returned\nError Source: %S\nError Description: %S\n",  
(long)hresult,(long)hresult,  
bstrSourceOfError ? bstrSourceOfError : L"No Source Description", 
bstrDescriptionOfError ? bstrDescriptionOfError : L"No Error Description"); 
 
MessageBox( NULL, (LPCTSTR)szBuffer, lpStrBuffer, MB_OK); 
 
if (pErrorInfoRec)     
{ 
pErrorInfoRec->Release(); 
pErrorInfoRec = NULL; 
} 
if( bstrSourceOfError ) 
{ 
SysFreeString(bstrSourceOfError); 
bstrSourceOfError = NULL; 
} 
if( bstrDescriptionOfError ) 
{ 
SysFreeString(bstrDescriptionOfError); 
bstrDescriptionOfError = NULL; 
} 
} 
 
// if we've process all the records we can go to end 
goto Exit; 
 
} //S_OK 
} //if (SUCCEEDED) 
 
DisplayHResult: 
// In some error cases we may not have extended error information and it still would be good to 
// post the error HRESULT 
sprintf(szBuffer, "HResult of 0x%0x (%ld) returned, no Extended Error Information posted or supported",  
(long)hresult,(long)hresult); 
MessageBox( NULL, (LPCTSTR)szBuffer, lpStrBuffer, MB_OK); 
 
 Exit :  
if (pErrorInfo) 
pErrorInfo->Release(); 
if (pErrorRecords) 
pErrorRecords->Release(); 
if( pSupportErrorInfo ) 
pSupportErrorInfo->Release(); 
if( pErrorInfoRec ) 
pErrorInfoRec->Release(); 
if( bstrSourceOfError ) 
SysFreeString(bstrSourceOfError); 
if( bstrDescriptionOfError ) 
SysFreeString(bstrDescriptionOfError); 
 
 return hr; 
} //PrintErrorInfo 
 
 
//********************************************************************** 
//  
// DumpErrorHResult 
//  
// Purpose: 
// 
//     Dump the OLE DB HRESULT in a Message Box with a text Title Bar. 
//   
// Parameters: 
// 
// HRESULThr    - OLE DB HRESULT 
// 
// LPSTR lpStrBuffer - Title Bar text 
// 
//  
// Return Value: 
// 
//      
// Function Calls: 
//     Function                    Location 
//  
//     assert                      c runtime 
//  
//      
// Comments:       
// 
//  
//********************************************************************** 
void DumpErrorHResult( HRESULT hr, LPSTR lpStrBuffer ) 
{ 
LPVOIDlpMessageBuffer; 
 
if(0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM, 
NULL, 
hr, 
GetUserDefaultLCID(), 
(LPSTR)&lpMessageBuffer, 
0, 
NULL)) 
{ 
MessageBox( NULL, (LPCTSTR)lpMessageBuffer, lpStrBuffer, MB_OK); 
LocalFree(lpMessageBuffer); 
} 
else 
{ 
lpMessageBuffer = LocalAlloc(LPTR, 256); 
 
if( lpMessageBuffer ) 
{ 
sprintf((LPSTR)lpMessageBuffer, "HResult of %ld returned", (long)hr); 
MessageBox( NULL, (LPCTSTR)lpMessageBuffer, lpStrBuffer, MB_OK); 
LocalFree(lpMessageBuffer); 
} 
} 
} 
 
//********************************************************************** 
//  
// NewIOpenRowsetWindow 
//  
// Purpose: 
//  
//     Create a new ICommand Object on the current IDBCreateCommand. 
//      
// Parameters: 
//  
// Return Value: 
//  
// Function Calls: 
//     Function                         Location 
//  
//   IDBCreateCommand::CreateCommandprovider's Command object 
//     ICommand::Release                provider's Command object 
//     
//      
// Comments:       
//  
//  
//********************************************************************** 
void FAR PASCAL NewIOpenRowsetWindow() 
{ 
int nCurrenthdbc;// Current PROVIDER 
charszBuffer[MAXBUFLEN+1];// String in PROVIDER ComboBox on Toolbar 
charszProvName[MAXBUFLEN+1];// DSN String 
MDICREATESTRUCTmcs;                    // MDI Child Window Create Struc 
 
IOpenRowset * pIOpenRowset= NULL;// IOpenRowset Object 
 
         
// check if there is PROVIDER selected in the Combo-Box 
if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR) 
{ 
MessageBox(hWndFrame, MAKECONNECT, NOSESSIONERROR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// check if the number of windows exceeds MAXCHILDWNDS 
if (nChildCount >= MAXCHILDWNDS) 
{ 
MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND); 
return; 
} 
 
// Scan PROVIDER string and IDBCreateCommand value from the combo-box 
SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer); 
 
 sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIOpenRowset); 
 
// create a new MDI client window. maximized, if the previous is so. 
mcs.szClass = OLEDBMDICLASS; 
mcs.szTitle = UNTITLED; 
mcs.hOwner  = hAppInstance; 
mcs.style   = hWndActiveChild && IsZoomed(hWndActiveChild) ? WS_MAXIMIZE : 0; 
mcs.x = mcs.cx = mcs.y = mcs.cy = CW_USEDEFAULT; 
hWndActiveChild = (HWND)(UINT)SendMessage(hWndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mcs); 
         
    // check if it was created, if it wasn't free up resource and flag warning 
    if (!hWndActiveChild) 
    { 
MessageBox(hWndFrame, CREATECHILDERR, EXECERROR, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL); 
return; 
    } 
         
// Display the Provider string, PROVIDER and IOpenRowset in the title 
// of newly created window. Increment the child window counter 
wsprintf(szBuffer, QUERY_STRING, pIOpenRowset); 
 
SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
wsprintf(szBuffer, PROVIDER_SESSION_COMMAND_FORMAT, (LPSTR)szProvName, pIOpenRowset, NULL); 
 
SetWindowText(hWndActiveChild, szBuffer); 
nChildCount++; 
 
// Update the Command Combo-Box on the tool bar. 
ChangeCurrentICommand(hWndStmtList); 
}