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);
}